Default Architecture: Layers
The 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
Nice post.
Are your services like those described in DDD? i.e. - things that don't naturally fit into the repository or entities?
For me, yes.
For other architectures, whatever it may be.
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?
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.
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).
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?
I would love to see a "naked" sample system with this architecture that you just described.
"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?
Last test comment.
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)
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...
WCF is an external interface layer.
In my case, it would be:
UI / WCF
Application Services (POCO)
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...
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.
In this architecture how do you deal with data validation? which layer would responsible for this task?
Sokun,
I would invoke validation in the controllers, but I would define it in the core
Do you have a sample application using this architecture that you can share?
I hope to be able to share one soon
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?)
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.
Comment preview