A well-designed piece of software includes specific places where the designer anticipated the need for alternatives, despite the fact that they may not have had a need for more than one at the time. These are often referred to as change points. This might be allowing for pluggable search or indexing algorithms to be added, alternate representations of a core datatype, or even an entire replacement for some core piece of functionality such as the backend of a system. A system without any change points is certainly bad: it is brittle and inflexible, and the alternatives must be grafted on with lots of if-else statements or #ifdefs. However, too much flexibility can be just as bad. Furthermore, while many designers are good at putting them in, they tend to be very bad at taking them back out again. We convince ourselves that we Just Might Someday Need That Flexibility, and It Doesn't Hurt To Leave It In. That's just plain wrong. It does hurt, in the form of the cost to maintain the flexibility throughout the design. There is cost in complexity, maintainability, and in many cases, a runtime performance cost.
If you make use of a change point and have implemented several alternatives, then this overhead is usually justifiable. For instance, architecting a system to allow for different databases to be plugged in, when you actually need to be able to run the system on several different types of database is a big win. Architecting the system to allow for database pluggability when you only ever need to run on MySQL is just a huge waste. Every time you add a new feature that affects that backend, you'll need to consider how that affects your generic database interface instead of of just implementing it for the one. I've seen too many projects bog down in this kind of unnecessary flexibility, where everyone spends their time worrying about how to keep the change points tidy instead of writing code that does anything. In describing the emphasis in Extreme Programming on meeting current needs rather than making things unnecessarily general, Kent Beck uses an economic analogy to show that since feature value tends to be highly unknown, and the value of many features holds essentially constant over time, by waiting on all the features that you don't absolutely need, you eliminate the risk of implementing a lot of worthless features. It's not that easy in practice since it is still hard to guess the value of features, especially points of code flexibilty, but the point is well-taken.
While you can't recover the costs of implementing a change point in the first place, you can help reduce their ongoing expense through a flexibility audit. The idea is simple: as you develop a piece of software, keep track of where you made an explicit decision to allow for alternatives, and a note about what you expected those alternatives to be. Every few iterations, go over the list with the team and ask:
- What is this change point costing us?
- Do we still need this level of flexibility?
- Could we get the same kind of flexibility in a less costly way?
- Has one alternative proven superior to others such that that alternative could become the only implementation?
- Where do we really need flexibility that don't currently have?
- Have any change points become significantly more or less costly than last time we audited?
The outcome should be kind of a score for each change point, which is the cost to keep it versus the value to the application. Then purge the ones that aren't worth the trouble. It's can be surprisingly cathartic to eliminate code flexibility as we spend so much time worrying about how to make things more general, and rarely get to make them concrete again. You can make your team happy by eliminating troublesome and never useful bits of flexibility, and your code will be better off for it.

Post new comment