Stay releasable by taking small steps instead of giant leaps
Sometimes in software development, we must make substantial changes that take weeks, months or perhaps even longer to implement. Think of changing a backend service or replacing your database or a third-party framework for a different one or splitting your service layer in multiple services.
A naïve approach is to just start making the momentous change in your application and not release your updated version until you are finished implementing it. The downside of this approach is that if you’re not finished with your change, you’re blocking other functionality from being released. In other words, your change is hijacking the release of your application!
One way to deal with this, is by implementing the change in a different branch in your version control system. This allows you to make the change while still being able to work on other functionality while keeping your software in a releasable state. Once you’re done with your big change, you merge your branch to integrate your big change with the other changes.
This seems like a good approach, especially since modern Version Control Systems like Git are very good at dealing with branches. But working with long-lived branches and delaying integration can cause integration problems to pop up (too) late in the process and cause quality issues. This also violates one of the principles of Continuous Integration (CI) since we want integration errors to pop up as soon as possible. Then it is still cheap to fix.
The thing we want to get rid of, is having outdated version of the application completely without the change and having another version of the application with the complete change in it. There are also ways to gradually implement a big change while still being able to release. When doing Continuous Delivery (CD), these ways are required to continuously be ready for release.
If we are working on new functionality that must be disabled because it is still unfinished or we don’t want it enabled yet from a business point of view, we can use Feature Toggles, a.k.a. Feature Flags. Feature Toggles allow you to deploy disabled functionality to production without making it visible or accessible. In other words, we separate the release of a feature (making it public) and the deployment of a feature (bringing it to production).
In a situation where we want to make a change in an already existing part of your application, we can use Branch by Abstraction as a pattern to gradually introduce a momentous change while keeping the application in a releasable state. You can use this when you’re for example changing your data access layer to use a different database. First, you create an abstraction around your current implementation and use the abstraction instead of directly calling the implementation. Then you start creating the replacement and let the abstraction route calls to your replacement for the parts that are finished, and route all other calls to your old implementation. The abstraction is an implementation of the Façade design pattern. Once the replacement is completely done, you can get rid of the old implementation and optionally remove the abstraction.
Branch by Abstraction is used on application level. But you can use the same principle in getting rid of legacy systems and gradually replacing them with a new implementation. In this case, the abstraction is called a Strangler application, named after Strangler Vines growing over a host tree till the host tree dies. This allows you to completely replace applications or services while avoiding a big bang approach.
What we want is to always be able to release our software and not being hijacked by big changes. A good way to do this, is by avoiding Big Bang methods where we introduce a big change all at once. Instead, we want to gradually introduce a change while still being able to release. Patterns like Feature Toggles, Branch by Abstraction and on higher level Strangler Application can help you achieve this. So, stop taking giant leaps and start taking small steps!
This blog was written by Harm Pauw.