Writing stable and maintainable software is hard and requires experience. This article will describe how to use dependency inversion and fakes to improve maintainability and efficiency.
Fake It Till You Create It
For the past few years, I have been developing backend services for various applications. Over the years some practices have evolved that help me write stable and maintainable software.
One of the most common practices I use is to create a fake implementation of the persistence layer. Most of the time, the fake is a simple in memory database built with a dictionary (or a similar data structure). This kind of fake is obviously not suitable for production, but it is really handy in development and testing since the persistence layer will be reset for each execution. The fake makes me more efficient since it allows me to focus on implementing and testing all parts of the application without having to deal with the overhead of actual persistence. Only when I have a working application, will I focus on implementing a persistence layer suitable for production.
How it works
To allow for seamless substitution of the persistence layer, I use the Dependency Inversion Principle (DIP). The application is dependent on a persistence layer, however, DIP makes the application dependent on an interface and not an actual implementation. Therefore the concrete implementation of the persistence layer can be substituted as long as the other implementation also adopts to the interface.
To demonstrate how it all works I have created a simple example that can be seen in figure 1.
First we define a class, Service, that handles business logic. This class requires some sort of persistence, therefore an interface called Repository is defined which holds all the required method for persistence. Service will hold a reference to an object that implements the Repository interface. This reference will be given to Service at initialisation by dependency injection.
The object given to Service can easily be substituted for another object that implements the Repository interface.
In figure 1, everything outside the grey box is defined in the same module, making this module the owner of the Repository interface. The classes inside the grey box can be part of the same module or live in separate modules, the only thing they have in common is that they implement the Repository interface, providing persistence to the Service class. Note that the arrow crossing the grey box points outward indicating that the grey box can be plugged in and that Service and Repository knows nothing about the existence of the grey box.