a-philosophy-of-software-design
Was er macht
Verwenden Sie es beim Schreiben, Ändern oder Überprüfen von Code, wann immer die Änderung einen exportierten oder importierbaren Namen hinzufügt, ein Modul, eine Klasse, eine Komponente, einen Helfer, Hook, Service oder Wrapper erstellt, wiederholten Code zentralisiert oder eine API ändert. Ousterhout-Regeln (tiefe Module, Informationsverbergung, Komplexität nach unten ziehen) plus der Invariant-Test für das Teilen von Code, der Leser-Kosten-Test und eine erforderliche Designnotiz am Ende.
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: a-philosophy-of-software-design description: Verwenden Sie es beim Schreiben, Ändern oder Überprüfen von Code, wann immer die Änderung einen exportierten oder importierbaren Namen hinzufügt, ein Modul, eine Klasse, eine Komponente, einen Helfer, Hook, Service oder Wrapper erstellt, wiederholten Code zentralisiert oder eine API ändert. Ousterhout-Regeln (tiefe Module, Informationsverbergung, Komplexität nach unten ziehen) plus der Invariant-Test für das Teilen von Code, der Leser-Kosten-Test und eine erforderliche Designnotiz am Ende. --- # A Philosophy of Software Design (John Ousterhout) ## Wann man diese Fähigkeit einsetzen sollte Setze diese Fähigkeit ein, wenn du Code entwirfst, schreibst, änderst oder überprüfst. Sie gilt für Modulentwurf, API-Änderungen, Zerlegung, Refactoring, Namen, Kommentare, Tests und Performance-Arbeiten. Nutze sie auch, wenn sich eine Änderung umständlich anfühlt oder wenn sich eine Änderung über viele Dateien erstreckt. ## Die zu korrigierende Voreingenommenheit Funktionierender Code ist nicht dasselbe wie einfacher Code. Kleine Teile, vertraute Muster, Flags, Wrapper und zusätzliche Dokumentation können ein Design komplexer machen. Das tun sie, wenn sie das Wissen erhöhen, das ein Leser haben muss, oder wenn sie Wissen an andere Module weitergeben. ## Entscheidungsregeln - Messe ein Design daran, wie sehr es Komplexität reduziert. Bevorzuge das Design, das die Last für den Leser verringert. Komplexität zeigt sich auf vier Arten: Eine Änderung erfordert Bearbeitungen an vielen Stellen. Abhängigkeiten sind versteckt. Schritte müssen in einer festen Reihenfolge erfolgen. Der Leser muss viele Fakten im Kopf behalten. - Betrachte Design als kontinuierliche Arbeit. Ein erster Patch, der funktioniert, ist nicht fertig, wenn er spätere Änderungen erschwert. Vergleiche bei einer Entscheidung über eine Schnittstelle, eine Modulaufteilung oder eine Abstraktion zwei oder mehr mögliche Designs. - Bevorzuge tiefe Module. Ein tiefes Modul hat eine kleine Schnittstelle und verbirgt eine große Menge Komplexität. Lehne Durchreichdienste, dünne Bibliotheks-Wrapper und kleine Hilfs-Module ab. Lehne jede Extraktion ab, die Namen hinzufügt, aber die Last für den Leser nicht verringert. - Entwirf eine Schnittstelle um das, was der Aufrufer wissen muss, nicht um die Funktionsweise der Implementierung. Vermeide fragile Setup-Sequenzen, Modus-Flags, Konfigurationsknöpfe und Argumente, die interne Entscheidungen zeigen. - Verstecke Entscheidungen, die sich ändern können. Beispiele sind interne Repräsentationen, Speicherform, Protokolle, Dateiformate und Performance-Tricks. Buchführung, Normalisierung und Randfälle sind weitere Beispiele. Halte jede davon im Modul, das das Wissen besitzt. - Ziehe Komplexität in das Modul, das die Details besitzt. Akzeptiere eine komplexere Implementierung, wenn sie den Aufrufern einen einfacheren Vertrag bietet und wiederholte Arbeit an jedem Aufrufort entfernt. - Mache ein Modul auf der richtigen Ebene allgemein. Passe ein Modul nicht an einen einzigen Aufrufer an. Füge keine vage Abstraktion für zukünftige Bedürfnisse hinzu. Halte seltene Randfälle aus dem Hauptpfad heraus und platziere spezielles Verhalten an einem eigenen Ort. - Verbinde oder teile Module nach der Gesamtkonplexität. Verbinde oder teile sie nicht nach Größe, nach der Reihenfolge, in der Code ausgeführt wird, nach Gewohnheit oder nach Aussehen. Halte zusammengehörigen Zustand, Verhalten, Regeln und Entscheidungen zusammen. Teile sie nur, wenn die neue Grenze tiefer ist und ein Leser jede Seite allein verstehen kann. - Mache die Menge der Ausnahmen kleiner. Ändere, wo möglich, die Schnittstelle oder die Regeln so, dass ungültige Zustände nicht auftreten können. Verlange nicht von jedem Aufrufer, denselben defensiven Code zu wiederholen. - Nutze Kommentare, um Komplexität zu reduzieren. Schreibe Schnittstellenverträge, Regeln, die wahr bleiben müssen, versteckte Designentscheidungen und deren Gründe auf. Schreibe auch schwierige Fakten auf, die Aufrufer nicht wissen müssen. Wiederhole den Code nicht in einem Kommentar. Nutze keinen Kommentar, um einen schlechten Namen, eine schlechte Aufteilung oder verwirrenden Kontrollfluss zu verbergen. - Behandle Namen, Konsistenz und Klarheit als Designinformationen. Ein Name sagt dem Leser die Abstraktion, nicht den Mechanismus. Verwandte Operationen verwenden dieselben Konventionen. Code, der den Leser überrascht, erhöht die Komplexität, auch wenn er kurz ist. - Schreibe Tests gegen öffentliche Verträge und stabile APIs. Teste die versteckte Komplexität und die Sonderfälle durch diese Verträge. Lass die Einfachheit eines Tests nicht eine flache oder undichte Schnittstelle erzwingen. - Füge eine Performance-Änderung, ein Muster, ein Paradigma oder ein Framework nur aus einem von zwei Gründen hinzu. Es reduziert Komplexität in diesem Codebasis, oder Beweise zeigen, dass der Kompromiss notwendig ist. Verstecke jede Optimierung hinter einer stabilen Schnittstelle. ## Signale und die Reaktion darauf - Ein Feature ist umständlich, oder eine Änderung erstreckt sich über Dateien, oder ein Prüfer muss versteckte Abhängigkeiten finden. Reaktion: Suche nach fehlender Informationskapselung und flachen Modulen. Suche auch nach Schritten in fester Reihenfolge und nach Komplexität, die Aufrufer tragen. - Du fügst ein Modul, eine Schicht, einen Service, Helfer, Wrapper oder eine Fassade hinzu. Oder du fügst ein Muster, eine Option, einen Callback oder ein Argument hinzu. Reaktion: Zeige, dass es mehr Komplexität verbirgt, als es hinzufügt. - Du änderst eine API. Reaktion: Prüfe, was ein normaler Aufrufer wissen muss. Ein Aufrufer darf die Reihenfolge der Aufrufe, die Repräsentation oder den Speicher nicht kennen müssen. Ein Aufrufer darf Transport, Cache, Protokoll oder Dateiformat nicht kennen müssen. Ein Aufrufer darf den internen Workflow oder viele Setup-Schritte nicht kennen müssen. - Du fügst einen Sonderfall, ein Flag, einen Ausnahmepfad, eine Bedingung oder einen Container hinzu, den Aufrufer sehen können. Reaktion: Frage zuerst, was das besitzende Modul stattdessen tun kann. Es kann den ungültigen Zustand entfernen, das ungewöhnliche Verhalten isolieren oder eine stärkere Operation anbieten. - Du teilst Code, extrahierst eine Funktion oder fügst eine Variable hinzu. Reaktion: Prüfe, ob die neue Grenze oder der Name Bedeutung trägt. Es darf nicht nur Sprünge, durchgereichten Zustand oder Zwischenschritte hinzufügen, die Aufrufer sehen können. - Code hat Phasen wie `prepare`, `process` und `finalize`, oder Aufrufer müssen Objekte in Stufen bauen. Reaktion: Prüfe, ob die zeitliche Reihenfolge das eigentliche Konzept ist. Wenn nicht, organisiere den Code um stabile Verantwortlichkeiten. - Ein Name ist vage, benennt einen Mechanismus, ist nicht konsistent oder überrascht den Leser. Reaktion: Denke noch einmal über die Abstraktionsgrenze nach. Akzeptiere keinen Namen, der nur fast korrekt ist. - Ein Kommentar ist lang, wiederholt den Code, erklärt eine verwirrende Schnittstelle oder zeigt Interna zur Erklärung der Nutzung. Reaktion: Ändere die Abstraktion oder verschiebe den fehlenden Vertrag in die Schnittstelle. - Du optimierst die Performance. Reaktion: Messe zuerst, dann verstecke die Optimierung. Gib Tiefe des Moduls oder Informationskapselung nicht ohne Beweise auf, dass der Kompromiss notwendig ist. - Du testest oder überprüfst. Reaktion: Schau dir das öffentliche Verhalten und Schnittstellenverträge an. Schau auch auf versteckte Komplexität hinter stabilen APIs und auf Sonderfälle, die hinter der Abstraktion verborgen sind. ## Abschließende Checkliste - Verringert die Änderung den Aufwand, das System zu verstehen, zu ändern, zu überprüfen und zu erweitern? - Verbirgt jedes Interface-Element, jeder Wrapper, jede Schicht, jeder Helfer, jede Option und jeder Name genug Komplexität, um gerechtfertigt zu sein? - Sind wichtige Entscheidungen an einem Ort? Sind Abhängigkeiten sichtbar? Sind die Einschränkungen, die Aufrufer benötigen, schriftlich festgehalten? Sind die Interna, die sich ändern können, geschützt? - Funktionieren die häufigen Fälle ohne zusätzliche Schritte? Bleiben seltene Steuerungen, Sonderfälle, Performance-Tricks und Ausnahme-Details aus dem normalen Pfad heraus? - Sind Namen genau und konsistent? Sind Kommentare aktuell, ohne Wiederholung des Codes? Folgt der Code den bestehenden Konventionen, es sei denn, neue Informationen geben einen Grund, sie zu ändern? ## Gate Verwenden Sie die vollständige Checkliste, wenn die Änderung einen Namen hinzufügt, den anderer Code exportieren oder importieren kann. Verwenden Sie sie auch, wenn die Änderung ein Modul, eine Klasse, eine Komponente, einen Helfer, Hook, Service oder Wrapper erstellt oder wiederholten Code an einem Ort zusammenfasst. Umbenennungen, Codemods, Konfigurationsänderungen, Datenänderungen und einzeilige Korrekturen benötigen sie nicht. ## Invariantentest: Teile nur Code, der zusammen geändert wird - Extrahieren Sie gemeinsamen Code nur, wenn er eine Regel schützt, die Sie benennen können. Der Beweis ist das gemeinsame Ändern: Die Historie zeigt, dass die Kopien zusammen korrigiert oder geändert wurden. Code, der nur ähnlich aussieht und unabhängig geändert wird, ist ein Reim. Lassen Sie Reime als Duplikate. Drei ähnliche Blöcke beweisen keine Regel. - Eine Korrektur muss das Problem beseitigen, nicht verschieben. Sechs Casts, die in einen generischen Cast-Helfer verschoben werden, sind immer noch sechs Casts. Schreiben Sie den typisierten Mapper, den die Casts verborgen haben. - Wenn eine Abstraktion falsch ist, setzen Sie den Code wieder inline und lassen Sie die Duplikation zurückkehren. Biegen Sie die Abstraktion nicht mit Flags. - Teilen Sie Code nicht nur wegen seiner Größe auf. Ein 400-zeiliges Modul, das eine Entscheidung verbirgt, ist besser als vier 100-zeilige Module, die dieselben Verknüpfungen durchsickern lassen. - Ein mechanisches Lesen von Clean Code oder SOLID (sehr kleine Funktionen, eine Klasse für jede Verantwortung) ergibt flache Module. Diese Fähigkeit hat Vorrang vor diesem Druck. ## Lesekosten: der dritte Test Der Tiefentest und der Invariantentest entscheiden, ob eine Grenze existieren muss. Der Lesekostentest entscheidet, ob der Code um die Grenze herum billig zu ändern ist. Der nächste Leser, eine Person oder ein Agent, zahlt für jede Zeile, die er lesen muss. Ein Agent zahlt in Tokens. Ein Agent findet Code durch Textsuche, Teil-Lesungen, Typprüfung und Tests. - **Findbar.** Verwenden Sie für jedes Konzept einen Namen. Schreiben Sie ihn überall gleich, damit die reine Textsuche ihn findet. Fehler: Namen, die aus Strings gebaut sind, Verkabelung durch Import-Nebeneffekte, zwei Namen für ein Konzept. Re-Export-Ketten, die die Definition verbergen, sind ebenfalls Fehler. - **Frühes Stoppen.** Setzen Sie den Vertrag oben in die Datei oder über den Export. Sagen Sie, was er verspricht, was er verbirgt und was er niemals tut. Dann kann der Leser früh stoppen. - **Maschinenprüfbar.** Verwenden Sie genaue Typen ein- und ausgehend von jeder Grenze, sodass eine Typprüfung das Lesen der Aufrufer ersetzt. Fehler: `any`, einfache Dictionaries, boolesche Flags, deren Bedeutung nur im Körper steht. - **Sichtbare Kopplung.** Zwei Stellen müssen zusammen geändert werden. Erzwingen Sie das mit einem gemeinsamen Typ, einem Test oder einer einzigen Quelle. Wenn Sie das nicht können, markieren Sie es an beiden Stellen. - **Kein Rauschen.** Entfernen Sie Kommentare, die den Code wiederholen, und auskommentierten Code. Entfernen Sie tote Zweige und Kommentare, die Änderungsverläufe aufzeichnen. Entfernen Sie einen alten Pfad, der neben seiner Ersatzversion bleibt. - **Vorhersehbar.** Folgen Sie dem bestehenden Layout des Repositories. Legen Sie den Test dort ab, wo ein Leser ihn sucht, und sorgen Sie dafür, dass er allein läuft. Dateigröße steht absichtlich nicht auf dieser Liste. Eine sehr große Datei ist ein Grund, nach einer zweiten verborgenen Entscheidung zu suchen. Sie ist niemals ein Grund, die Datei zu kürzen. ## Sicherheit Für bestehenden Code schreiben Sie zuerst einen Test, der das aktuelle Verhalten hält. Dann machen Sie das Modul tiefer. Für neuen Code schreiben Sie den Test, der das beabsichtigte Verhalten definiert. ## Designnotiz (erforderlich, wenn das Gate gilt) Wenn das Gate gilt, fügen Sie im Beschreibungstext des Pull Requests einen Abschnitt mit der Überschrift `## Design note` ein. Schreiben Sie zwei bis vier Zeilen: - Jede Grenze, die Sie hinzugefügt haben, und die Entscheidung, die sie verbirgt. - Jede Duplikation, die Sie absichtlich behalten haben, und den Grund. - Jeden flachen Teil, den Sie akzeptiert haben, und den Grund. Wenn das Gate nicht gilt, schreiben Sie `## Design note` gefolgt von `Gate not applicable: <reason>`. Fügen Sie die Designnotiz auch in die Zusammenfassung Ihres letzten Schritts ein. ## Review-Modus Verwenden Sie diesen Abschnitt, wenn Sie Code überprüfen oder testen, den ein anderer Agent oder eine andere Person geschrieben hat. 1. Prüfen Sie die Designnotiz. Wenn das Gate gilt und der Pull Request keinen Abschnitt `## Design note` hat, melden Sie einen blockierenden Befund. Wenn die Notiz nicht mit dem Diff übereinstimmt, melden Sie einen blockierenden Befund. 2. Ein Designbefund ist nur blockierend, wenn beide Bedingungen erfüllt sind: - Er nennt eine Regel dieser Fähigkeit. Die Regel ist eine Entscheidungsregel, das Gate, der Invariantentest oder ein Lesekostenpunkt. - Er nennt konkrete Kosten für den Leser oder die nächste Änderung. Beispiele: "Aufrufer müssen die Speicherform kennen." "Ein Konzept hat zwei Namen." "Eine Änderung der Obergrenze erfordert Bearbeitungen in drei Dateien." 3. Markieren Sie alle anderen Designbeobachtungen als nicht blockierend. Fassen Sie sie in einer separaten Liste mit dem Titel "Nicht blockierende Designnotizen" zusammen. Eine nicht blockierende Notiz schickt die Arbeit nie zurück an den Ersteller. 4. Melden Sie eine Präferenz nicht als Befund. Ein anderer Name, Dateilayout oder Stil ist eine Präferenz. Es wird nur dann ein Befund, wenn es eine benannte Regel bricht und konkrete Kosten verursacht. 5. Wenn derselbe Designbefund in einem zweiten Review-Zyklus zurückkommt, eskalieren Sie ihn. Fordern Sie dieselbe Änderung nicht ein drittes Mal an. ## Verwandte Skills (bei Installation) - `find-shared-code`: eine nur berichtende Suche der jüngsten Historie nach Code, der es wert ist, geteilt zu werden. Sie verwendet den Invariantentest und den Tiefentest dieser Fähigkeit. - `refactoring` und `working-effectively-with-legacy-code`: die sicheren Schritte zu einem tieferen Design. Diese Fähigkeit entscheidet, ob eine neue Grenze bleibt. ## Quelle und Lizenz Diese Skill baut auf den "mini"-Regeln für A Philosophy of Software Design im ciembor/agent-rules-books Repository auf GitHub (MIT-Lizenz, Commit 893a88a) auf. Das Gate, der Invariant-Test, der Reader-Cost-Test, die Design-Note und der Review-Modus sind Ergänzungen zu diesen Regeln. Das Repository enthält auch die vollständigen Regeln des Buches.
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.