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.
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:
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 😊).
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.
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.
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.
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.