Saturday, 7 February 2015

In defense of the 3-tier architecture

Lately, there's been a lot of buzz about Domain Driven Design, Rich Domain Models and the Onion Architecture. While this approach certainly has its merits, it often comes with a negative attitude towards the other, older alternative: the 3-tier architecture with an Lean Domain Model. In this article, I will explain why the old approach is not that bad at all and can be the preferred architecture in a lot of situations.

The good old 3-tier architecture consists out of the following components:

  • The frontend: The first tier. It does not matter what sub-architecture you use here, MVC or something else. That's beyond the scope of this article. All that matters is that the frontend talks to the service layer.

  • The service-layer: The second tier. It contains the business logic and talks to the DAO-layer.

  • The DAO-layer: The third tier. It connects to the database to store and retrieve data. This layer could also contain connectors to external systems, such as email or external webservices.

  • The domain entities: The domain entities contain all the data and are used throughout the three layers. Each entity often corresponds to a table in the database. The entities do not contain any logic, just data.
Let's compare this to the Onion architecture, which has no less than four layers (sometimes five, depending on who you ask), with numerous categories within each layer. I've created a comparison diagram between the two below (click for a larger version). Please note that the Onion architecture as depicted below is just one of many interpretations of the Domain Driven Design (DDD) approach, more complex versions exist!


If I look at the Onion architecture in this image, one word comes to mind: complexity. It is beyond the scope of this article to explain how the Onion architecture works, whole books have been written about it. In my opinion however, it is not a good thing if your developers have to read books before they can get started. The 3-tier architecture however, is clean, simple and understandable and has many other benefits compared to the Onion Architecture:

  • The 3-tier architecture is not truly object oriented, because in an object oriented design, each object contains both state and behaviour. Instead, the 3-tier architecture is more procedural: Upon user interaction, procedures run on data without holding any state. This is however, exactly what most applications need, since the vast majority of web applications is procedural in nature!

    The state is held in the database and when the user clicks a button, the necessary data is retrieved, changed, stored and the resulting page shown to the user. The application itself holds no state whatsoever. Compare this to a real-time strategy game, with buildings, tanks, soldiers, etc. Such an application lends itself very well for object oriented design, as each object in the game has both state and behaviour. Most web applications on the other hand, are better suited for a procedural programming style.

  • You know exactly where the business logic is. In the Onion Architecture, the logic could be anywhere and you might have to traverse a long call hierarchy to get to where you need to be. In the 3-tier architecture, the business logic can always be found in the service-layer.

  • If the requirements change, so that a piece of business logic suddenly needs an extra call to the database, you can simply do that. The logic is in the service-layer, which has access to the DAO's. In the Onion Architecture, when the logic is in a domain object, you have no access to the repositories. You have to solve it in either of two ways: Move the logic to a service, which is a significant refactoring, or pass in the needed data via a parameter. This leads to long lists of parameters being passed and will be difficult if you can only determine the required data halfway through the logic.

  • There's a very short learning curve. If a new developer joins the team, they can start working on their little part of the application almost immediately. They just have to know about a page, a service and a DAO. In the Onion Architecture, there's a long learning curve and new developers are required to understand the entire domain before they can make any changes.

  • There's only one way to do things, which will lead to simplicity and consistency throughout the application. In the Onion Architecture, different developers might have different ideas on how to model a certain use case, even if they're all OO-geniuses. This means that over time, the application becomes complex and inconsistent, increasing the learning curve even further. This will also become a problem if certain key developers leave the team.

    Simple rules lead to complex and intelligent behavior.
    Complex rules lead to simple and stupid behavior.

    - Dee Hock -

  • It's easier to enforce standards and guidelines, since each layer has very specific responsibilities. In the Onion Architecture, it's more difficult, as basically anything is allowed inside the domain objects.

  • There's a clear separation between logic and data. This makes it possible to accurately track changes in either, without being distracted by the other. Since logic changes often and data does not change very often, this can be quite useful.
Despite the benefits of the 3-tier architecture, the Onion Architecture also has some good practices that are worth mentioning. Each of them however, is not specific to the Onion Architecture, but can be applied in the 3-tier architecture as well:

  • In the Onion Architecture, there is no business logic in the repositories. This is a good practice, because the repositories are meant to be a thin layer above your database. In the 3-tier architecture, you can use the same practice for your DAO's: keep them lean and leave the business logic to the services.

  • Complex pieces of logic that are not specific to a single domain object and are therefore not inside a domain object, are separated out into components. These components can then be used by other classes. The benefit of this is that this complex logic can then be separately tested, instead of it being tested as part of the calling logic. In the 3-tier architecture, creating components that handle specific, complex pieces of logic is perfectly possible. These components live in the service layer and can be used by the services.
All in all, I think that the 3-tier architecture provides a lot of benefits for a typical web application and, equally important, a typical team where people come and go all the time. I'm not saying that the 3-tier architecture is always better than Domain Driven Design, but in most cases, the complexity that the Onion Architecture brings with it, is really not worth it. And when a web application becomes so large and complex that the 3-tier architecture no longer suffices, then, instead of moving to Domain Driven Design, it might be a better idea to look at SOA approaches and split up the application altogether.

A clever person solves a problem, a wise person avoids it.

- Albert Einstein -

If you would like to read another article that argues against complex multi-layers, then I can recommend this one from jOOQ.