How architectural boundaries apply to the use of databases
Boundaries between the domain and the database
Typically makes sense to draw a boundary between the actual domain logic and the database (unless your application is a thin layer around the database that doesn’t really have any domain logic)
One widespread convention: Repository pattern:
- All interaction with the database is encapsulated inside Repository classes
- The domain logic interacts with these classes, without having to know anything database-specific
If the domain logic is using the repository interface, then it also becomes easy to swap out the
SqlServerUserRepository for a different implementation, for example an in-memory repository for testing purposes.
The Repository pattern also makes it easy to implement caching. Ideally, the repository takes care of caching values and invalidating the cache as needed, without other code even being aware that there is any caching at all.
Separation at the database level
For larger systems, it can make sense to separate different parts of the application down to the database level. Each part uses different tables or a different database, with no links between data belonging to different parts. This kind of separation is considered good practice when setting up a microservices architecture. You can also do this in monolithic applications, potentially as a stepping stone towards a feature microservices architecture.
Separation at the database level makes it easier to reason about separate parts of the application without having to think about other parts. It also provides more flexibility to change the schema or database technology for a certain part of the system.
When drawing boundaries down to the database level, some data that is relevant to two parts of the system might exist on both sides of the boundary between them
See also Microservices
- Clean Architecture (book by Robert C. Martin)
- Building Evolutionary Architectures (book by Neal Ford, Rebecca Parsons and Patrick Kua) (summary slides )