ousterhout-quality-program
Was er macht
Verwenden Sie es immer dann, wenn Code geschrieben oder überprüft wird, der eine Grenze schafft oder ändert – ein neues Modul, eine Klasse, Komponente, Hilfsfunktion, Hook, Dienst oder Wrapper; jede Extraktion oder Zentralisierung von gemeinsam genutztem Code; jeder "Lass uns das wiederverwendbar machen"-Moment – und wenn explizit ein Modul überprüft, refaktoriert oder entworfen wird. Bewertet, ob eine Abstraktion ihren Zweck erfüllt: Modultiefe, ob eine Designentscheidung verborgen werden sollte, ob duplizierter Code eine gemeinsame Invariante schützt oder nur ähnlich klingt, ob eine Schnittstelle stabil ist. Schützt vor mechanischem SOLID/Clean Code, der viele flache Klassen erzeugt. Definiert außerdem den Leser-Kosten-Test (Code, der für Menschen und Agenten günstig zu lesen und zu ändern ist) und das Verfahren zur Refaktorisierung eines bestehenden Codes auf diesen Standard.
Die Installation öffnet diesen Eintrag in deiner AgentsRoom-Desktop-App. Ist die App noch nicht installiert, landest du auf der Download-Seite.
SKILL.md
---
name: ousterhout-quality-program
description: Verwenden Sie es immer dann, wenn Code geschrieben oder überprüft wird, der eine Grenze schafft oder ändert – ein neues Modul, eine Klasse, Komponente, Hilfsfunktion, Hook, Dienst oder Wrapper; jede Extraktion oder Zentralisierung von gemeinsam genutztem Code; jeder "Lass uns das wiederverwendbar machen"-Moment – und wenn explizit ein Modul überprüft, refaktoriert oder entworfen wird. Bewertet, ob eine Abstraktion ihren Zweck erfüllt: Modultiefe, ob eine Designentscheidung verborgen werden sollte, ob duplizierter Code eine gemeinsame Invariante schützt oder nur ähnlich klingt, ob eine Schnittstelle stabil ist. Schützt vor mechanischem SOLID/Clean Code, der viele flache Klassen erzeugt. Definiert außerdem den Leser-Kosten-Test (Code, der für Menschen und Agenten günstig zu lesen und zu ändern ist) und das Verfahren zur Refaktorisierung eines bestehenden Codes auf diesen Standard.
---
# Ousterhout-Qualitätsprogramm
## Überblick
Die Aufgabe eines Moduls ist es, Komplexität hinter einer kleinen Schnittstelle zu verbergen. Das Kernmaß ist die **Tiefe**: Ein tiefes Modul bietet eine einfache Schnittstelle über umfangreiche Funktionalität; die Schnittstelle eines flachen Moduls ist fast so komplex wie seine Implementierung, sodass es sich nicht auszahlt. Komplexität ist das, was man spürt, wenn eine Änderung erfordert, dass man Code versteht oder berührt, den man nicht erwartet hat — Ousterhout nennt zwei Quellen: **Abhängigkeiten** (du kannst A nicht ändern, ohne B zu ändern) und **Undurchsichtigkeit** (die wichtigen Informationen sind nicht offensichtlich).
Ousterhout allein sagt dir, wie sich ein gutes Modul *anfühlt*. Es ist am stärksten in Kombination mit einigen anderen Blickwinkeln, die dir sagen, wo die Grenzen liegen und wie man sich sicher auf sie zubewegt. Diese Fähigkeit ist diese kombinierte Sicht.
## Wo Reviews tatsächlich schiefgehen
Die zwei Fehler, die diese Fähigkeit korrigieren soll — die wiederholt in agentengeschriebenem Code beobachtet wurden — liegen in der **Behebung**, nicht im Urteil „teilen/nicht teilen“ selbst:
1. **Die flache Lösung.** Bei sechs `as unknown as`-Casts zentralisiert der ununterstützte Reviewer sie in einen generischen `castRows<T>()`-Helper — ordentlicher, aber die Undurchsichtigkeit bleibt bestehen. Die tiefe Lösung sind typisierte Zeilen→Domänen-Mapper mit zuerst festgelegten Tests (Parnas angewandt: ein Cast ist der Geruch einer fehlenden Grenze; Beck: beweise die Abbildung, bevor du sie verschiebst). Einen Geruch zu verschönern heißt nicht, ihn zu entfernen.
2. **Die reflexartige Extraktion.** Bei derselben Update-Logik, die in drei Geschwisterkomponenten wiederholt wird, sagte jeder ununterstützte Reviewer „extrahiere einen gemeinsamen Helper“ — der DRY-Reflex. Die Regel dieses Programms, die Metz erweitert: warte auf die Invariante, nicht auf das dritte Ähnlichkeitsbild — zentralisiere, wenn der Code eine gemeinsame Regel schützt, nicht wenn er sich reimt.
Wenn du dir selbst eine Behebung empfiehlst, prüfe sie mit beiden Fragen: Entfernt sie die Undurchsichtigkeit oder verlagert sie sie nur, und schützt die Extraktion eine Invariante oder dedupliziert sie nur eine Form?
## Proportionalitäts-Grenze
Überspringe die Sicht, wenn eine Änderung keinen neuen exportierten/importierbaren Namen hinzufügt, kein neues Modul/Klasse/Komponente/Helper/Hook/Service/Wrapper erstellt und nichts zentralisiert. Reine Umbenennungen, mechanische Codemods, Konfigurations-/Datenänderungen und einzeilige Korrekturen sind ausgenommen. Im Zweifel führe nur die zwei Kernprüfungen (Tiefe, Invariante) durch und höre dort auf.
## Die Regel in voller Länge
Jeder generierte oder überprüfte Code muss die Ousterhout-Sicht passieren, bevor die Aufgabe als erledigt gilt — nicht nur explizite Design-Reviews — außer bei Änderungen unterhalb der Proportionalitäts-Grenze (keine neue Grenze, keine Zentralisierung: Umbenennungen, Codemods, Konfigurationsänderungen). Zwei Tests: (1) **Tiefe** — eine neue Schnittstelle muss wesentlich mehr verbergen, als sie offenlegt; eine Schnittstelle, die so komplex ist wie das, was sie umschließt, zahlt sich nicht aus. (2) **Invariante** — extrahiere gemeinsamen Code nur, wenn er eine gemeinsame Regel schützt, niemals weil drei Stellen sich ähneln; und eine Behebung muss Undurchsichtigkeit entfernen, nicht verlagern (sechs Casts in einen Helper zu zentralisieren sind immer noch sechs Casts). Wenn eine Änderung eine Grenze schafft oder umgestaltet, finde zuerst, wie ein etabliertes Produkt ein Problem dieser Form und Größenordnung löst, und übernehme dessen Konventionen, sofern kein ausdrücklicher Grund dagegen spricht (ein aus dem Training erinnerndes Muster ist eine Behauptung, keine Quelle), und führe dann die untenstehenden Prüfungen durch.
## Wann verwenden
- Entscheiden, ob eine neue Klasse/Funktion/Hook ihre Schnittstelle wert ist oder nur ein flacher Durchgang.
- Eine Datei überschreitet eine Größenschwelle und du entscheidest *wie* du sie aufteilst, nicht nur, dass du es tun solltest.
- Wiederholter Code verleitet dich dazu, einen gemeinsamen Helper zu extrahieren.
- Entwerfen oder Überprüfen einer Grenze um eine Geschäftsregel (eine Autorisierungsscope-Prüfung, eine Geld-/Rundungsregel, eine Zustandsautomaten-Übergangsabsicherung, eine Datenaufbewahrungsregel).
- Eine Schnittstelle soll einen Parameter oder einen Sonderfall erhalten.
- Ein bestehender Codebestand soll auf diesen Standard gebracht werden — siehe „Refactoring eines bestehenden Codebestands zu diesem Standard“ weiter unten.
**Nicht für:** triviale mechanische Änderungen oder wenn eine Projektkonvention bereits die Struktur vorgibt — siehe die Proportionalitäts-Grenze oben. Ziehe `karpathy-guidelines` für disziplinierte chirurgische Änderungen und eine testgetriebene Entwicklungsfähigkeit als Refaktor-Sicherheitsnetz heran, wenn diese verfügbar sind.
## Die Sichtweisen
Jede Sicht fügt genau eine Frage hinzu. Ousterhout ist die Grundlage; die anderen korrigieren seine blinden Flecken.
| Linse | Die eine Frage, die sie hinzufügt | Wann sie überschreibt |
|---|---|---|
| **Ousterhout** — tiefe Module | Verbirgt diese Schnittstelle mehr, als sie offenlegt? | Standard-Grundgerüst. |
| **Parnas** — Informationsverbergung | Welche Designentscheidung (die sich wahrscheinlich ändert) verbirgt dieses Modul? | Der *Grund*, warum ein Modul tief sein sollte. Wenn es nichts verbirgt, das sich ändert, ist Tiefe kosmetisch. |
| **Brooks** — wesentlich vs zufällig | Entfernt dies zufällige Komplexität oder verlagert es nur wesentliche Domänenkomplexität? | Verhindert "Refactorings", die das Durcheinander nur verschieben, ohne es zu verkleinern. |
| **Evans** — Domain-Driven Design | Ist diese Grenze in Domänensprache benannt, nicht in generischer Hilfssprache? | Benenne `utils`/`helpers` um — benenne die Grenze nach dem Invariant, das dieses Repo tatsächlich hat. |
| **Fowler** — Refactoring / Gerüche | Was ist der kleinste sichere Schritt hin zu einem tieferen Design? | Macht aus "sollte tiefer sein" konkrete Schritte hinter bestandenen Tests. |
| **Beck** — einfaches Design, test-first | Habe ich das aktuelle Verhalten bewiesen, bevor ich die Naht vertiefe? | Eine Bremse gegen vorzeitige Architektur. Erst funktioniert und getestet machen, dann die richtige Naht vertiefen. |
| **Hickey** — einfach vs leicht | Vermischt dies unzusammenhängende Konzepte oder ist es wirklich ein Konzept? | Ein flacher Helfer ist meist *leicht* (nah, schnell), nicht *einfach* (wenige vermischte Konzepte). Bevorzuge einfach. |
| **Metz** — Duplikation statt falscher Abstraktion | Schützt dieser wiederholte Code ein gemeinsames Invariant oder sieht er nur ähnlich aus (Regel dieses Programms, erweitert Metz)? | Metz: Duplikation ist günstiger als die falsche Abstraktion — baue eine falsche Abstraktion lieber wieder inline zurück, als sie zu verbiegen. Dieses Programm erweitert sie: zentralisiere **nicht**, weil es sich wiederholt; zentralisiere nur, wenn es ein echtes Invariant schützt. Toleriere Duplikation, bis sich das Invariant zeigt. |
| **Hyrum's Law** — beobachtbares Verhalten | Werden Aufrufer sich auf Verhalten jenseits des Vertrags dieser Schnittstelle verlassen? | Spricht für kleine, stabile Schnittstellen: jedes beobachtbare Verhalten wird irgendwann tragend. |
## Das Kombinationsrezept
In dieser Reihenfolge anwenden — spätere Linsen sind nur relevant, wenn die früheren bestehen:
1. **Metz — das Zulassungstor.** Verdient diese Grenze/Abstraktion überhaupt Existenz? Regel dieses Programms, erweitert Metz: extrahiere nur, wenn der Code eine gemeinsame Regel schützt — drei Ähnlichkeiten sind kein enthülltes Invariant. Wenn nein, hier stoppen.
2. **Parnas / Ousterhout** — Verberge die volatile Entscheidung (Autorisierungsbereich, Rundungsregel, Übergangsschutz, Aufbewahrungsregel) hinter einem tiefen Modul.
3. **Evans** — Benenne dieses Modul in Domänensprache, nicht `utils`.
4. **Beck / Fowler** — Für bestehenden Code: sichere das aktuelle Verhalten mit Tests, dann refaktoriere in kleinen sicheren Schritten darauf zu. Für frisch generierten Code gibt es kein aktuelles Verhalten zu sichern — schreibe stattdessen den Test, der das beabsichtigte Verhalten definiert.
5. **Hickey** — Lehne Schnittstellen ab, die unzusammenhängende Konzepte mischen, nur weil die Abläufe ähnlich aussehen.
## Das strukturelle Anti-Pattern
**Mechanisches SOLID / Clean Code erzeugt flache Module.** Eine dogmatische Lesart —
je Klasse pro Verantwortung, jede Funktion extrahieren, alles winzig halten —
führt zu einem Schwarm von Klassen, deren Schnittstellen so komplex sind wie ihre Körper. Wenn
eine Regel sagt "teile das", frage, welche *Entscheidung* die Teilung verbirgt (Parnas) und
ob sie mehr verbirgt, als sie offenlegt (Ousterhout). Wenn sie nichts verbirgt, das
sich ändert, teile nicht. Diese Absicherung ist besonders wichtig unter Refactoring-Druck ("räum das auf", "diese Datei ist zu groß") — in ruhiger Analyse wehren sich Reviewer bereits dagegen; mitten im Refactoring, mit dem Auftrag sichtbare Änderungen zu erzeugen, wird der Schwarm flacher Dateien geschrieben.
## Häufige Fehler
- **Nur nach Größe teilen.** Ein 400-Zeilen-Abfragemodul, das eine kohärente Entscheidung verbirgt, kann tiefer sein als vier 100-Zeilen-Module, die alle dieselben Joins durchsickern lassen.
- **Die Teilung `helpers`/`utils` nennen.** Wenn du es nicht in Domänensprache benennen kannst (Evans), ist die Grenze wahrscheinlich falsch.
- **Beim zweiten Vorkommen extrahieren.** Regel dieses Programms, erweitert Metz: warte auf das Invariant, nicht auf den dritten Ähnlichen.
- **Vertiefen, bevor das Verhalten gesichert ist.** Beck: Ohne Test, der das aktuelle Verhalten beweist, ist ein "Vertiefungs"-Refactoring eine Neuschreibung.
- **Eine Durchleitung als Modul zählen.** Ein Wrapper, der seine Argumente weiterleitet, fügt eine Schnittstelle hinzu und verbirgt nichts — per Definition flach.
- **Eine Reimform mit einem Invariant verwechseln.** Das beste Indiz für ein gemeinsames Invariant ist gleichzeitige Änderung: die Kopien wurden zusammen in der Historie korrigiert oder geändert (derselbe Fehler an zwei Stellen behoben). Ähnlichkeiten, die unabhängig geändert werden, sind Reime; lass sie dupliziert.
- **Einen Geruch aufräumen statt entfernen.** Sechs Casts in einen generischen Cast-Helfer zu zentralisieren ist die ordentliche Version derselben Unklarheit. Die tiefe Lösung benennt die Grenze, die der Cast überdeckt hat.
## Leser-Kosten: der dritte Test
Tiefe und Invariant entscheiden, ob eine Grenze existieren sollte. Leser-Kosten
entscheiden, ob der Code drumherum billig zu ändern ist. Der nächste Leser, Mensch
oder Agent, bezahlt für jede Zeile, die er laden muss, um etwas sicher zu ändern.
Agenten bezahlen in Tokens und navigieren per Textsuche, Teillesungen und
Typprüfung/Testschleifen, daher kosten dieselben Defekte ihnen mehr. Frage:
- **Findbar?** Ein Name pro Konzept, überall gleich geschrieben, per Volltextsuche erreichbar. Mängel: Namen, die aus Strings zusammengesetzt sind, Verkabelung durch Import-Nebeneffekte, Re-Export-Ketten, die die Definition verbergen, zwei Namen für ein Konzept.
- **Kann der Leser früh abbrechen?** Der Vertrag steht oben in der Datei oder über dem Export: was er verspricht, was er verbirgt, was er niemals tut. Mangel: Der Vertrag kann nur durch Lesen des Inhalts abgeleitet werden.
- **Maschinenprüfbar?** Präzise Typen an jeder Grenze rein und raus, sodass ein Typcheck das Lesen der Aufrufer ersetzt. Mängel: `any`, nackte Dictionaries, boolesche Flags, deren Bedeutung im Inhalt lebt.
- **Ist die Kopplung sichtbar?** Stellen, die zusammen geändert werden müssen, sind erzwungen (ein geteilter Typ, ein Test, eine einzige Quelle) oder, falls nicht, an beiden Stellen markiert. Der Beweis für versteckte Kopplung ist gleichzeitige Änderung in der Historie, die im Code nirgends erwähnt wird.
- **Rauschfrei?** Keine Kommentare, die den Code wiederholen, kein auskommentierter Code, keine toten Zweige, keine Änderungsverlaufskommentare, kein veralteter Pfad neben seinem Ersatz.
- **Vorhersehbar?** Layout folgt dem bestehenden Muster des Repos; der Test ist dort, wo ein Leser ihn erwartet, und läuft eigenständig.
Dateigröße ist absichtlich nicht genannt. Eine sehr große Datei ist ein Grund, nach einer zweiten versteckten Entscheidung zu suchen, niemals ein Grund zum Kürzen: Leser können suchen und einen Bereich lesen, und eine Aufteilung, die nichts verbirgt, fügt Schnittstellen hinzu, ohne Last zu entfernen.
Für In-Code-Markierungen und eine Repo-Codemap verwende `context-audit`, wo verfügbar: dessen `AIDEV-NOTE:`-Anker (eine nicht wiederherstellbare Tatsache plus eine Herkunftsreferenz, höchstens zwei Zeilen, an der Stelle) ist die Konvention für Kopplung, die nicht erzwungen werden kann.
## Refactoring eines bestehenden Codebases nach diesem Standard
Ein Retrofit wird genauso beurteilt wie neuer Code; was sich unterscheidet, ist Reihenfolge und Zurückhaltung. Der Großteil eines Codebases sollte unangetastet bleiben.
1. **Bestandsaufnahme, nur lesend.** Liste die Grenzen (Module, Services, geteilte Helfer). Für jeden Eintrag: die Entscheidung, die er verbirgt, oder "keine"; Schnittstellengröße gegenüber Inhalt; Co-Change-Partner aus der Historie; Leser-Kosten-Mängel. Noch nichts ändern.
2. **Nach Änderungsrate sortieren, nicht nach Hässlichkeit.** Priorität ist, wie oft der Code sich ändert multipliziert mit den Lesekosten. Kalter Code, der funktioniert, bleibt wie er ist, egal wie oberflächlich. Wesentliche Domänenkomplexität bleibt, wo sie ist (Brooks).
3. **Pro Befund eine Maßnahme zuweisen:**
- Durchleitungsschicht oder Wrapper, der nichts verbirgt: löschen, Aufrufer verwenden, was er umhüllt hat;
- falsche Abstraktion, verbogen durch Flags und Sonderfälle: wieder inline einfügen (Metz), dann nach der echten Invariante suchen;
- oberflächliche Geschwister, die eine Entscheidung teilen: hinter einer Schnittstelle zusammenführen;
- ausgelaufene Entscheidung (Aufrufer kennen Format, Regel, Schema): in das Modul ziehen, das sie besitzt;
- generischer Name (`utils`, `helpers`, `manager`): umbenennen nach der Entscheidung, die er verbirgt, oder in seine Aufrufer auflösen;
- untypisierte Grenze: typisieren und Casts durch den Mapper ersetzen, den sie kaschierten;
- versteckte Kopplung: erzwingen oder beide Stellen markieren;
- Rauschen: löschen.
Reime, die unabhängig ändern, bekommen keine Maßnahme.
4. **Verhalten zuerst festlegen.** Keine Maßnahme beginnt, bevor ein Test das aktuelle Verhalten des berührten Codes beweist (Beck). Refactorings erhalten das Verhalten; eine Verhaltensänderung ist ein separater Commit.
5. **Arbeiteinheiten so schneiden, dass ein Agent sie allein abschließen kann.** Eine Grenze pro Einheit. Jede Einheit benennt die Dateien, die sie besitzt, den Vertrag, den sie bewahren muss, und den Befehl, der ihn eigenständig beweist. Keine zwei parallelen Einheiten schreiben dieselbe Datei; gemeinsame Dateien (Barrels, Registries, Routentabellen) bekommen einen einzigen Besitzer oder warten auf Integration. Schnittstellenänderungen, von denen mehrere Einheiten abhängen, landen zuerst als eigene Einheit.
6. **Ergebnis messen.** Wähle vor Beginn eine repräsentative Änderung und zähle die Dateien und Zeilen, die ein Leser laden muss, um sie zu verstehen; zähle danach erneut. Exportierte Namen und Gesamtzeilen sollten fallen oder gleich bleiben. Ein Refactoring, das Schnittstellen hinzufügt, schuldet einen angegebenen Grund.
7. **Stoppen**, wenn das, was bleibt, kalt, wesentlich oder ein Reim ist.
Verfügbare verwandte Skills: `repo-review` (Design-Typ) erzeugt die Bestandsaufnahme als rein beratendes Artefakt; `design-cleanup` führt die Fix-und-Rescan-Schleife für zufällige Komplexität aus; `context-audit` fügt Anker und die Codemap hinzu; `ousterhout-build-deep` ist die Autoren-Checkliste für die Agenten, die die Einheiten bearbeiten.
## Wo das steht
Dieser Skill ist die Review- und Urteilsebene: Nutze ihn, um zu entscheiden, ob eine Abstraktion tief ist, nach der richtigen Entscheidung benannt und das Extrahieren wert ist. `find-shared-code` verwendet ihn als Zulassungstest, wenn es die jüngere Historie nach teilenswertem Code durchsucht. Der Anhang unten gibt die Begründung jedes Autors.
---
## Anhang: Die Linsen im Detail
Der Fehlerfall, den jeder Autor erkennt, und der eine Schritt, den jeder dir gibt. Die obige Tabelle ist die Schnellreferenz; dies ist die dahinterstehende Begründung.
### Ousterhout — Tiefe Module (das Rückgrat)
*Eine Philosophie des Software-Designs.*
- **Tiefe** = Nutzen (versteckte Funktionalität) ÷ Kosten (Schnittstellenkomplexität). Ein tiefes Modul verbirgt viel hinter wenig. Die Schnittstelle eines flachen Moduls ist fast so komplex wie sein Inhalt, also bringt es nichts.
- **Komplexität** ist alles am System, was es schwer macht, es zu verstehen oder zu ändern. Zwei Quellen:
- **Abhängigkeiten** — man kann ein Teil nicht ändern, ohne ein anderes zu berühren.
- **Undurchsichtigkeit** — die wichtigen Informationen sind im Code nicht offensichtlich.
- **Symptome:** Änderungsverstärkung (eine Entscheidung, viele Änderungen), kognitive Belastung (wie viel man im Kopf behalten muss), unbekannte Unbekannte (man kann nicht sagen, welchen Code eine Änderung betrifft).
- **Schlüsselmaßnahme:** Komplexität *nach unten* ziehen — das Modul absorbiert den schwierigen Fall, damit Aufrufer ihn nicht haben. Konfigurationsparameter und Durchleitungen schieben Komplexität *nach oben* zum Aufrufer; das ist Flachheit.
Erkennt: Schnittstellen, die ihre Implementierung leaken; Helfer, die nicht helfen.
### Parnas — Informationsverbergung (warum Tiefe wichtig ist)
*Über die Kriterien zur Zerlegung von Systemen in Module (1972).*
- Zerlege um **Designentscheidungen, die sich wahrscheinlich ändern werden**, nicht um die Schritte einer Berechnung. Jedes Modul verbirgt eine solche Entscheidung.
- Dies ist der direkte Vorfahre des deep module. Ein Modul ist tief, *weil* es eine Entscheidung verbirgt, die sonst durch die Aufrufer hindurchwirken würde.
Fallen: Ein „Modul“, das nichts Flüchtiges verbirgt – seine Tiefe ist kosmetisch. Frage: Was ändert sich hinter dieser Schnittstelle, das Aufrufer nie sehen? Wenn die Antwort „nichts“ lautet, ist die Grenze nur Dekoration.
### Brooks — Wesentliche vs. zufällige Komplexität
*No Silver Bullet.*
- **Wesentliche** Komplexität ist inhärent im Fachgebiet (Bewertung ist wirklich so komplex). **Zufällige** Komplexität ist das, was unsere Werkzeuge und Struktur auferlegen.
- Nur zufällige Komplexität ist entfernbar. Ein Refactoring, das „aufräumt“, indem es wesentliche Domänenkomplexität von einer Datei in eine andere verschiebt, hat nichts bewirkt.
Fallen: Umstrukturierungen, die als Vereinfachung getarnt sind. Frage: Ist die Gesamtkonplexität gesunken oder nur verschoben?
### Evans — Domain-Driven Design
*Domain-Driven Design.*
- Grenzen sollten in der **allgegenwärtigen Sprache** der Domäne benannt werden, nicht in generischen Hilfsbegriffen. Ein Modul namens `helpers` benennt nichts; ein Modul namens `AccessScope` oder `PricingPolicy` benennt eine Invariante.
- Abgegrenzte Kontexte verhindern, dass Geschäfts-Invarianten über Schnittstellen hinweg durchsickern.
Fallen: korrekte Zerlegung mit bedeutungslosen Namen. Wenn du das Modul nicht in Domänensprache benennen kannst, hast du die Grenze wahrscheinlich an der falschen Stelle gezogen.
### Fowler — Refactoring und Code Smells
*Refactoring.*
- Gibt konkrete, sichere, benannte Schritte (Extract Function, Move Field, Replace Conditional with Polymorphism), um vom aktuellen Design zum tieferen zu gelangen.
- Jeder Schritt erhält das Verhalten und ist klein, sodass er umkehrbar bleibt.
Fallen: die Lücke zwischen „das sollte tiefer sein“ und dem Wissen um den nächsten Commit. Ousterhout setzt das Ziel; Fowler ist der Weg.
### Beck — Einfaches Design, Test-First
*Test-Driven Development; XP.*
- Vier Regeln für einfaches Design, in der von Beck veröffentlichten Reihenfolge: Tests bestehen, keine Duplikation, Absicht offenbaren, möglichst wenige Elemente. Dieses Programm folgt der späteren Fowler/Haines-Umsortierung – Absicht vor Duplikation – weil es die hier erweiterte Metz-Invariante bedient (siehe Metz unten): handle Duplikation erst, wenn du die Absicht benennen kannst, die sie schützt.
- Test-first ist eine Bremse gegen vorzeitige Architektur. Mach es erst funktionsfähig und beweise das Verhalten, dann vertiefe die Schnittstelle, die die Tests jetzt schützen.
Fallen: Architektur, die gebaut wird, bevor das Verhalten feststeht. Ohne Test, der das aktuelle Verhalten beweist, ist ein „Vertiefungs“-Refactoring eine unüberprüfte Umschreibung.
### Hickey — Einfach vs. Leicht
*Simple Made Easy.*
- **Einfach** = nicht verflochten: ein Konzept, nicht mit anderen vermischt (objektiv).
- **Leicht** = griffbereit, vertraut, schnell erreichbar (relativ zu dir).
- Die beiden sind unabhängig. Ein flacher Helfer ist meist *leicht* – schnell zu schreiben, nah – aber nicht *einfach*, wenn er unzusammenhängende Anliegen vermischt.
Fallen: Bequemlichkeit, die sich als Design tarnt. Bevorzuge Konstrukte, die Konzepte unvermengt halten, auch wenn ein verflochtenes schneller zu tippen ist.
### Metz — Bevorzuge Duplikation gegenüber der falschen Abstraktion
*„The Wrong Abstraction“ (2016).*
- Duplikation ist viel günstiger als die falsche Abstraktion. Eine zu früh extrahierte Abstraktion zwingt jeden zukünftigen Aufrufer, sich um Annahmen zu biegen, die nie für alle zutrafen.
- Wenn sich eine Abstraktion als falsch herausstellt, ist Metz’ Heilmittel, sie wieder einzufügen und die Duplikation zurückkehren zu lassen, statt sie an einen Fall anzupassen, für den sie nie gebaut wurde.
- **Diese Programmregel, die Metz erweitert: Zentralisiere nicht, weil Code sich wiederholt. Zentralisiere, wenn eine echte, geteilte Invariante geschützt wird.** Bis die Invariante sich zeigt, toleriere die Duplikation.
Fallen: Überzentralisierung – der flache gemeinsame Helfer, um den jetzt alle herumarbeiten müssen. Das ist das Gegengewicht zu einem mechanischen „DRY um jeden Preis“.
### Hyrum's Law — Beobachtbares Verhalten wird Vertrag
*„Mit genügend Nutzern wird jedes beobachtbare Verhalten deines Systems von jemandem abhängig sein.“*
- Was auch immer eine Schnittstelle *zufällig* tut – Reihenfolge, Timing, Fehlermeldung – darauf wird sich irgendwann jemand verlassen. Die Oberfläche, die du zeigst, ist also größer als die, die du dokumentiert hast.
- Das unterstützt Ousterhouts Vorliebe für **kleine, stabile Schnittstellen**: Je weniger du zeigst, desto weniger kann versehentlich tragend werden.
Fallen: breite Schnittstellen, die verknöchern. Jedes zusätzliche Beobachtbare wird zu einer zukünftigen Einschränkung.
### Wie sie zusammenpassen
- **Parnas → Ousterhout:** Verberge eine volatile Entscheidung → das Modul ist tief.
- **Brooks:** Bestätige, dass die Tiefe Komplexität entfernt und nicht nur verlagert.
- **Evans:** Benenne die Grenze in Domänensprache.
- **Beck → Fowler:** Fixiere Verhalten, dann refaktoriere in kleinen sicheren Schritten.
- **Metz:** Widerstehe Zentralisierung, bis die Invariante echt ist.
- **Hickey:** Halte die Schnittstelle auf ein Konzept beschränkt.
- **Hyrum:** Halte diese Schnittstelle klein, damit sie stabil bleibt.
Die Gefahr ist, Ousterhout mit einer mechanischen Lesart von SOLID oder Clean Code zu vermischen: Das erzeugt viele winzige Klassen und Funktionen mit flachen Schnittstellen – genau das Gegenteil von deep modules. Ousterhout, mit Metz als Gegengewicht, ist das Gegenmittel.
Tags
Claude Ads: das Claude-Code-Skill, das deine Werbekonten prüft
Claude Ads ist ein Open-Source-Skill für Claude Code: über 250 Prüfungen auf Google, Meta, LinkedIn, TikTok oder Amazon Ads, ein Score von 100 und ein priorisierter Aktionsplan, in rund zehn Minuten. Installation, Befehle, Grenzen und wie du es in AgentsRoom orchestrierst.
AGENTS.md: eine Kontextdatei für jeden Coding-Agenten (Codex, Antigravity, Claude)
AGENTS.md ist die portable Anweisungsdatei, die deine KI-Coding-Agenten lesen, bevor sie deinen Code anfassen. Was reingehört, wie sie sich von CLAUDE.md unterscheidet und wie du einen einzigen Kontext über Codex, Antigravity und Claude hinweg behältst.
AgentsRoom herunterladen
Führe alle deine KI-Agenten aus, in all deinen Projekten, aus einem einzigen Fenster.
Companion-App: Agenten auch unterwegs im Blick behalten
Nutzen Sie Claude, Codex, Antigravity CLI oder einen anderen KI-Anbieter.
Bugs und Wünsche direkt in dein öffentliches Backlog schicken.