Aller au contenu
14 août 2026·8 min de lecture

Monolithe ou microservices vus par la base de données

Traitez monolithe ou microservices comme un choix de propriété des données: cartographiez les transactions et ne séparez que les limites solides.

Monolithe ou microservices vus par la base de données

Une limite de service n'est crédible que si les données de chaque côté peuvent changer sans commit coordonné dans la base. Si deux morceaux de code doivent verrouiller les mêmes lignes, mettre à jour les mêmes tables ou convenir de la même fenêtre de déploiement, tracer une frontière HTTP change le transport, pas l'architecture.

Voilà pourquoi la comparaison utile entre monolithe et microservices commence par le schéma. On peut déplacer du code derrière un endpoint en un après-midi. La propriété, les invariants, les données historiques, les requêtes de reporting, les reprises et la récupération après panne restent attachées aux tables. Les équipes qui commencent par les classes et les packages le découvrent souvent après avoir créé un monolithe distribué: davantage d'appels réseau et de travail d'exploitation, avec le même couplage de base de données dessous.

Je ne suis pas opposé aux microservices. Je refuse de prétendre qu'une limite de processus crée une limite de données. Le schéma montre où le système fonctionne déjà comme une unité, où il partage seulement le stockage par commodité et où une séparation survivrait à un mauvais déploiement à deux heures du matin.

Une carte des transactions vaut mieux qu'un graphe de dépendances

Associez chaque opération métier aux lignes qu'elle lit et écrit avant de choisir les limites de service. Un graphe de dépendances du code indique quel module en appelle un autre. Il ne montre pas que l'enregistrement d'une facture, la réservation du stock et l'écriture d'une piste d'audit doivent tous réussir ou tous échouer. La base connaît cette contrainte, car ces écritures partagent une transaction.

Commencez par les opérations, pas par les tables. Pour chaque commande qui modifie l'état, notez l'acteur initial, les tables lues et écrites, les verrous pris, les contraintes utilisées et les conséquences d'une exécution partielle. Incluez les tâches, triggers, procédures stockées, imports de fichiers et scripts opérateur. C'est souvent là que la prétendue limite disparaît.

Une carte compacte pourrait décrire Passer une commande comme une lecture du client, du produit et du stock, suivie d'une écriture dans la commande, ses lignes et le stock. Son invariant interdit au stock de passer sous zéro; un échec partiel laisse une commande acceptée mais impossible à honorer. Encaisser le paiement lit la commande et les tentatives antérieures, puis écrit le paiement, l'entrée comptable et l'état de la commande en imposant un seul encaissement réussi. Annuler la commande touche l'expédition, le paiement, le stock, le remboursement et la commande, car un produit déjà expédié exige un circuit de retour.

Cette carte révèle deux couplages différents. Le couplage transactionnel signifie que les écritures doivent être validées ensemble pour préserver un invariant. Le couplage en lecture signifie qu'une opération consulte des données possédées ailleurs. Le premier peut empêcher la séparation. Le second réclame souvent une réplique, une projection alimentée par événements ou une requête explicite, sans imposer une propriété partagée. Les équipes confondent les deux, puis gardent tout ensemble indéfiniment ou distribuent une transaction qui n'avait aucune raison de l'être.

Suivez les requêtes de production autant que le code source. Le SQL dynamique, les instructions générées par l'ORM, les tâches nocturnes et les procédures stockées échappent parfois à l'analyse statique. Une table sans référence évidente peut encore alimenter la clôture mensuelle. Si supprimer un module fausse le rapport d'un comptable trois jours plus tard, ce module n'est pas isolé.

Les tables partagées reportent le coût de coordination

Une table partagée permet à deux services de livrer vite en faisant de la base leur API d'intégration privée. Le service de facturation insère une ligne, le reporting la lit directement et le service d'exécution ajoute une colonne d'état. Rien ne paraît coûteux jusqu'au jour où une équipe doit modifier une colonne, réinterpréter une valeur, reprendre les anciennes lignes ou restaurer une sauvegarde. Chaque lecteur devient alors partie prenante du changement.

Le coût ne vient pas du fait que deux processus peuvent techniquement interroger la même table. Il vient d'une autorité ambiguë. Quel service peut ajouter une contrainte? Qui décide si status = 4 signifie emballé ou expédié? Quel déploiement possède le backfill? Qui restaure la table si un service exige une restauration à un instant donné alors qu'un autre a déjà écrit un état plus récent? Le stockage partagé transforme un travail normal sur le schéma en calendrier interéquipes.

Les clés étrangères exigent une distinction précise. À l'intérieur d'une même limite de propriété, une clé étrangère constitue une documentation exécutable utile. Au-delà d'une future limite de service, elle signifie que la base impose encore un invariant entre services. La supprimer ne supprime pas l'invariant; elle déplace sa détection dans le code et autorise les références invalides. Gardez les systèmes ensemble jusqu'à pouvoir nommer ce qui remplacera cette garantie.

Cette requête de propriété offre un bon premier passage dans PostgreSQL:

SELECT table_schema, table_name,
       array_agg(DISTINCT application_name ORDER BY application_name) AS writers
FROM audit_statement_usage
WHERE command IN ('INSERT', 'UPDATE', 'DELETE')
GROUP BY table_schema, table_name
HAVING count(DISTINCT application_name) > 1
ORDER BY table_schema, table_name;

PostgreSQL ne fournit pas audit_statement_usage comme table native. Construisez-la à partir des journaux d'audit ou de la télémétrie des instructions, avec au moins application_name, la commande, le schéma et la table. La forme du résultat compte: toute ligne ayant plusieurs auteurs demande une décision de propriété, pas un endpoint. Ne déduisez pas la propriété des seuls rôles de base si plusieurs applications partagent des identifiants, car cette habitude rend les preuves inutiles.

Dans une cible saine, chaque table a un seul auteur faisant autorité. D'autres composants peuvent recevoir des copies conçues pour leurs propres requêtes. Une copie possède un contrat de fraîcheur et peut être reconstruite. Une table partagée cache plusieurs acteurs qui dépendent de sa forme actuelle, contrat bien plus difficile à voir.

Le besoin de cohérence choisit la limite

Gardez les données dans une même transaction lorsque le métier ne tolère aucun état intermédiaire observable. Séparez-les lorsqu'un accord différé est acceptable et que vous savez réparer le retard. C'est une décision produit exprimée par le comportement de la base, pas une préférence pour du code synchrone ou asynchrone.

Le paiement et le grand livre rendent le problème évident. Si le système peut enregistrer un paiement encaissé sans l'écriture comptable correspondante, même brièvement, une autre tâche peut le rembourser, le régler ou le déclarer à tort. On peut placer ces écritures dans des services séparés, mais il faut alors un protocole explicite pour l'intention atomique, les reprises, la déduplication et le rapprochement. Le réseau a transformé un invariant local en flux distribué. Ce choix peut se justifier, mais ce n'est pas un découplage gratuit.

La recommandation populaire qui consiste à placer un broker entre tous les éléments est mauvaise lorsqu'elle précède la décision de cohérence. Un broker transporte des messages de façon fiable sous des conditions définies. Il ne décide pas si une réservation peut être en retard sur une commande, quoi faire d'un événement reçu deux fois ni qui répare une projection absente. Cela relève de la sémantique applicative. Le cacher derrière publish() réduit les preuves disponibles pour l'équipe.

Posez quatre questions concrètes pour chaque limite envisagée:

  1. Quel état les utilisateurs ou les tâches peuvent-ils voir entre les deux commits?
  2. Combien de temps cet état peut-il rester incohérent?
  3. Quel côté recommence et comment le destinataire reconnaît-il un doublon?
  4. Quel processus détecte et répare un message qui n'a jamais produit l'état attendu?

Si la réponse à la deuxième question est pratiquement zéro, préférez une transaction unique, sauf si l'isolation réglementaire, la charge ou la propriété organisationnelle justifie le coût de la coordination distribuée. Si la réponse se compte en secondes ou minutes, écrivez cette limite et surveillez-la. Le mot eventual n'est pas un objectif de service.

Une base de données n'implique pas un seul propriétaire

On peut établir une véritable propriété de service dans une base unique en séparant les schémas, rôles, migrations et droits d'écriture. À l'inverse, des serveurs distincts restent fortement couplés si les services coordonnent chaque version et multiplient les appels synchrones pour reconstituer d'anciennes jointures. La séparation physique ne prouve une limite que si l'indépendance opérationnelle suit.

Une disposition transitoire utile donne à chaque composant son schéma et un compte qui ne peut écrire que là. Les lectures entre schémas deviennent des exceptions temporaires inventoriées. Les permissions transforment les écritures accidentelles en erreurs visibles:

REVOKE ALL ON SCHEMA billing FROM fulfillment_app;
GRANT USAGE ON SCHEMA billing TO fulfillment_app;
GRANT SELECT ON billing.invoice_summary TO fulfillment_app;
REVOKE INSERT, UPDATE, DELETE ON ALL TABLES IN SCHEMA billing FROM fulfillment_app;

Accordez l'accès à une vue dédiée comme invoice_summary, pas à toutes les tables de facturation. La vue offre au propriétaire une petite surface de compatibilité pendant que les consommateurs passent à une API ou une projection locale. Associez chaque droit à un propriétaire et une condition de retrait. Sinon, le pont temporaire devient la prochaine base partagée.

Database-per-service est aussi souvent mal compris. Cela signifie qu'un service possède son contrat de persistance et que les autres ne peuvent pas le contourner. Cela n'impose pas un cluster distinct par petit processus. Des bases logiques séparées peuvent aider pour la restauration et les permissions, tandis que des schémas dans une instance PostgreSQL peuvent suffire pendant l'extraction. Choisissez l'isolation qui impose la propriété sans multiplier l'exploitation avant que la limite ait fait ses preuves.

Toute jointure entre limites doit avoir un remplacement nommé avant l'extraction. Une jointure locale filtre, trie et pagine dans un instantané cohérent. La remplacer par plusieurs appels d'API peut charger des milliers d'enregistrements, créer un schéma N-plus-un et fusionner des résultats observés à des instants différents. L'endpoint peut renvoyer le bon JSON en test unitaire tout en échouant à l'échelle réelle.

Choisissez le remplacement selon la requête. Un écran qui réclame un statut de facturation actuel peut faire une demande directe avec délai d'attente et repli définis. Une recherche filtrant les commandes par attribut client a généralement besoin d'une projection locale conçue pour ce filtre. Un rapport hors ligne relève d'un entrepôt analytique. Copier certains faits est une duplication volontaire; empiler les appels directs jusqu'à créer une jointure distribuée par accident est un couplage caché.

La pagination expose un échec courant. Supposons qu'un appelant demande les 50 premières commandes classées selon le risque client, mais que commandes et risques aient désormais des propriétaires différents. Charger 50 commandes puis rechercher le risque ne peut pas produire les bonnes 50 premières. En charger davantage revient à deviner avec des performances instables. Placez le classement dans un modèle de lecture dédié ou changez le contrat produit. La dispersion réseau ne conserve pas la sémantique d'une base par optimisme.

Fixez la fraîcheur selon la décision prise par la requête. Un blocage antifraude peut exiger le statut actuel et refuser l'opération si son propriétaire est indisponible. Un tableau commercial peut accepter quelques minutes de retard. Inscrivez la version observée ou l'heure de mise à jour dans la projection afin que les appelants appliquent la règle. Sans provenance, les données en cache paraissent actuelles même si le flux est arrêté depuis des heures.

Ne découpez pas une base uniquement parce qu'une table est volumineuse. Le partitionnement, les index, l'archivage et l'isolation de charge répondent plus directement aux problèmes de stockage et de requêtes. Une limite de service mérite son coût lorsqu'elle sépare l'autorité de changement ou le comportement en panne. La taille seule renseigne peu sur ces deux points.

Les événements ont besoin d'une source atomique

Rompre le train de versions
CodeHero transforme les monolithes web et desktop en services Go et clients TypeScript possédés.

Utilisez une outbox transactionnelle lorsqu'un changement validé doit produire un événement de façon fiable. Écrire les données métier puis publier crée une brèche: le commit peut réussir et la publication échouer. Publier d'abord crée la brèche inverse. Une transaction distribuée peut la fermer, mais elle augmente le couplage opérationnel et reste rarement bien prise en charge par tous les systèmes concernés.

L'outbox place l'écriture métier et l'événement dans le même commit local:

BEGIN;
UPDATE orders
SET status = 'confirmed', version = version + 1
WHERE id = :order_id AND status = 'pending';

INSERT INTO outbox_event (event_id, aggregate_id, event_type, payload, created_at)
VALUES (:event_id, :order_id, 'order.confirmed', :payload, CURRENT_TIMESTAMP);
COMMIT;

Un relais publie les lignes non envoyées et enregistre sa progression. Il peut publier deux fois s'il s'arrête après l'envoi mais avant l'enregistrement du succès; les consommateurs doivent donc rester idempotents. Conservez un identifiant d'événement stable et conditionnez la modification d'état à l'absence de cet identifiant dans les événements déjà traités. Les promesses exactly-once se réduisent souvent à une livraison at-least-once et des effets dédupliqués. Dites ce que vous fournissez vraiment.

L'ordre compte aussi. Une séquence globale unique limite le débit et crée un faux couplage, tandis que l'absence de règle permet à une annulation de dépasser une confirmation. Ordonnez par agrégat lorsque le métier l'exige, incluez sa version et rejetez ou mettez de côté les trous. La procédure de réparation doit être assez banale pour qu'un opérateur l'exécute sans inventer d'état.

La capture des changements peut alimenter un relais d'outbox, mais la capture brute des tables ne remplace pas les événements métier. Une mise à jour de ligne dit que le stockage a changé. Elle n'explique pas si la commande a été confirmée, corrigée, importée ou réparée. Les consommateurs qui reconstituent l'intention depuis les colonnes se couplent au schéma que vous vouliez libérer.

Le reporting révèle la propriété cachée par les commandes

Les limites opérationnelles correspondent rarement aux questions analytiques. Le reporting doit donc combiner des copies possédées au lieu de retrouver un accès direct à toutes les tables de production. Un rapport de rentabilité client peut demander commandes, remboursements, coûts de support et écritures comptables. Faire appeler quatre services synchrones par le service de reporting recrée une jointure distribuée, avec plus de latence et de pannes.

Construisez un magasin de reporting depuis des événements, flux de changements ou extractions planifiées, avec des règles explicites de fraîcheur et de rapprochement. Il peut dénormaliser fortement puisqu'il ne possède pas la vérité opérationnelle. Lorsqu'une définition change, reconstruisez la projection depuis les faits conservés ou un instantané contrôlé au lieu d'exiger que chaque source maintienne toutes les anciennes formes de requête.

Méfiez-vous de la table partagée customer. Identité, payeur, destinataire, compte de connexion et partie juridique commencent souvent dans une ligne, puis divergent avec l'entreprise. Un service client universel peut devenir une dépendance pour presque chaque requête. Définissez quels faits appartiennent à chaque domaine et quels identifiants les relient. Dupliquer le nom affiché d'un client coûte souvent moins cher que d'exiger la disponibilité synchrone d'un profil central.

Le rapprochement rend la cohérence différée responsable. Comparez les volumes et montants sources par clés métier stables, suivez le plus ancien événement non traité et gardez une procédure de rejeu. Un tableau de broker vert ne prouve pas que les lignes de reporting correspondent au grand livre. Le contrôle doit comparer les résultats métier, pas l'activité du transport.

Dans un environnement réglementé, les copies touchent aussi la conservation, l'accès et l'effacement. Une projection reste une donnée. Inventoriez le chemin des champs sensibles, limitez ce que reçoit chaque consommateur et prouvez l'effacement ou la conservation sur toutes les répliques. Séparer le stockage ne fait pas disparaître la gouvernance.

Une extraction sûre déplace la propriété avant le trafic

Retirer le monolithe aux tables partagées
CodeHero réécrit les systèmes en services Go et Postgres sans recopier leur ancienne structure.

Déplacez une capacité métier en établissant son contrat de données, en observant son comportement en parallèle et en transférant l'autorité d'écriture avant d'y envoyer tout le trafic. Extraire le code en premier laisse le nouveau service dépendre des anciennes tables, et repousse la partie risquée à la fin sous la pression du calendrier.

Une séquence fiable suit ces étapes:

  1. Choisissez une capacité avec un propriétaire plausible et une limite de cohérence tolérable. Inventoriez chaque lecteur et auteur de ses tables.
  2. Encadrez le comportement actuel par des tests de caractérisation, y compris les échecs, reprises, arrondis, valeurs nulles et corrections opérateur. N'enregistrez des requêtes de production représentatives que selon les règles de confidentialité de l'organisation.
  3. Introduisez le futur schéma et remplissez-le par des tâches répétables avec checkpoints. Effectuez une double lecture silencieuse et comparez sans servir le résultat.
  4. Passez à un seul chemin d'écriture faisant autorité. Si une double écriture temporaire est inévitable, journalisez les deux résultats et lancez un rapprochement; ne supposez pas que deux écritures indépendantes resteront identiques.
  5. Basculez les lectures puis le trafic vers le nouveau propriétaire, conservez un retour arrière testé et ne retirez les anciens droits qu'après avoir maintenu retard et parité dans les limites convenues.

La difficulté tient au backfill pendant les changements en direct. Un instantané commence à un instant alors que la production continue. Prenez un instantané cohérent et une position de changement, puis appliquez les changements suivants dans l'ordre. Rendez le backfill idempotent afin qu'une reprise de plage ne duplique ni ne régresse les lignes. Enregistrez les rejets avec assez de contexte pour les réparer; une migration qui ignore silencieusement les anciennes données mal formées crée un schéma plus propre et un historique métier faux.

Évitez la synchronisation bidirectionnelle. Elle ressemble à un retour arrière sûr, mais ses règles de conflit deviennent vite une seconde application. À chaque phase, désignez une autorité par champ. Le retour arrière doit inverser le routage et rejouer un journal connu, pas permettre aux deux systèmes de modifier le même fait.

Une façade d'étranglement peut router les appelants, mais elle ne règle pas la propriété des données. Si elle envoie les nouvelles requêtes vers un service qui met encore à jour les tables du monolithe, seule la topologie de déploiement a changé. Mesurez le progrès par les auteurs retirés, les droits interschémas supprimés et les migrations coordonnées éliminées.

Les tests de parité doivent comparer les effets métier

Testez une réécriture par son comportement observable et l'état obtenu, pas par des codes de statut voisins. Les systèmes historiques cachent des règles dans les triggers, tâches planifiées, valeurs par défaut, troncatures, collations, fuseaux horaires et réparations manuelles. Une réécriture propre peut sembler logique et malgré tout modifier les factures ou les stocks.

Construisez un banc de parité qui envoie la même requête enregistrée ou synthétique aux deux chemins, normalise les différences autorisées et compare les réponses ainsi que les effets en base. Pour une commande, comparez les lignes créées, montants comptabilisés, événements émis et catégories d'erreur. Pour une lecture, comparez tri, pagination, comportement des valeurs nulles et filtrage des droits. Masquez les valeurs sensibles avant leur entrée et conservez le résultat comme preuve de migration.

Définissez les tolérances champ par champ. Les horodatages peuvent varier dans une fenêtre déclarée. Les identifiants générés peuvent différer tout en gardant les relations. Les montants décimaux devraient généralement correspondre exactement après la règle d'arrondi annoncée. Une comparaison JSON globale crée du bruit jusqu'à ce que les ingénieurs l'ignorent, ce qui annule le test.

Exécutez des cas de panne, pas seulement le chemin heureux. Arrêtez le relais après la publication, recommencez une requête expirée, livrez des événements dans le désordre, restaurez un instantané et déployez un ancien consommateur face à une nouvelle version. La limite est crédible quand ces pannes ont des effets bornés et une réparation documentée, pas quand le diagramme paraît net.

C'est là que l'approche de CodeHero pour les réécritures historiques compte: elle lit tout le code, modernise l'architecture et compare le comportement au trafic de production enregistré avec un banc de parité. La promesse d'une livraison en moins de 30 jours serait imprudente si les effets en base n'étaient pas traités comme du comportement et si les fichiers étaient simplement traduits un à un.

Les changements compatibles permettent des déploiements indépendants

Rendre la séparation crédible
CodeHero modernise l'architecture et compare ses effets métier au trafic de production.

Une limite n'est pas déployable indépendamment si chaque changement de schéma oblige tous les producteurs et consommateurs à basculer dans la même version. Concevez les changements de base et d'événements pour que les anciennes et nouvelles versions coexistent pendant une période définie. Ce chevauchement permet de déployer, observer et revenir en arrière sans convoquer tous les propriétaires.

Utilisez l'expansion puis la contraction pour les champs qui franchissent une limite. Ajoutez le nouveau champ sans retirer l'ancien. Faites écrire la nouvelle représentation, reprenez l'historique et laissez les lecteurs préférer la nouvelle valeur tout en acceptant l'ancienne. Vérifiez qu'aucun ancien lecteur ne subsiste, cessez de produire l'ancien champ puis retirez-le lors d'un changement ultérieur. Chaque phase demande un critère de sortie mesurable, par exemple aucune lecture de l'ancienne colonne pendant un cycle complet, plutôt qu'une date supposée.

Renommer directement une colonne paraît séduisant, car le schéma final est propre tout de suite. Cela casse aussi les anciens binaires, tâches oubliées et versions de repli. Ajoutez le nouveau nom, copiez sous une autorité unique puis contractez plus tard. La colonne supplémentaire est une complexité temporaire avec plan de retrait; une panne coordonnée est une complexité opérationnelle sans plan.

Les schémas d'événements exigent la même discipline. Les consommateurs doivent ignorer les champs inconnus, les producteurs ne doivent pas changer le sens d'un champ existant et tout nouveau champ obligatoire doit avoir un chemin d'introduction valide. Versionnez le contrat sémantique, pas chaque ajout inoffensif. Publier order.cancelled.v2 pour chaque attribut facultatif remplit le système de conversions sans protéger contre le vrai danger, qui consiste à redéfinir cancelled.

Les vues peuvent fournir une courte compatibilité pour des lectures renommées ou remodelées. Elles font de mauvaises API permanentes si les consommateurs dépendent de jointures ou plans non documentés. Donnez à chaque vue une condition d'expiration et observez qui l'utilise encore. La supprimer sur la seule foi d'une recherche de dépôt oublie le reporting ponctuel et les binaires extérieurs au build principal.

Le retour arrière révèle l'honnêteté du plan. Si la nouvelle application écrit une valeur illisible par l'ancienne, restaurer l'ancien binaire ne restaure pas le service. Testez l'ancien code sur l'état produit par le nouveau, avec les valeurs d'énumération, la nullabilité, les chaînes plus longues et les variantes d'événements. Un DDL rétrocompatible ne couvre que la moitié du problème; les données stockées doivent rester lisibles pendant toute la fenêtre de repli.

Le déploiement indépendant est donc une affirmation à prouver. Montrez que chaque version applicative fonctionne avec chaque phase compatible, que le backfill reprend et que la télémétrie du contrat trouve les consommateurs restants. Si cette matrice échoue, la limite partage encore un train de versions, même avec des dépôts et bases portant des noms différents.

Certains monolithes doivent rester monolithiques

Gardez un monolithe lorsqu'une équipe le modifie de façon cohérente, que ses transactions correspondent aux invariants métier, que le risque de déploiement est maîtrisé et que la charge n'exige pas un placement séparé. Un monolithe modulaire avec propriété imposée des packages et schémas offre presque toute la clarté organisationnelle recherchée, sans pannes réseau ni gestion d'une flotte.

La meilleure raison de séparer est une autorité de changement indépendante soutenue par une vraie limite de données. L'isolation d'une charge instable, un périmètre de sécurité distinct ou des besoins de calcul à autre échelle sont aussi de bonnes raisons. Aucune n'excuse un modèle de cohérence indéfini, mais elles peuvent en justifier le prix.

Ne décidez pas avec une formule liée à la taille des équipes. Deux équipes peuvent bien collaborer dans un dépôt, tandis qu'une seule peut créer une collection pénible de minuscules services. L'organisation compte parce que propriété et communication influencent la conception, mais la base continue d'imposer les faits. Si chaque version demande des migrations coordonnées, l'organisation n'a pas obtenu de livraison indépendante.

Avant d'accepter une séparation, exigez une courte fiche qui nomme les tables possédées, l'auteur faisant autorité, les lectures transversales, la fenêtre de cohérence, le contrat d'événement, l'unité de restauration, la séquence de migration et l'autorité de retour arrière. Refusez toute réponse les deux services ou eventually sans limite ni réparation. Cette règle évite plus de dégâts que les débats sur le nombre idéal de services.

Traitez aussi la restauration et la reprise après sinistre comme des tests de limite. Si un service ne peut restaurer ses données sans remonter un autre service dans le temps, ils partagent une unité opérationnelle. Si le rejeu exige des modifications non documentées dans des tables étrangères, le modèle de propriété est incomplet. Exercez la restauration avec les événements en attente et les projections en aval. Vérifiez que les consommateurs rejettent les rejeux périmés et reconstruisent leurs copies sans écrire directement dans le schéma restauré, puis consignez qui choisit le point de reprise et comment les écritures ultérieures reviennent.

La première amélioration utile est souvent plus petite qu'une extraction: arrêtez les identifiants partagés, journalisez les auteurs par application, donnez un propriétaire à chaque table et rendez visible tout accès transversal. Quand le schéma montre des limites honnêtes, le code peut suivre. Là où le schéma refuse de se séparer, écoutez-le.

FAQ

Chaque microservice doit-il avoir sa propre base de données?

Chaque microservice doit posséder sa persistance et empêcher les autres de contourner son contrat par une écriture directe. Cela peut signifier des bases séparées, mais des schémas et rôles dans une base unique suffisent parfois pendant une migration.

Une base partagée est-elle toujours mauvaise pour les microservices?

Un serveur partagé n'est pas forcément mauvais; l'autorité d'écriture partagée l'est. Si les services possèdent leurs schémas et utilisent des contrats de lecture explicites, un serveur unique peut rester un choix transitoire ou permanent raisonnable.

Comment trouver les limites de transaction d'un monolithe?

Suivez chaque commande métier jusqu'à toutes les lignes lues et écrites, sans oublier triggers, tâches, procédures stockées et scripts opérateur. Regroupez les changements qui doivent être validés ensemble pour préserver un invariant métier.

Une API peut-elle supprimer le couplage de base de données?

Une API masque le schéma, mais elle ne supprime pas le couplage si les appelants exigent encore des commits, versions ou restaurations coordonnés. La limite progresse lorsque le fournisseur possède les données et que les appelants acceptent son contrat de disponibilité et de cohérence.

Quand faut-il utiliser la cohérence différée?

Utilisez-la lorsque le métier accepte une durée d'écart nommée et que l'équipe possède les reprises, la déduplication, la surveillance et la réparation. Si le délai acceptable est nul, une transaction locale reste souvent plus claire.

Quelle est la manière la plus sûre de séparer une table partagée?

Choisissez un seul auteur, créez le schéma cible, reprenez l'historique depuis une position cohérente puis appliquez les changements en direct. Les lectures silencieuses et le rapprochement doivent prouver la parité avant la bascule.

Un broker résout-il les transactions distribuées?

Non. Le broker transporte les messages, mais l'application définit toujours les états partiels, doublons, ordres et réparations. Une outbox transactionnelle ferme l'écart entre commit local et création d'événement; les consommateurs ont encore besoin d'idempotence.

Comment produire des rapports après le découpage d'un monolithe?

Alimentez un magasin de reporting séparé avec des événements, flux de changements ou extractions contrôlées. Donnez-lui des règles de fraîcheur et de rapprochement au lieu d'interroger toutes les bases opérationnelles ou de joindre les services en direct.

Que doit couvrir le retour arrière d'un microservice?

Il doit couvrir le routage, la compatibilité du schéma, les événements en attente et les écritures acceptées par la version défaillante. Gardez une autorité par champ et rejouez un journal connu; les écritures bidirectionnelles compliquent les conflits.

Un monolithe modulaire vaut-il mieux que des microservices?

Oui lorsque transactions, propriété d'équipe et déploiement évoluent encore ensemble. Des modules et permissions imposés donnent une propriété claire sans appels réseau, récupération distribuée et exploitation séparée de chaque composant.