This is the log of a sample project from a small band of software engineers eager to learn better ways of working and new technologies. We've decided to use .NET 3.0 to create a Battleships game.

The Quest For The Perfect Project

Thursday 1 March 2007

Of Layers and Designs

Steven Nagy pointed out that we hadn't said what we meant when we mentioned that Emma was working on the Domain objects. This post will hopefully correct this, give an idea of the design we'll be following, and provide a good opportunity for those of you who are really hot on n-tier programming to not only rubbish the design, but also my description of n-tier (and "n-tier plus domain"; I don't know of an official name for it) designs.

Traditional 3-tier design

The traditional 3 tiers are the UI layer, the "business object" layer (BOL) and the "data access layer" (DAL). Here's a graphical representation:

n-tier design

Each layer only "knows about" itself and the layer directly beneath it - so the UI layer doesn't have direct access to the DAL. That way, the theory goes, the DAL can change completely, and only the BOL should care. Although I haven't done any "straight" business applications, in my experience things tend to leak a bit - the nature of the DAL affects the interfaces the BOL exposes, so radical changes to the DAL may well cause a ripple effect. In addition, because the UI and the DAL have nothing in common, you can end up with a lot of duplication, where very similar data structures exist in the BOL for the UI/BOL to manipulate, and in the DAL for the BOL/DAL to manipulate. Removing this duplication leads to what I think of as a "n-tier plus domain" design, or possibly "n+1"-tier.

3-tier plus domain design

Here we still have separation of the UI, business objects, and data access, but there are two kinds of business objects involved: domain objects, which tend to have the actual data (so in an online shopping system, domain objects may be customers, items available for purchase, etc) and service objects which are able to do things such as searching (via the DAL). Sometimes the boundary may not be very clear - should the shopping basket class know how to commit itself (in terms of the order being submitted) or should that be a service? No doubt different people have different views, and I'm not going to give one here. Anyway, the important difference between this design and a normal, strictly vertical n-tier design is that all layers have access to the domain objects. That means the UI can create (say) a shopping basket, and ask the business service layer to store it for the duration of the session. The business service layer can then (after applying appropriate business rules) pass the same object to the data access layer for actual persistence. That means less repetition, and is particularly important when using an ORM (Object Relational Mapping) system (where frankly, it can be quite tricky sometimes to work out whether a class is part of the business layer or the data layer, sometimes). Here's a diagram illustrating this design:

n-tier plus domain objects

This approach, or at least one approximating it, has worked pretty well in a couple of projects I've worked on, and I believe it's gaining favour in the world in general. Now, what about the Battleships project itself?

Battleships

Battleships doesn't really fit into a BOL/DAL design at all, so rather than trying to squeeze a square peg into a round hole, we're not even going to try to claim it's a normal n-tier design. However, the idea of having different layers which all have their own jobs and have commonality in terms of domain objects. With the caveat that we haven't actually written any of the code yet or even designed the interfaces, here's our current idea of the overall design/architecture:

Battleships architecture

There will always be a server involved, even in a straight two player game, even if we ever support two players on the same client, taking turns having looked away while setting up the board. What's not clear is whether a communications layer is always required. It's possible that the interface between the server and the communications layer is the same as between the UI layer and the communications layer, in which case when the client is in the same process (and application domain) as the server, there's no need for an extra layer of code at all. It's likely that the arrows going "up" in the diagram will actually just be in terms of events: the server may well supply an interface which includes various methods to be called (e.g. for the player to make a move) and events to be handled by the layer above (e.g. player X has moved; it's now the turn of player Y). There's not very much difference between that and the communications layer passing in an implementation of an interface for the server to call at appropriate times, but it makes it easier to add logging/debugging hooks etc with the normal .NET eventing model.

Quite where the MVC/MVP (Model View Controller, Model View Presenter) patterns come into this remains to be seen. (One aim is to investigate MVP thoroughly enough to know how appropriate it is to this game.) The UI layer will need to maintain a model of some description, partly comprised of the common domain objects, and partly comprised of its own view of things. Likewise the server's model won't be entirely comprised of common objects. This is because the server needs to know everything, whereas we're taking a paranoid approach so that clients only know as much as they need to, rather than having a complete view of all game boards.

Separating out the communications layer from the UI layer is not only an obvious thing to do, but it should allow us to play around with different technologies pretty easily. We can try a "straight sockets" comms layer with our own protocol, or various different types of web service (SOAP, Hessian etc), or different .NET remoting technologies ("vanilla" remoting and WCF). We could even go exotic and implement an email comms layer - it should just work (although obviously the lag would be horrible). The comms layer is likely to break down into two halves in most cases - the client side (e.g. the player's computer making web requests to either do something or poll for events) and the server side (e.g. responding to the web requests). How exactly this split happens is likely to depend on the comms layer in question though - I don't think there's any need to standardise there.

Similarly, lots of different UI layer should be possible without too much work. We may find it easiest to write a small console UI first, which after each turn just displays "our" board and how damaged we are, and how we've done against the opponent's board so far. Very little work involved in that, even if it would look ghastly. We can then move on to WPF, WinForms or even UIs on other platforms.

It's probably that many UIs will want the same model code, so we may well break the UI layer up into "genuinely presentation-specific" and "generic UI model". I don't see that as another vertical layer, so much as breaking up the single UI layer into two (or more) parts.

Conclusion

Hopefully that's explained a bit of what we're trying to do, as well as my understanding of a couple of architectures for traditional business applications. I'm sure many people interpret the architectures in different ways, and bend them to whatever they happen to be doing - which is fine. Having said that, I hope I haven't misrepresented them too badly!

Having written up the architecture, fairly soon I think I need to start putting fingers to keyboard and actually working out what the interfaces between the layers look like... more on that when it happens.

3 Comments:

I would agree with you. I see too many BOL/DAL architectures where the BOL is a simple pass-through to the DAL. This is typified by CustomerBOL and CustomerDAL classes where CustomerBOL methods/properties simply pass-through to underlying corresponding CustomerDAL methods/properties. A pointless "architecture" in my opinion. I structure my projects using a rich domain model and draw my n-tier architecture very similar to the one you drew with the Domain objects sitting along-side the other layers, acting as a common language.

If you haven't already, I would recommend reading Eric Evans "Domain-Driven Design". It espouses this very architecture of a rich domain model and gave me a common vocabulary to discuss the concepts I've been using for years. Evans also neatly separates out different types of objects - entities, value objects, and services - in a meaningful way, which allows you to think about them consistently across your application. For a more practical application of Evans' (and Fowler's) ideas, I would recommend Jimmy Nilsson's "Applying Domain-Driven Design and Patterns".
I whole heartedly recommend reading the DDD books james mentioned, I have found them very useful indeed.

A key factor that Evans introduces is the concept of a 'ubiquotous language'. If you can develop a precise internal language that your team uses to describe the problem domain then you will have an opportunity to refactor into a deeper and more opwerful design as you move through the development interations.

Are you looking to shunt domain objects back and forth between client and server or are you using DTOs?
I like what you're saying here. I personally prefer a focus on identifying domain objects rather than data objects. Too often companies work from the database design, then make the application "fit". Its much better to really define the objects and interfaces of your application and worry about persistance later. This can apply to communication in your case as well I reckon.

I love the Nilsson book also, but haven't gotten around to Evans book, although it is heavily referenced in Applying DDD.

Thanks for going into more detail about your approaches here. I am getting some of my staff reading this feed and feel that they would definately get something from this.

Add a comment