I have recently been looking how to create a clean Domain Driven Design architecture using SQLAlchemy and specifically how to map domain classes to tables. This post will discuss the two techniques available and why to choose one over the other.
Lets start with looking at the two strategies available. SQLAlchemy offers a Data Mapper out of the box. It is also possible to use an Active Record approach by using the Declarative Base ORM extension.
The Active Record approach is a very attractive way of working. It adds metadata to the domain objects that tells the engine how to save them to the database. It's quick and easy to use and avoids extra classes or configurations that handles the database mapping. It's a perfect fit for most web applications. The main drawback is that storage logic is tightly coupled with the domain objects. This can make the domain difficult to work with over time. It also means that any changes required in storage logic will force changes into the domain breaking the Single Responsibility Principle. Active Record will also prove very costly if the project finds that a change of storage technology would be beneficial. A not to unlikely event with such a variation in industry strength storage technologies available.
Data Mappers provides high decoupling by keeping all meta data for mapping objects to tables separate from the domain. The mapping can be placed in its own module which makes it easy to divide the domain into coherent modules with no need to cater for storage concerns. It also makes it easy to model more advanced relational concepts in a large database. Since it allows for complete separation of concerns for domain and data access it is also easy to change or swap out the data storage technology completely without any needs to change the domain. It does however increase the complexity of the application since it adds an extra module/package.
If the project in question is going to use a clean implementation of Domain Driven Design only the Data Mapper works. It is also the only possible choice if it is likely that the project will be changing storage technology.
If, however, the project is a traditional web application with a domain model that is simple or close to non-existing then Active Record is a good choice. It will provide more speed of development. Making a clear distinction between domain logic tests and data access tests will make it easier to later extract data access out into Data Mappers if needed.
The façade pattern is one of my most used patterns. It works as the glue both within an application and as a boundary to dependencies.
It mainly comes in handy when solving the following problems:
- Fluid design and readable APIs
- Protection against external forces and changes
Ever so often test driving development becomes extremely expensive because the interfaces the code depends on is impossible to test against. This may just as well be internal legacy libraries as external libraries. To remedy the problem I use a façade interface that provides the operations I need. I then mock the expected behaviour of the operations when writing code required. With some careful planing the binding of the library implementation to my façade can then be done without to much hassle.
Fluid design and readable APIs
Each component within an application strives to resolve it's own domain. This often results in the boundaries becoming a bit awkward. To help creating fluidity in design and APIs it is therefore often useful to create façades matching each domains language and a thin layer of bindings that glues the libraries together.
Protection against external forces and changes
When using external libraries, apart from the above issues with testability and fluidity, façades also help reduce the cost of upgrading the dependencies. Whenever an external library changes the only code in the application that will need to change is the binding to the façade.
The overhead for getting the above benefits is actually remarkably low. It is usually enough to create an interface that delegates it's operations to the library it is a façade for. The binding can the be done using dependency injection or factories.
Even when it's more difficult it's usually only a matter of composition. I have some times had to compose the the logic of the integration on a couple of abstraction levels but then it has still been well worth it since it has simplified the usage of the API considerably.
It is a shame that I don't get to see this pattern used more often. It would have reduced cost and complexity on many occasions.
A recent discussion thread on the Design Patterns LinkedIn group got me thinking that a blog on how to create a factory for strategies in Java would be useful. The method below removes the need for if or switch statements.
I will start with the code and then go on to look at the details.
The Strategy interface:
The Factory class:
A strategy implementation:
Another strategy implementation:
The example code is fairly simple. The complexity lies in how to create the factory and what responsibility it should have compared to the strategies. According to the single responsibility principle a class should only have one responsibility. Therefore the strategy should not do anything else then execute. The factories responsibility is to provide strategies to the client. Therefore it's singleton instance does just that.
The client only need to know the key of the strategy it needs. This can be derived by class name, key word or something else and is stored as the key in the map that finds the correct strategy instance. To make the client logic simpler I have used Enum types to maintain keys in the past. The enum will then be able to create a valid key based on whatever is logical for the specific client.
Also note the access modifiers used for constructors. All creation logic is isolated to the package. This makes it easy to maintain since we know that nothing outside of the package can create new instances and instead has to use the factory to get an instance of the strategy.
The same recipe works well for creating other similar factories as well, for example Command factories.