Keep It DRY, Shy, and Tell the Other Guy

software construction
Editors: Dave Thomas and Andy Hunt ■ The Pragmatic Programmers
d a v e @ p r a g m a t i c p r o g r a m m e r. c o m ■ a n d y @ p r a g m a t i c p r o g r a m m e r. c o m
OO in One Sentence:
Keep It DRY, Shy, and Tell
the Other Guy
Andy Hunt and Dave Thomas
S
ome people feel that “getting” objectoriented programming is a difficult,
time-consuming process. But does it
need to be that hard? And is the difficulty even specific to OO programming? Many of the cornerstones of
OO programming benefit other programming
paradigms as well. Even if you’re writing shell
scripts or batch files, you can use these techniques to great advantage.
What’s good code?
There are many aspects to writing good
code, but most of these hinge on a single underlying quality: flexibility. Flexibility means
that you can change the code easily, adapt it to
new and revised circumstances, and use it in
contexts other than those originally intended.
Why does code need to be flexible? It’s largely
because of us humans. We misunderstand communications (be they written or oral). Requirements change. We build the right thing the
wrong way, or if we manage to build something
the right way, it turns out to be the wrong thing
by the time we’re done.
0740-7459/04/$20.00 © 2004 IEEE
Despite our fondest wishes, we’ll never
get it right the first time. Our mistakes lie in
continually assuming that we can and in
searching for salvation in new programming
languages, better processes, or new IDEs. Instead, we need to realize that software must
be soft: it has to be easy to change because it
will change despite our misguided efforts
otherwise.
Capers Jones, in his book Software Assessments, Benchmarks, and Best Practices (Addison-Wesley, 2000), showed that requirements
change at a rate of about 2 percent per month
(which really starts to add up after a year or
two). But the problem with changes to projects
is by no means limited to the common scapegoat of “requirements,” nor is it limited to the
software industry.
According to a study of building construction in the UK (“Rethinking Construction,”
Construction Task Force report to the Deputy Prime Minister, 1998), some 30 percent
of rework isn’t due to requirements changes
at all. It’s due to mistakes: plain, old human
errors, such as cutting a joist 2 inches too
short. Using the wrong kind of nail. Cutting
the window in the wrong wall. It’s just human nature that we’ll get some things wrong,
so what differentiates software quality is how
well—and how quickly—we can fix or
change something. Flexible code can be
changed easily and cheaply, regardless of
whether the change is necessitated by volatile
requirements or our own misunderstanding.
Most of the important lessons to be learned
about object technology—how to avoid many
Published by the IEEE Computer Society
IEEE SOFTWARE
101
SOFTWARE CONSTRUCTION
getOrder().getCustomer().getAddress().getState()
Figure 1. Example of the “train wreck” style of dynamic coupling.
common mistakes and keep code flexible—can be summed up in one sentence: “Keep it DRY, keep it shy, and
tell the other guy.” Let’s take a look at
what that means and how you can apply these lessons to all good code, not
just OO code.
Keep it DRY
Our DRY (Don’t Repeat Yourself)
principle deals with knowledge representation in programs (see The Pragmatic Programmer, Addison-Wesley,
2000). It’s a powerful idea that states:
Every piece of knowledge must
have a single, unambiguous, and
authoritative representation
within a system.
In other words, you should represent any idea, any scrap of knowledge,
in a system in just one place. You might
end up with physical copies of code for
various reasons (middleware and database products could impose this restriction, for instance). But only one of
these physical representations is the authoritative source. Ideally, you’d be
able to automatically generate or produce the nonauthoritative sources from
the single authoritative source.
Why go to all this trouble? So that
when a code change is required, you
only have to make it in one place. Anything else is a recipe for disaster, introducing inconsistencies and potentially
hard-to-find bugs.
DRY applies to code but also to
every other part of the system and to
developers’ daily lives—build processes,
documentation, database schema, code
reviews, and so on.
Keep it shy
The best code is very shy. Like a
four-year old hiding behind a mother’s
skirt, code shouldn’t reveal too much
of itself and shouldn’t be too nosy into
others affairs.
But you might find that your shy code
102
IEEE SOFTWARE
w w w . c o m p u t e r. o r g / s o f t w a r e
grows up too fast, shedding its demure
shyness in favor of wild promiscuity.
When code isn’t shy, you’ll get unwanted
coupling; these axes of ill-advised coupling include static, dynamic, domain, and
temporal.
Static coupling exists when a piece
of code requires another piece of code
to compile. This isn’t a bad or evil
thing—far from it. Even the canonical
“Hello World” program requires the
standard I/O library and such. But you
have to be aware of accidentally dragging in more than you need.
Inheritance is infamous for dragging
in a lot of excess baggage. Often it’s
more efficient, more flexible, and safer
to use delegation instead of inheritance
(which should be reserved for true is-a
relationships, not has-a or uses-a). Shy
people don’t talk to strangers, and shy
code should be equally wary of other
code that wants to come along for the
ride.
Dynamic coupling occurs when a
piece of code uses another piece of code
at runtime. This can get seriously out of
hand using a style we call the “train
wreck” (see Figure 1).
To get the state for an order, this
code has to have detailed knowledge of
an address, a customer, and an order—
Always plan on writing
concurrent code
because the odds are
good that it will end up
that way anyhow,
and you’ll get a
better design as a
fringe benefit.
and rely on these three components’
implied hierarchal structure. If anything in that mix changes, we’re in
trouble; this code will break. Shy code
only talks to code it deals with directly
and doesn’t daisy-chain through to
strangers as in the previous example.
Domain coupling takes place when
business rules and policies become embedded in code. Again, that’s not necessarily a bad thing unless mirroring realworld changes becomes difficult. If the
real world is particularly volatile, put
the business rules in metadata, either in
a database or property file. Keep the
code shy by not being too nosy about
the details: the code can act as an engine for the business rules. The rules
can change at whim, and the code will
merrily process them without any
change to the code itself. Small interpreters work well for this (really
small—like a case statement, not a large
yacc/lex endeavor).
Temporal coupling appears when
you have a dependency on time—either
on things that must occur in a certain
order, at a certain time, by a certain
time, or worse, at the same time. Always plan on writing concurrent code
because the odds are good that it will
end up that way anyhow, and you’ll get
a better design as a fringe benefit. Your
code shouldn’t care about what else
might be happening at the same time; it
should just work regardless.
Code shouldn’t be nosy. I used to
have a neighbor who would peer
hawklike over her kitchen sink out the
front window and keep track of every
neighbor’s comings and goings. Her life
hung at the mercy of every whim of the
entire neighborhood; it wasn’t a
healthy position for her to be in, and it
isn’t a healthy position for your code
either. A big part of not being nosy lies
in our next item.
Tell the other guy
One of our favorite OO principles is
“Tell, Don’t Ask” (see IEEE Software,
Jan./Feb. 2003, p. 10).
To recap briefly: as an industry, we’ve
come to think of software in terms of
function calls. Even in OO systems, we
ADVERTISER / PRODUCT INDEX
view an object’s behavioral interface as a
set of function calls. That’s really not a
helpful metaphor. Instead of calling software a function, view it as sending a
message.
“Sending a message” to an object
conveys an air of apathy. I’ve just sent
you an order (or a request), and I don’t
really care who or what you are or (especially) how you do it. Just get it
done. This service-oriented, operationcentric viewpoint is critical to good
code. Apathy toward the details, in this
case, is just the right approach. You tell
an object what to do; you don’t ask it
for data (too many details) and attempt
to do the work yourself.
By “telling the other guy” in this
way, you ensure an imperative coding
style that keeps your code from becoming too nosy and from getting involved in details that it shouldn’t care
about. Such involvement would make
your code much more vulnerable to
change. To make this work in a system, you’ll need to preserve the commonsense semantics of commands
(that is, every object that has a print
method should behave similarly when
called).
This isn’t an OO-specific technique either. Even shell scripts can
benefit from this approach. In fact, a
common Linux command employs
polymorphism at the command line.
The command fsck (which is not a
cartoon swear word—really) performs a file system check. When you
invoke fsck, it determines the file system type and then runs a delegate,
such as fsck.ext2, fsck.msdos,
or fsck.vfat, that performs the actual tests for that kind of file system.
But you, as the requester, don’t care.
You tell the system to check the disk
via an fsck command and it just does
it. It’s just the right amount of apathy.
S
o remember to “keep it DRY, keep
it shy, and tell the other guy.”
Andy Hunt and Dave Thomas are partners in
The Pragmatic Programmers and authors of the Jolt Productivity
Award-winning The Pragmatic Starter Kit book series. Contact
them via www.PragmaticProgrammer.com.
MAY/JUNE 2004
Advertiser / Product
Page Number
Agile Development Conference 2004
Cover 4
JavaOne 2004
11
Pace University
1
SAP Labs
9
Scientific Toolworks, Inc.
10
Software Development 2004
83
Springer-Verlag New York, Inc.
Cover 2
Classified Advertising
47
Advertising Personnel
Marion Delaney
IEEE Media, Advertising Director
Phone: +1 212 419 7766
Fax:
+1 212 419 7589
Email: [email protected]
Sandy Brown
IEEE Computer Society,
Business Development Manager
Phone: +1 714 821 8380
Fax:
+1 714 821 4010
Email: [email protected]
Marian Anderson
Advertising Coordinator
Phone: +1 714 821 8380
Fax:
+1 714 821 4010
Email: [email protected]
Advertising Sales Representatives
Mid Atlantic
(product/recruitment)
Dawn Becker
Phone: +1 732 772 0160
Fax:
+1 732 772 0161
Email: [email protected]
Midwest/Southwest
(recruitment)
Darcy Giovingo
Phone: +1 847 498-4520
Fax:
+1 847 498-5911
Email: [email protected]
New England (product)
Jody Estabrook
Phone: +1 978 244 0192
Fax:
+1 978 244 0103
Email: [email protected]
Midwest (product)
Dave Jones
Phone: +1 708 442 5633
Fax:
+1 708 442 7620
Email: [email protected]
New England (recruitment)
Barbara Lynch
Phone: +1 401 739-7798
Fax:
+1 401 739 7970
Email: [email protected]
Will Hamilton
Phone: +1 269 381 2156
Fax:
+1 269 381 2556
Email: [email protected]
Joe DiNardo
Phone: +1 440 248 2456
Fax:
+1 440 248 2594
Email: [email protected]
Connecticut (product)
Stan Greenfield
Phone: +1 203 938 2418
Fax:
+1 203 938 3211
Email: [email protected]
Southeast (recruitment)
Jana Smith
Phone: +1 404 256 3800
Fax:
+1 404 255 7942
Email: [email protected]
Southeast (product)
Bob Doran
Phone: +1 770 587 9421
Fax:
+1 770 587 9501
Email: [email protected]
Southwest (product)
Josh Mayer
Phone: +1 972 423 5507
Fax:
+1 972 423 6858
Email:
[email protected]
Northwest (product)
Peter D. Scott
Phone: +1 415 421 7950
Fax:
+1 415 398 4156
Email: [email protected]
Southern CA (product)
Marshall Rubin
Phone: +1 818 888 2407
Fax:
+1 818 888 4907
Email: [email protected]
Northwest/Southern CA (recruitment)
Tim Matteson
Phone: +1 310 836 4064
Fax:
+1 310 836 4067
Email: [email protected]
Japan (product/recruitment)
German Tajiri
Phone:
+81 42 501 9551
Fax:
+81 42 501 9552
Email: [email protected]
Europe (product)
Hilary Turnbull
Phone: +44 1875 825700
Fax:
+44 1875 825701
Email: [email protected]
Europe (recruitment)
Penny Lee
Phone: +20 7405 7577
Fax:
+20 7405 7506
Email: [email protected]
IEEE Software
IEEE Computer Society
10662 Los Vaqueros Circle
Los Alamitos, California 90720-1314
USA
Phone: +1 714 821 8380
Fax: +1 714 821 4010
http://www.computer.org
[email protected]