Starting new project requires hours of talks from you and your team. You’ll need to choose technologies, libraries, code repository maybe even process framework. Each of those is very important, but most of them you can change during working on project easily, it might be harder if you notice error too late. There is one thing you’ll have to live for rest of your project live. Architecture.
Changing architecture may involve amount of work approximate to rewriting whole project. In this article we’ll get to know one of the most common architecture, multitier and similar to multitier, onion.
Multitier Architecture
Multitier architecture is one of the most common architecture. To be honest I learned it during learning programming, because every tutorial was using 3 tier architecture.
Name is taken from construction of this type of architecture, project has multiple layers. The most common type of multitier is 3 tier architecture, it will contain 3 layers. Data Access Layer, Business Logic Layer and Presentation Layer, but it’s not rule, you can decide how many layers you need.
General rules
Basic rule is that layer above can access only one layer below it. Thanks to that when we change something in one layer we will need to make additional changes only in one layer instead of whole application.
Additionally to minimize need for changes we should use DTO, data transfer objects when we move data from one layer to another, but it’s not rule. It may be over-engineering in some cases.
Data Access Layer
As name states, this layer is responsible for accessing data it doesn’t matter if you get your data from database or rest api. You should put your data access classes in this layer. Additionally I put here entities for Entity Framework or other ORMs.
It is important that any data access related class won’t leave this layer. It should be possible to just switch something in layer without making changes in multiple layers.
Business Logic Layer
Business Logic Layer is heart of your application. Here should be stored every functionality. Additionally you should return your domain models from methods.
Only Business Logic Layer can access Data Access Layer. It’s simple rule but it will force you to create “go thru” classes when you’d like to just load some data to display to client. Your business class would run method from data access layer.
Presentation Layer
Last Layer is used to store every class that will connect to client, it may be controllers if you create API or Views for web application. This layer can access only Business Logic Layer, it shouldn’t know anything about loading data or source of data for the same reason, if you change something in repository you don’t want to make changes in view.
Onion Architecture
Unfortunately Multitier architecture creates coupled project, Presentation Layer is coupled to Business Layer and Business is coupled to Data Access. For that reason Onion architecture was created.
General rules
Onion architecture is similar to multitier architecture. It also has layers but instead of vertical layers onion has circular layers. Layers can depends on layers near center or on the same level.
Additionally Onion requires using Dependency Inversion as there are layers in core just for interfaces. Additionally Onion distinguishes Infrastructure Interfaces, which are basically repository interfaces and Service Interfaces which are used to implement Business Logic of our application.
Thanks to that Onion is decoupled even in theory. By implementing Onion in our project we’ll have to create decoupled code.
Core
In the middle of our application are projects that defines our domain, like domain classes, entities, business service interfaces or data access interfaces.
We want to have in core things that won’t change too often, because every project of application may depend on core, that means change in core may require change everywhere.
Of course changes in core will occur, but from my experience it’s mostly extending existing functionality. We can’t define unchangeable domain.
Additionally you can see that core contains more than one project. Simplest solution shows three projects, but you can extend that.
Application Services
In Application Services we will implement every feature. There isn’t too much magic here, just that. Services can use other services and core.
Again Application Services may be one project or multiple projects. Architecture shouldn’t limit us, it’s tool just like nuget packages, IDE, etc. Personally I’m okay with creating only one project and splitting it, if project get too big.
Last Layer
The most outer layer contain rest of our application. Client application, tests, data access implementation.
Infrastructure Layer
You might be surprised that Data Access – Infrastructure is in last layer. In multitier architecture database is center of our application, but onion changes it. Here database is something outside. It’s done this way, because accessing data changes most often. Putting Data Access Layer just below Business Services force us to change them every time Data Access change.
Having it this way we still can use Infrastructure Interfaces in business logic, but we won’t be able to use implementation straight in services.
Additionally using EF DbContext in controllers is still cool with onion, because it’s the same layer.
Client application layer
Finally client application. Here you can have Web API project, but also whole frontend client application.
As before, you can have multiple projects in one layer. When I create client application I’m also using there onion. Client application as a whole is in last layer in API project, but also have its own onion with its own core, services etc.
You won’t break onion by this, because your API can’t use App and at the same time App will depend on API.
Onion project setup
It’s example, I always create Core project which will contain domain models and entities.
Core.Interface will have data access interfaces. In this project I didn’t use business services, but I would create another project for business interfaces.
Infrastructure project implements data access interfaces. Finally WebApi which contains client access.
You might ask about two additional projects at top. It’s very common to have some functionality that is used in your application, but can’t be called Business Logic. In my case it was email sending.
The best solution is to put things like that to in different place. It’s because other projects may use it as well. All you need to do then is move those projects do different solution and creating nuget package from them.
Outro
I become big fan of onion, earlier I’ve been using only multitier architecture. At the beginning it was hard to understand, but once you find out that onion is similar to multitier, only assumptions change you’re at your ground.
Additionally Onion force you to use DI. It’s great for newbies. I truly understood DI after I started using Onion, before that I coupled my projects using implementations everywhere.