This post is part of The Software Architecture Chronicles, a series of posts about Software Architecture. In them, I write about what I’ve learned on Software Architecture, how I think of it, and how I use that knowledge. The contents of this post might make more sense if you read the previous posts in this series.
The Onion Architecture was coined by Jeffrey Palermo in 2008. As I see it, it builds on the Ports & Adapters Architecture by adhering to the idea of placing the domain in the centre of the application, externalising the delivery mechanisms (UI) and infrastructure used by the system (ORM, Search engines, 3rd party APIs, …). But it goes further and adds internal layers to it.
We went from the Layered Architecture, with usually 4 layers (Presentation, Application, Domain, Persistence), to the Ports & Adapters Architecture which only implicitly mentions two concentric layers:
- An external layer representing the delivery mechanisms and infrastructure;
- An internal layer representing the business logic.
Both Ports & Adapters and Onion Architecture share the idea of isolating the application core from the infrastructure concerns by writing adapter code so that the infrastructure code does not leak into the application core. This makes it easier to replace both the tools and the delivery mechanisms used by the application, providing some protection against technology, tooling and vendor lockdown.
It also gives the application the pleasant ability to be able to run without the need for real infrastructure nor delivery mechanisms as they can be swapped by mocks, which is great for testing.
However, the Onion Architecture also tells us that, in enterprise applications, we will have more than those two layers, and it adds some layers in the business logic which we might recognise from Domain Driven Design:
Furthermore, it makes explicit the implicit idea of Ports & Adapters Architecture about the direction of dependencies:
- Outer layers depend on inner layers;
- Inner layers do not know about outer layers.
This means that the direction of coupling is towards the centre, providing us with an independent object model (domain model), who in its core depends on nothing. We have the flexibility of being able to change the outer layers without impacting the inner, and more important, layers. It makes use of the Dependency Inversion Principle, at an architectural level.
Key tenets of Onion Architecture:
- The application is built around an independent object model
- Inner layers define interfaces. Outer layers implement interfaces
- Direction of coupling is toward the center
- All application core code can be compiled and run separate from infrastructure
Jeffrey Palermo 2008, The Onion Architecture: part 3
Also, any outer layer can directly call any inner layer, which does not break the coupling direction and avoids creating proxy methods and even proxy classes that contain no business logic, just for the sake of complying with some layering scheme. This also comes in line with the preferences expressed by Martin Fowler.
[…] the layers above can use any layer beneath them, not just the layer immediately beneath.
Jeffrey Palermo 2008, The Onion Architecture: part 3
Onion Architecture builds on the Ports & Adapters Architecture to add some internal organisation to the business logic of the application based on a few Domain Driven Design concepts.
Again, this is an evolution in further segregating responsibilities, providing for low coupling and high cohesion, which in turn provides for more testability and maintainability.
2002 – Martin Fowler – Patterns of Enterprise Application Architecture
2008 – Jeffrey Palermo – The Onion Architecture: part 1
2008 – Jeffrey Palermo – The Onion Architecture: part 2
2008 – Jeffrey Palermo – The Onion Architecture: part 3
2013 – Jeffrey Palermo – The Onion Architecture: part 4 – After Four Years
14 thoughts on “Onion Architecture”
Well done. I like your articles very much. They are simple, subject focused, no white noise inside. Thank for you job!
Thanks for your great post 🙂
In this post, you said you disagree with Jeffery Palermo for placing repository interfaces in the domain services layer. The reason is all ports should be placed in the application layer because this layer is the edge of our internal core and near the external infrastructure (like your hexagonal blog post)? Or it has another reason?
The way i see it is that the domain knows nothing about persistence. I imagine it as the entities being some kind of planets floating around in void with some moons (value objects) around them.
There might be collections in the domain, like atar systems in void.
Repositories are collection-like objects, but not quite collections, their whole reason to exist is persistence, and since domain should have no knowledge of persistence, i feel repositories should not be in the domain layer (neither domain model layer nor domain services layer).
In practice, i don’t think there is any positive or negative impact of any of the approaches, but i feel that conceptually its more correct to put them in the application layer.
Regarding using repository interfaces as ports, that is one way to go about it, but not the root reason i disagree with Palermo, as i hope u can see by my explanation above.
I see that abstracting from persistence can be done using repository interfaces as ports, but another option is to create a port/adapter for the ORM. The first option is far simpler, the second option I find more correct. Both options are fine. The first might bring problems down the line if we want to make deep changes to how we handle persistence because we need to make changes in all repositories, the second option adds a lot of complexity which makes it more risky because there’s a higher chance of us making a mistake.
I usually leave it up to the team to decide and i go with the flow. 🙂
Hope this helped.
Thanks for your complete explanation about repository,
So, In general all ports should be placed in the application layer, because the application layer (that our ports exists here) is the nearest layer to the outer layer that our adapter exists?
Another of my question is, What about Cross cutting concerns like logging, caching, … and something will use in all layers.
Should we create a separate project for them like a Common project? And put all cross-cutting concerns interfaces and implementations there?
I explain that in other posts, you can check
Thanks for your guide 🙂
Thanks for your great content,
In this post, you said you disagree with Jeffery Palermo for placing repository interfaces in the domain services layer. Is the reason, all ports (interfaces for Infrastructure concerns and application services) should be placed in the application layer because this layer is the edge of our internal core and near the external infrastructure (like your hexagonal blog post)? Or it has another reason?
Hey , i really love this series of post , really hope it won’t go offline… Any way you can Zip it or something?
You did all the work for us , reading all those books while the only book i have read was clean architecture , it seems that ivar said it all long time ago ,but here and then people re-discover it.
Any recommended book if can read only one?
Tkx, and you’re welcome.
The book that had the most impact on me was the blue book, “Domain-Driven Design: Tackling Complexity in the Heart of Software” by Eric Evans. There is a more recent one on tge same subject “Implementing Domain-Driven Design” by Vaughn Vernon but I haven’t read it.
Another very good one is “Lean Architecture for agile software development” by James Coplien, and another MUST READ is “The mythical man month” by Frederick P Brooks.
These 3 books are, for me, the MUST READs for any serious software engineer and/or software architect. They were game changers for me.