Bad Copy and Paste, Good Copy and Paste
Note: This post is based on a discussion that I participated in at the Joel on Software message board. I’ve reused (but cleaned up) my own posts, but I’ve rewritten the original question - as that bit doesn’t belong to me.
Question: Is copy-and-pasting chunks of code into our app, a good example of code reuse? My boss thinks that it’s a good idea, as we are making extensive reuse of code that we already wrote earlier in the development cycle rather than writing new code from scratch. Code reuse is supposed to be a good thing, right? (I’m not sure why, but I feel uncomfortable about duplicating so much code).
Bad Copy and Paste
The questioner (or perhaps more so, his boss) has a basic misunderstanding. The boss is assuming that Code Reuse is a goal in itself.
He’s wrong. It isn’t.
A key fundamental goal in software development, since we all want to do things in a way that avoids unnecessary time and expense, is to reduce duplication of effort.
Code Reuse is simply one method of working towards that fundamental goal. By putting code into subroutines or functions or classes or libraries, you (a) only have to write the code once initially, and (b) only have to go to one place in the code to maintain that algorithm.
If you copy and paste code, adding near-duplicate chunks of code in scattered places throughout your application, what happens? You’ve reduced the initial effort - as you only have to write the initial code once - but you’ve vastly increased the maintenance effort. Now if you want to make a change to that algorithm, you need to make the same change in all 57 (or whatever number!) of places it occurs in your code, you also have to try to remember to update all those 57 places (which is a struggle in itself), and finally you have to deal with extra bugs that arise because you forgot to update some of those 57 different places.
Maintenance and bug-fixing is by far the largest section of work in most projects, and copy-and-paste tends to vastly increase the duplication of effort, the exact opposite of the fundamental goal, which is to reduce duplication of effort.
Good Copy and Paste
There are cases however when copying-and-pasting code, duplicating it, can be a good thing. The reason is that reducing duplication of effort isn’t always the most important fundamental goal. Sometimes a more important fundamental goal is to reduce coupling.
Used intelligently copy-and-paste can reduce coupling. If you are fighting a tough schedule, a bit of copy-and-paste between projects can eliminate a bottleneck where two or more groups of developers are all awaiting a single change in a shared module. If there were only one bottleneck of this type, then the bottleneck probably wouldn’t have too much impact on your schedule, but if there are dozens or hundreds of these bottlenecks, then copy-and-paste, even if it involves duplicating code, can be a reasonable solution. In fact in this case, unless you copy-and-paste, your schedule may no longer be under your group’s control and become entirely unpredictable. In essence, the argument in favor of copy-and-paste is the same argument about removing dependencies that Joel used in his article, In Defense of Not-Invented-Here Syndrome.
One More Case
If life was simple (or maybe if I was a better self-editor?), I’d conclude after looking at the bad case and the good case, and then ask the reader to evaluate each situation from this point of view.
But there’s a third case…
Another argument that is sometimes made in favor of copy-and-pasting near-duplicate of sections of code, is that it reduces coupling by reducing the ripple effect of changing a shared function.
Here’s the example, let’s say there’s function X. It’s placed in a shared library (maximum code reuse!), and called by various modules in several different applications. A programmer then comes along and changes X (fixes a bug, adds a feature, changes the function’s side-effects, etc.,) so it now does something slightly different - which doesn’t affect where he is calling from - but does cause an unintended effect on the other places where X is called from.
Duplicating the innards of X as inline code at each point in the calling code, rather than calling a common function, would have avoided this problem, right?
Technically, provided you only focus in on the narrow details of this one function, this is argument is correct. However in this case, I have to think the cure is worse than the disease. Taken to the extreme, this in fact would be an argument in favor of never using functions - it takes us back to the Bad Copy and Paste situation that we’ve already discussed.
As far as I’m concerned the real problem is NOT that there is a shared function X, but rather that, what X is supposed to do, was never sufficiently well-defined. If what X does had been properly specified, including a clean API (including no weird or undocumented side effects), and programmers were aware that changing X from its specified behavior would have knock-on consequences, then the problem wouldn’t have arisen in the first place.
None of this is Rocket Science
Like the subheading says, this isn’t rocket science. What is needed is thought: thought about the goals and priorities when writing code, and thought about how to achieve them.
One thing I’ll say for sure though, based on my anecdotal experience: 99 times out of 100, copying-and-pasting of chunks of code is done without any deep thought at all - and in those cases, it’s nearly always pathological.
Leave a Reply