A reference architecture (part 1)


Software architecture is part of my job. And in my experience I can honestly say that if you would ask several people to design a system, they would all come up with something different. As such, it’s often very subjective. Of course there are objective arguments for choosing this or that, but quite often they come with a flavor of personal taste.

Anyway, my point is that in the course of previous years the ideas I had about architecting systems have evolved. As a matter a fact, if I look back at some of the designs I did, I would probably do it completely different nowadays. Because with experience comes maturity, and of course, also technology evolves. I’m confident that the ideas I have now will change again in the future, and in fact this is exactly what makes my job fun to do. Just always remember that there is no such thing as a perfect architectural design that is a solution for every problem.

The goal of this series is to show you an example how you could design a system. It’s kind of a reference architecture that I like to use (I have used it – a number of times in middle-sized projects, and I’m still quite happy about it), but it’s up to you to decide if you find some ideas to be usable in your specific environment. In no way I claim that these ideas are the one and only truth, instead, I would like to take this opportunity to learn from your comments and maybe change ideas based on feedback and new insights. So, this will always be a work in progress.

In this series…

Currently I posted 12 parts in this series:

Part 1: introduction, layers, onion architecture
Part 2: separating the commands from the queries, not so strict CQS
Part 3: a simple scenario, visual studio solution and projects, the domain layer
Part 4: the application layer
Part 5: the infrastructure layer (data access)
Part 6: the service layer
Part 7: the infrastructure layer (tests)
Part 8: the query side
Part 9: throwing business faults
Part 10: validation
Part 11: logging
Part 12: conclusion, where is the source code?


According to me, the design of a system should be as simple as possible (but not too simple), yet adaptable and extendable when needed. It means: don’t create anything that you might need later, only what you really need now, but be sure everything is in place so that you can relatively easy create it later if you need it (scale out). In other words, don’t make everything hopelessly complex just because you can and it looks nice, but choose wisely because there’s a valid reason for it.

In order to build a scalable and flexible system, it’s a good idea to group components into logical layers, define the relation between them as well as their dependencies. In general, we can define five layers.

Presentation layer

The presentation layer consists of everything that is visible to the consumer of the system, in other words, everything that has a UI. This is a thin layer, so it delegates all work to the service layer, and is only dependent on that layer. Typically it uses service operations that have been designed in the most optimal way to be used by the UI.

Service layer

The service layer holds everything that is needed to expose functionality to other systems. Typically exists of service contracts that define the interface of the exposed service operations, data transfer objects that define the requests and responses for those operations and service adapters that glue the layer to the application layer. It takes care of serialization of data, defining communication protocols and other configuration needed for interaction with other systems. This layer has dependencies on the application and domain layers.

Application layer

The application layer is a thin layer responsible for application workflow. It orchestrates the work by using the domain layer and calls to external components, and defines transaction scopes in which they should be executed. This is also a good place to implement security and high-level logging. The logic in this layer can be exposed by the service layer in an asynchronous or synchronous way, or can be logic that is triggered by events. It has only a dependency on the domain layer.

Domain layer

This is the business heart that models the system and where the domain logic is implemented. Typically it contains domain entities, domain services and repository interfaces, all used by the application layer to execute domain logic. It has no dependencies to other layers.

Infrastructure layer

This layer contains everything that is related to infrastructure, so this is the layer that is the most coupled to technological decisions: data access logic needed to talk to databases (concrete implementations of the repository interfaces defined in the domain layer), external libraries and providers, logging frameworks, file system logic and so on. This is the outer layer which is dependent on all the other layers.

Onion architecture

To define relations between the layers, you probably know the traditional layered architecture that exists of UI on top, then business and then infrastructure layer, and where each layer talks to the layer directly under it. However, the problem is that in this representation the business layer is coupled to infrastructural concerns.

So instead of the traditional layered approach, I’m a big fan of the onion architecture to define dependencies between the layers of the system and to determine the coupling between them. Representing layers as an onion means that every layer can only depend on layers more central: coupling is done towards the center:


This architecture is an exact match to visualize the dependencies of the various layers that we defined; and goes hand in hand with inversion of control principle: implementation details are injected by the outer layers at runtime; the inner layers just define and use interfaces. As an example, the domain layer defines the repository interfaces it needs in order to be able to perform the work; but the concrete implementation is coded and injected by the infrastructure layer.

Next time I will continue on this, and talk a little about one of the key principles: separating queries and commands.


7 thoughts on “A reference architecture (part 1)

  1. Norbicikli says:

    It’s a very useful, very detailed and well organized article. It’s uncommon to read quality discussions like this.
    I’ll try to implement a pilot project using this architecture.

    Would it be possible to share the source code?

  2. Hi Ludwig,

    Would it be reasonable for the UI to bypass the service layer and communicate directly with the app layer in your implementation? This seems to be the implied by Martin’s Clean Architecture and more directly prescribed by Palermo’s Onion Architecture. But of course your architecture here may depend on this type of communication even from a directly linked UI; or maybe I’m just not interpreting some of these things correctly. Could you explain why you think it might be a better approach in whatever cases? What types of things might you do in the service layer that would justify putting it between the UI and App layer? So that I can consider it in my own work.


    • Ludwig Stuyck says:

      There is no ‘right’ approach; it depends on your specific requirements and what you find important. In some of my projects I use a service layer (web API or WCF for example) in front of the application layer because there are multiple clients consuming this service, and so the service is an abstraction to remove the dependencies. If you don’t have this need, you could bypass the service layer; or, what I would do, just keep the service layer and use it from your UI (for example your controllers in an ASP.NET MVC app) directly (like a class library) without using WCF/Web API. This way you keep it simple at this time, but you are still flexible enough to change it with reasonable effort later if needed. In this service layer I typically implement security by injecting an authorization service that checks if a command can be executed by the user that is currently logged in or limits the result of a query so that only data is returned for which the user has required permissions.

      • That’s exactly the kind of response I needed to connect everything. You approach makes a ton of sense.

        Thanks for explaining and for the great information all around!

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s