Multidimensional Separation of Concerns
Separation of concerns is a popular idea in software. Divide your design up into separate pieces that “know” as little as possible about each other, so you can think about them independently.
The most popular example given in discussions of this topic is a layered or “tiered” architecture:
If you ask someone how their design works, or more specifically what problem it is intended to solve, and they show you a picture like that, they’re showing you diddly-squat. There might just as well be boxes labelled Source Code, Compiler and so on. These are things that all applications have. It doesn’t tell you anything about their particular problem domain. A more honest, less pretentious diagram would have boxes like this:
These are the actual concerns of a real application – the very things its users talk and think about. The problem is, the users will likely change their minds about stuff like this. This is the foam and froth – I don’t mean to imply that users foam froth at the mouth when they talk; I just mean the nautical metaphor about rough seas. Several weeks into the project, someone will realise that we need to deal with FirstName as well as LastName, and so suddenly your diagram would be out of date. So people tend to draw diagrams of things that don’t change. Unfortunately that pretty much excludes everything specific and interesting about their own project.
They then structure their application according to the diagram. The diagram says that there are separate tiers for presentation, business logic and data access, and so that is what we end up with. The closest thing we can get to a complete diagram would be:
As a real world example, this could mean a presentation tier written in HTML and little bits of jQuery, and a business logic tier written in Java, C#, Ruby or what-have-you, and finally a data access tier consisting of an RDMBS wrapped in a suitable ORM, or something more fashionable like CouchDB.
The vertically stacked tiers look like well-separated cohesive units, which is nice I guess. But it’s not actually that beneficial, because they’re such well understood static concepts that we are unlikely to be that confused by them anyway, and nor are we likely to rip any of them out and totally replace them.
The real pain is what has happened to our specific domain concepts. They’re each fragmented into separate pieces for each tier. They exist only as analogous patterns that crop up encoded in different ways depending on the tier. For example:
<label>First Name <input type="text" name="FirstName"></input></label> <label>Last Name <input type="text" name="LastName"></input></label>
That’s the presentation tier’s way of encoding domain knowledge. One aspect of the existence of a FirstName concern is that it crops up as a certain pattern with the HTML. But there will be similar manifestations within the business logic layer, encoded in a different language, and then in the data access layer, and so on. There isn’t a single statement anywhere that a FirstName is something we deal with; rather, each tier is structured in a way that (hopefully) matches up with the other tiers, and so they all contribute a different aspect to what FirstName consists of.
So on the day when someone realises we need to concern ourselves with a MiddleInitial as well, we have to visit each tier in turn and make a different kind of update to each one. And if we decide to remove an existing concern from the design, we also have to visit each tier and delete something (or possibly do something more complex).
This situation is sometimes called “cross-cutting concerns”. It’s a pretty poor state of affairs if all of your most specific and relevant concerns are forced to be cross-cutting in nature.
The things that are most likely to require changes have been rendered unnecessarily hard to change.
It would be much more convenient if the existence of LastName was stated in one place. And then from that statement the system would automatically generate the necessary incantations in the various tiers. All it needs to know is what type of information LastName is. The type would encapsulate such things as how to represent the information in the user interface as an interactive value, using HTML, scripting, controls and so on, and also it would encapsulate some common operations required by the business logic such as retrieving or applying a value using a common persistent format, and of course the type would also define a way to map itself into the data tier (for example, the RDBMS data type to use).
The same type definition would then be applicable for both FirstName and LastName. Similarly for dates – what is true for one date field is likely to be true for another.
Here’s another diagram:
By inventing a system of types, in which each type encapsulates how a piece of information should be presented and stored, we can then describe the rest of our system purely in terms of fields, each of a specific type, along with appropriate business logic to operate on the information. We can then forget about the fine details of presentation and data access. Those aspects are driven entirely by the types.
We’ve now succeeded in achieving a separation of concerns between the tiers, just as originally intended. We can think about the domain concerns and their business logic without having to worry about the details of presentation and data access. That’s the whole point of a tiered design.
But you can only get to that point by considering the two dimensions involved: the technical concerns and the domain concerns. It is essential to prioritise making the domain concerns into independent, solid, several (in the old-fashioned sense) chunks. You need to be able to add, remove, rearrange and separately modify them safely and rapidly, because it is the domain concerns that carry the unique value of your project, and which will need to change continuously to respond to the needs of your users.