Replacing legacy code
In this article i will try to guide you through the process we're following for modifying or replacing a legacy codebase. Please note, that's a guide only and not as a solution for all circumstances.
Isolate the work
When starting a refactor it's a good to ensure the work is done in a separate branch. We only commit changes related to the refactoring and don’t mix in any other changes, otherwise we risk breaking or conflicting with changes made by other teammates when our branch is merged.
Provide good test coverage
Refactoring is when you’ve made modifications to your code without changing its external behavior, and the only way to be sure you haven’t changed its external behavior is using tests. In other words before making any changes, we create or add additional tests that verify the existing behaviour.
Deprecate, the existing legacy code
We will start by deprecating the existing implementation. In Swift we can make use of @available attributes to indicate that the legacy type or methods should not be used. Eg:
extension CustomClass {
// ...
@available(*, deprecated, renamed: "newMethod()")
public func oldMethod() -> Void {
}
// ...
}
When replacing a legacy Objective-C implementation we use the DEPRECATED_ATTRIBUTE and DEPRECATED_MSG_ATTRIBUTE macros defined in AvailabilityMacros.h.
Refactor by abstracting
After deprecating the existing code we will introduce an abstraction such as a protocol factory or strategy around the legacy code so that it can be dropped in later without changing so many classes.
The advantage of abstracting our logic is it helps us keep the existing legacy code as we incrementally create a new implementation and avoid situations where the application is broken or does not compile.
Once the new implementation is complete tested and proven to work as expected we can make the new implementation the default.
Communicate with the team
As the new code comes into the project’s main branch, we will let other team members know about it so they can start using it. As our ultimate objective is to completely remove the legacy code from the codebase. We can only do that if everyone stops using it and knows how to use the new implementation correctly.