SymmetricLayers

Context
In a traditional layered architecture, each layer has an interface that describes the operations that are performed by that layer. Each layer explicitly references the layer(s) “Below” it. Therefore it is difficult to make layers talk to a layer other than the one that it was originally intended to talk to. Yet, many circumstances exist where we would like to have layers be more orthogonal to one another. Consider a common smart client system with four Asymmetric Layers: UI->Network->Domain->DataAccess. Here are several problems you would have a hard time solving using asymmetric layers.
- You might want to put the object-relational mapping task off to the end, by building an in memory stand-in for your database during testing. Along the same lines you might want your application to support multiple database vendors.
- Under special circumstances (such as for administrative purposes) you might want to let your UI talk directly to DataAccess layer, without going through the intermediate network layer. With asymmetric layers, you cannot do this because your ui code deals with the network system explicitly.
- You want to support bidirectional communication by letting the DataAccess layer call on the Domain or Network layer, to notify clients of an event.
- You want to express the business requirements of your application in code using a a single set of test cases that can be run against multiple layers. With asymmetric layers, you will create different tests for each layer, and different parts of the requirements will be captured by each test. Some requirements will be duplicated, and others will be scattered across several tests for different layers. When the requirements change, maintaining the test code will be a major task.
- You want a straightforward way of supporting new types of clients. For example, your users might ask to send or receive data by sms message, email, or the latest new wireless device. Or you might want to expose your application as a service to another application.
Problem
How can layers be as loosely coupled as possible, so that any layer could communicate with any other layer?
Solution
Make all layers implement the same interface, so that it never matters which layer is sending a request, and which one is receiving it. Have layers communicate by sending domain level command objects between layers.
Unified Test Cases
If all layers implement the same interface, it is possible to create a single set of test cases that will run against each layer. The differerences between your tests will not be in the test code itself; it will be in the configuration of layers that implement the tests. Here are a set of tests you might run for a distrubuted system.
- Memory Database - Create an in-memory simulation of your database so that you can get the tests and the command classes right before implementing a relational database. This gives you a good proving ground for your IndependentDomainModel, and your test cases.
- Memory Database with Network - Call on your in memory database using the the network interface that your real system will use. Ex. Web services, remoting, etc…
- Real Database - Run the same tests against your real database.
- Real Database with Network - just like Memory Database with Network, but with the real database.
- User Interface - if your system is bidirectional, ie, the user interface handles incoming commands, you can test the ui just like the memory database.
If you have the memory database working well, you should be able to run the entire system, ui, and all, without a working relational database. In the real world, this capability can be a huge time saver because developers will not be held up behind database changes. Also, because database changes are often more expensive than code changes, it makes sense to put them off to the end so they can be done only once.
Bidirectional Communication
In a system with SymmetricLayers, every Layer can issue commands and handle them. Therefore, commands do not have to start at the ui and end up at the database; they can do just the opposite, starting at the database, and ending up at the ui. Suppose you want to notify users when someone else comes online. When someone comes online, they might send a Logon command from the user interface, which will end up in the data access layer. With AssymetricLayers, you would have to wait until the other user does some kind of refresh before they could see that someone came online. However, with SymmetricLayers, the data access layer can reissue the command, notifying connected clients immediately. If you want to do bidirectional communication, SymmetricLayers are essential.
Swapping Layers
Because SymmetricLayers are loosely coupled, it is possible to swap out layers without impacting other layers. A good example of this is working with an in-memory database, rather than a persistent one. However, other examples abound. Microsoft is beginning to push something called a “Channel Adapter” which would let you use .net remoting inside the firewall and web services outside. This can be acheived today using SymmetricLayers. Another example is incrementally adding layers to the system. For example, your customer might want to start by building a simple client-server system, but might also want the flexibility to add a web services or remoting interface later on. You can build the client-server system today using SymmetricLayers, and hosting the UI and DataAccess layer in the client process. If business needs warrant it, you can later add the intermediate tier without having to drastically change existing functionality or incurring an unneccesary upfront cost.
Example Code
Coming Soon…