-
Notifications
You must be signed in to change notification settings - Fork 120
Architecture Documentation
In the past (until this last commit) we used a Monolithic Architecture and inside it, we used Onion Architecture for development. After a while, when the app was in a stable state, we decide to migrate the Architecture from Monolith to Microservices by following Strangler application pattern. According to the Microservices architecture, we extract some services by using aggregate and BC concepts of DDD and develop them separately using Onion Architecture.
At the first step of refactoring the architecture from Monolithic into Microservices, we prepared the development architecture like below diagram and then considered the monolith as a single service, so we were able to extract each services step by step.
You can browse the code related to the first step from this commit.
After extracting all services and making communication between them and implementing API Gateways, observability, monitoring, etc. the architecture is like following diagram:
As you see in the TaskoMask development architecture diagram, each service is developed over Onion Architecture like following diagram:
So generally we have the following layers in each service:
- Domain (Domain.DomainModel & Domain.DataModel)
- Infrastructure (Infrastructure.CrossCutting & Infrastructure.Data)
- Application (Application & Application.Core)
- API
- Tests (Unit & Integration)
This layer contains the domain model for the services, and it could have 2 or 1 of the following layers:
- Domain.DomainModel : Rich domain model following DDD concepts to be used in Write side.
- Domain.DataModel : Anemic domain model to be used in Read side.
If a service doesn't need to have separate Read and Write models then we follow Anemic domain modeling for the Write side and use it for the Read side too, so the name of the layer should be Domain.DomainModel.
Infrastructure part of application architecture divided into 3 layers just to keep things clean and relevant, so we define Infrastructure.Data to hold all items related to data configuration like database context, event store, repositories:
- Infrastructure.Data.Read : It holds the configs and implementation for Read Side Database related to Domain.DataModel.
- Infrastructure.Data.Write : It holds the configs and implementation for Write Side Database Domain.DomainModel.
- Infrastructure.Data.Generator : This layer exists to generate some sample data to be used in integration tests or admin panel demo.
Also, we use Infrastructure.CrossCutting to implement any other cross-cutting concern like bus, ioc, mapper and so on.
In this layer we mainly implement application services and CQRS and handle any other things about use cases. In application part of our application architecture, you see a layer named Application.Core. This layer acts as seed work, and we put all seed work items in it, for example base classes, behaviors, resources and so on. But it just contains items that Application need them, so any other items must place in another layer by their usage.
This is the Presentation part of service architecture and contains some web API project. These API services are not accessible directly from the outside world and just can be used through API Gateways.
It contains all Unit & Integration for the service.
This is an open source project, and sometimes it can have some differences between docs and the source, so if you had a problem please tell us in issues or feel free to fix it by a pull request