The term Onion Architecture or Architecture onion was coined by Jeffrey Palermo in the year 2008 because of the big problem that comes with the style N Layers that is the unnecessary coupling that is generated between the layers and between several responsibilities of infrastructure (database, services Web, mail servers, ftp servers, etc). This architecture’s main aim is to address the challenges faced with 3-tier architecture or n-tier architecture, and to provide a solution for common problems.
When a class is dependent on a concrete dependency, it is said to be tightly coupled to that class. A tightly coupled object is dependent on another object; that means changing one object in a tightly coupled application, often requires changes to a number of other objects. It is not difficult when an application is small but in an enterprise level application, it is too difficult to make the changes.
It means two objects are independent and an object can use another object without being dependent on it. It is a design goal that seeks to reduce the inter-dependencies among components of a system with the goal of reducing the risk that changes in one component will require changes in any other component.
- Each layer is coupled to the bottom layer, this design creates an unnecessary link
- Each layer depends on some infrastructure issues.
- The presentation layer depends indirectly on the data layer, any changes occurring in the database will have an impact on the upper layers.
- The presentation layer cannot work if the business layer is not present and the business layer does not work if the data layer does not exist.
- This design violates the SOLID Dependency Inversion principle which states the following: Abstractions should not depend upon details. Details should depend upon abstractions.
- The business layer (abstraction) should not depend on the data (detail). The details must depend on the abstractions
The onion architecture is nothing new, it has been around for a while. Some may call hexagon architecture or ports and adapters pattern. They all essentially refer the same layering structure which promises more maintainable applications since it embraces the separation of concerns throughout the system.
Onion Architecture addresses both the separation of concern and tight coupling issues. The overall philosophy of the Onion Architecture is to keep the business logic, data access logic, and model in the middle of the application and push the dependencies as far outward as possible means all coupling towards to center.
Advantages of Onion Architecture
There are several advantages of the Onion Architecture, as listed below.
- It provides better maintainability as all the codes depend on layers or the center.
- It provides better testabilty as the unit test can be created for separate layers without an effect of other modules of the application.
- It develops a loosely coupled application as the outer layer of the application always communicates with inner layer via interfaces.
- Any concrete implantation would be provided to the application at run time
- Domain entities are core and center part. It can have access to both database and UI layers.
- The internal layers never depend on external layer. The code that may have changed should be part of an external layer.
- Communication between layers is done using interfaces. Any implementation is provided at runtime.
- Any external dependencies, such as databases or web services, belong to the outer layer.
- The UI also belongs to the outer layer.
- The objects that represent the business belong to the inner layers.
- The outer layers depend on the inner layers.
- The inner layers cannot depend on the outer layers.
- Everything you can change must be on an outer layer.
Peeling the Onion
- Domain Entities Layer
At the very core is the Domain layer which holds all of your domain objects and also have domain interfaces, but just the interfaces and not any kind of implementation. The idea is to have all of your domain objects at this core. Please restrict yourself by keeping just the properties or definitions inside your domain objects and not any piece of code which talks to database or has any other business functions.
- Service Interface Layer
Common operations like Add, Save, Delete should go in here within interfaces. You can define your transactional interfaces like (IOrderService.SubmitOrder) here. One of the most important thing to notice here that service interfaces are kept separate from its implementation, which ensure the loose coupling and separation of concerns.
- Application Services Layer
The implementation of Interfaces defined in Service Interface layers comes here. The service implementation gets data from repositories and processes requests coming in from UI layer. This layer acts as a middleware to provide data from Infrastructure to UI. It holds business logic for an entity so it’s called business logic layer as well.
- Infrastructure Layer
This is the outermost layer of onion architecture which deals with Infrastructure needs and provides the implementation of your repositories interfaces. In other words, this is where we hook up the Data access logic or logging logic or service calls logic. Only the infrastructure layer knows about the database and data access technology (Entity framework or Ado.net) and other layers don’t know anything about from where the data comes and how it is being stored.
This layer is where the user interface project is located, it can be a web project, console application, Web Api Project, etc.
The basic principle of Onion Architecture is to follow the boundaries of these layers – the inner layer can’t depend on its outer layer but can depend on layers beneath. For example, domain layer can’t depend on Infrastructure layer, but Infrastructure layer can depend on Domain layer. The strategy is to make interfaces defined in the domain layer and put the implementation in Infrastructure layer. Following this principle makes sure we have loose coupling between layers and a real implementation comes only at real time.
Additionally, the Onion Architecture relies heavily on the Dependency Inversion principle to provide the interface implementations at runtime.
The clean architecture
Defined by Robert C. Martin, it is the union of all styles that share the same principle of not depending on things that change or can change.
Also known as Ports and Adapters, this type was defined by Alistair Cockburn and adopted by Steve Freeman and Nat Pryce in his book Growing Object Oriented Software.