Ayende @ Rahien

Refunds available at head office

Default Architecture: Layers

imageThe question came up in the ALT.Net group, and it seems like a good idea to post my thought about it.

You can see my overall default design for most just about any system. No, this isn't the end all be all design dogma, it is just something that has served me well in a wide number of applications.

This architecture has only one thing at its code, it is focused on clearly defining responsibilities between different parts of the application.

On the face of it, this looks like the traditional Model View Controller approach, but while there is some relation (specifically, the idea of controllers is shared), there aren't a lot of similarities between how I applied this in many cases.

Let us get to the specific, and see what we have.

External Interface

The external interface is the entry point to the system. It can be the UI, a service call, a message handler, a scheduled task or anything that is executing as a result of external input. The external interface is where you establish your current context. In general, it is strongly recommended to put as much as possible into the external interface context rather than the global context. This allows you more control overall.

Note that we explicitly recognize that we may have more than a single external interface into our application. Each of those external interfaces can be simple (Service Call) or complex (non trivial User Interface), but what is important is that it is mainly dealing with the issues of the external interface, not with the actual application. That is the responsibility of the controllers.

Controllers

The controllers (which is a generic term, in the past I have used commands, handlers and tasks to name the part of the application that perform this duty) are responsible of taking a particular use case and making it happen. This is the place where you start the unit of work and the transaction, this is the scope of what you are doing.

However, the controller is only dealing with the Core API to invoke domain behaviors. It is responsible for aggregating those behavior into the particular use case, but that about it. It is in the core that you actually perform the business behavior.

Core

The core is where your real business logic lives. This is where you define your domain model, define the operations and services that deal with it, etc. I'll not touch on how to structure the core here, there is enough material elsewhere for this. I'll say that the core exposes the complete set of operations that can be perform by the application.

In fact, one major rule to observe in this scenario is that the controllers layer should not add any higher level operations on top of what the core already has. Its responsibility is merely to coordinate.

Infrastructure

The infrastructure layer contains... well, the infrastructure. The OR/M, the container, the works. Note that unlike traditional layering, we don't have just the core touch the infrastructure, rather, we have the infrastructure used by all parts of the application. And no, the infrastructure is not merely a set of of utility methods and classes.

What do we gain by using this approach?

First, we have a clearer separation of concerns, which is always good. But more to the point, we avoid the case where the external interface is taking over the entire design of all the lower layers. I distinctly remember seeing 3 tiers applications where it was abundantly clear that the design process was primarily focused on the UI functionality. To the point where a functionality change in the application was much harder to deal with, because everything was so focused on the UI.

This approach allow us to offer a rich set of operation on the domain, allow us to contain the logic for use cases in a well defined locations and reuse them as needed, in matching use cases across different external interfaces. It also tend to make new development far easier in the long run.

A note about controllers, however. While they can and should be shared if you are using the same use case in several external interfaces, note that this should not bleed into the controller itself. If it does, it might be a good idea to create two controllers, and declare this as two separate use cases, because the requirements of the external interfaces are different enough even though the underlying business scenario is the same.

Comments

Tobin Harris
07/25/2008 10:57 AM by
Tobin Harris

Nice post.

Are your services like those described in DDD? i.e. - things that don't naturally fit into the repository or entities?

Ayende Rahien
07/25/2008 11:15 AM by
Ayende Rahien

For me, yes.

For other architectures, whatever it may be.

Colin Jack
07/25/2008 11:36 AM by
Colin Jack

Excellent post, interested to know how strict you are on the layering. For example does the UI ever talk directly to the model and the models services, or does it always go through the services at the external interface? I guess you are varying that application by application?

Ayende Rahien
07/25/2008 11:46 AM by
Ayende Rahien

There is variance per application, yes.

The UI would only talk to the model as a way to display them.

Setting properties would be the realm of the controller, in the specific use case.

The UI tend not to talk to the service layer at all.

Colin Jack
07/25/2008 11:54 AM by
Colin Jack

Ta for clarification, I've used a similiar style to what you are going for here but we were slightly looser about UI-model as we did allow some direct communication where what we were doing was simple (a single update to a single class in the model).

David
07/25/2008 03:23 PM by
David

I'm trying to understand the "external vs global context" you were talking about.

Let's say I have some business objects "in memory", that I display in the UI. Does the UI manage those objects, or are those objects in the Core, that that UI references? From what you were saying, I think I can infer that the UI/Whatever external interface manages the "state" of the application, not the Core. The Core is stateless.

Could you clarify?

Gonzalo
07/25/2008 07:04 PM by
Gonzalo

I would love to see a "naked" sample system with this architecture that you just described.

Nick
07/25/2008 07:55 PM by
Nick

"While they can and should be shared if you are using the same use case in several external interfaces, note that this should not bleed into the controller itself"

It sounds as though these are playing the role that Evans' application layer services are. Is this correct? If so, regarding a .NET project, given that you may have several different UI's, do you have your controllers in an separate assembly? I.e. one below the UI's which they can share?

jdn
07/25/2008 07:56 PM by
jdn

Last test comment.

Ayende Rahien
07/25/2008 08:25 PM by
Ayende Rahien

No, the application layer services are in the core.

The controllers are the bridge between the external interface and the core, for a specific use case.

For deployment scenario, probably, if I wanted to share them, but in general, sharing controllers is done when you have several endpoints that does much the same (imagine exposing the same behavior using different protocols)

Matt
07/26/2008 08:45 AM by
Matt

It would be nice to have a concrete example of this - I'm a bit confused as to the role of the "controller" here. Here's the breakdown of the layers in a system I'm working on - maybe you could map it to yours?

UI

Application Services (WCF)

Domain (Model / Services)

Infrastructure (shared across layers as well)

Here I'm using the term "application services" in the DDD sense as the externally facing layer that insulates the domain and is consumed by clients. (in my case multiple web UI's and other types of client applications who converse with the application services using DTOs) I might be using that term incorrectly, but that was my understanding based on the book. (obviously the choice to make that layer comprised of web services was my own as the system is distributed - I'm just using WCF for the sake of argument, insert your preferred technology here - nServiceBus, etc...) Within each application service I'm doing the same sorts of things as you describe within your controllers - transactions, etc...

Ayende Rahien
07/26/2008 08:52 AM by
Ayende Rahien

WCF is an external interface layer.

In my case, it would be:

UI / WCF

Application Services (POCO)

Matt
07/26/2008 03:52 PM by
Matt

Alright, so two questions:

1) Where would the controllers go and what would their function be?

2) Would your POCO application services map their input and output to DTOs? If not, what separates them from the domain services? Not to nitpick - might be missing something here...

Ayende Rahien
07/26/2008 04:05 PM by
Ayende Rahien

1) They serve the same purpose as controllers in MVC application.

2) They would not return DTO, because their function is not returning data, their function is to coordinate a use case.

c.sokun
07/28/2008 03:04 PM by
c.sokun

In this architecture how do you deal with data validation? which layer would responsible for this task?

Ayende Rahien
07/29/2008 01:30 PM by
Ayende Rahien

Sokun,

I would invoke validation in the controllers, but I would define it in the core

Devora
08/19/2008 06:31 PM by
Devora

Do you have a sample application using this architecture that you can share?

Ayende Rahien
08/19/2008 06:32 PM by
Ayende Rahien

I hope to be able to share one soon

Niraj
09/01/2008 01:10 PM by
Niraj

Thanks for the post.

Couple of questions:

1) How would you alter the architecture for a partial trust interface (like XBAP / Silverlight)

2) How do you see SOA fitting into your architecture (is it just an external interface?)

Ayende Rahien
09/01/2008 02:57 PM by
Ayende Rahien

1) I would not, really. This is for a web app, which is most of what I do, the client is already assumed to be untrusted.

2) Depending on how I think about this. External interface can be a client for a service or it can be a part of a service.

Comments have been closed on this topic.