 | Level: Introductory Allen Holub, Contributing Editor, JavaWorld
01 Aug 2000 In July we started this series by talking about how to prioritize your design process. This month, I'll start actually designing a piece of software. I wanted a project that would be nontrivial, yet compact enough that we can do it in a reasonable timeframe. I also wanted to use a program that was honestly useful, rather than a pure pedagogic exercise. I decided on a piece of educational software that is described in this article. Over the course of several months, I'll present a complete design and (Java) implementation of the program, so you'll be able to see the whole process, from start to finish. I've also (deliberately) not edited my mistakes out of the process so that you'll have an honest look at the way things happen in the real world. So let's get started.
OO requirements gathering
I once came across the statistic that something like 60 percent of the
programs written each year are discarded within a few months of
completion, not because the program doesn't work, but because it
doesn't do anything useful. The resulting loss of productivity is
staggering, of course. Moreover, much of this code is produced by
shops that are very "high-ceremony" -- they generate enormous
volumes of paper in the pursuit of what they think is design. Clearly,
what they're doing isn't working (see Steve McConnell's editorial listed in Resources), but equally clearly, proceeding with no design at all doesn't work either. Given the failure rate of high-tech start-up companies, I'd guess that the percentage is now even higher than 60 percent.
I strongly believe that one of the main reasons for this failure is the fact
that most programmers embark on the journey of software
development without a clear idea of where they're going. For a
program to be useful, it's essential to ask someone who's going to use it
what it has to do. Often this stage is omitted entirely. Instead,
self-appointed proxies for the real users (such as salespeople) make up
fantasies that they call "requirements." Many times real users are indeed
consulted, but in such a way that they don't or can't make their needs
known. Our first task, then, is to figure out what has to be done, not
how to do it. (Most programmers immediately focus on the how: What
database will we use? What will the data model look like? What will
the UI look like? What is the data structure? The how is irrelevant at
this stage -- try to suppress the impulse!)
In OO parlance, this first stab at problem definition is called a formal
problem statement, and building one of these will be our task for the
next couple months.
In a procedural system, the problem statement is often omitted in favor
of something called requirements gathering. I prefer the term problem
definition because "requirements gathering" usually carries a lot of
incorrect (at least from the OO perspective) assumptions about what a
requirement is and how you go about gathering it. In a traditional
procedural environment, you would produce a Functional
Requirements Specification, often working from a list of features
provided by some outside third party, such as a marketing department.
In fact, often the "requirements" are a fait accompli, over which you
have no control. You'll find that in an OO environment, these sorts of
documents -- the feature list, in particular -- are almost worthless.
Those "functional requirements" that provide algorithms and specify
performance requirements will make a useful appendix to the OO
deliverables, but they are not central. The "functional requirements" that
specify UI behavior, workflow, and so on, are virtually worthless, for reasons
that we'll see over the next few months.
 |
The problem statement
Crafting the problem statement, then, is always the first step in any
design. Your goal, here, is to succinctly, but accurately, state the
problem that you're trying to solve. Again, you're interested in what
and why, but not how.
Before you can start defining the problem, you must first learn
something about the problem domain, however. Although every OO
design team must have a domain expert (ideally an end user) as a team
member, the other members of the design team must also know the
domain, though not as thoroughly as the expert. You have sufficient
domain knowledge when you can hold an intelligent conversation using
the vocabulary of the domain itself, without the expert having to stop
and explain the basic concepts.
Consequently, you must begin any design project with a research
phase. If you're doing an accounting program, go take an Accounting
101 class at a local junior college. Again, you don't have to be an
expert, because that's your user's job, but you do have to be able to
hold your own in conversations with domain experts. Without some
knowledge of the subject, you won't even know what questions to ask
or how to ask them.
Crafting your statement
It's critical to the success of the entire design effort that the problem
statement be a well-crafted essay. A bunch of bullet points and
sentence fragments simply won't do, as they rarely capture the subtlety
of the problem in any detail. If you can't say it in clear, well-structured
English, then you don't understand the problem well enough to design
anything. Good grammar is also important; it gives structure and
precision to otherwise disorganized thoughts. A good copy editor is an
important member of any OO design team.
There's also something about the writing process itself -- that is, the need for
accuracy that you typically don't have in conversation -- that helps you
discover new facets of the problem. I find that the only time I'm not
stumped by something when I start coding is when I've written out the
problem first. This reasoning applies even to simple method definitions
-- if you write the comments before you write the code, the coding will
go much faster and the code will be less buggy.
The discussion has to be couched entirely in the vocabulary of the
problem domain. If you're solving an accounting problem, the problem
statement should be written entirely in the vocabulary of accounting.
That is, any competent accountant should be able to make sense of the
problem statement without having to ask any questions. It is a general
rule of thumb about the completeness of a design that a competent
programmer who's familiar with the domain at the level of an intelligent
layman must be able to read through the design documents and
completely understand both the specific problem being solved and the
general solution to that problem. If this level of understanding isn't
possible, then, again, the design document isn't complete.
I cannot emphasize too greatly that a problem statement is not a
discussion of a computer program. A problem statement should define
the problem itself, not a computer-based solution to the problem. It is a
discussion of the real-world problem that your end user is trying to
solve. Words like "computer," "menu," "dialog box," "internet,"
"Worldwide Web," and so forth typically have no place here. A
problem statement never contains a sentence like "The system must..."
or "We need to write a computer program that..." Writing a computer
program might be your problem, but computers are rarely involved in
the problem that your end user is struggling with (though they may be
involved in the solution). Most problems can be described and solved
perfectly well without computers, though the computer might make the
solution easier or faster.
Though you will eventually have to write a description of the
computer-based solution, we're going to focus, for now, on the
domain-level part of the document. Remember that computer jargon
simply has no place here, and any accountant should be able to clearly
understand our accounting-domain problem statement.
Acknowledge problems and solutions when possible
Conversely, solutions to the problem that are part of the problem
domain itself should certainly be discussed. All OO systems must
model something. If an existing problem has a good solution, and the
real problem is that the existing solution can't be performed fast enough
by real people, then just model the existing solution. That is, often the
automation of an existing manual process is all that's required, and your
problem statement will be a complete description of that manual
process.
One critical thing to identify in a problem statement is the goal of the
user. What exactly is the user trying to accomplish? The goal can
drastically affect the direction of the solution. (For example, is it your goal to
schedule a meeting or to maintain a calendar? In the first case, the only
place in the program where you might see something that looks like a
traditional calendar is in the output.) Alan Cooper, in his book About
Face, calls this way of working "goal-directed design." (See Resources.)
You also have to address the desired outcomes. What are the end
products of the solving the problem? What information do these end
products have to convey? (Note that we're interested in the
informational content at this stage, not the physical layout or the way
that the content will be presented.)
Insofar as it's possible, ignore the existence of legacy systems. It's
rarely the goal of a user to improve a legacy system; rather, the user
has to get some job done and is coming to you because the legacy
system isn't working. Start with a clean sheet.
Don't try to get too formal in the problem statement. Just describe what
you want to do as if you were having a conversation with a peer. (I've
often been asked "how do I say
?" My
response, invariably, is, "Just like that -- you just said it.")
Normally, the next step is to have several conversations with real users
and domain experts and to try to define the problem cogently. Then,
capture the problem on paper using domain vocabulary, and run the
problem statement back by your users to make sure you got it right.
Thinking that I could skip the interviewing process since I am myself a
domain expert (a parent), I just started writing. (It turns out that I was
mistaken in taking this shortcut, but I'll get into that next month.)
So, here's what I came up with:
The Bank of Allen
One of the best ways to teach kids how to manage money
(and how interest works) is by setting up a bank account
for them. Real banks, however, don't pay enough interest
to catch a kid's interest, so to speak. (At a nominal annual
rate of 3.5%, $20.00 earns a big $0.72 in a year, after
all). Taking my cue from a piece I heard on National
Public Radio's "Marketplace," I decided to open the
Bank of Allen (or BofA), which pays out an effective
5%/month (that's right, per month -- 60% annually), but
compounded daily. At this rate, $20.00 deposited in the
Bank of Allen earns $15.91 over a year. Despite the
high interest rate, the Bank of Allen works like a real
bank. Kids have their own accounts, over which they
have control of everything but the interest rate. They can
look at (or print) their passbooks whenever they want.
They can make deposits and withdrawals at will.
To make saving more interesting to the kids, the
passbooks must show them how much money they're
earning from interest in addition to the usual stuff
(deposits, withdrawals, running balance).
The kid must also be able to play what-if games with
projected interest: "How much money will I have if I don't
withdraw any money for two whole months?" The point is
to demonstrate that you can make money by not spending
it.
There are a few security issues. Only the bank (that is, the
parents) can change the interest rate or set up a new
account (and the initial balance). Like a real bank, kids
can't make a deposit or withdrawal by modifying their
pass books; they have to ask the bank to do it; the bank
processes the transaction and updates the passbook. That
is, the kid gives money to the bank, which puts it into the
account. The bank takes money out of the account, and
dispenses it to the kid. (Practically speaking, this means
that only parents can make deposits or withdrawals, but
parents should process withdrawal requests when asked
or the kids will assume that the bank is a ruse for not
letting them get at their own money.)
Goals (ranked by importance):
- To teach kids to save money
- To show how compound interest works
The "Bank of Allen" is a trademark of Allen I. Holub. This program,
and the design thereof, is (c) 2000, Allen I. Holub. All rights
reserved.
I don't pretend that this problem statement is complete, but it's a start.
In general, a problem statement is not complete if any reasonable
questions have not been addressed. This is typically a tremendous
amount of detail. A problem statement for an average small program --
one that might take a small team six to eight months to implement -- can
easily get to 80 pages or so before all the details are hashed out. So,
obviously what I've done so far is way too brief.
Pre-code details
The point of the exercise is to think about as many details as possible
before you start coding. You are not trying to bolt things into concrete.
Don't kid yourself into thinking that you'll be able to capture all the
details up front. Unless you're working in a very static environment, it's
nigh on impossible for all of the details to be settled (or even
discovered) in advance, and in any event, as the system goes into
production and is actually used, the end users themselves will discover
things that they hadn't thought about initially. This after-the-fact
discovery is natural, and any design methodology that can't handle the
late-breaking changes will be too brittle to use in most programming
environments. In practice, then, the problem definition will change as
the design and implementation evolve. That's why it's essential to have
an end-user on the design team: to make sure that you don't break
things rather than improve them.
Nonetheless, the initial problem definition should be as complete as
possible. Do a total brain dump to paper. Don't leave out any details,
even simple ones. One of the things I do for a living is mentor teams
through their first OO design effort, and often I don't get called in until
the effort is already underway. Usually, I ask for my clients to send me
their design documents so I can prepare for our first meeting, and,
more often than not, I'm told that I'll have to come in and talk in order
to fully understand what the problem is. That response sets off all sorts
of warning bells. If the problem hasn't been written down in enough
detail that an outsider can understand the problem by reading, then I
know that the client probably doesn't understand the problem
well enough to have started designing. Though I certainly believe that
"analysis paralysis" exists, I've never witnessed it; rather, I've seen the
opposite: teams who have jumped to coding way too early without
sufficient up-front analysis.
Looking back at the incipient problem statement, you'll notice that I
haven't mentioned computers anywhere. I'm describing the problem,
not a computer program. The problem domain, here, is parenting, not
banking. Consequently, the statement is written for a parent, not a
banker, to read.
Also, note the relatively simple structure of the sentences. Avoid the
passive voice and other turgid academic prose styles like the plague. A
simple declarative sentence (subject/verb/direct-object) identifies the
initiator of an action (the subject), the operation performed (the verb)
and the receiver of the message that requests the operation (the direct
object). The passive voice only identifies the last two of these three
parts. Use "I," "you," and so forth whenever it makes sense to do so.
Happy trails
So that's it for this month. We've made a start by defining the basic
problem. Next month I'll continue the exercise, flushing out and refining
the problem statement so that it will be sufficiently useful.
Resources - Read a great editorial in the March/April, 2000
issue of IEEE Software on the confusion of paperwork with
progress. The editorial is called "Cargo Cult Software Engineering" by Steve McConnell.
- Learn more about UI design in About Face: The Essentials of User Interface
Design by Alan Cooper (IDG Books). It is ironic that the author of a great book about UI design is also the "father of Visual Basic," the tool responsible for many of the worst
user interfaces ever foisted on the computing public. Cooper has a
lot of opinions, some of which I agree with and some of which I
don't. (In particular, I don't think of a program as a UI with
intelligent warts hanging off of it, as Cooper seems to do).
Nonetheless, Cooper is always entertaining, and there's a lot of
good advice here.
-
I find that most of the books on UI design are written either by
programmers (who put the convenience of the programmer above
the needs of the user) or graphic artists (who put concepts like art,
impact, and originality above the needs of the user). In either case,
the user loses. It's refreshing to read a book about UI design written
by a knowledgable programmer who not only insists on putting the
user first, but also has a good design sense.
From the Cooper Design "Manifesto" on Cooper Design's Web
site:
In fact, most of today's software might as well
have an interface like this:
About the author  | |  | Allen Holub is the author on this article. |
Rate this page
|  |