There is a C++ function that calculates something (I am not sure if C++ matters here at all, anyway…). It is called in 50 or more places. Now it turned out that this function works wrongly. And in order to work correctly it needs three more arguments.
How can this code be refactored most efficiently in terms of the number of necessary changes and compactness.
BTW newly added arguments are such that it is not reasonable to have default values for them. They should be always passed to the function.
Many people asked for an example. Here it is:
//old syntax of function
int f(int a1, int a2)
{
return a + b;
}
//new syntax of function
int f(int a1, int a2, int a3, int a4, int a5)
{
if (a3 == 10)
{
return a1 + a2;
}
else
{
return a1 + a2 + a4 + a5;
}
}
Does this example help? I need a way of doing this using a general approach, like a design patterns, like a principle of refactoring, but not for a specific example…
It really depends on where the three arguments come from. If we can’t have default values and it is not possible to create a common pattern for the extra parameters, then you may have no alternative but to attack each of the 50 calls in groups. In this case, you’d keep the original call and make a direct copy with a slightly different name. You then move gradually over so that eventually all the calls call the new function with the extra parameters. You can then retire the old one.
On the other hand, if we can start with defaults or at least make them independent of the calling code then the following might be a good plan. The thing to bear in mind is that as a large change, this would presumably have to be done in phases to control the potential impact if anything went wrong.
First, I would change the name of the function from
xxxxtoxxxx_<tag>where<tag>is a handle for the change – possibly a bug # from a defect tracker or change management system. Then I’d create a new function calledxxxxwhich simply callsxxxx_<tag>recompile everything. So far so good:Next I’d change the signature of
xxxx_<tag>to add the extra three parameters and the call to it. Now I’d rebuild again:Key point here is also to add comments for future maintainers describing why this wrapper exists. Unfortunately, this is as far as some of these changes get so code gets left behind the purpose of which isn’t immediately obvious.
I would then plan to phase in the 50 changes in say groups of five or ten so that you change your original call to the new call:
becomes:
Each section of calling code can be individually tested so that your are happy that (a) it works like it always did (i.e. fully backwards compatible) and (b) it fixes any problems.
Finally, once all this is done, you can then do a single change to remove the new function
xxxx()and renamexxxx_<tag>toxxxxAgain, you’d have to fully rebuild and test.Conclusion
Whichever way you go I’d recommend: