We 'like' to put blame on factors that (in our opinion) lie beyond our control - stone-carved deadlines, outdated legacy, unimaginative Product Owners who always dump tech debt-related work items into abyss of Nice-To-Have. Some call it 'victimship' & it's all about giving up at the slightest indication on resistance due to bias we've developed in our past (by ourselves or just learned from others).
We learn to live with issues & impediments instead of getting rid of them ("that's the way it works here ..."). What I find truly ironic is the fact that many of these problems have simple & straightforward (it doesn't mean easy or painless though!) remedies - one of them is the tool I'm bringing up today:
Strangler Pattern
What's "Strangler Pattern"? You may have read about it on Martin Fowler's Bliki or in Michael Feathers'es "Working Effectively with Legacy Code", but if you didn't - here's my concise rewording:
Strangler Pattern - getting rid of unwanted piece of software by:
- putting it behind newly defined contract (compatible with current implementation)
- removing direct references (replacing them with contract references)
- substituting legacy contract implementation (gradually: service by service, etc.) with new one
- decommissioning unwanted software once it has been replaced & is not needed anymore
Sounds ... familiar, right? Using common software engineers' lingo it's about:
- identifying proper bounded contexts (so the re-implementation is properly structured)
- building an interface (contract) that will work as something between traditional "facade" & "mediator" - the goal is to make it usable in future (with the replaced implementation), so keeping 1:1 adequacy is not a must
- treating this interface (& necessary "gluing layer" beneath, if it had to be introduced) as an anti-corruption layer, to prevent unwanted legacy abstracts from leaking up
It looks simple, but in many cases it translates into shitloads of unpleasant & tedious work to be done. Needless to say, to make it work you really have to put some effort into designing a future-proof interface - only then you will be able to build new implementation w/o old implementation's flaws & treat implementation (in general) as a "blackbox". But the benefits can be very tangible:
- you can reorganize old code into new context boundaries that way
- it enables transparent move from one (unwanted) technology to another (preferred) - smart transition like that can leave a lot of technical debt behind
- your data schemas are no longer a limitation: you can remodel them, their dependencies & relations - all according to the model you prefer
- and at last but not least, you don't have go for "big bang" approach - iterative, step-by-step replacement is the way to go
So if Strangler looks almost like a Silver Bullet for dealing with legacy, why don't people utilize it that much? Reasons may vary, the ones I've encountered are quite simple:
-
Even if Strangler doesn't really demand refactoring legacy internals, it still requires understanding the model legacy follows (to build a proper contract) - many people are allergic to legacy & even that may be too much to them. Not to mention the fact that working out the new contract (compatible with both legacy stuff & the future vision of system) may be a big challenge & responsibility.
-
Introducing new contract means a lot of point changes in all places where legacy is references directly - these are usually very simple, but many legacy systems I've encountered had very flawed build & deployment routines - not very repeatable, not very reliable - one really wanted to minimize the changes & do only what's truly necessary to have this shit runnin'
-
Replacing references may be challenging, assuming ... that you were able to identify all of them first. Sometimes integrations are that messy & out of any control, that you can't even be sure that you know all the ways other systems / applications were interfacing with the legacy you want to get rid of ...
-
Strangling works only if you cut off the oxygen completely -> the message should be very clear: starting with today, all the interactions happen via interface; starting with today, we're not developing any changes in legacy, but only in the new implementations.
No-one said it's gonna be perfect or the easiest thing ever - and frankly, it isn't. But it's either that or falling into victimship, passivity & silent acquiescence to helplessness.
Header pic: © Aleksey Stemmer - Fotolia.com
Facade pic: © http://www.zachariegaudrillot-roy.com/