I got the following question while I was giving the talk Mainline Development and Feature Toggles and how it helps teams to make progress in small steps even for complicated Architectural Changes or Database Changes.
We are making a significant change to our application, and we want to do that in small batches using Feature Toggles. We have a lot of utilities apart from the main application which also will be impacted by the change. These utilities are not maintained well, and we also need to add the check for the toggles which makes it more complicated. We don’t like these if..else in the code, what is the best way to handle such a situation?
It is difficult to give an answer which is “actionable” without getting enough context. And giving the standard consultant answer “it depends” is not very “useful”.
It always helps to go back to the basics in such situations. If the issue is having difficulty in understanding a specific area of the codebase, the feedback is that it requires refactoring, which can be as small as “renaming for better understanding” “refactoring for better design by introducing right abstractions or design patterns”. So my answer was:
If a change requires updates in multiple places in your application, the feedback it gives is that the code is not abstracted well. Ideally, these changes should be restricted to a few areas. So it seems you first need to refactor the existing codebase to make it easier for the change. I know the constraint will be time, but if you are not doing enough refactoring to support the future changes, it can introduce bugs, and you will find it hard to make progress.
Create an isolating layer to provide clients with functionality in terms of their own domain model. The layer talks to the other system through its existing interface, requiring little or no modification to the other system. Internally, the layer translates in both directions as necessary between the two models.
Eric Evans — Domain Driven Design.
In the book Domain Driven Design, Eric Evans refers Anti-Corruption layer — a layer to help you keep the sanity even if there is a change in the external systems it depends upon. For e.g, imagine that an application is relying on Google Calendar, for scheduling and reminder for events. To sync the data to and from Google Calendar, we will need to map the data between the two systems, i.e. our application and Google Calendar. This is because the data models and structure will be different in these systems.
We design a service to map the data between the two systems and also to communicate the same using APIs. And this service acts as a protection layer to manage the changes that occur with the external systems, in this case, the Google Calendar API.
Apart from making the code DRY, maintainable and readable, these abstraction layers also give the advantage of“Evolvability” — ability for the system to adapt. Imagine a situation we decide to move away from Google Calendar and use another service. This layer helps us to make the change using the Branch by abstraction technique.
The book Building Evolutionary Architecture talks about how Anti-corruption layer helps for Evolvability. The book refers to how a team moved from BackgroundDRb to another scheduler by using Anti-Corruption Layer and Branch by Abstraction.