a-philosophy-of-software-design
Wat het doet
Gebruik tijdens het schrijven, wijzigen of beoordelen van code telkens wanneer de wijziging een geëxporteerde of importeerbare naam toevoegt, een module, klasse, component, helper, hook, service of wrapper creëert, herhaalde code centraliseert, of een API wijzigt. Ousterhout-regels (diepe modules, informatieverberging, complexiteit naar beneden trekken) plus de invarianttest voor het delen van code, de lezer-kostentest, en een verplichte ontwerpnotitie aan het einde.
Installeren opent dit item in je AgentsRoom-desktopapp. Is de app nog niet geïnstalleerd, dan word je naar de downloadpagina gestuurd.
SKILL.md
--- name: a-philosophy-of-software-design description: Gebruik tijdens het schrijven, wijzigen of beoordelen van code telkens wanneer de wijziging een geëxporteerde of importeerbare naam toevoegt, een module, klasse, component, helper, hook, service of wrapper creëert, herhaalde code centraliseert, of een API wijzigt. Ousterhout-regels (diepe modules, informatieverberging, complexiteit naar beneden trekken) plus de invarianttest voor het delen van code, de lezer-kostentest, en een verplichte ontwerpnotitie aan het einde. --- # A Philosophy of Software Design (John Ousterhout) ## Wanneer deze skill te gebruiken Gebruik deze skill wanneer je code ontwerpt, schrijft, wijzigt of beoordeelt. Het is van toepassing op moduleontwerp, API-wijzigingen, decompositie, refactoring, namen, commentaar, tests en prestatieverbeteringen. Gebruik het ook wanneer een wijziging ongemakkelijk aanvoelt, of wanneer één wijziging zich over veel bestanden verspreidt. ## De bias om te corrigeren Werkende code is niet hetzelfde als eenvoudige code. Kleine stukjes, vertrouwde patronen, flags, wrappers en extra documentatie kunnen een ontwerp complexer maken. Ze doen dit wanneer ze toevoegen aan wat een lezer moet weten, of wanneer ze kennis lekken naar andere modules. ## Beslissingsregels - Meet een ontwerp aan hoezeer het complexiteit vermindert. Geef de voorkeur aan het ontwerp dat de belasting van de lezer verlaagt. Complexiteit heeft vier tekenen. Eén wijziging vereist bewerkingen op veel plaatsen. Afhankelijkheden zijn verborgen. Stappen moeten in een vaste volgorde plaatsvinden. De lezer moet veel feiten onthouden. - Behandel ontwerp als continu werk. Een eerste patch die werkt is niet af als het latere wijzigingen moeilijker maakt. Vergelijk voor een beslissing over een interface, een modulesplitsing of een abstractie twee of meer mogelijke ontwerpen. - Geef de voorkeur aan diepe modules. Een diepe module heeft een kleine interface en verbergt een grote hoeveelheid complexiteit. Verwerp doorgeefservices, dunne bibliotheekwrappers en kleine hulpprogrammamodules. Verwerp elke extractie die namen toevoegt maar de belasting van de lezer niet vermindert. - Ontwerp een interface rond wat de aanroeper moet weten, niet rond hoe de implementatie werkt. Vermijd fragiele opstartsequenties, modusflags, configuratieknoppen en argumenten die interne keuzes tonen. - Verberg beslissingen die kunnen veranderen. Voorbeelden zijn interne representaties, opslagvorm, protocollen, bestandsformaten en prestatie-trucs. Boekhouding, normalisatie en randgevallen zijn andere voorbeelden. Houd elk binnen de module die de kennis bezit. - Trek complexiteit naar beneden in de module die de details bezit. Accepteer een complexere implementatie als het aanroepers een eenvoudiger contract geeft en herhaald werk bij elke aanroepplek verwijdert. - Maak een module algemeen op het juiste niveau. Pas een module niet aan op één aanroeper. Voeg geen vage abstractie toe voor toekomstige behoeften. Houd zeldzame randgevallen buiten het hoofdpad en plaats speciaal gedrag op een eigen plek. - Voeg modules samen of splits ze op basis van totale complexiteit. Doe dit niet op basis van grootte, de volgorde waarin code draait, gewoonte of uiterlijk. Houd gerelateerde staat, gedrag, regels en beslissingen bij elkaar. Splits ze alleen als de nieuwe grens dieper is en een lezer elke kant afzonderlijk kan begrijpen. - Maak de set uitzonderingen kleiner. Verander waar mogelijk de interface of regels zodat ongeldige toestanden niet kunnen voorkomen. Laat niet elke aanroeper dezelfde defensieve code herhalen. - Gebruik commentaar om complexiteit te verminderen. Schrijf interfacecontracten, regels die waar moeten blijven, verborgen ontwerpbeslissingen en hun redenen op. Schrijf ook moeilijke feiten op die aanroepers niet hoeven te weten. Herhaal de code niet in een commentaar. Gebruik een commentaar niet om een slechte naam, slechte splitsing of verwarrende controleflow te verbergen. - Behandel namen, consistentie en duidelijkheid als ontwerpinformatie. Een naam vertelt de lezer de abstractie, niet het mechanisme. Gerelateerde operaties gebruiken dezelfde conventies. Code die de lezer verrast voegt complexiteit toe, zelfs als het kort is. - Schrijf tests tegen publieke contracten en stabiele API's. Test de verborgen complexiteit en speciale gevallen via die contracten. Laat de eenvoud van een test geen oppervlakkige of lekke interface afdwingen. - Voeg een prestatieverbetering, patroon, paradigma of framework alleen toe om een van twee redenen. Het vermindert complexiteit in deze codebase, of bewijs toont aan dat de afweging noodzakelijk is. Verberg elke optimalisatie achter een stabiele interface. ## Signalen en de reactie op elk - Een functie is ongemakkelijk, of één wijziging verspreidt zich over bestanden, of een beoordelaar moet verborgen afhankelijkheden vinden. Reactie: zoek naar ontbrekende informatieverberging en oppervlakkige modules. Zoek ook naar stappen in een vaste volgorde en naar complexiteit die aanroepers dragen. - Je voegt een module, laag, service, helper, wrapper of facade toe. Of je voegt een patroon, optie, callback of argument toe. Reactie: toon aan dat het meer complexiteit verbergt dan het toevoegt. - Je wijzigt een API. Reactie: controleer wat een normale aanroeper moet weten. Een aanroeper mag de volgorde van aanroepen, de representatie of opslag niet hoeven te kennen. Een aanroeper mag het transport, de cache, het protocol of het bestandsformaat niet hoeven te kennen. Een aanroeper mag de interne workflow of veel opstartstappen niet hoeven te kennen. - Je voegt een speciaal geval, een flag, een uitzonderingspad, een conditie of een container toe die aanroepers kunnen zien. Reactie: vraag eerst wat de eigenaar van de module in plaats daarvan kan doen. Die kan de ongeldige toestand verwijderen, het ongebruikelijke gedrag isoleren of een sterkere operatie geven. - Je splitst code, extraheert een functie of voegt een variabele toe. Reactie: controleer of de nieuwe grens of naam betekenis draagt. Het mag niet alleen sprongen, doorgegeven staat of tussenliggende stappen toevoegen die aanroepers kunnen zien. - Code heeft fasen zoals `prepare`, `process` en `finalize`, of aanroepers moeten objecten in fasen opbouwen. Reactie: controleer of de tijdsvolgorde het echte concept is. Zo niet, organiseer de code rond stabiele verantwoordelijkheden. - Een naam is vaag, benoemt een mechanisme, is niet consistent of verrast de lezer. Reactie: denk opnieuw na over de abstractiegrens. Accepteer geen naam die bijna correct is. - Een commentaar is lang, herhaalt de code, legt een verwarrende interface uit of toont internals om gebruik uit te leggen. Reactie: verander de abstractie, of verplaats het ontbrekende contract in de interface. - Je optimaliseert prestaties. Reactie: meet eerst, verberg dan de optimalisatie. Geef diepte van modules of informatieverberging niet op zonder bewijs dat de afweging noodzakelijk is. - Je test of beoordeelt. Reactie: kijk naar publiek gedrag en interfacecontracten. Kijk ook naar verborgen complexiteit achter stabiele API's en naar speciale gevallen achter de abstractie. ## Eindchecklist - Vermindert de wijziging de inspanning om het systeem te begrijpen, te wijzigen, te verifiëren en uit te breiden? - Verbergt elk interface-element, wrapper, laag, helper, optie en naam genoeg complexiteit om het te rechtvaardigen? - Zijn belangrijke beslissingen op één plek? Zijn afhankelijkheden zichtbaar? Zijn de beperkingen die aanroepers nodig hebben opgeschreven? Zijn de interne onderdelen die kunnen veranderen beschermd? - Werken de veelvoorkomende gevallen zonder extra stappen? Blijven zeldzame controles, speciale gevallen, prestatie-trucs en uitzonderingsdetails buiten het gewone pad? - Zijn namen exact en consistent? Zijn opmerkingen actueel, zonder herhaling van de code? Volgt de code de bestaande conventies, tenzij nieuwe informatie een reden gaf om ze te veranderen? ## Gate Gebruik de volledige checklist wanneer de wijziging een naam toevoegt die door andere code kan worden geëxporteerd of geïmporteerd. Gebruik het ook wanneer de wijziging een module, klasse, component, helper, hook, service of wrapper creëert, of herhaalde code op één plek plaatst. Hernoemingen, codemods, configuratiewijzigingen, gegevenswijzigingen en één-regel fixes hebben het niet nodig. ## Invariant test: deel alleen code die samen verandert - Extraheer gedeelde code alleen wanneer het een regel beschermt die je kunt benoemen. Het bewijs is co-verandering: de geschiedenis toont dat de kopieën samen werden gefixt of veranderd. Code die er alleen vergelijkbaar uitziet en onafhankelijk verandert is een rijm. Laat rijmen als duplicaten. Drie vergelijkbare blokken bewijzen geen regel. - Een fix moet het probleem verwijderen, niet verplaatsen. Zes casts die in één generieke cast-helper worden verplaatst zijn nog steeds zes casts. Schrijf de getypte mapper die de casts verborgen. - Wanneer een abstractie verkeerd is, zet de code terug inline en laat de duplicatie terugkeren. Buig de abstractie niet met flags. - Splits code niet alleen vanwege de grootte. Eén module van 400 regels die één beslissing verbergt is beter dan vier modules van 100 regels die dezelfde joins lekken. - Een mechanische lezing van Clean Code of SOLID (zeer kleine functies, één klasse per verantwoordelijkheid) geeft oppervlakkige modules. Deze skill heeft prioriteit boven die druk. ## Leeskosten: de derde test De dieptetest en de invarianttest bepalen of een grens moet bestaan. De leeskosten-test bepaalt of de code rond de grens goedkoop te wijzigen is. De volgende lezer, een persoon of een agent, betaalt voor elke regel die ze moeten lezen. Een agent betaalt in tokens. Een agent vindt code door tekstzoek, gedeeltelijke lezingen, typecheck en tests. - **Vindbaar.** Gebruik één naam voor elk concept. Schrijf het overal hetzelfde, zodat gewone tekstzoek het vindt. Defecten: namen opgebouwd uit strings, bedrading via import-zijdeffecten, twee namen voor één concept. Re-exportketens die de definitie verbergen zijn ook defecten. - **Vroege stop.** Zet het contract bovenaan het bestand of boven de export. Zeg wat het belooft, wat het verbergt en wat het nooit doet. Dan kan de lezer vroeg stoppen. - **Machine-checkbaar.** Gebruik exacte types in en uit elke grens, zodat een typecheck het lezen van de aanroepers vervangt. Defecten: `any`, gewone dictionaries, booleaanse flags waarvan de betekenis alleen in de body zit. - **Zichtbare koppeling.** Twee plaatsen moeten samen veranderen. Handhaaf dat met een gedeeld type, een test of één bron. Als dat niet kan, markeer het op beide plaatsen. - **Geen ruis.** Verwijder opmerkingen die de code herhalen, en code die is uitgecommentarieerd. Verwijder dode takken en opmerkingen die wijzigingsgeschiedenis vastleggen. Verwijder een oud pad dat naast zijn vervanging blijft staan. - **Voorspelbaar.** Volg de bestaande indeling van de repository. Zet de test waar een lezer ernaar zoekt, en laat hem alleen draaien. Bestandsgrootte staat bewust niet in deze lijst. Een heel groot bestand is een reden om naar een tweede verborgen beslissing te zoeken. Het is nooit een reden om het bestand te knippen. ## Veiligheid Voor bestaande code, schrijf eerst een test die het huidige gedrag vasthoudt. Maak dan de module dieper. Voor nieuwe code, schrijf de test die het bedoelde gedrag definieert. ## Ontwerpnotitie (verplicht wanneer de gate van toepassing is) Wanneer de gate van toepassing is, zet dan een sectie met de kop `## Design note` in de beschrijving van de pull request. Schrijf twee tot vier regels: - Elke grens die je hebt toegevoegd, en de beslissing die het verbergt. - Elke duplicatie die je bewust hebt behouden, en de reden. - Elk oppervlakkig deel dat je hebt geaccepteerd, en de reden. Als de gate niet van toepassing is, schrijf dan `## Design note` gevolgd door `Gate not applicable: <reden>`. Zet de ontwerpnotitie ook in de samenvatting van je laatste stap. ## Reviewmodus Gebruik deze sectie wanneer je code reviewt of test die door een andere agent of persoon is geschreven. 1. Controleer de ontwerpnotitie. Wanneer de gate van toepassing is en de pull request geen `## Design note` sectie heeft, meld dan een blokkerende bevinding. Wanneer de notitie niet overeenkomt met de diff, meld dan een blokkerende bevinding. 2. Een ontwerpbevinding is alleen blokkerend als het aan beide voorwaarden voldoet: - Het noemt een regel van deze skill. De regel is een beslissingsregel, de gate, de invarianttest of een leeskosten-item. - Het vermeldt een concrete kost voor de lezer of voor de volgende wijziging. Voorbeelden: "Aanroepers moeten de opslagvorm kennen." "Eén concept heeft twee namen." "Een kap-verandering vereist bewerkingen in drie bestanden." 3. Markeer elke andere ontwerpwaarneming als niet-blokkerend. Zet het in een aparte lijst met de titel "Niet-blokkerende ontwerpnotities". Een niet-blokkerende notitie stuurt het werk nooit terug naar de bouwer. 4. Meld geen voorkeur als bevinding. Een andere naam, bestandsindeling of stijl is een voorkeur. Het wordt een bevinding alleen als het een benoemde regel breekt en een concrete kost heeft. 5. Wanneer dezelfde ontwerpbevinding terugkomt in een tweede reviewcyclus, escaleer het. Vraag niet voor de derde keer dezelfde wijziging. ## Gerelateerde skills (wanneer geïnstalleerd) - `find-shared-code`: een rapport-only zoekopdracht in recente geschiedenis naar code die het delen waard is. Het gebruikt de invarianttest en de dieptetest van deze skill. - `refactoring` en `working-effectively-with-legacy-code`: de veilige stappen naar een dieper ontwerp. Deze skill beslist of een nieuwe grens blijft. ## Bron en licentie Deze skill bouwt voort op de "mini" regels voor A Philosophy of Software Design in de ciembor/agent-rules-books repository op GitHub (MIT-licentie, commit 893a88a). De poort, de invarianttest, de leeskostentest, de ontwerpaantekening en de beoordelingsmodus zijn aanvullingen op die regels. De repository bevat ook de volledige regels van het boek.
Tags
Meer over dit onderwerp
Claude Ads: de Claude Code vaardigheid die je advertentieaccounts controleert
Claude Ads is een open source vaardigheid voor Claude Code: 250+ controles op Google, Meta, LinkedIn, TikTok of Amazon Ads, een score uit 100 en een geprioriteerd actieplan, in ongeveer tien minuten. Installeren, commando's, limieten, en hoe het te orkestreren in AgentsRoom.
AGENTS.md: Eén contextbestand voor elke coderingagent (Codex, Antigravity, Claude)
AGENTS.md is het draagbare instructiebestand dat je AI-coderingsagents lezen voordat ze je code aanraken. Wat erin te zetten, hoe het verschilt van CLAUDE.md, en hoe je één context behoudt over Codex, Antigravity en Claude.
Download AgentsRoom
Draai al je AI-agenten, op al je projecten, vanuit één enkel venster.
Companion-app: houd je agents onderweg in de gaten
Breng je eigen: Claude, Codex, Antigravity CLI of andere AI-provider.
Stuur bugs en verzoeken direct naar je openbare backlog.