5.1 KiB
Regels bij het coderen
Deze regels gelden voor nieuwe code en voor code die inhoudelijk wordt gewijzigd. Bestaande code hoeft niet mechanisch te worden herschreven zonder functionele reden.
Algemeen ontwerp
- Los het probleem op in de laag die eigenaar is van de invariant.
- Houd de oplossing klein en samenhangend; bouw geen framework voor één geval.
- Gebruik statische
require-afhankelijkheden. Vermijddynamic-requireals middel om moduleontwerp uit te stellen. - Geef configuratie en betekenisvolle dependencies expliciet door.
- Bewaar beveiliging en dataintegriteit server-side.
- Maak een databasebewerking atomair wanneer haar afgeleide gegevens samen met de bron moeten veranderen.
- Behoud backward compatibility van database, CMap-document en API tenzij een migratie expliciet is ontworpen.
Racket-stijl
Kies expliciete, goed leesbare constructies boven compacte combinaties van kleine idiomen. Gebruik benoemde tussenwaarden wanneer zij de reden van een stap duidelijk maken. Gebruik het Unicode-symbool λ voor anonieme procedures.
Schrijf cond-clausules met blokhaken:
(cond
[(not page) #f]
[(archived? page) (archive-result page)]
[else (current-result page)])
Vermijd constructies waarin and, falsy waarden en filtering tegelijk de datastructuur vormen. Schrijf de bedoelde keuze expliciet:
(filter (λ (value) value)
(list (if include-title? 'title #f)
(if include-tags? 'tags #f)))
Gebruik mutatie wanneer die de toestand werkelijk modelleert en lokaal blijft. Verberg een eenvoudige hash-set! of set! niet achter een abstractie die geen domeinbetekenis toevoegt.
Procedures en contractcommentaar
Een publieke of niet-triviale procedure beschrijft waar nuttig:
goal : Waarom bestaat deze procedure?
pre : Welke invoer en toestand worden verondersteld?
post : Welke toestand is na succes veranderd?
result : Welke waarde of fout krijgt de aanroeper?
Commentaar verklaart beslissingen, grenzen en afwijkend gedrag. Het herhaalt niet regel voor regel de code.
Gebruik betekenisvolle namen zoals valid-page-reference?, read-concept-map en replace-current-attachment-references!. Een predicaat eindigt op ?; een procedure die duurzame toestand wijzigt meestal op !.
Module-interfaces
Exporteer alleen wat een andere module gebruikt of als publieke API bedoeld is. Een opslagmodule accepteert domeinwaarden en config, niet een HTTP-request. Een HTTP-handler bouwt geen SQL.
Maak een helper wanneer:
- dezelfde invariant op meerdere plaatsen identiek moet blijven;
- de naam domeinbetekenis toevoegt;
- een pure, testbare grens ontstaat;
- foutafhandeling daardoor op de juiste laag komt.
Maak geen helper die slechts één aanroep doorgeeft zonder extra contract.
SQL en transacties
Gebruik queryparameters voor alle waarden. Dynamisch samengestelde SQL is alleen toegestaan voor vaste, door de code gekozen fragmenten zoals een bekende kolomlijst.
Lees bij een optimistic-lock-write de rij met FOR UPDATE, controleer de basisversie en schrijf actuele toestand, historie en afgeleide indices binnen dezelfde transactie. Zet een normale domeinfout om in een herkenbare fout zoals version-conflict; verberg onverwachte databasefouten niet.
Een migratie krijgt een nieuw oplopend nummer. Wijzig een reeds uitgebrachte migratie niet alsof installaties haar nog niet hebben uitgevoerd.
JavaScript en DOM
Gebruik de centrale api()-functie voor JSON-calls, zodat CSRF en uniforme foutafhandeling behouden blijven. Routeer via de centrale hashnavigatie; wijzig niet alleen de zichtbare view terwijl de URL achterblijft.
Alle HTML uit Markdown gaat door DOMPurify. Gebruik textContent voor gewone tekst en bouw elementen expliciet. Als innerHTML noodzakelijk is, moet de bron en sanering in dezelfde functie zichtbaar zijn.
Een nieuwe DOM-id wordt tegelijk in index.html en de bijbehorende code toegevoegd. Een nieuwe vertaalkey krijgt ten minste Engelse en Nederlandse standaardtekst.
CMap-bewerkingen gebruiken de editor-API en eindigen als één herkenbare Undo-transactie. Verander niet rechtstreeks een grafisch element zonder het bijbehorende editorrecord en de serialisatie bij te werken.
Fouten en logging
Vang alleen uitzonderingen die op de huidige laag betekenisvol kunnen worden vertaald. Geef bij een technische fout component en veilige identifier mee. Log geen wachtwoord, databasecredential, sessietoken, CSRF-token of herstelcode.
Browsermeldingen zijn begrijpelijk voor de gebruiker. Technische details mogen aanvullend in console of serverlog staan, maar niet in plaats van een concrete uitleg.
Versie en release
Bij iedere release:
- verhoog
info.rkt; - werk zichtbare frontenddiagnostiek en componentversies bij;
- voeg een README-changelogitem toe;
- pas relevante architectuurpagina's aan;
- compileer Racket en draai tests;
- controleer JavaScript, DOM-id's en vertaalkeys;
- inspecteer het ZIP-archief op volledigheid en geheimen.
Zie Onderhoudbaarheid voor de werkwijze en Modulariteit voor de gewenste afhankelijkheidsrichting.