Chapter 3. Do One Thing, and Do It Well
There's only one way to eat an elephant: a bite at a
time. That's also the best way to code. Each bite of
clear, simple Java code must have a single purpose. The best Java
programmers keep a maniacal focus on a single problem at a time and
go to extraordinary lengths to maintain that focus. If you want to
improve, emulate them.
I'm a whitewater kayaker. For a long time, I walked
around every serious rapid that I faced. I could see how to run a
one-shot waterfall or drop, but I couldn't get my
head around the linked moves that would take me safely through
Humpty-Dumpty on the Little River, or .25-mile Pine Creek on the
Arkansas. A light clicked on for me on the Watauga River in
Tennessee. I learned that I just couldn't bomb down
continuous Class IV rapids with a preconceived set of moves in my
head. Instead, I needed to find the natural break points
within the rapids, and run many little ones. I
learned to read the river and find the natural resting places within
the whole. Then I could conquer one section, set up, and attack the
next section. When I approached the problems this way, I received
unexpected benefits. Coding, to me, is similar:
It's usually easier to clearly define a piece of a
big problem than the whole. We all tend to get overwhelmed by large
problems, but not as much by many smaller ones. Our brains just work
that way, whether we're on a river or behind a
keyboard. When things go wrong, it's easier to adjust or adapt
if your plan is segmented. Plans change; it's harder
to change a grand, sweeping plan than several smaller ones. You can protect yourself from disaster. On the river, I now plan for
safety one small section at a time. While coding, we must build test
cases that identify problems quickly in each logical section. You can better reuse techniques and code. On the river, I learn new
moves that I can use elsewhere. Instead of frantically paddling
through a section, I use a draw stroke to avoid one rock, an
aggressive brace and sweep to punch a hydraulic, and so on. In code,
I build collateral and learn techniques to solve smaller, more
general problems. Each design pattern that you learn in context is
worth any 20 that you read about.
Whether you're a kayaker running a Class V rapid, a
physicist working on a space station, or a programmer dealing on a
massive problem, your approach should be the same.
- Understand the problem
-
You must understand a problem to solve it well. Effective programming
goes beyond your code editor and debugger. You need to be able to
accurately gather requirements, and control the scope and
expectations of your customers. There is nothing worse than a
solution without a problem; it just generates more problems.
- Distill the problem to its essence
-
It's often said that programming is more of an art
than a science. Nowhere is this axiom more obvious than in the
ability to cut through clutter and find the core problem.
You've got to recognize what belongs in the center
of your problem space and what you can push out to other classes
around the perimeter, or out of the project altogether. Most of the
time, less is more.
- Layer the architecture
-
If you're solving a difficult problem and you can
only focus on one thing at a time, you must layer your architecture,
with each layer handling one task. The broadest, most successful
design patterns help you build effective, decoupled layers.
Model-view-controller lets you design user interfaces with three
layered components. Façades allow you to build clean
interfaces between major layers in your application. If you like to
study design patterns, pay attention to how often this theme arises.
- Periodically refine your approach
-
Left to its own devices, software loses focus over time.
You've got to make a concentrated effort to
refactor, decoupling your software into autonomous layers. Automated
tests will help you refactor with confidence and design decoupled
code in the first place. Getting feedback from teammates and clients
often helps make sure the approach still solves the right problems.
In this chapter, we explore each of these concepts in detail. You
don't need to go through them all to see a
difference in your programming—you can benefit from each
technique individually. But combining them multiplies their impact.
|