This architecture doesn’t really scale. You can see analysis of architectures post to have more information about it.
Then Eric Evans came up with Domain Driven design and we have the following architecture.
However, development and architecture should actually be simpler because HTTP is a very simple protocol. We mostly use HTTP GET and POST. To create resources we use POST, to retrieve resources we use GET.
GET operations are safe and idempotent. GET can be called over and over. GET can be seen as queries. POST is unsafe and not idempotent. POST is commands.
One of the handicap with traditional layered architecture is that, a change in the system has to propagate through all the layers.When there is a change in UI layer or to introduce a new feature, all the layers gets affected. We have to make changes across all the layers from Presentation to Persistence layer. This can become very tedious and hard to manage.
During development lot of merge conflicts can occur as well. If more than one person changing the layers there will be conflicts.
In traditional N-tier architecture Interface segregation principle is usually violated by having so many methods within repositories or services.
A repository usually have methods as queries and commands. Interfaces can be separated for Queries and Commands. CQRS to the rescue.
Features can be collapsed in to slices. For example for User feature, you can have Query, QueryValidator and QueryHandler, then you can have Command, CommandValidator, CommandHandler. All these methods can be stacked within a single entity. Everything can be found in one place.
We want to have the following architecture.
Validation, Authentication and Authorization can be domain agnostic and used in other projects. Every request in a system should be validated.
Features can use different technologies or different storage. For user management, you can use NoSQL stores etc.
How does this architecture fit in SOLID principles?
SRP (Single responsibility principle): One class per feature or concept. Since every request has one class, it has one reason to change.
OCP (Open-Closed Principle): Extend through cross cutting concerns.
LSP (Liskov Substitution Principle): Since there is no inheritance anymore, there is no substitution.
ISP (Interface Segregation Principle): We separate queries from commands.
DIP (Dependency Inversion Principle): Only true dependencies and external dependencies can be wired.
While still being a monolith feature based architecture resolves some of the problems traditional n-tiered architecture has.
We consider agility of traditional layered architecture is low due to propagating changes across layers. Responding to change can be low. However with feature based architecture, responding to change can be high, since you will make changes only within a single class.
Development of this architecture is also easier and can be developed efficiently in a team without causing any conflicts.
Since feature sets are independent, testing features independently also proves high testability.
Due to monolith nature, deployment can be as problematic and not easy similar to traditional layered architecture.
Performance and Scalability can be low with this approach as well.