Ask any developer how he or she feels about “copy-paste programming” and you are very likely to be treated to a zealous denunciation of the practice. If you ask me, you would probably be treated to an especially zealous rant. It frustrates me to no end to see developers solving problems by finding code that solves a problem similar to their own, replicating it, and modifying it ever-so-slightly to meet their needs. Copy-paste coding seems to be a straight forward violation of core programming principles, such as DRY. However, in some sense, copy and paste is unavoidable because the nature of our job requires us to solve similar problems over and over again. For example, we often need to:
- Create a windows service
- Add a new screen to the UI
- Request data from a remote service
When faced with one of these problems, every developer, even those developers that are quick to denounce copy-paste (like me), will start by copying and pasting an existing instance of the pattern, or at the very least, referring to one. When creating a new service, you will probably start by replicating the Main method of an existing service. You are likely to model a new screen off an existing one and wire it into the application in the same way. Fundamentally, we are all copy-paste programmers.
Have we been living a lie? Is our hatred of CTRL+C and CTRL+V pure hypocrisy? No and no. Embracing copy and paste does not mean that we should give up on code reuse; it means that we should strive to write code that we would be happy to see copy-pasted. Application code should primarily contain information that is specific to the application. It should not be polluted with a lot of boilerplate “noise” that is simply required to implement an existing pattern. Patterns should be encapsulated in infrastructure and invoked by application code in a lightweight manner. If the application code is copy-paste friendly, a large percentage of it will require modification post-paste to solve the new problem. All that will remain from the original are the few calls into the infrastructure that encapsulate the common patterns.
For example, consider the case of Windows Services. Out-of-the-box, Visual Studio provides you with templates to create a service and an associated installer (“templates” should set off your copy-paste spidey senses – strike one). The template classes it creates can then be manipulated in a designer to mold them to your specific needs (a designer, really? strike two). The templates lack useful features like running from the console and self-installation (strike three). Instead of copy-pasting this blob of designer-generated code every time you want to create a service, wouldn’t it be better if you could copy-paste a one line main function that gave you a service with the ability to run from the command line and install itself? Those of you who have been following the site will notice that we’ve built infrastructure to achieve this in our how-to series on windows services. The main function of a service using our infrastructure is one line:
BasicServiceStarter.Run<MyService>("MyService"). A developer can create a new service by copy-pasting this line and implementing
MyService (probably changing its name as well as the service name passed to the infrastructure). The copy-paster has replicated a lot of functionality without replicating a lot of code, and he needed to modify a good chunk of the pasted code to make it fit his needs.
When creating a shared components, it is very important to think about the application code that will use it. Your goal is to make that application code small, straightforward, and copy-paste friendly. Write some sample application code using your component, and ask yourself:
- If someone copy-pasted this, how much would have to change to suit another use case? You want the answer to be “a lot”. Ideally every line would have to change, as would about half of the information content of each line. Application code should have a high signal-to-noise ratio – the infrastructure should fade to the background allowing the application code to shine.
- If someone copy-pasted this, how much value would they gain relative to the amount of code copied? A few calls into the infrastructure should get the caller all the functionality it needs. Infrastructure calls should have a high return on investment, or if you prefer, the infrastructure should have a high functionality-to-API ratio.
Instead of religiously fighting copy and paste, we should embrace it and let it inform the way we think about creating shared code. By making our code copy-paste friendly, we allow our tendency to copy-paste-modify to be used for good instead of evil. Making sure that copy-pasted code is still quality code is a key to leading your organization into the pit of success.