You don’t need to finish a feature and your users don’t need to see it to be able to release and start battle-testing it. Slice it as much as possible and release the chunks ASAP to shorten the feedback loop and decrease risk.
My colleagues have been working on a crucial change in our webshop – replacing our legacy shopping cart and checkout process with a new one and implementing some new, highly desired functionality that this change enables. We have decided to decrease the risk of the change by doing it first only for product accessories. However the business wanted the new feature included and that required changes to the UI. But the UI has to be consistent across all sections so we would need to implement it also for the main products before going live – which would necessitate implementing also the more complex process used by the main products (and not yet supported by the new backend). And suddenly we had a a load of work that would take weeks to complete and would be released in a big bang deployment.
Such a large-scale and time-consuming change without any feedback from reality whatsoever and then releasing it all at once, having impact on all our sales – I find that really scary (and have fought it before). It is essentially weeks of building risk and then releasing it in a big kaboom. How could we break it down, to release it in small slices, without making the business people unhappy?
Then we realised that we don’t need to do both the “refactoring”1 (introducing the new client-side shopping cart and switching to the new backend) and the new features all at once. And that we can first let the new shopping cart talk to the old backend just as the application always has done – and then later, perhaps in parallel, start talking (also) to the new backend (see Parallel Change). We don’t need to change the UI and the users don’t need to notice there is any change. So this became our new battle plan:
- Implement the new client-side shopping cart, i.e. an object where the UI stores whatever the user selects – which is then eventually sent to the old backend; keep the checkout process as-is. Do this initially only for accessories.
- Extend it later also to the main products.
- Integrate incrementally the new backend, talking to it in parallel to using the old one; incrementally switch over to the new one.
- Implement the new UI everywhere.
- Implement the new features.
(Some of the steps may interleave so we have certain freedom of experimentation and discovery.) Each step, or even a part of it, is released to production as soon as possible so that when the next chunk arrives, it will be battle-tested. The risk and uncertainty are minimised, and we nearly always work on production code.
PS: Many thanks to Alex York an my other colleagues for their help
1) Arguably this is not (just) a refactoring since we do not change only the internal structure.