small medium large xlarge

The Art of Tradeoffs

There seems to be a common misunderstanding among netizens who create
software for a living. There are those who proclaim loudly that one
must model the whole world before committing to code—and that those
who jump into code early are merely “code-like-hell” hackers.

Then there’s the crowd that says, Hey, wait a minute. You can’t learn
enough from a simple model up front. You have to explore with code of
some type. Otherwise, you could very easily miss important details,
or even create a model that can’t be built!

The One True Answer

So which camp is correct? Those who prefer hacking around in code, or
the those who insist on fully modeling their perception of the world
before even thinking about code?

Well, in a way, they are both right. At least, they are trying to
solve the same problem—gaining sufficient knowledge to correctly
implement a system.

See, a software project is unlike projects in other engineering
disciplines. Software projects are inherently projects of discovery.
You and your team will learn more as time goes by. Your
knowledge of the customer, the application, the environment, the
sponsor—you will come to know much more about each of these topics
as you go along.

And you must be prepared to act on that new-found knowledge. The
error of the classic waterfall approach is that there isn’t any feedback.
Discoveries made at the lower levels of coding have no way to affect
requirements or architecture in a waterfall model. Yet these lower
level details can often have profound effects on your understanding of
the higher levels!

Mitigate Risk

Mitigation of risk is at the heart of traditional engineering. When
you build a bridge, you don’t build it as a perfect structure that
will never collapse. Instead you build it to withstand 500
year winds, 200 year floods, 300% expected maximum load, etc. If you
didn’t make these design trade-offs, every bridge would be solid
concrete from the deck to the ground, and would be something like 500
feet wide. Engineering is all about making these compromises, and so
is software engineering.

The difference is that with software engineering, much of the risk is
in the process of building it, as well as in the finished
structure, due to the nature of discovery.

Knowing that you will continue to make discoveries as you proceed,
it comes down to the fact that you want to minimize the risk of
discovering something that invalidates too much of your existing work.

Those who jump right into hacking out production code are already
in trouble before they begin: large changes in direction (brought
about by increased knowledge) are hardest to change here, and are the
most expensive.

Those who propose modeling fully before doing any implementation run
the same risk of making important discoveries while creating
production code. The model, being an abstract version of reality,
must forfeit some details. And the devil may well be lurking in those

Then there are those who try to balance these two extremes, by
modeling a little, and coding a little, or by modeling with a
disposable prototype or tracer-bullet code. Many of the Usenet
discussions of this topic seem to bogged down in the details here of
breadth-first versus depth-first; when do you model and when do you
code, and so on. Different methods will suggest different ways of
attacking this problem.

Methods R Us

eXtreme Programming is based on the premise of mitigating risk, and in
a way, so are all the other popular design methods of the
day—whether they admit to it or not.

Published methods attempt to answer the question ``How do I and my
team gain the most knowledge about the problem and solution domain in
the most economical way possible in order to create a software

Clearly, risk is inherent in the discovery process of a project. But
that discovery is ongoing, and we can’t afford to make crucial
discoveries late in the game. Ideally, we want to discover everything
we’ll need to know up-front and understand it perfectly. It will never
happen that way, of course, so every method tries to create an
environment where you can make the important discoveries as early as
possible. The golden Answer of a particular method is based on how to
lower your risk of making crucial, late discoveries.

But those answers will be different for everyone. The answer depends
on your team, your project, your experience, your problem domain, your
work environment, etc. Once you have found a method that works well
for one project, there is no guarantee that it will work well on the
next. If any of these listed factors change, your process will likely
need revising.

It ain’t Perfect

You see, unlike the pristine beauty of an algorithm or sequence of
tightly-coded machine instructions, it ain’t perfect.
Processes and methods depend on people to carry them out and to
understand the material being examined. And people are fallible.

So in the end, it comes back around to the idea of managing trade-offs.
You could spend six months on a project diddling around with an object
model, only to discover that you misunderstood the customer’s
performance requirements during implementation. You could jump into
implementation too early, and lock yourself into a design or
architecture that won’t support important requirements that you
haven’t gotten to yet.

Or you can weigh the trade-offs to minimize overall risk, and analyze
a little, design a little, and code a little. The relative proportion
of each task, the order, the amount of feedback—all of these will be
different for each project, and each practitioner. There are no
right answers that are correct all the time, in all contexts.
Once must be pragmatic, and make the choice that fits the current
problem, the current team, the current environment, and so on.

So next time you enter into a discussion of computer as an engineering
exercise versus an art, consider the art of trade-offs. Other
disciplines must live with trade-offs concerning the physical world; we must
live with trade-offs concerning ourselves.

And then we can proceed to develop software.