by Conrad Weisert
© 2002 Information Disciplines, Inc., Chicago
NOTE: This article may be circulated freely as long as the copyright notice is included.
|Related articles on this and other web sites
as of October, 2003
|Agile Methods and Torpid Programmers|
|The #1 Serious Flaw in Extreme Programming|
|Software Reality web site -- articles, book reviews, and experience reports|
|Book review: An Extreme Programming Book for Non-Extremists|
Just about every article or presentation on extreme programming includes a warning against too much flexibility in program design. XP gurus stress the "YAGNI principle" (you aren't going to need it), pointing out that software developers have been known to fritter away time designing and building extra features ("bells & whistles) that turn out to have little if any value.
"Just build what the users need today and worry about the future in a later iteration" is their advice. Unfortunately, programmers taking that advice are building naively inflexible software components.
The problem is that many programmers who take that advice confuse adding fancy features with generalizing scope of applicability at the level of individual components. In many cases it takes little additional effort, if any, to avoid an unreasonable restriction. The infamous "Y2K crisis" is a glaring example: Developers who extended the scope of their date representations beyond the user's immediate need avoided huge costs at almost no upfront expense. They didn't have to implement any additional date functionality or features, just a sensible representation.
For years we've been proclaiming and reporting the huge benefits of reusable components. Using an existing component, whether a single subroutine, a complete object-oriented class, an application "framework", or any other sort of building-block, not only reduces development time but also contributes to operational reliability and manageable future maintenance.
Indeed, many experts believe that among all tools and methodologies, reuse is the single most significant contributor to programming productivity.
When we discourage generality of scope or penalize programmers for going beyond their users' immediate needs, we insure that our projects will rarely if ever contribute new complete, cohesive, and reliable items to our component library. And if our library is full of undocumented fragments having severely limited scopes, we insure that our programmers will rarely if ever draw upon it.
Martin Fowler, in defending YAGNI1, has
given us a powerful example against it. He posits a
Money class in an application
that needs to add two amounts of money but doesn't today need to
multiply an amount of money by a scalar. With that incomplete class
Money objects, then:
totalDue = totalDue + unitPricewill work as expected, but
totalDue = unitPrice * quantityOrderedwill not work, and
totalDue += unitPricemay or may not work work depending on the class developer's whim
This is just unacceptable at an application level, even in the middle of incremental and iterative development. A reasonable application programmer would be irate upon discovering such anomalies.
In a course or textbook on object-oriented programming in C++ we advise our students:
a+athen you're obliged to support both
a = a+b;then you're obliged to support
a += b;
The picture of hordes of class designers violating (in pairs) such common-sense principles is alarming in the Xtreme.
So, how much additional effort would be needed to make our
Money complete? Very little. In
fact, if we've been serious about building up a library of reusable
components, it may actually take less effort to build a reliable
Money class than to
build an ad hoc class fragment.
Money is an instance of a
pattern that arises often with numeric data types. Whenever the type
has a unit of measure and is closed under addition, the same arithmetic
and relational operators are required. We can capture and
(in C++ but not Java2) implement that pattern as reusable code for the
benefit of programmers building classes such as
Money example yields
a further demonstration. In our
class we're going to need either an output-stream operator (C++) or a
conversion function (Java). We must then choose a default external
data representation, e.g.
Our implementation of that function
then uses three character constants, the currency symbol ($), the group
separator (,), and the decimal point (.). All of them would have to be
changed to use our class for, say, Norwegian money. However, it takes
very little additional effort to give those constants names, and to use
those names instead of the hard-coded values. This is one of the oldest
principles of good programming practice, and it's painful to see
XP extremists violating it.
Money class on this web
site in C++ and
Java illustrates a complete and
coherent numeric data type.
1 -- "Is Design Dead?", Software Development Magazine, April, 2001.
2 -- You can do it initially in Java by pasting the pattern into the source code in an editor, but you'll be stuck with dual maintenance in the future if the pattern should be improved or corrected.
Return to IDI home page
Last modified April 10, 2007