Layering Software Architecture
I've seen many people describing software layers in the same old way, all over and over again. Here, I'm going to introduce my vision of how to layer the software architecture. This might seem like an outcome of the other definitions you can find online; however, the slight difference is in the accuracy of belongings to each layer. I hope that the readers will find it refreshingly new.
In my world, software architecture is layered as follows (description will come after the diagram):
UI layer is responsible for the presentation of the software. This is a common part of the most layering approaches.
Domain & DAL model is referenced by the UI layer. I understand that the name is a little bit complex, but that's because this layer consists of 2 pieces that I want to consider as a whole - Domain and DAL (abstract). Domain is a sub-layer that contains the main model for the software. However, Domain usually references DAL in an abstract way, so the boundary between these two is somewhat blurry (or clearly, non-existent).
DAL (implementation) is another layer that actually references DAL abstractions (which are defined as part of Domain & DAL abstractions layer), and implements those abstractions in a concrete way, by incorporating database or other concrete means of the data source.
Database is an actual data source for the software.
Instantiation of the software happens inside UI layer (often expressed as a Client class in the UI layer). Here we have Domain's model instantiated by injecting DAL implementations into it.
Benefits of the Approach
Benefits achieved by using above layering approach include:
- Software model (Domain & DAL model) layer is fully unit-testable. Indeed, it does not reference any particular kind of platform or technology. Theoretically, a 100% code coverage can be achieved on this layer.
- DAL Implementation is replaceable. Indeed, UI application needs minimal knowledge about DAL (implementation) layer, - and that's for instantiation purposes only. Upon request (e.g. to replace Database), we can re-implement DAL (abstract) layer in a different (concrete) way again. As about the instantiation, - that part is often handled by IoC containers, which make this approach even more attractive.
- Members (classes) of each layer can be physically split into different software projects or libraries, so that they only hold references to needed assemblies/packages. Together with the discipline and systematic code review practices, this will decrease the number of referential violations, such as business logic objects referencing database directly (which I have seen very often, unfortunately).
To take the most out of the layering approach described above, I would recommend following the topic of Modeling Software Architecture as well.
Drawing Parallel with Classical Approach
Now, let me draw a logical line between the above approach and classical approach of layering software. Obviously, they translate into each-other, but I would always present it the way I showed above since that clearly depicts the layers and their responsibilities, as well as architectural correctness of the overall software.
Here is the diagram that shows classical layers on top of my layers introduced in this topic:
As you can see, UI (presentation) layer has the same boundaries in the classic approach. However, differences start popping up in the Business as well as DAL layers.
When designing business layers with classical approach, we often make it limited to the core domain objects only, by deferring the logic of manipulating business objects to DAL layer. That forces us to have DAL layer responsible for too many things; and next thing we do is, we make Domain layer aware of the DAL. This is a serious referential violation already, since business logic starts being aware of the platform-specific data source. So, if you have gone thus far, stop and rethink your layering approach.