Thu 4 Jun 2009
“Reinventing the wheel” is used as a common metaphor in software development for rewriting code that has already been written. For example, SlickEdit contains a number of features that traverse directories and process files, including Find in Files, DIFFzilla, Add Tree, and more. In each case the syntax used to exlclude files or directories is different. Sometimes the exclude specs are space delimited; sometimes they are delimited with semi-colons. Some require the use of asterisks to specify a directory; some don’t.
The basic reason for this is that each feature was written in isolation without finding and reusing the capabilities of the other features. This is a very common problem on most software projects. To address this issue, I believe that software development should be broken down into two different workflows: mechanism application and mechanism creation.
We can define a mechanism as a component with a cohesive set of functionality, like the wheel. In most cases, mechanisms are meant to be reusable, though it is possible that there will be only one use for that mechanism in a particular program. Common mechanisms in software include login processors, calendar widgets, and sorted lists. These elements perform a specific function that is independent of what they are used for.
Mechanisms can also be specific solutions to common design problems, like error logging, object persistence, and thread synchronization. Ideally, these would be encapsulated in a library that is used by other developers, but in some instances it is more a matter of following a specified convention.
For example, one project I worked on specified that each function would contain #ifdefs for tracing and logging with specific information that each function should output. This still represents a mechanism that defines a cohesive functionality, in this case, tracing. But instead of writing a reusable library, the mechanism was primarily a set of conventions we all followed when writing our functions.
During mechanism application, the specialized functionality of a feature is built using existing mechanisms. You can work on your own unless you have a question about the specs or need assistance from another developer. The code being written is unique to the feature, so little attention is given to reuse unless a new mechanism is needed. Then you enter mechanism creation.
During mechanism creation, you are developing a generalized capability that is specifically intended to be reusable. This requires a totally different workflow. You have to stop and do a degree of analysis before you create the new mechanism. Several questions need to be answered. Are you sure there isn’t already a mechanism for this? If not, what are the essential behaviors of this mechanism? Where should it be stored?
These questions are best addressed with other members of the team. The goal is to produce a mechanism that can be used by everyone, not just by you. So, you need to get their input to make sure it does more than meet your immediate needs, or at least doesn’t prevent someone from extending it in the future.
When a developer tackles the new mechanism as part of their normal development, two common problems occur. Often the programmer includes the mechanism as part of the feature-specific code, rather than placing the mechanism into the library where others can find it. Even when they do put the code in the proper place, it often is written in such a way that it is only useful for this feature. You can’t make it reusable without breaking the feature that already depends on it.
In most applications, mechanism application is very straightforward, simple programming and requires little creativity. Mechanism creation, on the other hand, requires a great deal of creativity and design effort. You have to think more about algorithms and efficiency.
So why don’t programmers naturally break their work into these separate workflows? I think there are a number of explanations.
First, I think programmers get very focused on completing a feature. If they have to interrupt that work to enter the slower and more deliberate workflow required to create a new mechanism, then it delays the attainment of their goal.
Secondly, programmers like to program. Designing reusable components requires meetings, documentation, and reviews–all of which get in the way of programming.
Thirdly, most programmers aren’t too keen on collaboration. When you talk things over in a group, you have a chance of not getting your way. If you just build it yourself, you can do it the way you think it should be done.
Finally, by separating the two workflows, the creation of a needed mechanism might be assigned to a different programmer. Since the creation of these mechanisms is often more challenging and, therefore, more fun; developers are hesitant to initiate a workflow that would potentially deprive them of this fun.
Basically, it’s more fun to reinvent the wheel than to determine whether a suitable wheel already exists. If the wheel does need to be invented, it’s less fun to do it with a committee of your peers who may disagree with your vision for the wheel.