Be Software Architecture Wise
Be Wise Apps

Read in English · Leer en español · Auf Deutsch lesen

Section 7.1 sur 7.8 · Intermédiaire · 24 min de lecture

Propriété des données et base de données par service

Leçon vidéo

5 min · narré en anglais, avec sous-titres
Écouter seulement (audio)
Lire la transcription

Le code se découpe assez facilement en services ; les données, non. Dans cette leçon, vous allez découvrir la première et la plus importante question sur les données : à qui appartient chaque donnée.

Imaginez un tableau d’affichage de cuisine où n’importe qui peut effacer et réécrire les commandes du jour. Avec deux cuisiniers, cela fonctionne. Avec dix, des commandes sont écrasées et personne ne sait qui a changé quoi. Une cuisine mieux organisée donne à chaque poste son propre tableau. Le grill écrit les commandes du grill. Les autres postes les lisent, ou demandent au grill de les modifier. C’est cela, la propriété des données : décider quelle partie d’un système a le droit de modifier chaque information.

Un système de référence est la source qui fait autorité pour une donnée : l’endroit dont la valeur l’emporte quand les copies divergent. Dans une banque en ligne, le grand livre central est le système de référence des soldes. Le solde affiché dans l’application mobile est une copie. Le propriétaire est le seul composant qui écrit les données, fait respecter leurs règles, décide de leur schéma et les publie pour les autres. Une règle utile : le service qui écrit dans une table en est le propriétaire.

Ce schéma montre deux façons de fournir leurs données à trois services d’une plateforme de livraison de repas. À gauche, ils partagent tous une seule base de données. Chaque table devient une interface publique : renommer une colonne peut donc casser des services dont personne ne savait qu’ils la lisaient, et les modifications de schéma exigent une mise en production coordonnée. Les règles métier se retrouvent aussi dupliquées dans chaque service qui écrit dans une table, et le gros rapport d’un service ralentit tous les autres. À droite, la base de données par service. Chaque schéma est privé, il n’y a pas de jointures entre bases de données, et les données ne franchissent les frontières que par des appels d’API et des événements. Chaque propriétaire peut modifier son schéma seul. Le prix à payer : les jointures, les transactions et les contrôles d’intégrité entre services doivent être remplacés par des API, des événements, des sagas et des pipelines de reporting.

La propriété se complique quand deux services modifient tous deux les mêmes données. C’est la propriété conjointe, et il existe quatre façons de la résoudre. Vous pouvez scinder la table, pour que chaque service possède les colonnes qu’il écrit. Vous pouvez garder un petit domaine de données partagé : c’est simple, mais c’est une base de données partagée volontairement limitée. Vous pouvez déléguer : choisir un seul propriétaire, et faire en sorte que l’autre service lui envoie des demandes au lieu d’écrire. C’est la réponse la plus courante pour les commandes, les paiements et les réservations. Ou vous pouvez fusionner les services, la réponse honnête quand ils ont été découpés trop finement.

Voici un exemple commenté. Trois services écrivent tous la colonne de statut d’une même table des commandes partagée, et des clients ont vu des commandes repasser de « récupérée » à « en préparation ». C’est une propriété conjointe. La dernière écriture l’emporte, des messages tardifs font reculer le statut, et la règle d’annulation est vérifiée dans deux services, différemment. Le geste décisif est de remarquer qu’une seule colonne cache trois faits : l’état du bon de cuisine, l’état de la mission de livraison, et le statut que voit le client, qui combine les deux. Une scission de table a été rejetée, car la règle d’annulation n’aurait toujours pas eu de place. La fusion a été rejetée elle aussi : trois équipes, avec des charges très différentes. Commandes devient donc le seul rédacteur du statut de commande. Le statut ne fait qu’avancer : un message tardif est enregistré, mais ne peut pas le faire reculer.

Voici le résultat. Les services Restaurants et Livraison possèdent leurs propres faits, et publient des événements comme FoodReady et PickedUp. Le service Commandes est le seul rédacteur du statut, et le stocke dans sa propre base de données. Une annulation venant du restaurant est une demande adressée à son API, qu’il peut accepter ou refuser. Tous les autres, comme l’app client et l’outil de support, lisent le statut par l’API. Chaque fait a exactement un seul rédacteur.

Les autres services peuvent appeler l’API du propriétaire, ce qui donne des données à jour mais les lie à lui, ou garder une copie locale alimentée par des événements, ce qui est rapide mais cohérent à terme seulement. L’erreur courante est de laisser une copie devenir un maître. Dès qu’un lecteur corrige sa propre copie, il existe deux systèmes de référence, et ils vont diverger. Entre équipes, un contrat de données précise le schéma, la signification de chaque champ, les attentes de qualité et la fraîcheur, idéalement vérifiés automatiquement. Donc, pour chaque fait important, demandez-vous : qui est le seul rédacteur, où ses règles sont-elles appliquées, et à quel point chaque copie peut-elle être périmée ? Si l’une des réponses est « ça dépend », la conception n’est pas terminée.

La section complète traite aussi en détail du reporting transversal aux services et des contrats de données. Ensuite, dans la section sept point deux, nous verrons comment choisir une base de données. À très vite.

Ce qu’il faut savoir

Pourquoi la propriété est la première question sur les données

Le chapitre 6 a découpé les systèmes en services déployés, mis à l’échelle et modifiés indépendamment. Le code se découpe assez facilement ; les données, non. Une commande fait référence à un client, à un plat de la carte, à un restaurant et à un livreur, et chaque équipe veut lire, et souvent modifier, une partie de ces informations. La question la plus importante d’une architecture de données distribuée n’est donc pas de savoir quelle base de données acheter, mais à qui appartient chaque donnée : quel composant a le droit de la modifier, lequel applique ses règles, et comment tous les autres peuvent la voir.

La propriété compte parce que les données survivent au code. Les services sont réécrits tous les quelques ans ; les comptes clients, les grands livres et les dossiers médicaux sont conservés pendant des décennies. Se tromper sur la propriété produit le type coûteux de dette architecturale : deux services qui ne peuvent pas être mis en production séparément parce qu’ils partagent des tables, un champ de statut que trois équipes écrasent tour à tour, ou un rapport mensuel que personne ne peut reproduire parce que les chiffres viennent de cinq copies discordantes des mêmes données.

Cette section utilise deux exemples récurrents qui reviennent tout au long du chapitre : une plateforme de livraison de repas (clients, restaurants, livreurs, commandes) et une banque en ligne (clients, comptes, paiements, grand livre).

Système de référence et propriété des données

Un système de référence (system of record) est la source qui fait autorité pour une donnée : l’endroit dont la valeur l’emporte quand les copies divergent. Dans la banque, le grand livre central est le système de référence des soldes des comptes ; le solde affiché dans l’application mobile, celui du cache du moteur antifraude et celui du chargement de la nuit dernière dans l’entrepôt de données sont tous des copies. Dans la plateforme de livraison de repas, le service de carte propre au restaurant est le système de référence des prix, même si l’index de recherche, le cache hors ligne de l’application mobile et les lignes de commande en détiennent tous des copies.

La propriété des données transforme cela en responsabilité. Le composant propriétaire (et l’équipe qui en a la charge) est le seul à écrire les données, à faire respecter leurs invariants (des règles qui doivent toujours être vraies, comme une écriture du grand livre n’est jamais modifiée, seulement contrepassée), à décider de leur schéma et à les publier pour les autres au moyen d’une interface qu’il contrôle. La propriété est une décision de conception, pas une propriété de la base de données : deux services peuvent résider sur le même serveur de base de données et avoir malgré tout une propriété claire, et deux services dotés de bases séparées peuvent encore se disputer les mêmes faits si la frontière entre eux est mal tracée.

Une règle utile tirée de Software Architecture: The Hard Parts (Neal Ford, Mark Richards, Pramod Sadalage et Zhamak Dehghani, 2021) veut que le service qui écrit dans une table en soit le propriétaire. La lecture se partage à peu de frais ; l’écriture, non, car celui qui écrit doit faire respecter les règles.

La base de données partagée, et pourquoi elle couple les services

La façon la plus simple de permettre à plusieurs applications de travailler sur les mêmes données est de leur donner à toutes accès à une seule base de données. Martin Fowler a appelé cela une base de données d’intégration (2004) : une base qui constitue le point d’intégration entre des applications, par opposition à une base de données d’application qui ne sert qu’une seule application. Elle semble séduisante : aucune API à construire, les jointures fonctionnent sur tout, et une seule transaction peut mettre à jour ensemble les commandes et les paiements. Le verdict de Fowler, partagé par la plupart des architectes, est qu’il faut éviter les bases de données d’intégration, car le couplage qu’elles créent est profond et en grande partie invisible.

Considérez les formes de couplage qu’elle introduit. Couplage de schéma : chaque table et chaque colonne est de fait une API publique. Renommer orders.state en orders.status casse tout service qui la lit, et personne ne peut savoir avec certitude lesquels le font, car les requêtes SQL sont dispersées dans de nombreuses bases de code, rapports et tableurs. Couplage de déploiement : une modification de schéma doit être coordonnée entre toutes les équipes qui touchent la table, si bien que des services censés être mis en production indépendamment le sont ensemble. Couplage sémantique : le schéma doit servir tous les clients, il devient donc plus général et plus confus (Fowler note qu’il finit par tenter d’unifier des concepts qui relèvent de contextes délimités distincts), et les règles métier d’une table finissent dupliquées, de façon incohérente, dans chaque service qui l’écrit. Couplage à l’exécution : la requête de reporting lente ou le traitement par lots gourmand en verrous d’un service dégrade tous les autres services, et la base de données devient un point de défaillance unique partagé et un plafond pour le nombre de connexions.

Rien de tout cela n’est fatal pour une application unique ou pour un monolithe modulaire dont les modules respectent les tables les uns des autres, ni pour l’architecture à base de services à gros grain, dans laquelle une poignée de services de domaine partagent souvent délibérément une base de données. Cela devient un problème quand les équipes attendent une déployabilité indépendante mais conservent les tables partagées, ce qui est une voie classique vers un monolithe distribué.

Base de données partagée ou base de données par service

À gauche : trois services lisent et écrivent les mêmes tables d’une base partagée. À droite : chaque service a une base privée, et les autres n’accèdent à ses données que par son API ou ses événementsBD partagée (d’intégration)Base de données par serviceCommandesCuisineLivraisonUne seule BDcommandes, cartes,livreurs : tout partagétout service peut lireou modifier toutmodif. de schéma = mise en prod. communeCommandesCuisineLivraisonBD CmdesBD CartesBD LivreursAPI et événementsseulement entre serviceschaque schéma est privé ;aucune jointure entre BDpropriétaire maître du schéma
Avec une base de données partagée, chaque table est une interface publique ; avec une base de données par service, chaque schéma est privé et les données ne franchissent les frontières que par des API et des événements.

Base de données par service

L’alternative, associée aux microservices, est le patron base de données par service : les données persistantes de chaque service lui sont privées, et les autres services ne peuvent y accéder que par l’API du service ou les événements qu’il publie. Le catalogue de patrons de Chris Richardson (microservices.io) note que cela ne signifie pas forcément un serveur distinct par service. Il existe trois niveaux de séparation, et la ligne importante est la première.

Trois façons de garder privées les données d’un service

NiveauCe qui est séparéSolidité de la frontièreUsage typique
Tables privées par serviceChaque service a son propre ensemble de tables dans une base de données partagée, avec des identifiants distincts qui ne donnent accès qu’à ces tables.La plus faible : repose sur les permissions et la discipline ; partage encore la capacité et les défaillances.Au début d’une migration ; petits systèmes ; monolithes modulaires.
Schéma par serviceChaque service a son propre schéma (espace de noms) sur un serveur partagé.Propriété et contrôle d’accès clairs ; partage encore les performances et la disponibilité du serveur.La plupart des équipes qui débutent avec plusieurs services ; moins coûteux à exploiter.
Serveur de base de données par serviceChaque service a sa propre instance de base de données, éventuellement d’un type différent.La plus forte : mise à l’échelle, défaillances et choix technologiques séparés.Services dont la charge, la forme des données ou les besoins de disponibilité sont très différents.

Les avantages sont le reflet des coûts de la base partagée : les propriétaires modifient librement leurs schémas, mettent à l’échelle et règlent leurs bases indépendamment, choisissent le bon type de base de données et circonscrivent les défaillances. Les coûts sont réels et doivent être indiqués dans tout enregistrement de décision. Les jointures entre services disparaissent et doivent être remplacées par une composition d’API ou des données répliquées. Une seule transaction ACID ne peut plus couvrir à la fois les commandes et les paiements ; les changements entre services deviennent des sagas avec des étapes de compensation. L’intégrité référentielle entre services (chaque commande pointe vers un client réel) n’est plus garantie par des clés étrangères. Le reporting exige un pipeline distinct. Et il y a davantage de bases de données à sauvegarder, à mettre à jour et à superviser.

The Hard Parts présente la décision comme un équilibre de forces. Les désintégrateurs poussent à séparer les données : le contrôle des changements (combien de services cassent quand une table change), les limites de connexions, la scalabilité, la tolérance aux pannes, le souhait d’unités déployables indépendamment et le besoin de types de bases de données différents. Les intégrateurs rassemblent les données : les relations qui exigent l’intégrité référentielle, et les opérations qui ont réellement besoin d’une seule transaction atomique. Si deux tables sont toujours modifiées ensemble dans une même transaction et n’ont pas de vie indépendante, c’est un indice fort qu’elles appartiennent au même propriétaire.

Quand plusieurs services écrivent les mêmes données

Les questions de propriété deviennent difficiles quand plus d’un service modifie légitimement la même entité. The Hard Parts distingue trois situations. En propriété unique, un seul service écrit dans la table, et il en est simplement le propriétaire. En propriété commune, la plupart des services écrivent dans la même table (un journal d’audit ou un ensemble de paramètres de configuration, par exemple) ; la réponse habituelle est de créer un service dédié qui possède les données et de donner une API à tous les autres, souvent asynchrone pour ne pas ralentir les rédacteurs. En propriété conjointe, un petit nombre de services, généralement deux, écrivent dans la même table, le plus souvent au sein du même domaine. Le livre propose quatre techniques pour la propriété conjointe.

Résoudre la propriété conjointe

TechniqueComment ça marchePrincipal compromis
Scission de tableScinder la table pour que chaque service possède, dans sa propre table, les colonnes qu’il écrit. Dans la plateforme de livraison de repas, la ligne orders devient une commande possédée par Commandes et un bon de cuisine possédé par Cuisine.Propriété nette, mais la création ou la suppression de l’entité parente doit désormais être synchronisée entre services, et toute vue d’ensemble a besoin des deux.
Domaine de donnéesGarder la table partagée entre les quelques services concernés, dans un petit schéma partagé qu’ils contrôlent conjointement.Simple et rapide, et les transactions restent possibles, mais c’est une base de données partagée volontairement limitée : les services sont couplés lors des changements de schéma et la frontière entre eux s’affaiblit.
DélégationChoisir un seul propriétaire ; l’autre service lui envoie des demandes (appels synchrones ou commandes asynchrones) au lieu d’écrire. Le propriétaire est choisi selon le domaine principal (à qui appartient ce concept ?) ou selon les caractéristiques opérationnelles (quel service a besoin des écritures les plus rapides et les plus disponibles ?).Propriété et règles claires, en un seul endroit, au prix d’un saut réseau supplémentaire, d’un nouveau mode de défaillance et éventuellement d’une cohérence à terme pour le service qui délègue.
Consolidation des servicesFusionner en un seul service les services qui partagent les données.Supprime le problème et rétablit les transactions locales, mais crée un service plus gros, dont le déploiement, la mise à l’échelle et l’isolation des pannes sont plus grossiers.

Aucune technique n’est gratuite, et la bonne dépend de la fréquence à laquelle les données changent, de la rigueur de leurs règles et du degré d’indépendance nécessaire aux équipes. En pratique, la délégation est la réponse la plus courante pour les entités métier dotées d’un cycle de vie (commandes, paiements, réservations), la scission de table fonctionne bien quand les colonnes écrites conjointement sont en réalité des faits différents qui se trouvaient stockés ensemble, et la consolidation est la réponse honnête quand les deux services ont été découpés trop finement dès le départ.

Lire des données dont vous n’êtes pas propriétaire

Une fois la propriété établie, tous les autres services ont encore besoin de lire les données. L’écran de la cuisine a besoin des instructions de livraison du client ; le moteur antifraude a besoin des paiements récents du compte. Il existe quatre grandes options, et chacune arbitre entre fraîcheur et couplage. Notez que les conceptions pilotées par les événements, traitées au chapitre 6, fournissent la troisième et la quatrième.

Façons de lire les données d’un autre service

OptionComment ça marcheFraîcheurCouplage et coût
Appel synchroneInterroger l’API du propriétaire au moment où les données sont nécessaires.À jour, au moment de l’appel.Couplage à l’exécution : si le propriétaire est lent ou en panne, l’appelant l’est aussi ; les latences s’additionnent le long d’une chaîne.
Réplication de colonnesCopier les quelques colonnes nécessaires (par exemple le nom et l’adresse du restaurant) dans la propre base de données du lecteur, tenues à jour par des événements ou par capture des données modifiées.Cohérence à terme : périmé du délai de réplication.Lectures et jointures locales rapides ; le lecteur doit gérer les mises à jour tardives ou manquées et ne doit jamais écrire dans la copie.
Cache répliquéUne grille de données en mémoire (comme Hazelcast ou Apache Ignite) conserve une copie des données du propriétaire dans chaque service consommateur, synchronisée par la grille.Quasi temps réel.Lectures très rapides ; coût mémoire, chargement au démarrage et complexité opérationnelle de la grille.
Événements (transfert d’état porté par les événements)Le propriétaire publie des événements qui transportent les données modifiées ; les lecteurs conservent ce dont ils ont besoin.Cohérence à terme.Couplage temporel faible ; les lecteurs doivent gérer les doublons, l’ordre et l’évolution des schémas.

Fowler appelle la quatrième option transfert d’état porté par les événements (event-carried state transfer) : des événements comme MenuItemPriceChanged transportent les nouvelles valeurs, si bien que les consommateurs n’ont pas besoin de rappeler le propriétaire. Un mécanisme apparenté, la capture des données modifiées (CDC), lit le journal de la base de données du propriétaire et transforme chaque changement validé en événement, ce qui évite le problème de la double écriture (écrire dans la base de données et publier un événement séparément, si bien que l’un peut réussir et l’autre échouer). L’outbox transactionnelle, qui résout le même problème depuis l’intérieur de l’application, est traitée avec les sagas.

Le reporting transversal aux services

La base de données par service complique une tâche ancienne : le rapport transversal. Le chiffre d’affaires par restaurant et par semaine, net des remboursements, ventilé par type de livreur exige les commandes, les paiements, les restaurants et les livraisons. Le produire en appelant quatre API page par page est lent et fait peser la charge du reporting sur les services opérationnels. Interroger directement leurs bases de données réintroduit par la petite porte le couplage de la base partagée.

La réponse habituelle consiste à séparer le reporting des opérations. Fowler a décrit une base de données de reporting : une base distincte, conçue pour les requêtes et alimentée par les systèmes opérationnels, que les utilisateurs du reporting peuvent lire librement. Aujourd’hui, il s’agit généralement d’un entrepôt de données ou d’un lakehouse alimenté par CDC ou par des événements, traité dans analytique et streaming. Pour de petites vues en quasi temps réel au sein du produit (le tableau de bord des commandes du jour d’un restaurant), un service peut construire son propre modèle de lecture à partir d’événements, l’idée à la base de CQRS. Dans les deux cas, les pipelines qui alimentent le reporting dépendent des structures de données des propriétaires, et c’est pourquoi ils ont besoin de contrats.

Contrats de données

Un contrat de données est un accord explicite et versionné entre le propriétaire d’un jeu de données et ses consommateurs. Il précise le schéma (champs, types, lesquels peuvent être nuls), la signification de chaque champ (amount est-il en pence ou en livres, TVA comprise ou non ?), les attentes de qualité (aucun identifiant de commande en double, au plus 0,1 % de lignes sans restaurant), les niveaux de service (fraîcheur des données, durée de conservation), le propriétaire et la manière dont les changements sont annoncés. Il applique l’idée d’un contrat d’API aux données qui circulent entre équipes au moyen d’événements, de flux CDC et de tables d’entrepôt de données.

Les contrats sont surtout utiles lorsqu’ils sont lisibles par une machine et vérifiés automatiquement : un pipeline qui rejette une modification de schéma qui casserait des consommateurs enregistrés, ou un test qui échoue quand une règle de qualité est enfreinte. L’Open Data Contract Standard (ODCS), maintenu par le projet Bitol au sein de la Linux Foundation AI & Data, définit un format YAML couvrant le schéma, les règles de qualité, les niveaux de service, les rôles et les canaux d’assistance. Les contrats de données ne sont pas gratuits : quelqu’un doit les rédiger et les maintenir, et des contrats trop stricts ralentissent le changement. The Hard Parts oppose les contrats stricts (précis, vérifiables, fortement couplants) aux contrats souples (plus faciles à faire évoluer, mais demandant davantage de tests), et propose comme voie médiane les contrats pilotés par le consommateur, dans lesquels les consommateurs indiquent ce qu’ils utilisent réellement. La manière de modifier un schéma sans casser les consommateurs fait l’objet de l’évolution des schémas.

Exemple commenté

Exemple commenté : à qui appartient le statut des commandes dans la plateforme de livraison de repas ?

La plateforme compte trois services qui s’intéressent à l’avancement d’une commande : Commandes (prend les commandes et les fait payer), Restaurants (la tablette de la cuisine : accepte les commandes, signale que les plats sont prêts) et Livraison (affecte les livreurs, suit la récupération et la remise). Aujourd’hui, les trois écrivent la colonne status d’une table orders partagée. Des clients ont vu des commandes repasser de Récupérée à En préparation, et personne ne sait dire où se trouvent les règles d’annulation.

DiagnosticPropriété conjointe d’une colonne par trois rédacteurs. Chacun écrit ce qu’il sait, la dernière écriture l’emporte, et des messages tardifs font reculer le statut. La règle une commande ne peut être annulée qu’avant que la cuisine commence est vérifiée dans deux services, différemment.
Séparer les faitsIl y a en réalité trois faits : l’état du bon de cuisine (possédé par Restaurants), l’état de la mission de livraison (possédé par Livraison) et le statut de la commande présenté au client, qui combine les deux et porte les règles métier (annulation, remboursements, dédommagement).
Option : scission de tableDonner à chaque service sa propre colonne de statut et laisser les lecteurs les combiner. Rejetée : chaque lecteur (app, outil de support, notifications) réimplémenterait la combinaison, et la règle d’annulation n’aurait toujours pas de place.
Option : consolidation des servicesFusionner les trois en un seul service. Rejetée : trois équipes, des charges très différentes (les mises à jour de position des livreurs arrivent toutes les quelques secondes) et des cycles de mise en production différents.
Décision : délégationCommandes est le seul rédacteur de order_status. Restaurants et Livraison possèdent leurs propres faits et publient des événements (OrderAccepted, FoodReady, PickedUp, Delivered). Commandes les consomme et applique une machine à états. Une annulation depuis la tablette du restaurant est une demande adressée à l’API de Commandes, qui l’accepte ou la refuse.
Machine à étatsPLACED, ACCEPTED, PREPARING, READY, PICKED_UP, DELIVERED, avec CANCELLED autorisé seulement depuis PLACED ou ACCEPTED. Les transitions ne vont que vers l’avant : un FoodReady tardif qui arrive après PickedUp est enregistré mais ne change pas le statut ; les doublons sont ignorés.
ConséquencesUn seul endroit pour les règles ; plus de retours en arrière ; chaque équipe met en production indépendamment. Coûts : le statut est en retard sur la cuisine du délai des événements (généralement bien moins d’une seconde), Commandes doit être disponible pour accepter les annulations, et les événements deviennent un contrat qui doit être versionné.

Le geste décisif n’a pas été de choisir une technique dans le tableau, mais de remarquer qu’une seule colonne cachait trois faits différents, avec trois propriétaires naturels.

Consignez la décision dans un enregistrement de décision d’architecture (ADR), en incluant les options rejetées ; la prochaine équipe qui demandera pourquoi ne pas simplement mettre à jour le statut depuis l’app du livreur ? en aura besoin.

Le statut des commandes après la décision

Les services Restaurants et Livraison possèdent leurs propres faits et publient des événements ; le service Commandes les consomme et est le seul rédacteur du statut de commande, que les clients et le support lisent via son APIService Restaurantspossède le bonacceptée, prêteService Livraisonpossède la missionaffectée, récupéréeOrderAccepted,FoodReadyPickedUp,Delivereddemande annul. (API)Commandesseul à écrireorder_status(machine à états)OrderCancelledBD CmdesApp clientlit le statut par APIOutil supportlit le statut par APIChaque fait a un seul rédacteur ; les autres lisent ou demandent
Chaque fait a un seul rédacteur : Restaurants et Livraison publient ce qu’ils possèdent, et le service Commandes est le seul à transformer ces événements en statut présenté au client.

Erreurs courantes

Découper les services mais garder les tables partagées. Les équipes subissent le coût opérationnel de la distribution sans l’indépendance qu’elle devait apporter. Si des services ne peuvent pas être déployés sans coordonner une modification de schéma, ils ne sont pas indépendants. Les services d’entité. Un CustomerService qui n’est rien d’autre que des opérations de création, lecture, mise à jour et suppression sur une table, appelé par tous les autres services, est une base de données partagée avec de la latence en plus ; la propriété doit suivre les capacités métier et leurs règles, pas les noms communs. Des copies qui deviennent discrètement des maîtres. Voir l’avertissement ci-dessus. Ignorer le reporting jusqu’à la fin. Le premier rapport financier après le découpage révèle souvent que personne n’a prévu comment les données seraient rassemblées. Traiter la propriété comme une question purement technique. La propriété est aussi organisationnelle : quelqu’un doit répondre de la qualité des données et, selon la loi de Conway, les frontières de données qui traversent les frontières d’équipes ont tendance à ne pas durer.

Un bon test de toute conception de données consiste à poser, pour chaque fait important, trois questions : qui est le seul rédacteur, où ses règles sont-elles appliquées, et à quel point chaque copie peut-elle être périmée ? Si l’une des réponses est ça dépend ou plusieurs services, la conception n’est pas terminée.

Vérifiez votre compréhension

Deux services mettent chacun à jour la colonne status de la même table. De quel type de propriété s’agit-il ? Citez deux façons de la résoudre.

Propriété conjointe. On peut la résoudre en scindant la table, en déléguant les écritures à un seul propriétaire, en gardant un petit domaine de données partagé ou en consolidant les services.

Pourquoi une base de données partagée compromet-elle le déploiement indépendant ?

Chaque table est de fait une interface publique : une modification de schéma doit donc être coordonnée avec chaque service qui la lit ou l’écrit, ce qui impose des mises en production conjointes.

Quelle est la différence entre la réplication de colonnes et un appel synchrone pour lire les données d’un autre service ?

La réplication conserve une copie locale, cohérente à terme, rapide et disponible même si le propriétaire est en panne ; un appel synchrone renvoie des données à jour mais lie la disponibilité et la latence de l’appelant à celles du propriétaire.

Qu’apporte un contrat de données au-delà d’un schéma ?

La signification des champs, les attentes de qualité, les niveaux de fraîcheur et de conservation, la propriété, et la manière dont les changements sont annoncés et versionnés.

Suivant · 7.2Choisir une base de donnéesCe que chaque famille de bases de données fait bien et mal, du relationnel au vectoriel et au SQL distribué, et comment choisir selon la forme des données, les schémas d’accès, la cohérence, l’échelle, l’exploitation et les compétences de l’équipe.Continuer →

Sources et lectures complémentaires

Une question sur cette section ? ArchitectBot, l’assistant d’étude IA du cours, répond d’abord à partir du cours.

Demander : « Nous découpons notre monolithe en services, mais ils utilisent tous encore la même table des commandes. Comment décider quel service possède quelles données ? »