Software Architectuur
Het Gevaar van Framework-Driven Development
Veel softwareprojecten beginnen als een overzichtelijk, snel itererend project gebouwd op een populair framework (zoals Laravel, Spring Boot of Django). Naarmate de applicatie groeit en er jaren verstrijken, gebeurt er iets verraderlijks: de kern van de applicatie — de unieke bedrijfslogica die waarde creëert — raakt onlosmakelijk verweven met de database-ORM, de HTTP-controllers en externe API-clients. Wanneer een bedrijf na vijf jaar besluit om over te stappen van een MySQL-database naar MongoDB, of van een REST-API naar een GraphQL-API, blijkt dit een vrijwel onmogelijke, kostbare herschrijf-operatie. Dit wordt ‘vendor lock-in’ door framework-verstrengeling genoemd.
Om applicaties te bouwen die decennia lang onderhoudbaar blijven, grijpen senior architecten terug op ontwerppatronen zoals Clean Architecture (Robert C. Martin) of de Hexagonal Architecture (Ports and Adapters van Alistair Cockburn). Deze architecturen delen één fundamenteel doel: het isoleren van het kloppende hart van de applicatie.
Dependency Inversion en Binnenste Cirkels
In een traditionele ‘gelaagde’ architectuur (Layered Architecture) hangt de business-laag (de bedrijfslogica) direct af van de data-laag (de database). Dit betekent dat veranderingen in de database direct de kernlogica breken. Clean Architecture draait dit om via het ‘Dependency Inversion Principle’.
U structureert de applicatie als een ui, met verschillende concentrische cirkels. De kerncirkel bevat uitsluitend uw ‘Entities’ (het domeinmodel) en ‘Use Cases’ (de acties die uw applicatie kan uitvoeren). De gouden regel van Clean Architecture stelt: Afhankelijkheden wijzen altijd naar binnen. De binnenste lagen mogen géén enkele notie hebben van de buitenste lagen. Een ‘Use Case’ voor het verwerken van een betaling weet in code absoluut niet of het een HTTP-request, een CLI-commando of een Kafka-event verwerkt, en het weet al helemáál niet of de betalingsdata wordt opgeslagen in PostgreSQL, Firebase of in het geheugen.
Ports and Adapters (Hexagonal Architecture)
Hoe slaat u dan data op als de kern niets van databases mag weten? Hier introduceert de Hexagonal Architecture ‘Ports’ en ‘Adapters’. Een Port is simpelweg een abstracte Interface (bijvoorbeeld IPaymentRepository) gedefinieerd in de binnenste kern. De kern dicteert: “Ik heb iets nodig dat kan voldoen aan deze interface.”
Aan de buitenkant van de applicatie (de infrastructuur-laag) schrijft de ontwikkelaar een ‘Adapter’. Dit is de daadwerkelijke, lelijke code die communiceert met de externe wereld, bijvoorbeeld een PostgresPaymentAdapter die de IPaymentRepository interface implementeert. Via Dependency Injection wordt de adapter tijdens het opstarten van de applicatie in de Use Case geïnjecteerd. Dit maakt de architectuur extreem flexibel (pluggable).
De Winst voor Test-Driven Development (TDD)
De grootste en meest directe winst van deze extreme ontkoppeling merkt u in uw test-suite. Unit-testen van bedrijfslogica in een traditionele applicatie vereisen vaak complexe mock-databases, netwerk-stubs en web-server emulatie, waardoor testen traag en broos (flaky) worden. In Clean Architecture kunt u een InMemoryPaymentAdapter schrijven, deze injecteren in uw Use Case, en uw volledige bedrijfslogica binnen een fractie van een milliseconde in compleet isolement (zonder database of server) testen.
Hoewel Clean Architecture in eerste instantie veel abstractie en ‘boilerplate’ code vereist (en dus te zwaar is voor kleine projecten), is het de ultieme architectuur voor kritieke enterprise-systemen. Lees meer over architectuur overwegingen in deze gids op AG Connect.
Volgende: Test-Driven Development (TDD) en E2E Automatisering met Playwright
