In a previous post we met object orientation’s worst enemy (i.e. strong, unplanned dependencies among classes). It is now time to have a closer look at Dependency Inversion, which is one of the most efficient OOP techniques available with which to fight our adversary.Our aim with this discussion is to avoid having the already discussed Domino Effect, Butterfly Effect, and Banana-Gorilla Effect. Please refer to the initial article if you are unfamiliar with these concepts. The following concrete example makes use of UML, and addresses a real-case scenario within the e-commerce domain.
Obviously, the schema presented here is just part of a complete software architecture – for the purposes of this discussion we assume that all orders issued are stored in a relational database instance (MySQL more specifically). The natural way of thinking leads the architect to model a dependency from Order to MySQL, mainly because the former class is the one responsible for deciding when database transactions begin. However, the resulting dependency leads to at least three undesirable consequences, as follows:
- Business objects and rules start depending on purely technical matters such as database manipulation. We all know that what is cutting-edge technology at the moment, is likely to become obsolete in a few month’s time. Business concepts, on the other hand, tend towards stability – an order will always be an order, potentially keeping the same attributes in the long-run. It’s important to notice that the undesirable direction of the dependency may force the developers to change business objects whenever the database technology they are using changes.
- The architecture assumes that storage will always be handled by a specific relational database. This is a risky assumption, since the development team may decide to swap out the database provider. Moreover, alternative storage mechanisms like the file system itself may come up as a viable option in the future.
- Unit testing becomes painful. This sort of dependency makes it difficult to use the mock objects technique, which is quite common within unit testing methods.
We can address these issues by placing an interface between the classes, and therefore inverting the related dependency. As demonstrated below, we have just succeeded in decoupling storage manipulation from business objects.
The dependency inversion technique has addressed all the problems we identified. People usually think of an interface as just a simple set of common functions, but it’s not. Instead, a strategically applied interface contributes desirable outcomes such as mobility, flexibility, reusability, and maintainability.
OK, but wait a minute, the business object Order still needs to send messages to the data access layer, doesn’t it? Yes, it does, but interfaces do not exist at runtime, only objects do. Therefore, IStorage is replaced by an object defined by a class that realizes this interface, the MySQL class in our example. It’s now clear that we could also have realizations to other database providers and storage mechanisms (Oracle, MSSQL, PostgreSQL, and File System).
Visualizing the dependency inversion is even easier when we deal with components, instead of classes. The first component diagram below does not take advantage of the technique we just learned.
Unlikely the previous diagram, the following schema turns over the dependency between the components, making the business component independent, and enabling new data providers.
The black-box notation makes things even clearer:
Again, the dependency inversion:
Techniques such as the one presented by this post prevent the Active Record pattern from being a complete failure. Now I bet you realize how powerful dependency inversion is, right? So back to your dashboard and take your interfaces to the next level!
Related posts:







