I’m confident there’s nothing new here, but I’ve never saw this approach being linked to (functional) purity, as in, side-effects free.
Let’s say that you have a piece of code to be refactored. What we’ll do is implement, aside of the current implementation, the new implementation. Saying it otherwise, the old implementation won’t be removed until the refactoring is complete, and guaranteed to be correct.
A pleasant addition to this is to have extra layer of indirection(s), allowing to isolate both implementations, and eventually select either one via a configuration flag.
For example, say you have a function dostuff()
. You’ll
want to add a function dostuff_new()
for the new implementation,
and say, (there are many ways of doing this), rename
the current dostuff()
to dostuff_old()
and have
dostuff()
select between dostuff_new()
or dostuff_old()
.
What’s great about this option is that:
- you can implement it progressively: in particular, the
code can be committed bit by bit:
- no need for endless refactoring branches rebasing;
- bits of the new refactored code (e.g. utilities) can be used early on.
- the working code isn’t disturbed at all, and continue to work as it used to. It can be maintained as usual, without creating a complicated merge soup with the new implementation, as both are kept isolated;
- the new implementation can be tested in a production setting, with the ability to revert to the old version if needed. The old version can be kept in the tree for as long as necessary.
Hence the title of this article: this is a side-effects “free” approach to refactoring: instead of altering a piece of code, we add a an “altered” version next to the old one.
Note: A similar approach can be taken to implement “versioning” to an API: if there’s a need for an interface update, just add a new route. There’s then little need to bake versioning within the API itself.
Comments
By email, at mathieu.bivert chez: