This project presents the domain driven design concepts.
Domain and Application projects are structured using vertical slices/screaming architecture/by aggregates. Nevertheless, for Infrastructure, Persistence, Presentation projects, I have decided to create a folder structure based on respective types. From my perspective it is a preferred approach, because these projects do not have many aggregate-related structures. Thus, organizing them in screaming architecture would result in less readable and less maintainable solution.
If you like or are using this project to learn about Domain Driven Design, please give it a star. Thanks!
The solution in designed using the Clean Architecture in the following form.
I prefer to present it like this instead of using other Clean Architecture images, because in my opinion this is more readable. The runner layer is required so that the Presentation, Infrastructure and Persistence layers can be truly separated.
This layer should register dependencies and run the program. In terms of presented architecture schema it is a runner.
This layer should provide endpoints for the end user.
Therefore, it is like a "frontend" for the backed program.
This layer should provide handlers that orchestrate domain objects to obtain business features.
Therefore, we place here middlewares, CQRS structure and mappings.
This layer should provide additional tools (not database specific) that we are going to use.
Therefore, we place here services, options, validators, adapters, providers, policies and so on.
This layer should provide database specific structures, configurations, repositories, specifications, background jobs.
This is the heart of the whole solution. We store here entities, value objects, enumerations, domain events and other core structures.
Project to present structure of unit tests.
It contains also domain tests, architecture tests and utility tests.
This layer contains integrations tests.
Here we do not use the WebApplicationFactory approach, but we create DI container in more manual way.
Moreover, tests are done on the test database, but the test cleaning is required (see TestDataGeneratorBase.CleanDatabaseFromTestData).
Note: use these tests without containerized application and for the database that is locally installed.
This layer contains integrations tests.
Here we use the proper approach of using the WebApplicationFactory.
Moreover, we use TestContainers library, to make all integrations tests in sql database inside the container, so the additional database cleaning is not required (like in Shopway.Tests.Integration).
This layer contains performance tests.
We use NBomber as a performance test framework, because we can use it with xunit.
Note: use these tests without containerized application and for the database that is locally installed.
- Tests should follow T1_T2_T3 convention where:
- T1 is the name of the system functionality that is under test
- T2 is the expected result
- T3 is the test scenario
GetById_ShouldReturnProduct_WhenProductExists
Note: Alternative naming convention: switch T2 with T3:
GetById_WhenProductExists_ShouldReturnProduct
- Mocks should end with "Mock" suffix:
_productRepositoryMock
- Select Shopway.App as startup project.
- Create databases called DDDUniveristy and DDDUniversityTest.
- Run the application
Note: Portainer is used to investigate containers if required.
- Select docker-compose as startup project.
- Run the application
Alternatively:
- Open console at the solution level
..\DomainDrivenDesignUniversity>
- Run in detached mode:
docker compose -f docker-compose.yml -f docker-compose.override.yml up -d
To stop containers use:
docker compose -f docker-compose.yml -f docker-compose.override.yml down
If image rebuild is required:
docker compose -f .\docker-compose.yml -f .\docker-compose.override.yml up --build
To get all postman endpoints configured for local environment and docker containers:
- Go to
docs
folder. - Import collection
DomainDrivenDesignUniversity.postman_collection.json
- Import workspace globals
workspace.postman_globals
- Import local postman environment
LOCAL.postman_environment
- Import docker postman environment
DOCKER.postman_environment
All collection and global variables are set after requests. For instance, Login endpoint automatically sets a bearer token. Then, this token is used in the authentication process.
Currently there are two workflows setup for this repository:
- Continuous Integration
- This workflow setups and builds the application. Then, it runs unit tests and publishes test reports.
- Conventional Pull Request Validation
- This workflow validates if the pull request name matches the conventional commit rules. If validation succeeds, it adds a meaningful label to the pull request and assign author to the pull request.