Was macht Codebase Design – Tiefe Module entwerfen?
Entwerfen Sie tiefe Module: viel Verhalten hinter einer kleinen Schnittstelle, platziert an einem Seam, an dem Aufrufer und Tests zusammentreffen. Ziel ist Hebelwirkung (Leverage) für Aufrufer, Lokalität für Wartende und Tests, die Refactorings überstehen.
Regeln
- Tiefe ist eine Eigenschaft der Schnittstelle, nicht der Implementierung. Ein tiefes Modul kann aus kleinen, austauschbaren Teilen bestehen; sie gehören nur nicht zu seiner Schnittstelle. Es kann interne Seams für eigene Tests sowie den externen Seam an seiner Schnittstelle besitzen.
- Führen Sie den Löschtest durch. Stellen Sie sich vor, das Modul zu löschen. Verschwindet die Komplexität, war es ein Durchlauf. Taucht die Komplexität bei mehreren Aufrufern wieder auf, hat es seine Daseinsberechtigung.
- Die Schnittstelle ist die Testoberfläche. Aufrufer und Tests überqueren denselben Seam. Wenn Sie hinter der Schnittstelle testen müssen, hat das Modul vermutlich die falsche Form.
- Ein Adapter bedeutet einen hypothetischen Seam; zwei machen ihn real. Fügen Sie einen Seam nur dort hinzu, wo etwas tatsächlich variiert – normalerweise Produktion und Test.
- Verkleinern Sie die Schnittstelle. Weniger Methoden, einfachere Parameter, mehr Komplexität im Inneren verborgen.
- Akzeptieren Sie Abhängigkeiten, anstatt sie zu erzeugen. Übergeben Sie das Zahlungs-Gateway, anstatt es innerhalb der Funktion zu konstruieren.
- Liefern Sie Ergebnisse zurück, anstatt Seiteneffekte zu erzeugen, wo das Design es erlaubt.
Vokabular
Verwenden Sie diese Begriffe exakt. Ersetzen Sie sie nicht durch „Komponente“, „Service“, „API“ oder „Grenze“.
- Modul: etwas mit einer Schnittstelle und einer Implementierung, in jeder Größenordnung: eine Funktion, Klasse, ein Paket oder ein schichtenübergreifender Schnitt.
- Schnittstelle (Interface): alles, was ein Aufrufer wissen muss, um das Modul korrekt zu nutzen: Typen, Invarianten, Reihenfolge, Fehlermodi, erforderliche Konfiguration und Performance. Nicht nur die Signatur.
- Implementierung: der Code innerhalb eines Moduls. Ein kleiner Adapter kann eine große Implementierung haben (ein Postgres-Repository) und ein großer Adapter eine kleine (ein In-Memory-Fake).
- Tiefe: Hebelwirkung an der Schnittstelle – das Verhalten, das ein Aufrufer oder Test pro Einheit der zu lernenden Schnittstelle ausüben kann. Ein Modul ist tief, wenn viel Verhalten hinter einer kleinen Schnittstelle sitzt, und flach, wenn die Schnittstelle fast so komplex ist wie die Implementierung.
- Seam (Michael Feathers): eine Stelle, an der sich Verhalten ändern lässt, ohne diese Stelle zu bearbeiten; dort lebt die Schnittstelle eines Moduls. Die Wahl des Seams ist eine eigene Entscheidung.
- Adapter: ein konkretes Objekt, das eine Schnittstelle an einem Seam füllt. Es benennt eine Rolle, nicht den Inhalt.
- Hebelwirkung (Leverage): was Aufrufer aus der Tiefe gewinnen. Eine Implementierung zahlt sich über viele Aufrufstellen und Tests aus.
- Lokalität: was Wartende aus der Tiefe gewinnen. Änderung, Fehler, Wissen und Verifikation konzentrieren sich an einem Ort.
Abgelehnte Formulierungen: Tiefe als Verhältnis von Implementierungszeilen zu Schnittstellenzeilen (belohnt Aufblähung); „Schnittstelle“ nur als Typ-Schlüsselwort oder die öffentlichen Methoden (zu eng); „Grenze“ (kollidiert mit DDDs Bounded Context).
Wenn das Projekt ein CONTEXT.md-Glossar führt, verwenden Sie dessen Domänenbegriffe gemeinsam mit diesen.
Tiefer eintauchen
- Um einen Cluster flacher Module nach Abhängigkeitstyp zu vertiefen, lesen Sie DEEPENING.md.
- Um mehrere radikal unterschiedliche Schnittstellen zu vergleichen, lesen DESIGN-IT-TWICE.md. Es startet drei oder mehr Unterassistenten – verwenden Sie es nur, wenn der Benutzer danach fragt.