Backend side architecture evolution (N-layered, DDD, Hexagon, Onion, Clean Architecture)

iamprovidence
14 min readJun 27, 2023

--

Hola!šŸ¤  So you want to be an architect, don't ya? Donā€™t lie to me, I know you do. Even if you donā€™t, you still want to be a better developer. Otherwise, you would not spend time reading this article šŸ˜

It is commendable. After all, we all want to be better if not the best in what we are doing. Here am I, to help you with that.

So, how do you become an architect? Obviously, by learning all the architectures! šŸ˜‚ Of course, that is not true. You donā€™t need to know everything. You also donā€™t need to have experience with all of them. However, knowing at least the most popular ones, such as N-Layered, DDD, Hexagon, Onion, and Clean architecture; understanding their history, their usage, and the differences between those will definitely distinguish you from other developers.

The architectures we are about to discuss are complicated, and it is easier to understand them when you see the reasoning behind each change. Moreover, since you see how those developed you can improvize, remove components that are unnecessary for you, or add something new.

I hope that was enough introduction words to engage you. If you are still interested, letā€™s get started šŸ˜‰

Where it all began?

Back in the good old days, there was no architecture at all. What blessing days were those. You could call yourself an architect only by knowing GoF patterns šŸ˜Œ

However, computers became more powerful, the userā€™s demand increased which caused an applicationā€™s complexity to grow.

The first thing that developers solved was splitting UI from business logic. Depending on UI framework, different MVC-like patterns were born:

That helped for a while, but not so much. If you are from C# community, the same as I am, you probably mistakenly think that the yellow box called Model, on those diagrams is just DTOs. Itā€™s all because of Microsoft. They confused us with their ASP MVC framework. Damn you, Microsoft! Do you think you are smarter than me just because I am stupider? šŸ˜¤

In fact, Model here stands for Domain Model, also known as business logic, which is quite crucial in any application.

Could you gamble, which of those three components from above causes the most problem? While View is just simple images and buttons, Controllers serve to be men in the middle, all the complexity concentrated in the Model.

That was a period where GoF patterns were simply not enough. So new ideas had to appear. How do we handle the complexity? Right! Divide and conquer. We already did it with MVC, so letā€™s do it once again.

2002 ā€” N-Layered

Ideal architecture did not appear from anything. As with everything, it went its own way with attempts and mistakes.

The guy who pioneered the software development architecture and influenced entire generations of developers for the upcoming decade is called Jesu.. khe Martin Fowler. He was like:

So they did.

He published ā€œPatterns of Enterprise Application Architectureā€ where N-layered architecture was described.

The idea is simple here, to group all related code together and call those layers.

However, there is a little more to that. Fowler knows how harmful inconsistency can be. So to prevent us from shooting ourselves in the leg, he tried to guide us with some restrictions:

  • you can name layers the way you want
  • you can have as many layers as you need
  • you can add layers in between
  • you can have multiple components in the same layer
  • just make sure there is a clear hierarchy between layers in a way they are referencing each other one by one

It helped developers not only to get rid of code duplication, but finally to structure their code.

Even though, those rules are pretty agile, in practice, 3 layers were more than enough for most of the projects.

  • User Interface (UI) ā€” is responsible for interaction with users.
  • Business logic layer (BLL)ā€” represents concepts of the business. It rules what your application is doing and makes it so unique compared to others.
  • Data Access layer (DAL) ā€” persists data in memory and keeps a state of your application

Here we have a clear separation between business logic and UI. Database turned out to be as important as business rules, so it deserved its own layer. Actually, all the external technologies can go to that last layer too. Everything is as the book says šŸ˜Œ

If you are wondering what those colorful rectangles and arrows mean to you, do not worry, it is simple. Those layers are just projects in your solution and arrows represent dependencies between those.

The separation not necessarily has to be physical with projects, but can be just logical with folders. You can also combine both the approaches. Use what suits you the best.

The difference between folder and project is major. A project actually allows you to control your dependencies. With folders, you may not even notice, when one layers start using components from another. On the other hand, with too many projects, the code became more fragile and harder to maintain. Keep in mind, there are no strict rules to it. Try yourself and see what suits best for you. As always, it is a trade-off between reliability and complexity. My advice here is not to create too many projects unless you really need them, one project per layer is more than enough.

Each layer calls the one below by its API, which usually is represented in the form of an interface. Access modifiers on each class are as important as those layers:

This may seem obvious to you right now, but that is only because you were not living through a really hard time. It is always easy to use but hard to invent. šŸ˜

2003 ā€” Domain Driven Design

In the year of 2003, a young, 46-years old developer from Boston, Eric Evans published his own book ā€œDomain-Driven Design: Tackling Complexity in the Heart of Softwareā€ which made at least one Martin in a world really sad.

Actually, DDD is a separate topic that should be described in its own series of articles, so we wonā€™t do it right now, just focus on all architecture changes it adds.

Evans agreed with all of Fowlerā€™s ideas, that project dependencies should be targeted in one direction. However, he also mentioned it is fine for low-level modules to call the ones above unless it did not break the dependency direction rule. It can be achieved with callbacks, observer patterns, and so on.

He also, saw that controllers have too much logic, so he moved it to another layer called Application. We start getting the germ of use cases, but not completely yet.

But the most important thing Evans did was by saying ā€œF*uck the database, Business logic is more importantā€. He said that and then did nothing about itšŸ¤·ā€ā™‚ļø. Yeah, yeah, yeah I knowā€¦ DDD and so on. However, from an architectural point of view, he had not change much.

In his architecture, the next layers are defined:

  • Presentation Layer ā€” is responsible for interaction with users.
  • Application Layer ā€” coordinates tasks and delegates work to domain objects.
  • Domain Layer ā€” represents concepts of the business. It rules what your application is doing and makes it so unique compared to others.
  • Infrastructure Layer ā€” persists data in memory and keeps a state of your application

You can see, he did some renaming.

User Interface implies you have users, which is not always the case. Sometimes it is GUI (Graphical User Interface) for users, sometimes it is CLI (Command Line Interface) for developers, and often it is API (Application Programming Interface) for programs. The Presentation layer is just a more generic and suitable name.

Business logic was confusing for some developers, especially for those who do no business at all, so a new name was introduced ā€” Domain.

The database is not the only external tool we are using, so all email senders, event buses, SQL and other cršŸ’©p were moved to the Infrastructure.

That is basically it. Some renaming here. Plus one new layer there. A lot of effort was given to the domain. But it is the same architecture with the same dependencies. If only he knew about the dependency inversion principle šŸ˜‰.

2005 ā€” Hexagon (Ports and Adapters)

Previously, modules has to reference the next one in line. With the discovery of dependency inversion, everything has changed.

That was an incredible opportunity for software developers. We finally learned how to control dependenciesā€™ direction to point them in the way we like! That means the business logic has no longer reference the data access. If you are wondering why it is possible, and what interfaces have to do with it, you can find it here.

The first guy who saw potential here was Alistair Cockburn. The guy was high, drew a hexagon, tried to call a Satan, and so on. I donā€™t need to tell you, you know better yourself how it goes on rock parties šŸ˜’. Nothing special here, one day you smoke some weed, the next one, waking up in the morningwith a strong hangover finding yourself accidentally discovered a new architecture.

Alistairt got tired of rectangles, so he drew a hexagon, came up with two names for everything, tried to make it sacred. But donā€™t get scary my fella-developer. In fact, this architecture is not much complicated than N-layered one:

There was a lot of spinning and moving around, so letā€™s see what actually happened there.

Cockburn made Evans dream come true. Now Domain is a central component of the system, not only in words, but in actions. It does not references any other project.

To emphasize it is indeed the heart, Business Logic was renamed to Core.

Infrastructure modules were split in half ā€” abstraction (interfaces) and implementation. Abstractions became part of Business logic and were renamed to ports. Implementation stayed in the Infrastructure layer. Now they are called adapters. In practice, UI turned out to be the same framework layer as DB, so it suffered the same fate.

Having infrastructureā€™s interfaces in your business logic, causes the Domain to be autonomic and dependency-free. As a result, business logic can work in any environment, with any tools. Do you want to change the DB? Just change the implementation, implement the needed adapter, and ā€œplug itā€ into the available port.

Changes in any adapter (database, email sender, ui) wonā€™t affect business logic. The interfaces stay the same.

Each component can be deployed separately. If you change data access only data access needs to be rebuild. If you change UI only UI changes.

Since modules can be deployed separately, it means they can be developed separately.

Only all the pluses.

Forget to mention, adapters that call our system called primary (driving). Those that are called by our system are called secondary (driven). It is not important to know, but knowing it will make you sound educated šŸ¤“

In terms of solution structure, those work best for me:

Again, folder vs project is something you should decide for yourself.

Just follow the references and make sure they donā€™t cross where they should not:

2008 ā€” Onion

This one going to be spooky, so prepare yourself šŸ˜Ø

Jeffrey Palermo. It is a sad story full of sorrow and darkness about the boy whose innocent childhood was marred by the cruel contemplation of onions. As he grew, a fiery hatred raged within him, burning with a promise of revenge that he would one day fulfill:

And believe me on that, he held to his promise for good. The little onion of him makes millions of developers around the world weeping and crying while running to motherā€™s hands.

This architecture enhances a lot from the ports and adapters. It still involves dependency inversion. It splits code by abstraction and implementation. Ports are still parts of business logic. Only this time Palermo adds the Application layer from Evans schema, which can contain some ports too.

The biggest challenge with this architecture, which causes so much confusion is dependencies between modules.

However, the rule is simple: any outer layer can only and only depend on the inner layers.

Not so simple, ha? šŸ¤” That is what I thought. So letā€™s slice that onion šŸ”Ŗ.

Domain is in the very middle. There is no inner layers inside it, so it should not depend on any other layer.

Application wraps only Domain, so that is exactly the only dependency it should have.

Infrastructure and Presentation layers are on the same level, they can not depend on each other, but they can depend on Application and Domain, where all needed interfaces are defined.

You can also see it has all the modules from DDD architecture but handle them differently. It actually makes a big deal! The key here, to have in the middle components that are modified rarely, and have frequently changed ones on the edges. Changes in Application, or any other layer, wonā€™t affect Domain, only dependent layers. The only reason for your Domain to change is when business logic changes, and that is the case that affect the entire system anyway.

That how it looks it theory. In practice, your composition root (Main() function where all dependencies are registered and modules are composed together) will be part of the presentation layer (ASP, WPF, CLI), so the diagram will have the next look:

Does it look familiar to you? It is N-layered architecture, but the components are in a different order.

No matter, how it looks, hexagon, ports or onion, the ultimate goal you should aim for your dependencies to point out in the form of an acyclic graph or a tree.

2012 ā€” Clean Architecture

šŸŽµšŸŽµšŸŽµ
Thereā€™s a man named Uncle Bob,
Heā€™s the cleanest coder on the job,
With his agile moves and architecture too,
Heā€™ll make your code shine like brand new,
Uncle Bob
šŸŽµšŸŽµšŸŽµ

I mean, one can not simply write an article about architecture without mentioning Robert C. MartinšŸ˜….

He saw all the hype around architecture, and decided to crash the party. Martin know the main secret of any developer, so he wasnā€™t even trying to hide it. Just brazenly steal peopleā€™s ideas and call them his own.

Just joking, there are no much original ideas these days, everybody steals from each otheršŸ˜‰ Letā€™s see what Martin brought up here:

Our poor Domain got renamed, once again. Now it is Entities. However, that is not only it. It implies you donā€™t have domain services and anemic models, but rich classes with both data and behaviour.

Interfaces of repositories and other ports are moved from Domain to the Application layer. Which in its turn got a more appropriate name ā€” Use Cases.

Presentation and Infrastructure layers stay the same. However, Martin also adds one extra layer on top, which includes Frameworks, DLL and other external dependencies. It does not necessarily means that your DB will have a reference to Entities, it just prevents you from having reference from inner layers to those external tools.

Once again, there is no strict rule. You can add as many layers as you need at any level you want. So if you want to define a layer for Domain services you can.

Martin also has drawn a small diagram near the architecture.

It shows that users communicate with a system by triggering the controllerā€™s endpoint, which calls a use case, and then returns data via presenter (black lines). Use case can invoke any ports its likes, by interfaces (green lines). While actual implementation is part of the outer layers (orange lines).

It tries to highlight that execution flow (dotted line) does not always correspond to dependency direction (straight line), which is just the dependency inversion principle.

Basically, it highlights the usage of inversion of control once again. You already have seen this when we were discussing ports and adapters.

Usually in ASP we donā€™t have a separate component for a Presenter. This is done by the Controller as well. So that whole diagram can be represented in the code like this:

class OrderController : ControllerBase, IInputPort, IOutputPort
{
[HttpGet]
public IActionResult Get(int id)
{
_getOrderUserCase.Execute(id);

return DisplayOutputPortResult();
}
}

Other forms of isolation

All those architectures aiming a goal to isolate one code from another by splitting responsibilities. However, there are other forms of isolation: vertical slices, bounded context, modules, microservices, and so on. The goal here is to split code by features.

Some do not consider them to be ā€œtrueā€ architectural approaches, while some do. It is up to you. In the end, they will grow to the point, where they still would use any of the architecture styles from above or even a combination of those:

Conclusion

In this article, we discussed N-layered, DDD, Hexagon, Onion, and Clean architectures. Those are not the only architecture that exists. However, the ones described are the most famous ones. You may also have heard about BCE, DCI, and so on.

Regardless of the minor difference in details, all the architectures are almost the same. They all serve the same purpose ā€” to split responsibilities. They all do it by splitting code on separate layers. The whole difference is what components are defined and what dependencies exist between those layers.

Now that you have the whole picture, I highly encourage you to read this article once again. Highlight the difference between architecture by yourself. You can also try and play with projects on your own. Write some classes with interfaces, pay attention to references between your projects, where interfaces and implementations are placed, what access modifiers are used.

I hope starting from now, every time you create a class, review a PR , talk to your college you will consciously think and question those stuff šŸ˜‰

šŸ’¬ Let me know in the comment section what have I missed? Where I was wrong? Are you interested in those stuffs?

āœ… Subscribe to not miss future articles

šŸ‘ Clap it, if you think my effort is worth your time

šŸ‘Øā€šŸ‘¦ā€šŸ‘¦ You can also share this article with your friend. Argue a little on it. It is known that the truth is born in a dispute

ā¬‡ļø Check out my other articles

ā˜•ļø Arrange a coffee break for me

šŸ™ƒ Stay determined, stay focused, and keep going

--

--

iamprovidence

šŸ‘ØšŸ¼ā€šŸ’» Full Stack Dev writing about software architecture, patterns and other programming stuff https://www.buymeacoffee.com/iamprovidence