Aller au contenu

Database Guidelines

Status: CONTRACT

Rôle

Cette page définit les règles de conception à respecter lorsqu'on fait évoluer la persistance de CMonChoix Platform.

Elle ne décrit pas un schéma précis et ne prouve pas l'existence d'une table ou d'un service dans le Runtime courant. Elle sert de garde-fou pour décider stocker une donnée, qui a le droit de l'écrire et comment vérifier qu'une évolution reste compatible avec l'architecture.

Principe central

La Database conserve des états. Elle ne décide pas de leur signification métier.

Sources marchandes
      ↓
Pipeline / normalisation / enrichissement
      ↓
Domain Core + Vertical Modules
      ↓
Décision ou état métier
      ↓
Builder / Write Service
      ↓
Persistance
      ↓
Readers / Frontend / Runtime

Une valeur présente dans SQL n'est donc pas une preuve suffisante de vérité métier. Il faut connaître sa provenance, son statut et la couche qui l'a produite.

Concevoir une nouvelle structure

Avant de créer une table, une colonne ou un index, répondre explicitement à ces questions :

  1. quelle responsabilité cette structure porte-t-elle ?
  2. s'agit-il d'une donnée source, intermédiaire, métier, dérivée ou technique ?
  3. quelle couche la produit ?
  4. quel Write Service ou mécanisme de persistance l'écrit ?
  5. quels Readers la consomment ?
  6. est-elle reconstruisible ?
  7. quelles informations de traçabilité sont nécessaires ?
  8. comment sera-t-elle migrée, sauvegardée et vérifiée ?

Si plusieurs responsabilités apparaissent dans la même réponse, la structure est probablement trop large.

Une responsabilité par structure

Séparer autant que possible :

  • données d'import ou de Stage ;
  • états intermédiaires de traitement ;
  • résultats métier ;
  • projections ;
  • historique ;
  • caches ;
  • états techniques d'exécution.

Une table ne doit pas devenir simultanément source métier, cache de lecture et journal d'exécution.

Cette règle n'interdit pas qu'une structure comporte des métadonnées techniques utiles à sa traçabilité ; elle interdit de lui attribuer plusieurs autorités fonctionnelles concurrentes.

Ne pas déplacer la logique métier dans SQL

La Database peut imposer des contraintes techniques : types, unicité, clés, index, relations ou garanties de stockage.

Elle ne doit pas décider :

  • si deux produits sont identiques ;
  • si une résolution doit devenir resolved ;
  • si un cas ambiguous ou conflict doit être forcé ;
  • quelle règle spécifique s'applique à une verticale ;
  • quel produit doit être mis en avant ;
  • quelle offre est « meilleure » selon une politique métier.

Ces décisions appartiennent au Domain Core, aux Vertical Modules ou aux services applicatifs prévus à cet effet.

Préserver les statuts d'incertitude

Les statuts resolved, unknown, ambiguous et conflict décrivent des résultats métier différents.

Une évolution du schéma ne doit pas :

  • transformer automatiquement unknown en absence de ligne ;
  • fusionner ambiguous et conflict dans une catégorie générique d'erreur ;
  • considérer resolved comme simple conséquence de la présence d'un identifiant ;
  • supprimer les reason codes ou preuves nécessaires au diagnostic.

La persistance doit permettre de relire l'incertitude, pas seulement le résultat positif.

Données dérivées et projections

Une projection ou un cache est dérivé et doit rester reconstruisible.

Le flux attendu est :

Données de référence
    ↓
Builder déterministe
    ↓
Résultat en mémoire
    ↓
Write Service explicite
    ↓
Projection persistée

Le Builder décide les lignes ou le modèle projeté. Le Write Service contrôle l'écriture. Le Frontend et les Readers consomment le résultat sans le corriger.

Une projection persistée ne doit pas devenir une nouvelle source de vérité simplement parce qu'elle est facile à requêter.

Traçabilité minimale

Pour toute donnée importante, il doit être possible de retrouver selon le cas :

  • le run, snapshot ou batch ;
  • la source ou le feed ;
  • la version de code ou de règle ;
  • la date de production ;
  • le statut ;
  • les raisons ou avertissements ;
  • l'opération d'écriture ayant produit l'état.

La traçabilité doit être proportionnée au risque et au besoin de reconstruction. Elle ne justifie pas de transformer chaque table en journal exhaustif.

Optimiser après mesure

Une optimisation Database doit répondre à un problème mesuré : latence, volume, contention, temps de rebuild ou coût de lecture.

Avant de modifier index, structure ou cache :

  1. établir une baseline ;
  2. identifier la requête ou le chemin réellement coûteux ;
  3. vérifier que le problème n'est pas dans une mauvaise couche ;
  4. tester la modification sur un périmètre représentatif ;
  5. comparer les performances et la cohérence ;
  6. vérifier qu'aucun contrat de lecture n'est cassé.

Une optimisation qui change la signification fonctionnelle des données n'est plus une optimisation technique.

Évolutions et migrations

Une évolution de schéma potentiellement destructive suit le cycle :

Observation
  ↓
Conception
  ↓
Simulation / dry-run lorsque possible
  ↓
Sauvegarde ou stratégie de restauration
  ↓
Migration explicite
  ↓
Reconstruction ciblée si nécessaire
  ↓
Audit et vérification

Ne jamais utiliser une requête SQL manuelle en production comme substitut silencieux d'une migration ou d'un Write Service réutilisable.

Ce qu'une observation SQL permet de conclure

Une requête read-only est utile pour :

  • compter des lignes ;
  • vérifier des valeurs ou nullabilités ;
  • repérer doublons ou relations cassées ;
  • comparer deux snapshots ou projections ;
  • mesurer la fraîcheur d'un état.

Elle ne suffit pas, à elle seule, à conclure :

  • qu'une règle métier est correcte ;
  • qu'une identité devrait être fusionnée ;
  • qu'un statut doit être changé ;
  • qu'une projection doit être réparée manuellement.

Il faut relier l'observation au Domain Core, aux contrats et aux audits concernés.

Vérification avant merge

Pour une évolution Database significative :

  • vérifier le sens fonctionnel de la structure ;
  • identifier readers et writers concernés ;
  • vérifier les migrations et le rollback ;
  • tester l'idempotence lorsque l'opération peut être rejouée ;
  • vérifier les compteurs et erreurs partielles ;
  • exécuter les audits pertinents ;
  • reconstruire les projections concernées si le contrat le demande ;
  • confirmer que les contextes read-only ne déclenchent aucune installation ou migration implicite.

Anti-patterns

Éviter notamment :

  • une table « fourre-tout » ;
  • un SQL frontend qui reconstruit une décision métier ;
  • un UPDATE manuel sur une projection pour masquer un bug amont ;
  • une vue SQL qui devient propriétaire d'une règle métier ;
  • un cache utilisé comme référence lors d'un rebuild ;
  • une migration cachée dans un bootstrap passif ;
  • une colonne ajoutée sans owner, cycle de vie ni stratégie de dépréciation ;
  • un statut d'incertitude supprimé pour simplifier les requêtes.

Invariants

  1. La Database persiste ; elle ne décide pas la vérité métier.
  2. Chaque structure possède une responsabilité identifiable.
  3. Les projections et caches restent dérivés et reconstruisibles.
  4. Les écritures importantes sont explicites et traçables.
  5. Les statuts d'incertitude restent représentables.
  6. Une optimisation ne modifie pas le sens fonctionnel.
  7. Une évolution destructive dispose d'une procédure de migration et de vérification.
  8. Le Frontend ne corrige pas directement les données persistées.
  9. Les contextes read-only ne doivent pas muter le schéma par effet de bord.

Voir aussi