Het goed structureren van je applicatie is van groot belang om te zorgen dat een applicatie aanpasbaar blijft naarmate de applicatie groeit. Een veel gebruikte structuur is een meer-lagen structuur waarbij de applicatie wordt opgesplitst in een presentatielaag, businesslaag en datalaag. Iedere laag heeft in deze structuur over het algemeen een referentie naar de onderliggende laag, eventueel met een cross-cutting kolom die door iedere laag gebruikt mag worden. Het nadeel van deze benadering is dat er vaak een “tight-coupling” ontstaat tussen lagen en daardoor uiteindelijk de presentatielaag vrij rigide aan de datalaag vastzit. Het is mogelijk binnen een meerlagen structuur netjes te werken en deze koppelingen te voorkomen, maar de praktijk is dat de meeste teams dit niet doen.
Het onion architectuurmodel
Het onion architectuurmodel gaat uit van een domain driven aanpak waarbij het domein van de applicatie losgekoppeld wordt van externe factoren. Misschien wel het belangrijkste verschil met de meer-lagen structuur wordt zichtbaar in het feit dat de datalaag ook als extern wordt gezien, en dus in de buitenste laag zit en niet in de binnenin. Gouden regel binnen deze architectuur is dat alle afhankelijkheden naar binnen lopen.
De kern “het domain model”
In de kern van de applicatie bevindt zich het domein model. Onion architectuur staat en valt met een object georiënteerde aanpak en in het domein zouden bijvoorbeeld POCO-entiteit classes kunnen zitten.
De buitenkant “application services”
Ofschoon de presentatie of UI laag natuurlijk uiteindelijk de buitenkant vanuit de gebruiker is, vormt de application services laag het abstracte contract tussen de binnenkant en de externe assemblies. Dit dwingt het ontwikkelteam om na te denken over duidelijke contracten.
De domain services
In de domain services vind je enerzijds businesslogica en anderzijds interfaces voor externe objecten geïnjecteerd moeten worden in de module (bijvoorbeeld een repository interface).
Externe koppelingen
Aan de buitenste rand van de onion bevinden zich de koppelingen naar de buitenwereld. Enerzijds is dit vaak de client applicatie, maar ook de verbinding met de database of een testproject wordt als een externe koppeling gezien.
Wanneer gebruik je de onion architectuur
Voor een simpele (web)applicatie is de onion architectuur waarschijnlijk een over-complicering van wat nodig is. Onion is vooral op zijn kracht in combinatie met domain driven design en zal vaak ingezet worden bij applicaties met een lange levensduur of complexe businesslogica.
Een (versimpeld) voorbeeld van een onion
Stel dat ik bijvoorbeeld een eenvoudige applicatie heb waarin ik klanten kan beheren. De applicatie moet een lijst van klanten, maar ook klantdetails kunnen opleveren. In de klantdetails wordt onder andere het aantal orders van de klant opgenomen en op basis van het totale orderbedrag wordt bepaald of het een premium klant is.
In het domain van de applicatie zouden bijvoorbeeld een POCO voor customer en een POCO voor orders zitten.
In de domain services zit een CustomerDetailModel die informatie uit zowel Customer als Order combineert. Daarnaast bevat de domain services een interface voor ICustomerRepository.
De application service bevat twee methodes: GetCustomerList() en GetCustomerDetails(int id) – om het voorbeeld te versimpelen houd ik bewust zoekfilters en dergelijke buiten beschouwing. Daarnaast wordt in de application service een implementatie van de ICustomerRepository geïnjecteerd.
In het database project wordt een implementatie van de CustomerRepository gemaakt die gematerialiseerde data teruggeeft aan de applicatie services.
In de applicatie wordt gebruik gemaakt van Inversion of Control (bijvoorbeeld SimpleInjector) en wanneer de applicatie de application service aanroept wordt automatisch de juiste instantie van de Repository meegegeven. De applicatie service gebruikt vervolgens de Repository in combinatie met objecten uit de domainservices om de juiste data op te halen en te presenteren.
Auteur: Menno Jongerius, Bergler Competence Center 2016