Clean Architecture: Dependency Inversion en Repository Pattern

In de vorige blog heb ik het Repository Pattern behandeld. In dit blog laat ik zien hoe je het repository pattern in een clean architecture plaatst. Ook leg ik uit wat Dependency Inversion is in een clean architecture.

Als je niet weet wat het repository pattern is, dan raad ik je in de eerste plaats aan om eerst deze blog te lezen.

Auteur:

Kenniscentrum Cloud Software Engineering

Lead Cloud Software Engineering

<Wat is clean architecture?>

Clean Architecture is een set principes en richtlijnen voor het ontwerpen van software systemen op een modulaire, testbare en onderhoudbare manier. Clean Architecture adviseert scheiding van verantwoordelijkheden en onafhankelijkheid van componenten. Deze onafhankelijkheid wordt gerealiseerd door het gebruik van lagen. Elke laag heeft afhankelijkheden naar de eigen laag of lagen binnen de laag.

Het doel van clean architecture is dus onafhankelijkheid creëren. Bijvoorbeeld onafhankelijkheid van gebruikersinterfaces of databronnen. Deze onafhankelijkheid vergroot de testbaarheid en vereenvoudigt het onderhoud van applicaties. In implementaties van clean architecture zie je vaak de volgende lagen:

  1. Web: de interface naar de applicatie.
  2. Infrastructure: de koppelingen naar externe afhankelijkheden. 
  3. Services: de business logica op applicatie niveau. 
  4. Core: de domein objecten en business logica op domein niveau. 

In de onderstaande figuur staan deze lagen grafisch weergegeven met 3 cirkels. Het zijn als de lagen van een ui (De groente, geen user interface 😊). 

 

Een model van wat er in de bovenstaande tekst word beschreven. Het model bestaat uit 3 cirkels, in elkaar. In de middelste cirkel staat 'Core'. De cirkel daarbuiten bevat de 'Services'. De buitenste cirkel bevat "Web" en 'Infrastructure'.

Web en infrastructure zijn afhankelijk van services. Web, Infrastructure en services zijn afhankelijk van de core. De core bevat geen afhankelijkheden. Bij kleinere applicaties en micro-services voegen software designers de Core en Services vaak samen tot een enkele laag.

In een clean architecture beschouw je databronnen niet als onderdeel van de business logica. Je beschouwt ze als onderdeel van het persisteren van data. De logica om databronnen te benaderen zit bij een clean architecture daarom in de infrastructure laag, niet in de core laag. 

In de volgende paragraaf gaan we hier dieper op in door het repository pattern te positioneren in een clean architecture.

<Repository pattern in clean architecture>

In onderstaande figuur zie je hoe de objecten van het repository pattern in een clean architecture zijn verdeeld.

In de Core laag zitten de business objecten (Order, OrderLines, ShippingAdress) en de interface objecten (voor de objecten OrderRepository: IOrderRepository). De Services laag bevat de interface naar de business logica (OrderService). Deze interface maakt gebruik van de Core objecten om data te persisteren.

In de Infrastructure laag zit de implementatie van de Repository (OrderRepository).  Deze class implementeert de repository structuur en zorgt voor het persisteren van de data naar de datastore. 

De afbeelding bevat een model van een software systeem, gebouwd volgens de bovenstaande tekst.

<Dependency Inversion in clean architecture>

Met Dependency inversion ontkoppel je de verschillende lagen in een clean architecture met behulp van abstracties.

Dependency Inversion Principle stelt dat ‘High Level Modules’ afhankelijk zijn van abstracties en niet van de implementatie. In voorgaand schema is de Orderservice afhankelijk van de interface class IOrderRepository en van de implementatie van de interface. Hiermee voldoet het ontwerp aan het Dependency Inversion Principle (DIP).

Dependency inversion zorgt voor ‘Loose-Coupling’ op de onderliggende classes en de gebruikte frameworks. Door deze loose-coupling kun je de business logica onafhankelijk van de databronnen testen.  Voor het testen maak je dan een ‘mock’ van de repositories om de werkelijkheid de simuleren. Als gevolg hiervan maak je het unit testen ook eenvoudiger. Vergeet niet dat je ook integratietests nodig hebt voor het testen van de communicatie tussen de lagen.  

Het gebruik van Dependency inversion vereenvoudig je met een Dependency Injection framework. Zo’n framework zorgt dat de juiste implementatie aan een ‘High Level Module’ wordt meegegeven. Niet als de concrete class maar de interface. 

<Conclusie>

In dit blog heb ik laten zien hoe je design patterns in een clean architecture plaatst. Met het repository pattern als voorbeeld heb ik Dependency Inversion uitgelegd als manier om je software architectuur te ontkoppelen.

Clean architecture is een veelzijdige architectuur waarin je design patterns gestructureerd kunt opnemen. Met Dependency inversion ontkoppel je de verschillende lagen in een clean architecture met behulp van abstracties.

Door aandacht en zorg te besteden aan je architectuur maak je de software beter testbaar, gemakkelijker onderhoudbaar en goedkoper over de gehele applicatie lifecycle gezien. Het verdient zich eerder na weken dan na maanden terug, zoals je kunt lezen door op onderstaande knop te klikken.

In de volgende blog behandelen we het verschil tussen het EntityFramework en het repository pattern.