The idea of effective reuse is a pervasive one. Software organizations have searched for ways to avoid “reinventing the wheel” for as long as there has been a software industry. But all research on research on reuse indicates that it is much more expensive than people expect. There are a few delicate balances that a reuse effort needs to observe. The ones I’ve notices the most have been Quality versus Expediency and Control versus Evolution. How can we deal with these forces and come out ahead?
Robert Glass writes in Fact and Fallacies of Software Engineering that It is three times as difficult to build reusable components as single use components. For people who’re not dealing with in-house reused components on a fairly daily basis, this is a hard fact to accept. As part of my job the last years, I have been asked to help create reusable components, and I’ve noticed some of the reasons why it is so hard.
First, organizations seem to oscillate between having a “reuse group” or department responsible for creating “the framework” on the one extreme, and having everyone develop everything independently on the other hand. It is possible to get reuse even if things are developed independently, but the reused components will be incomplete – mostly only supporting the use that the first group developing them encountered. The advantage of this approach is that we won’t waste time, energy and lines of code writing speculative functionality that someone might need “someday.” The framework departments of the world should be held in infamy for the amount of gold plating that occurs when someone has to make a software component for someone else. It is extremely hard to anticipate correctly what functionality your “client projects” will need and what will be just good enough.
The approach of trying to grow reused components organically from projects is certainly safer and less risky in the short term. But components grown this way will usually grow more and more complex as time goes by. Most people are nervous about touching code that already work, so instead of changing the code we inherited, we build functionality that sits next to it, in effect duplicating the code. Or we build wrappers.
Wrappers is one of the most common ways I’ve seen to try and take control of the code that you’ve inherited. A class Foo doesn’t do exactly what you need, so you build your FooAdapter or FooWrapper that makes it a bit friendlier for your use. As your FooWrapper is even friendlier than the original Foo, people start reusing it, and building their own FooWrapperWrapper on top of it. The phenomenon could be described as “software calcification”.
The only way I have found of battling software calcification is to change the original code when it doesn’t fulfill your needs. However, this means that the reused code is changing. When you’re reusing changing code, you can choose to assert control over the changes by locking yourself to a specific version or branch of the code, or you can “live on the trunk”. That is, you use whatever version is at any time the newest.
My position is that any user of a reused library that lives on a locked version of the reused library will always end up wrapping the library to support the changes they need instead of changing the library itself. This means that the library will eventually be as deserted as the grain of sand at the heart of a pearl. Lets just hope the final result is a pearl!
At some point, preferably before every time you release your code, you need to lock the version of code you depend upon. It might be smart to do this as late as possible. Catching up with the latest version is a very expensive affair, and it’s even more expensive if you’ve forked the code.
Reuse groups and organic reuse are both imperfect solution to the question of who creates and maintains the reused code, and we have to find a way to balance between them. Locking yourself to a version of the reused code will isolate your project from changes, which has both positive and negative effects.
When it comes to reuse, there is no perfect solution, and it is pays to be aware of the real costs. Are the benefits worth it? Sometimes.
So what can we safely do to achieve the benefits of reuse? First: Reuse third-party components (preferably open source). Second: Shellfish builds pearls to protect themselves from the irritation of a small grain the sand. Like the grain of sand, your reused core should be small. You might want to skip the irritation part, though.