Clean Architecture vs. Onion Architecture vs. Hexagonal Architecture

There are three architectural models that are repeatedly mentioned and applied:

  • Hexagonal architecture (ports and adapters)
  • Onion Architecture
  • Clean Architecture

In our trainings The differences between clean architecture and onion architecture - which is better?

The following section looks at the differences between the three approaches and what they have in common. This is followed by a critical examination of the disadvantages and, finally, an alternative is presented in the form of the IODA architecture.

Development of the architecture models

Hexagonal architecture, 2005

The hexagonal architecture was Described by Alistair Cockburn in 2005. It is also known under the name Ports and Adapters as this is the central concept of the architecture. The core idea of this application architecture is to direct the dependency in its direction from the outside to the inside. At the core of the hexagon lies the application logic. This is the most important aspect of a software system. It is fundamental that this can be easily tested automatically. Consequently, it would be very obstructive if technical code were dependent on database access, for example.

Figure 1 Hexagonal architecture clean architecture vs. onion architecture
[Figure 1: Hexagonal architecture]

There are inner layers and outer layers in the presentation. The further outwards we go, the more technical the responsibility becomes. At the core of the application is the domain model, which is responsible for the technicality of an application. This logic should be independent of technical code. The division of responsibilities must therefore ensure that, for example, the user interface is on the outside and is internally dependent on other aspects such as domain services or application services. If we divide and implement our code in this way, we can ensure that the business logic is essentially independent of the user interface and database.

The hexagonal architecture achieves the reversal of dependencies through the introduction of so-called Ports and Adapters. An adapter is one of the best-known design patterns. Whenever an inner aspect requires a service from an outer aspect, we are faced with the question of how to deal with the dependency. In order to achieve a reversal, the inner aspect defines a so-called Port. In software terms, this is an interface. The internal aspect uses the interface to define which services it requires from the external aspect.

Since the external aspects often cannot be modified, the adapters ensure that an external aspect implements a port. Let's assume that the level of the Application requires services of a Frameworks. We consider the framework to be a 3rd party dependency for which we are not responsible. In particular, we cannot modify the source code so that it implements the port (an interface). Therefore, an adapter realizes the connection: on the one hand, the adapter implements the port. This means that the application can use the adapter because it implements the interface. On the other hand, the adapter uses the framework to provide the services.

Ultimately, this approach is Dependency inversion. The hexagonal architecture is therefore based on the Dependency Inversion Principle (DIP).

Onion Architecture

In the year In 2008, Jeffrey Palermo coined the term onion architecture. The most important differences to hexagonal architecture lie in the naming. Furthermore, onion architecture no longer makes an explicit statement about how the dependency direction is to be achieved in terms of software technology. However, it is also clear here that the dependencies run from the outside to the inside. It is therefore also a DIP-based architecture with which high code quality is to be achieved.

 

Figure 2 - Onion Architecture
[Figure 2: Onion Architecture]

Clean Architecture, 2012

The last to arrive was Bob C. Martin 2012 around the corner and has coined another term for the same model: the Clean Architecture. Ultimately, nothing new is delivered here. It also uses slightly different terms. But at its core, clean architecture is the same as onion or hexagonal architecture: DIP-based. The dependencies run from the outside to the inside. The technical details such as persistence are on the outside, the functional logic on the inside.

Clean Architecture
[Figure 3: Clean Architecture]

Critical appraisal

First of all, it should be noted that the three DIP-based architectures outlined above make a very important contribution in terms of Changeability and Correctness to perform. It is only through dependency inversion that we are able to write automated tests in which individual units are released. To do this, we use dummies that can be used in the test instead of real implementations. In this way, the business logic can be tested automatically without, for example, a database having to be available for the test. This is a significant step forward, especially for the application core, because we can now ensure its correctness in unit tests. A database connection is no longer required in the test, which significantly improves the testability of the application core in particular.

At the same time, automated tests based on dummies are comparatively more complex to implement and maintain. The dummies very often expose internal information that can cause a test to fail if the internal implementation is changed.

On the other hand, the Dependency Inversion Principle (DIP) and clean architecture often lead to projects overdoing it with interfaces. Suddenly it becomes the standard that every class is assigned an interface. Whether this is actually needed is often not questioned. Such patterns can quickly become an end in themselves.

Last but not least, the ability to test individual units in isolation using dummies means that integration tests are neglected. If the application is only tested using unit tests with dummies, there is no guarantee that the interaction of these units will work correctly. A certain amount of real integration tests are always required, against the real database, against the real hardware, etc. Docker containers and the TestContainers Project about which I elsewhere I have already written.

The bottom line is that the application of clean architecture often results in too much structure, which is not absolutely necessary to achieve changeability and correctness.

Interim conclusion

Let us first note that the three architectures mentioned are ultimately the same thing, even if different terms are sometimes used for the different aspects. A comparison of the terms can be found in this blog article by maibornwolff to find.

The core idea of the DIP-based architectures is to lead the dependencies from the outside to the inside. All three models achieve this. This architectural style assumes that the dependencies are resolved via interfaces and dependency inversion as well as dependency injection.

It could be argued that such a software architecture is an important step in the right direction. However, the question arises as to whether alternatives have been developed after so many years of use. And indeed, they do exist: the IODA architecture.

Integration Operation Data API Architecture, 2015

The IODA architecture has been described, applied and taught by Ralf Westphal and the author, Stefan Lieser, since around 2015. It differs from the three others mentioned in that it uses a different solution to the problem of dependencies: the separation of Integration and Operation.

If you look at the Dependency Inversion Principle, you can see that even after the introduction of an interface, there is still a mixture of aspects. The following illustration shows that the functional unit A is still responsible for two things: On the one hand, it takes care of what is written on it, so to speak: A does what A is supposed to do. For example, if the class is called Productit contains the logic behind the topic of products. So far so good. However, the class also integrates. It calls functions from the ProductRepository on. It does this, guided by the DIP, via the detour of an interface. However, it remains the case that the Product class is responsible for the technicality on the one hand and for the integration of the repository on the other.

Figure 4 SRP violation despite DIP clean architecture vs. onion architecture
[Figure 4: SRP violation despite DIP]

The IODA architecture is based on the Integration Operation Segregation Principle (IOSP). It is therefore an IOSP-based architecture. The aspects lie next to each other on the middle level. This is a fundamental difference to DIP-based architectures, in which the aspects are layered. The IODA architecture is therefore not a layered architecture, even if the picture may give the impression that it is. There are no interdependencies within the level of operations. The interaction is achieved through the integrations above. In this way, responsibilities are clearly separated: either a functional unit contains some form of logic, in which case we call it an operation. This can be domain logic, but also database or Ui logic.

Figure 4 IODA architecture clean architecture vs. onion architecture
[Figure 5: IODA architecture]

If a functional unit uses other functional units, its responsibility is integration. It then contains no logic. As a result, we are dealing with operations that can be tested in isolation without the use of dummies. The operations are already isolated. This eliminates the need for dependency inversion and interfaces. On the other hand, with the integrations we have units on which the integration tests can be based. As the real units are integrated during an integration test, interfaces and dependency inversion are not required here either.

Conclusion

We have had very good experience using the IODA architecture for many years. It fits perfectly with the test pyramid and thus optimally supports a test strategy consisting of system, integration and unit tests. We can do without many interfaces and only very rarely have to deal with dummies in the test. The IOSP is a further development of the DIP and offers many advantages when testing and understanding a code base. Why not try implementing a sample application in the IODA architecture?

Our seminars

course
Clean Code Developer Basics

Principles and tests - The seminar is aimed at software developers who are just starting to deal with the topic of software quality. The most important principles and practices of the Clean Code Developer Initiative are taught.

to the seminar "
course
Clean Code Developer Trainer

Conducting seminars as a trainer - This seminar is aimed at software developers who would like to pass on their knowledge of Clean Code Developer principles and practices or Flow Design to others as a trainer.

to the seminar "

Leave a Comment

Your email address will not be published. Required fields are marked *

en_USEnglish