Zum Inhalt springen
14. Aug. 2026·8 Min. Lesezeit

Eine Servicegrenze aus Datenzugriffsmustern

Finden Sie eine Servicegrenze aus Datenzugriffsmustern, indem Sie gemeinsame Schreibvorgänge, Entscheidungslesezugriffe und Transaktionen messen.

Eine Servicegrenze aus Datenzugriffsmustern

Eine Servicegrenze ist glaubwürdig, wenn jede Seite ihre eigenen Änderungen festschreiben kann, ohne dass die andere Seite an derselben Transaktion teilnehmen muss. Organigramme, Capability Maps und die Substantive aus einem Workshop können zeigen, wo die Suche beginnen sollte. Ob die vorgeschlagene Trennung den Produktionsbetrieb übersteht, verrät die Datenbank.

Ich beginne mit Datenzugriffsmustern, weil alte Systeme ihre tatsächlichen Verträge in Lesezugriffen, Schreibvorgängen, Sperren, Triggern, Jobs und Wiederanlaufverfahren festhalten. Die schwierige Aufgabe besteht darin, zufällige Kopplung von einer fachlichen Invariante zu unterscheiden. Eine Maske, die Kundennamen neben Rechnungen liest, erzeugt eine Abhängigkeit für die Darstellung. Eine Buchungsroutine, die eine Rechnung, einen Buchungssatz und einen Kreditsaldo in einem Commit aktualisiert, kann eine Invariante abbilden, die keinen Teilerfolg verträgt. Diese beiden Abhängigkeiten müssen verschieden behandelt werden.

Das nützliche Ergebnis ist kein hübsches Domänendiagramm. Es ist ein Belegpaket: eine Zuordnung der Tabellenverantwortung, eine Matrix der Tabellen, die in derselben Transaktion geschrieben werden, eine Karte der Lesezugriffe über mögliche Domänengrenzen hinweg und eine kurze Liste der Invarianten hinter den stärksten Gruppen. Mit diesen Belegen kann ein Team eine Grenze wählen und genau benennen, was vor dem ersten unabhängigen Deployment geändert werden muss.

Mit Transaktionen beginnen, nicht mit Tabellennamen

Tabellen, die in derselben Transaktion geschrieben werden, liefern das stärkste erste Signal, denn die Anwendung behandelt diese Änderungen derzeit als eine gemeinsame Einheit für Erfolg oder Fehlschlag. Wenn invoice, ledger_entry und customer_balance wiederholt unter derselben Transaktionskennung geändert werden, würde eine Trennung auf mehrere Services den lokalen Commit durch Koordination, Kompensation oder eine geänderte Fachregel ersetzen.

Namen führen leicht in die Irre. Eine Tabelle namens customer kann Kontenidentität, Kreditstatus, Versandpräferenzen und eine denormalisierte Verkaufssumme enthalten. Eine Tabelle namens order_status kann als gemeinsame Warteschlange für Versand und Abrechnung dienen. Präfixe zeigen oft das Team, das eine Tabelle angelegt hat, nicht das Verhalten, das heute von ihr abhängt. Selbst Fremdschlüssel beschreiben nur deklarierte referenzielle Beziehungen. Sie sagen nichts über ein nächtliches Programm aus, das drei Tabellen liest, zwei weitere schreibt und nach Zeile 80.000 wiederanlaufen können muss.

Definieren Sie eine Transaktion so, wie die Datenbank sie sieht: alle Anweisungen zwischen Begin und Commit oder Rollback, einschließlich der Anweisungen aus Triggern und gespeicherten Prozeduren. Jede Autocommit Anweisung bildet eine eigene Transaktion. Batchprogramme brauchen zusätzlich eine Identität für Joblauf und Prüfpunkt, weil eine Schleife mit einem Commit nach jeweils 500 Datensätzen einen größeren fachlichen Vorgang umfasst als jede einzelne Datenbanktransaktion.

Erfassen Sie für jeden beobachteten Zugriff mindestens diese Felder:

  • Transaktionskennung und Zeitstempel
  • ausführbare Datei, Job, Route oder Einstiegspunkt
  • Tabelle und Operationsart
  • betroffene Zeilen oder eine grobe Größenklasse
  • Aufrufkette oder Name der gespeicherten Prozedur, soweit verfügbar

Ordnen Sie nicht gleich am Anfang jede Tabelle einer Domäne zu. Bauen Sie zuerst eine Faktengrundlage auf, ohne sie in die gewünschte Antwort zu pressen. Die Domänenbezeichnungen kommen erst hinzu, nachdem die Gruppen gemeinsam geschriebener Tabellen sichtbar sind. Diese Reihenfolge verhindert, dass der Wortschatz des Workshops die Messung verfälscht.

Eine Co-Write-Matrix macht atomare Arbeit sichtbar

Eine Co-Write-Matrix zählt, wie oft zwei Tabellen in derselben Datenbanktransaktion Schreibzugriffe erhalten. So werden Tausende Traces zu einem gewichteten Graphen: Tabellen sind Knoten, und eine Kante verbindet zwei Tabellen, sobald mindestens eine Transaktion beide schreibt. Das Kantengewicht kann die Zahl der Transaktionen, die Zahl der betroffenen Zeilen oder den Anteil der Schreibzugriffe jeder Tabelle innerhalb des Paars abbilden.

Angenommen, normalisierte Traces landen in einer Tabelle namens data_access:

create table data_access (
  captured_at timestamp not null,
  transaction_id varchar(100) not null,
  entry_point varchar(200) not null,
  table_name varchar(200) not null,
  operation varchar(10) not null,
  rows_affected bigint
);

with writes as (
  select distinct transaction_id, table_name
  from data_access
  where operation in ('INSERT', 'UPDATE', 'DELETE')
), pairs as (
  select a.table_name as table_a,
         b.table_name as table_b,
         count(*) as shared_transactions
  from writes a
  join writes b
    on a.transaction_id = b.transaction_id
   and a.table_name < b.table_name
  group by a.table_name, b.table_name
)
select table_a, table_b, shared_transactions
from pairs
order by shared_transactions desc;

Die Ausgabe hat die Form table_a | table_b | shared_transactions. Die größten Werte verdienen eine Untersuchung, doch reine Häufigkeiten reichen nicht. Ein Wartungsjob kann das Volumen dominieren, ohne eine Invariante für Benutzer abzubilden. Eine seltene Jahresendbuchung kann dagegen die strengste Anforderung an Atomarität tragen. Nehmen Sie den Einstiegspunkt in die Gruppierung auf und vergleichen Sie dasselbe Tabellenpaar über Onlineanfragen, geplante Jobs, Importe und Werkzeuge für den Betrieb.

Normalisieren Sie das Gewicht in beide Richtungen. Wenn 98 Prozent der Schreibzugriffe auf customer_balance gemeinsam mit ledger_entry auftreten, ist diese Kante wichtig, selbst wenn die Transaktionen nur einen kleinen Teil des gesamten Ledger Verkehrs ausmachen. Ich verwende zwei bedingte Maße: Transaktionen, die A und zugleich B schreiben, geteilt durch alle Transaktionen, die A schreiben, sowie die umgekehrte Richtung. Ein asymmetrisches Ergebnis zeigt oft eine Satellitentabelle, die zu einem größeren Aggregat gehört.

Sampling muss Transaktionsgrenzen erhalten. Jede hundertste SQL Anweisung zu erfassen zerstört die Belege, weil die Stichprobe eine Hälfte eines gemeinsamen Schreibvorgangs behalten und die andere verwerfen kann. Wählen Sie vollständige Transaktionen anhand der Transaktionskennung aus oder erfassen Sie alle Transaktionen für ausgewählte Einstiegspunkte. Werte können maskiert werden, doch Tabellennamen, Operationsarten, Zeitpunkte und Transaktionszugehörigkeit müssen erhalten bleiben.

Fachliche Invarianten von Implementierungsgewohnheiten trennen

Eine dichte Gruppe gemeinsam geschriebener Tabellen schlägt eine Grenze vor, sie beweist sie nicht. Das Team muss erklären, warum jede starke Kante existiert und was kaputtginge, wenn beide Schreibvorgänge getrennt festgeschrieben würden. Diese Erklärung trennt eine fachliche Invariante von Code, der zufällig dieselbe Verbindung nutzt.

Verlangen Sie einen Satz, der den Fehler beschreibt. Für eine Rechnung und ihren Buchungssatz könnte er lauten: „Die Finanzbuchhaltung darf eine Rechnung nie ohne die passenden Soll- und Habenbuchungen erfassen.“ Für einen Auftrag und einen Auditdatensatz vielleicht: „Der Betrieb braucht einen Nachweis darüber, wer den Auftrag geändert hat.“ Die erste Regel kann atomaren Zustand oder ein sorgfältig neu entworfenes Buchungsmodell verlangen. Die zweite lässt sich meist in ein dauerhaftes Ereignis oder ein Datenbank Outbox Muster verschieben, ohne die Audittabelle zum Teil der Auftragsverantwortung zu machen.

Ordnen Sie jede Co-Write-Kante einem von vier Gründen zu:

  1. Eine fachliche Invariante verlangt, dass alle Änderungen gemeinsam erfolgreich sind.
  2. Referenzielle Bereinigung oder Kaskadenlogik hält gespeicherte Daten konsistent.
  3. Ein abgeleiteter Wert oder Index wird für schnellere Lesezugriffe synchron gepflegt.
  4. Der Code hat eine Transaktion wiederverwendet, weil die Tabellen nahe beieinander lagen.

Nur der erste Grund ist ein starker Beleg dafür, dass die Tabellen hinter dieselbe Konsistenzgrenze gehören. Der zweite kann verschwinden, wenn ein Service die Löschung besitzt und eine Tatsache veröffentlicht. Der dritte ist in der Regel ein Projektionsproblem. Der vierte ist Migrationsschuld.

Trigger brauchen besondere Aufmerksamkeit, weil Anwendungstraces sie verbergen können. Eine Routine scheint vielleicht nur shipment zu aktualisieren, während ein Trigger inventory anpasst, stock_movement einfügt und eine Integrationswarteschlange schreibt. Lesen Sie die Triggerdefinitionen und die Körper gespeicherter Prozeduren. Ordnen Sie deren Schreibzugriffe anschließend der auslösenden Transaktion und dem Einstiegspunkt zu. Sonst scheitert die vorgeschlagene Grenze beim ersten Produktionsfall, der verborgenes Datenbankverhalten aktiviert.

Sperren und Fehlerbehandlung liefern zusätzliche Belege. Code, der einen Deadlock über zwei Tabellen erneut versucht, eine Constraint Verletzung auf eine fachliche Meldung abbildet oder beide Änderungen nach einer fehlgeschlagenen Validierung zurückrollt, verlässt sich wahrscheinlich auf ihr gemeinsames Schicksal. Dokumentieren Sie den genauen Constraint oder die Wiederherstellungsregel. „Diese Tabellen sind gekoppelt“ ist zu ungenau für einen Migrationsentwurf.

Domänenübergreifende Lesezugriffe sind eine andere Art Schuld

Ein Lesezugriff über mögliche Domänengrenzen hinweg macht die Grenze nicht automatisch ungültig. Lesezugriffe können APIs, replizierte Projektionen, Caches, Snapshots oder Analysespeicher verwenden, ohne Commits koordinieren zu müssen. Die Entwurfsfrage lautet, wie frisch und vollständig die Daten sein müssen, wenn der Leser eine Entscheidung trifft.

Erstellen Sie eine Lesematrix, nachdem mögliche Schreibverantwortliche sichtbar geworden sind. Die Zeilen stehen für Einstiegspunkte, die Spalten für vorgeschlagene Domänen. Jede Zelle hält gelesene Tabellen, Häufigkeit, Kardinalität und die Information fest, ob derselbe Einstiegspunkt irgendwo schreibt. Achten Sie besonders auf entscheidende Lesezugriffe, deren Ergebnis einen folgenden Schreibvorgang steuert. Ein Bericht, der Abrechnungs- und Kundendaten verbindet, kann eine verzögerte Projektion vertragen. Eine Kreditprüfung vor der Annahme eines neuen Auftrags braucht möglicherweise aktuelle Daten oder ein Reservierungsprotokoll.

Das gefährliche Muster lautet: aus Domäne B lesen, im Anwendungscode rechnen und anschließend Domäne A schreiben, während der Code annimmt, dass B unverändert blieb. Ein lokaler Monolith kann dieses Rennen innerhalb einer Datenbanktransaktion verbergen, indem er Zeilen in B sperrt. Nach der Servicetrennung liefert ein synchroner API Aufruf einen Wert zurück, verlängert aber die Transaktion des Aufrufers nicht über das Netzwerk. Der Wert kann sich ändern, bevor A den Commit ausführt.

Erfassen Sie für jeden grenzüberschreitenden Lesezugriff eine Aktualitätsklasse:

  • exakt zum Entscheidungszeitpunkt
  • begrenzte Verzögerung mit festgelegtem Maximum
  • letzter bekannter Wert mit Abgleich
  • historischer Snapshot
  • nur zur Anzeige

Diese Einteilung macht aus der vagen Abhängigkeit „Aufträge brauchen Kundendaten“ einen Vertrag. Kundennamen, die nur angezeigt werden, können in einer Auftragsprojektion liegen. Eine Prüfung des Kreditlimits kann verlangen, dass die Kundendomäne eine Reservierung besitzt. Dann bittet der Auftragsservice sie um die Reservierung von Kapazität, anstatt eine Zahl abzurufen und selbst zu entscheiden.

Breite Joins für Berichte sollten keine Transaktionsgrenzen bestimmen. Verschieben Sie sie in eine Berichtsprojektion, die aus Änderungen der jeweiligen Eigentümer gespeist wird, oder behalten Sie während des Übergangs ein Lesereplikat. Wenn operative Services einander für jede Zeile aufrufen müssen, nur damit ein alter Bericht weiterläuft, entsteht ein langsamer Netzwerk Join, der Ausfälle weiterträgt. Berichte brauchen ein ausdrücklich verantwortetes Datenprodukt und keinen zufälligen Zugriff auf jedes operative Schema.

Views und gespeicherte Abfragen können die Überschreitung verbergen. Lösen Sie jede View beim Aufbau der Matrix bis zu ihren Basistabellen auf, behalten Sie aber den Viewnamen als Vertrag des Verbrauchers. Ein Dutzend Programme kann open_account_summary lesen, ohne zu wissen, dass die View Forderungen, Kundenstatus und Reklamationsdaten verbindet. Eine einmalige Ablösung der View kann leichter sein als die Änderung jedes Programms, doch ihre Aktualisierungsregel braucht weiterhin einen Eigentümer. Messen Sie, ob Aufrufer filtern, aggregieren oder ganze Ergebnismengen laden, denn davon hängt ab, ob Projektion, Abfrageendpunkt oder Massenexport der sinnvolle Ersatz ist.

Untersuchen Sie auch negative Lesezugriffe. Code fragt oft, ob eine Zeile nicht existiert: keine unbezahlte Rechnung, keine aktive Sperre, keine frühere Anfrage mit dieser Referenz. Durch Replikationsverzögerung wird Abwesenheit besonders gefährlich, denn eine veraltete Projektion sieht genau wie eine Erlaubnis zum Fortfahren aus. Stellen Sie diese Prüfungen neben andere entscheidende Lesezugriffe und benennen Sie die zuständige Autorität. Wenn die Prüfung Eindeutigkeit oder ein Ausgabenlimit schützt, verschieben Sie die Entscheidung zu dieser Autorität, statt die Tabelle zu kopieren und auf den Ausgang des Replikationsrennens zu hoffen.

Auch das Verhalten bei Lesefehlern gehört in den Vertrag. Wenn der entfernte Eigentümer nicht verfügbar ist, muss der Aufrufer sicher ablehnen, einen begrenzt alten Wert verwenden, Arbeit einreihen oder mit einem ausdrücklich benannten Risiko fortfahren. Die richtige Wahl hängt von der Fachregel ab. Eine allgemeine Retry Regel verschiebt die Entscheidung bis zu einem Ausfall, wenn der Betrieb am wenigsten Zeit zum Nachdenken hat.

Eine Grenze scheitert, wenn die Invariante sie überschreitet

Jeden verborgenen Schreiber finden
CodeHero liest den gesamten Quellbestand, damit vergessene Schreiber an der geplanten Grenze sichtbar bleiben.

Der praktische Test für eine vorgeschlagene Trennung ist einfach: Kann jede Seite ihre eigenen Befehle mit den Daten annehmen oder ablehnen, die sie besitzt, und dabei die benannten Fachregeln erhalten? Wenn ein Befehl auf Seite A verlangt, dass Seite B am selben Commit teilnimmt, ist die Grenze nicht bereit.

Betrachten Sie eine Auftragsroutine, die in einer Transaktion Folgendes tut:

  1. Das verfügbare Kundenlimit mit einer Zeilensperre lesen.
  2. Auftrag und Auftragspositionen einfügen.
  3. Die gebundene Kreditsumme des Kunden erhöhen.
  4. Einen Auditdatensatz einfügen und committen.

Ein Organigramm kann Kundenverwaltung und Auftragsverwaltung verschiedenen Abteilungen zuordnen. Eine direkte Serviceextraktion würde die Schritte zwei und drei zu einer verteilten Transaktion machen. Zuerst den Kundenservice aufzurufen löst das Problem nicht, denn das Einfügen des Auftrags kann nach der Erhöhung der Kreditsumme fehlschlagen. Der Aufruf am Ende erzeugt die umgekehrte Waise. Blindes Wiederholen kann doppelt zählen.

Es gibt drei ehrliche Möglichkeiten. Kreditbindung und Auftragsannahme bleiben in einer Grenze. Oder die Entscheidung wandert in eine Kreditreservierung auf der Kundenseite, mit einer idempotenten Reservierungskennung und ausdrücklichen Operationen zum Bestätigen oder Freigeben. Oder die Fachregel ändert sich so, dass eine zeitweilige Abweichung erlaubt ist, danach wird abgeglichen und ein betroffener Auftrag gesperrt. Jede Möglichkeit ändert Verantwortung oder Semantik. Ein Message Broker allein ändert beides nicht.

Der Reservierungsansatz braucht Zustände und zeitliches Verhalten, keinen hoffnungsvollen Ereignisnamen. reserve muss für dieselbe Kennung dasselbe Ergebnis liefern. confirm muss Wiederholungen vertragen. Ein Ablauf muss eine verspätete Bestätigung berücksichtigen. Der Betrieb muss Reservierungen sehen können, die nie einen Endzustand erreichen. Kann die Organisation diese Regeln nicht benennen, hat sie die verteilte Transaktion nicht entfernt, sondern die Unsicherheit umbenannt.

Darum widerspreche ich der Empfehlung „nach fachlicher Fähigkeit trennen“ als vollständiger Methode. Der Rat ist beliebt, weil Fähigkeiten Diagramme ergeben, über die Führungskräfte und Entwickler gemeinsam sprechen können. Als Quelle für Kandidaten ist er nützlich. Als abschließender Test ist er falsch, weil eine Capability Map weder Commit Umfang noch Triggerverhalten, gesperrte Entscheidungslesezugriffe oder Wiederanlaufsemantik zeigt.

Batchjobs zeigen, was Onlinetraces übersehen

Onlineverkehr deckt selten den vollständigen Vertrag eines Altsystems ab. Monatsabschluss, Abrechnung, Importe, rückwirkende Verarbeitung und Korrekturen durch den Betrieb berühren häufig Tabellen, auf die gewöhnliche Anfragen nie zugreifen. Eine nur anhand von HTTP Traces gewählte Grenze kann sauber aussehen, bis der erste geplante Lauf beginnt.

Inventarisieren Sie jede ausführbare Komponente mit Datenbankverbindung, darunter Skripte aus Schedulern, gespeicherte Jobs, Desktopclients, Tabellenkalkulationsmakros und Supportwerkzeuge. Ordnen Sie Datenbanksitzungen möglichst über Programmnamen oder Zugangsdaten zu. Gemeinsame Zugangsdaten erschweren das, deshalb sollten Sitzungsmetadaten, Schedulerdefinitionen, Quellcodesuche und Auditdatensätze der Datenbank zusammengeführt werden.

Der Commit Takt eines Batchprogramms ist wichtig. Ein Programm, das alle ungebuchten Rechnungen liest, Buchungssätze erzeugt, Quelldatensätze markiert und nach jeweils 500 Einträgen committet, hat mindestens drei Geltungsbereiche:

  • die Datenbanktransaktion für jeden Block
  • den Prüfpunkt zum Fortsetzen des Laufs
  • die fachliche Anforderung für die gesamte Buchungsperiode

Eine Servicetrennung kann die Block Commits erhalten und trotzdem das Wiederanlaufverhalten zerstören. Stellen Sie sich vor, der neue Ledger Service nimmt 430 Einträge an, bevor der Aufrufer abstürzt. Das alte Programm startet am letzten Prüfpunkt und sendet diese Einträge erneut. Ohne stabile Quellkennung und idempotente Annahme bucht das Ziel doppelt. Mit Idempotenz, aber ohne Abgleich kann die Quelle weiterhin 70 Einträge als ausstehend zeigen, obwohl das Ledger sie angenommen hat.

Gehen Sie für jeden wichtigen Batch einen echten Wiederanlaufpfad durch. Halten Sie fest, wo der Prüfpunkt liegt, welche Schreibzugriffe davor stattfinden, wie das Programm frühere Arbeit erkennt, was der Betrieb prüft und wie ein Teillauf repariert wird. Weisen Sie anschließend die Verantwortung für diesen Wiederherstellungsprozess zu. Servicediagramme lassen Betriebsverfahren gern aus, obwohl gerade sie häufig die einzige funktionierende Definition von Konsistenz enthalten.

Seltene Jobs müssen nach Folgen und nicht nur nach Häufigkeit gewichtet werden. Ich markiere eine Kante als betrieblich bedeutsam, wenn ein Fehler Abschluss, Gehaltslauf, Versand, regulatorische Berichte oder ein anderes benanntes Geschäftsereignis blockiert. Das ist fachliches Urteil und kein künstlicher mathematischer Wert. So verhindern Sie, dass viele Login Aktualisierungen eine seltene Buchungsinvariante verdecken.

Tabellenverantwortung kommt vor dem API Entwurf

Den gemischten Quellbaum lesen
COBOL, JCL, PL/SQL, Skripte und Clients werden gemeinsam statt in Einzelprojekten analysiert.

Jede veränderbare Tabelle braucht einen vorgeschlagenen Eigentümer, bevor der API Entwurf beginnt. Gemeinsamer Schreibzugriff erlaubt beiden Services, die alten Abkürzungen beizubehalten. Die Grenze existiert dann nur im Deploymentdiagramm. Verantwortung bedeutet, dass ein Service gültige Zustandsübergänge entscheidet, Schreibvorgänge ausführt und Reparaturen behandelt.

Erstellen Sie ein Tabellenregister mit diesen Spalten: Tabelle, vorgeschlagener Eigentümer, schreibende Einstiegspunkte, Co-Write-Gruppe, grenzüberschreitende Entscheidungslesezugriffe, Trigger, Batchjobs und ungeklärte Invariante. Tragen Sie auch für abgeleitete Tabellen einen Eigentümer ein. „Gemeinsam“ ist ein vorübergehender Migrationszustand mit einer Ausstiegsbedingung, keine Domäne.

Suchen Sie anschließend im gesamten Quellbaum nach jedem Schreibpfad. Statische Suche findet Anweisungen und ORM Mappings, die in den Traces fehlten. Dynamische Traces finden erzeugtes SQL und wenig offensichtliche Prozeduraufrufe, die die Suche übersah. Keine Quelle reicht allein. Vergleichen Sie beide und erklären Sie Abweichungen, besonders bei ruhenden Hilfsprogrammen, die noch Produktionszugangsdaten besitzen.

API Befehle sollten Entscheidungen ausdrücken, für die der aufgerufene Service zuständig ist. reserveCredit(orderId, amount) ist stärker als getAvailableCredit(customerId) mit einer anschließenden Berechnung beim Aufrufer. postInvoice(invoiceId, lines) ist stärker als offengelegte CRUD Operationen für Ledger Tabellen. Ein Befehl erlaubt dem Eigentümer, seine Invariante auch bei Änderungen des Speichers zu schützen.

Auch Lesezugriffe brauchen Verantwortung, selbst bei kopierten Daten. Eine Projektion im Auftragsservice kann Kundenname und Status enthalten, doch der Kundenservice bleibt die Autorität. Speichern Sie Quellkennung und Version oder Ereignisposition, damit ein Abgleich fehlende oder vertauschte Aktualisierungen erkennt. Entscheiden Sie, was der Leser bei einer veralteten Projektion tut: fortfahren, warnen, ablehnen oder synchron abrufen. Überlassen Sie diese Wahl nicht dem Entwickler, der den ersten Vorfall bearbeitet.

Datenbankberechtigungen können die Grenze vor der physischen Extraktion durchsetzen. Geben Sie dem künftigen Eigentümer Schreibrechte und machen Sie andere Schreiber in kontrollierten Stufen zu Aufrufern. Protokollieren Sie verweigerte Versuche im Test. Eine Schematrennung ohne geänderte Berechtigungen ist kosmetisch, weil jeder alte Job weiterhin darüber hinweggreifen kann.

Kandidaten nach der nötigen Arbeit bewerten

Eine brauchbare Bewertung einer Grenze schätzt Migrationsaufwand und Betriebsrisiko. Sie behauptet nicht, Architektur durch Rechnen zu entdecken. Ich vergleiche Kandidaten mit denselben beobachtbaren Fragen und bewahre die Rohbelege neben jeder Bewertung auf.

Halten Sie für jede vorgeschlagene Grenze Folgendes fest:

  • Zahl und fachliche Bedeutung der Transaktionen, die beide Seiten schreiben
  • Entscheidungslesezugriffe, die aktuellen entfernten Zustand verlangen
  • Batch- und Wiederherstellungsabläufe über der Grenze
  • Tabellen mit mehreren aktiven Schreibern
  • Berichte und Exporte, die einen neuen Lesepfad brauchen

Verwenden Sie eine kleine ordinale Skala wie nicht vorhanden, beherrschbar, erheblich und blockierend. Fassen Sie nicht alles zu einer Dezimalzahl zusammen. Zwei Kandidaten mit demselben Gesamtwert können ganz verschiedene Risiken tragen: Einer verlangt vielleicht viele einfache Projektionen, der andere hat eine einzige blockierende Finanzinvariante. Die zweite bestimmt die Entscheidung.

Die beste erste Grenze hat gewöhnlich zusammengehörige Schreibvorgänge und langweilige Lesezugriffe. Eine Gruppe besitzt ihre Aktualisierungen, während externe Verbraucher deren Daten überwiegend anzeigen oder auswerten. Diese Form eignet sich für eine Outbox, Projektionen und eine kleine Befehlsoberfläche. Die schlechteste Grenze umfasst vielleicht wenige offensichtliche Tabellen, aber viele aktuelle Entscheidungslesezugriffe und gemeinsame Schreiber. Ein kleines Schema bedeutet keine geringe Kopplung.

Das Ergebnis ändert sich mit dem Zeitfenster. Analysieren Sie repräsentative Geschäftsperioden einschließlich geplanter Läufe und seltener Bedienaktionen. Vergleichen Sie gewöhnliche Tage mit Abschluss- oder Abrechnungsperioden. Eine Matrix aus einem ruhigen Nachmittag unterschätzt die Kopplung. Die Quellenanalyse sollte das Fenster ergänzen, indem sie Einstiegspunkte aufführt, die im erfassten Verkehr fehlen.

Halten Sie Unsicherheit sichtbar. Markieren Sie Tabellen mit unvollständigen Traces, dynamischen Namen, externen Schreibern oder unbekannten Prozeduren. Eine ungeklärte Kante zählt nicht als null. Ich würde eine Grenzentscheidung rund um eine unbekannte Buchungsroutine aufschieben, statt einem sauber aussehenden Graphen aus lückenhaften Belegen zu vertrauen.

Die Grenze mit Schattenverhalten beweisen

In dreißig Tagen abschließen
Jede Neufassung wird in unter 30 Tagen samt neuer Architektur und Paritätsbelegen geliefert.

Eine Grenze verdient Vertrauen, wenn die vorgeschlagenen Eigentümer aktuelle Ergebnisse auf aufgezeichneten Arbeitslasten reproduzieren können, ohne Schreibzugriffe zu teilen. Bevor Produktionsbefehle an neue Services gehen, sollte die mögliche Architektur im Schatten laufen und ihre Zustandsübergänge mit dem Original vergleichen.

Der Testaufbau sollte Befehle oder erfassten Verkehr mit stabilen Kennungen wiederholen, Datenbankeffekte beobachten und fachliche Ausgaben statt physischer Zeilenreihenfolgen vergleichen. Normalisieren Sie Zeitstempel, erzeugte Kennungen und andere nichtdeterministische Felder. Vergleichen Sie Summen, Status, veröffentlichte Fakten, Fehlerklassen und Ergebnisse von Wiederanläufen. Eine Abweichung braucht eine eingeordnete Erklärung, keine allgemeine Erfolgsquote.

Nehmen Sie Fälle auf, die die Grenze belasten:

  1. erfolgreiche Befehle mit Schreibzugriffen bei genau einem Eigentümer
  2. abgelehnte Befehle nach einer entfernten Reservierung oder Validierung
  3. Wiederholungen nach Timeouts und doppelter Zustellung
  4. Batch Wiederanlauf von jeder Prüfpunktposition
  5. veraltete oder fehlende Projektionsdaten

Aufgezeichneter Verkehr liefert Realitätsnähe, enthält aber selten jeden Fehler. Fügen Sie kontrollierte Störungen zwischen den Schritten ein, die früher denselben Commit teilten. Stoppen Sie den Verbraucher nach seinem Schreibvorgang, aber vor der Bestätigung. Verzögern Sie eine Projektionsaktualisierung. Wiederholen Sie eine Befehlskennung. Lassen Sie eine Reservierung genau beim Eintreffen der Bestätigung ablaufen. Diese Tests zeigen, ob der neue Entwurf ausdrückliches Wiederherstellungsverhalten besitzt.

CodeHero verwendet beim Umschreiben von Altsystemen einen Paritätstest gegen aufgezeichneten Produktionsverkehr. Das passt zu dieser Aufgabe, denn Architekturänderungen sind nur glaubwürdig, wenn das Verhalten gegenüber dem Original rechenschaftspflichtig bleibt. Die Belege sollten für die Entwickler des Kunden lesbar bleiben: Eingabekennung, altes Ergebnis, neues Ergebnis, normalisierte Unterschiede und die Regel, nach der sie angenommen oder abgelehnt wurden.

Verlangen Sie keine Gleichheit jedes Bytes, wenn die Migration die Architektur absichtlich ändert. Verlangen Sie Gleichheit für zugesagtes Verhalten und dokumentierte Zustimmung für beabsichtigte Unterschiede. Wenn sich die Buchungsreihenfolge ändert, Salden, Referenzen und Wiederherstellungsregeln aber korrekt bleiben, ist die physische Reihenfolge vielleicht unwichtig. Wenn ein Fehler nach einem Timeout zum Erfolg wird, ist das auch bei gleicher finaler Tabellenzahl relevant.

Die erste Extraktion muss eine Transaktionsgrenze entfernen

Wählen Sie den ersten Service erst, wenn Sie seine Tabellen, Befehle, veröffentlichten Fakten, grenzüberschreitenden Lesezugriffe und Wiederherstellungsregeln benennen können. Das Team sollte auf jeden alten Schreibvorgang über die Grenze zeigen und sagen können, ob er entfernt, in einen verantworteten Befehl umgewandelt oder als vorübergehende Migrationsbeschränkung mit datierter Ausstiegsbedingung akzeptiert wurde.

Ich verwende ein einziges Releasekriterium: Kein Produktionspfad darf Tabellen auf beiden Seiten der vorgeschlagenen Grenze schreiben. Vorübergehende doppelte Schreibvorgänge in einem Migrationsadapter zählen weiterhin als grenzüberschreitend. Sie brauchen Idempotenz, Vergleich und einen Entfernungsplan, beweisen aber keine unabhängige Verantwortung.

Die Extraktionsreihenfolge folgt den Belegen. Setzen Sie zuerst genau einen Schreiber pro Tabelle durch. Ersetzen Sie danach Anzeige- und Berichtslesezugriffe durch Projektionen oder genehmigten Übergangszugriff. Verschieben Sie Entscheidungslesezugriffe in Befehle des Eigentümers oder ausdrückliche Reservierungsprotokolle. Ändern Sie erst dann Deployment- und Speichergrenzen. Die umgekehrte Reihenfolge erzeugt Netzwerkaufrufe, während die alte Datenkopplung bestehen bleibt.

Behalten Sie Co-Write- und Lesematrix nach der Extraktion. Sie werden zu Regressionstests. Ein neuer gemeinsamer Schreiber, ein Befehl, der aktuellen entfernten Zustand liest, oder ein Batchjob, der die API umgeht, sollte eine Prüfung auslösen. Architekturdiagramme altern unbemerkt, Zugriffsdaten zeigen den Verstoß.

Manche Systeme enthalten eine Invariante, die lokal bleiben sollte. Akzeptieren Sie dieses Ergebnis. Ein größerer Service mit einer zusammenhängenden Transaktion ist günstiger und sicherer als zwei Services, die durch synchrone Aufrufe, verteilte Sperren und Reparaturen des Betriebs zusammengehalten werden. Das Ziel ist unabhängige Änderung dort, wo die Fachregeln sie erlauben, nicht die größtmögliche Zahl von Deployments.

Wenn die Belege eine Trennung stützen, ist die Grenze keine Meinung über Substantive mehr. Sie wird zu einer widerlegbaren Behauptung: Diese Tabellen ändern sich gemeinsam, diese Lesezugriffe vertragen diesen Vertrag, diese Befehle erhalten die Invariante, und diese Fehlertests zeigen unabhängige Wiederherstellung. Das reicht für den Schritt von einer Workshopgrenze zu einer Produktionsgrenze.

FAQ

Was ist der stärkste Beleg für eine Servicegrenze?

Tabellen, die wiederholt in einer Transaktion geändert werden, liefern den stärksten ersten Beleg, weil das System diesen Schreibvorgängen ein gemeinsames Ergebnis gibt. Prüfen Sie vor der Grenzziehung den Grund, denn manche gemeinsamen Transaktionen sind nur Bequemlichkeit und keine Fachregel.

Definieren Fremdschlüssel die Servicegrenzen?

Nein. Fremdschlüssel zeigen deklarierte referenzielle Beziehungen, während Servicegrenzen von Schreibverantwortung, Entscheidungsregeln, Wiederherstellung und zulässiger Konsistenz abhängen. Nicht deklarierte Abhängigkeiten in Prozeduren und Batches sind oft wichtiger als der Schema Constraint.

Wie viel Produktionsverkehr sollten wir für die Grenzanalyse erfassen?

Erfassen Sie vollständige Transaktionen über repräsentative Geschäftsperioden hinweg, einschließlich geplanter Jobs, Abschlussprozesse, Importe und Bedienerkorrekturen. Eine feste Zahl von Tagen ist weniger nützlich als die Abdeckung aller wichtigen Einstiegspunkte und Wiederherstellungspfade.

Braucht jeder domänenübergreifende Lesezugriff eine synchrone API?

Nein. Anzeige, Berichte und historische Lesezugriffe passen meist zu Projektionen, Snapshots oder Massenexporten. Verwenden Sie einen verantworteten Befehl oder eine Reservierung, wenn der Lesezugriff einen Schreibvorgang steuert und aktuellen Zustand verlangt.

Wie finden wir Datenzugriffe in gespeicherten Prozeduren und Triggern?

Untersuchen Sie Prozedur- und Triggerdefinitionen, verbinden Sie sie mit Audittraces der Datenbank und ordnen Sie ihre Lese- und Schreibzugriffe der auslösenden Transaktion zu. Anwendungstraces allein können einen Vorgang über mehrere Tabellen wie einen einzelnen Tabellenschreibzugriff aussehen lassen.

Kann ein Message Broker eine verteilte Transaktion überflüssig machen?

Ein Broker transportiert Nachrichten, er entscheidet keine Invariante. Sie brauchen weiterhin verantwortete Zustandsübergänge, Idempotenz, Wiederholungsverhalten, Abgleich und eine Regel für Teilerfolg.

Sollten Berichtsjoins operative Servicegrenzen beeinflussen?

Sie sollten den Leseentwurf beeinflussen, nicht den Transaktionsentwurf besitzen. Speisen Sie eine Berichtsprojektion aus autoritativen Änderungen, statt operative Services zeilenweise Netzwerk Joins ausführen zu lassen.

Was tun wir, wenn zwei Domänen wirklich atomare Schreibvorgänge brauchen?

Halten Sie die Invariante in einem Service, führen Sie ein ausdrückliches Reservierungsprotokoll ein oder ändern Sie die Fachregel so, dass zeitweilige Abweichung mit Abgleich erlaubt ist. Wenn keine Möglichkeit akzeptabel ist, liegt die vorgeschlagene Trennung falsch.

Wie setzen wir Tabellenverantwortung vor der Serviceextraktion durch?

Geben Sie einem künftigen Eigentümer Schreibrechte, führen Sie andere Schreiber über verantwortete Befehle und protokollieren Sie verweigerte Versuche im Test. So werden vergessene Jobs und Werkzeuge sichtbar, bevor ein physischer Datenbankumzug die Fehlerkosten erhöht.

Wie beweisen wir, dass eine gewählte Servicegrenze funktioniert?

Spielen Sie aufgezeichnete Arbeitslasten durch die vorgeschlagenen Eigentümer und vergleichen Sie fachliche Ergebnisse, Wiederholungen, Batch Wiederanläufe und Fehlerfälle mit dem Original. Die Grenze ist glaubwürdig, wenn keine Seite Tabellen der anderen schreiben oder an deren Commit teilnehmen muss.