4.3 KiB
Modulariteit en afhankelijkheden
Huidige modulegrenzen
De backend is functioneel opgesplitst. Configuratie, databaseverbinding, migraties, authenticatie, paginaopslag, CMap-opslag, mail, setup en vendorbeheer hebben ieder een herkenbare module. Deze modules communiceren hoofdzakelijk met gewone Racket-waarden: structs, hashes, lijsten en strings.
De belangrijkste grens is die tussen server.rkt en de opslagmodules. server.rkt hoort HTTP te begrijpen; storage.rkt, cmap-storage.rkt en auth.rkt horen domeinbewerkingen en database-invarianten te begrijpen. Geen opslagprocedure mag een webrequest nodig hebben.
De frontend heeft een vergelijkbare grens. cmap-racket-wiki.js implementeert een editorcomponent met callbacks voor openen, selectie en wijzigingen. wiki.js koppelt die callbacks aan routes, API's en dialoogvensters.
Sterke punten
De volgende onderdelen zijn al goed geïsoleerd:
wiki-configbundelt runtimekeuzes en voorkomt verspreide globale configuratie.call-with-wiki-databasecentraliseert openen en sluiten van verbindingen.- opslagprocedures kapselen SQL en transacties in.
- de CMap-documentvorm is een expliciet JSON-contract met
schemaVersion. - Markdownrendering gaat via één frontendfunctie voor lezen, preview en historie.
- vertalingen hebben één effectieve bron voor backend en frontend.
- frontend-vendorbestanden worden door één module beheerd en gecontroleerd.
Huidige concentraties
server.rkt bevat zowel routing als veel requestparsing en handlerlogica. static/js/wiki.js bevat vrijwel de hele single-page applicatie. Dat maakt zoeken eenvoudig, maar vergroot de kans dat een wijziging onverwacht een ander view- of routepad raakt.
private/storage.rkt combineert pagina's, historie, zoeken, bookmarks, aliases en uploads. Die onderdelen delen pagina-identiteit en transacties, maar hoeven niet onbeperkt samen te groeien.
Deze concentraties zijn technische schuld, geen automatische opdracht tot een grote opsplitsing. Een splitsing moet een concreet voordeel hebben: een kleiner contract, onafhankelijke tests of duidelijker eigenaarschap.
Gewenste afhankelijkheidsregels
- Een buitenste laag mag een binnenste dienst kennen; omgekeerd niet. HTTP kent opslag, opslag kent geen HTTP.
- SQL blijft in database- en opslagmodules. JavaScript bouwt geen SQL-achtige querysemantiek na.
- Authenticatie en autorisatie blijven server-side. UI-zichtbaarheid is alleen gebruiksgemak.
- Cross-cutting gedrag krijgt één expliciete helper wanneer er werkelijk meerdere gebruikers zijn. Maak geen wrapper voor één triviale aanroep.
- Een module exporteert alleen procedures en structs die een andere module werkelijk nodig heeft.
- Gebruik geen
dynamic-requireom een heldere statische afhankelijkheid te verbergen. - Een nieuwe module krijgt één samenhangende reden om te wijzigen; een verzameling toevallige helpers is geen moduleontwerp.
Waarschijnlijke toekomstige extracties
Wanneer server.rkt verder groeit, ligt opsplitsing per adaptergebied voor de hand: sessie/profiel, pagina's, CMaps en beheer. De centrale router kan dan dun blijven. Handlers ontvangen config expliciet en roepen dezelfde bestaande diensten aan.
Wanneer wiki.js verder groeit, zijn route/state, pagina-editor, CMap-host, graph-view en admin-views natuurlijke grenzen. Splits alleen met native ES-modules wanneer de setup- en cacheversies van alle scripts tegelijk beheerst worden.
Wanneer paginaopslag wordt aangepast, kunnen bookmarks, aliases en uploads later eigen modules krijgen. De pagina-schrijftransactie en afgeleide indices moeten daarbij als één consistente operatie behouden blijven; opsplitsing van bestanden mag geen opsplitsing van de transactie veroorzaken.
Contracten tussen modules
Een goed contract specificeert:
- geldige invoer en normalisatie;
- welke toestand wordt gelezen of gewijzigd;
- transactiegrens en concurrencygedrag;
- resultaatvorm;
- herkenbare domeinfouten;
- maximale document- of uploadgrootte waar relevant.
De bestaande goal / pre / post / result-commentaren zijn hiervoor geschikt, zolang zij het niet-zichtbare contract beschrijven en niet slechts de procedurecode navertellen.
Zie Regels bij het coderen voor de concrete stijl en Testbaarheid voor het testen per grens.