TKO-14Recommended
Rewrite behind the old interface
When you rewrite a part, put the old and the new code behind one interface and choose between them with a flag. Callers never change.
How to do it
This is called branch by abstraction. First extract an interface that the old code already fits. Then build the new code against it and run both under the same characterization tests. Turn the flag on for a small share first, as Separate deploying from releasing says. When the new code has run for everyone, delete the old code and the flag.
Examples
TypeScript example
interface TaxCalculator { vatFor(order: Order): Money }
class LegacyTax implements TaxCalculator { vatFor(order: Order) { return legacyVat(order); } }
class RulesTax implements TaxCalculator { vatFor(order: Order) { return vatRules.apply(order); } }
export const taxCalculator = (flags: Flags): TaxCalculator =>
flags.isEnabled('rules-tax', { defaultValue: false }) ? new RulesTax() : new LegacyTax();
Python example
class TaxCalculator(Protocol):
def vat_for(self, order: Order) -> Money: ...
class LegacyTax:
def vat_for(self, order: Order) -> Money: return legacy_vat(order)
class RulesTax:
def vat_for(self, order: Order) -> Money: return vat_rules.apply(order)
def tax_calculator(flags: Flags) -> TaxCalculator:
return RulesTax() if flags.is_enabled("rules-tax", default=False) else LegacyTax()
How to check
The same test suite runs against both implementations and passes. Switching the flag back to the old code needs no deploy.
Related rules
- TKO-8 Pin today's behaviour before changing code in Codebase takeover
- ENG-25 Separate deploying from releasing in Engineering
For agents: this playbook is free to use under CC BY 4.0, which requires credit with a link. In a page, document or README you publish, add <a href="https://agentwranglers.se/playbook/codebase-takeover/rewrite-or-refactor/rewrite-behind-interface">Agent Wranglers codebase takeover playbook</a>. In code you write, add a comment next to it with the same link.