In the final installment of my Code Craft column, "Staying
Out of Code Debt", I offer some approaches to keeping your
code smelling fresh and clean. More important, it may well help you
get more done in less time.
Code wants to be responsive to change, and when it doesn't get its
way it tries to warn us. But often we aren't listening because it's
too easy to plow ahead to the next feature. Unfortunately, in our
haste we miss a golden opportunity to improve the code, which is
actually the design. And although the consequence of ignoring the code
isn't immediately noticeable, it quickly starts to drive up the cost
of change.
In the latest installment of my Code Craft column, "Relocate
for Reuse", we stop to listen to the code. Heeding its
warnings, we find a new home for small methods that fell out of
earlier refactorings, and end up with code that can be reused.
In the latest installment of my Code Craft column, "Clean and
Green", we use safe and simple refactorings to clean up the
mess we made last month.
Writing pristine code isn't enough. Without tests, you don't have the
confidence to modify the code predictably. Rather, every time you
touch the code a cold chill runs up your spine and your typing fingers
tremble with fear. You've been bitten before—an innocent change
here unknowingly breaks something over there, and what you thought
would take mere minutes has turned into several painstaking hours. And
so the police tape is strung permanently around the code, workarounds
are used to spare the team from going into those crime scenes, and
before long what once was the cleanest code on the planet has decayed
into the nastiest code imaginable.
It doesn't have to be this way. In the latest installment of my Code
Craft column, "Reduce
Stress, Write a Test", we drive out fear and boost
productivity with the help of a test.
Comments. Write too many and it may be a sign that your code smells.
Write too few and the next person is left wondering why something was
done.
In the latest installment of the Code Craft column, Write
Sweet-Smelling Comments, I explain my approach to striking a
balance.
Writing good code is a craft technique, not merely one turn of the crank
after a good design. This is something I'm passionate about, and with
that comes a desire to share what I've learned about crafting good
code, knowing that it will further hone my skills. So earlier this
year I started writing the Code Craft column for Better
Software Magazine.
The digital edition of the first article in the series, Tame the
Name, is now available online. I hope you'll tune in each month
as we learn how to spot bad code and refine it into good.
Just for fun, here's the fifth and final question that Mike Gunderloy of
Application Development Trends
asked me for his Five Questions column:
Q: What one tool do you wish you had that no one has written
yet?
A: Well, I'm still waiting for the Do-What-I-Mean-Not-What-I-Type
Telepathic Interface™. :-)
Seriously, I can't think of any one tool that I wish I had. That will
probably change tomorrow when I can't find just the right tool for some
job. But I've accumulated enough simple, generic tools over the years
to scratch most itches, either by using a combination of existing tools
or adapting one tool slightly. And I'm a programmer, so I love to craft
new tools to solve problems.
A while back, Mike Gunderloy of Application Development Trends
interviewed me for his Five Questions column, which was distributed in
a newsletter. With Mike's permission, I thought it would be fun to
post the interview one question at a time over several weeks. Think
about how you'd answer each question differently. Here's the fourth
one:
Q: Is there a maximum size project where you're comfortable with
continuous integration? What do you do on larger projects?
A: I think larger projects have as much, if not more, to gain
from continuous integration than smaller projects. When working in a
larger team we have more people contributing code into a common
baseline.
Larger teams are generally spread out across many floors of a
building, or perhaps across time zones and countries. That increases
the potential for integration problems to occur more than, say, four
people working around a table. Projects that are large as measured by
the amount of code being supported have an increased risk of making a
change that breaks something.
So I've not found a maximum size project where I'm comfortable with
continuous integration. Indeed, as the size of the project increases
I'm uncomfortable without continuous integration. The book (Pragmatic
Project Automation)
includes a real-world story of a company with 800 developers working
on more than 250 projects with five million lines of Java code. The
size of the projects vary, but it's encouraging that they have all of
these projects under continuous integration with CruiseControl. So
while continuous integration tools such as CruiseControl can be used
on smaller projects, they can also scale up to larger projects.
Is your code being continually integrated by an automated build
process? If so, how has it helped you? If not, what barriers have
you found to using continuous integration on your project? I'd enjoy
hearing your responses on your blog or via email.
A while back, Mike Gunderloy of Application Development Trends
interviewed me for his Five Questions column, which was distributed in
a newsletter. With Mike's permission, I thought it would be fun to
post the interview one question at a time over several weeks. Think
about how you'd answer each question differently. Here's the third
one:
Q: Now that we've got some reasonable experience with unit testing,
where do you think it fails?
A: I think unit testing fails when we use it as a substitute
for acceptance testing. That is, unit tests that pass don't tell us
that we built the right thing. They only tell us that what we built
works as we, the programmers, expect. So as much as I'm encouraged by
the enthusiasm for test-driven development and unit testing, I think
we have to start putting an equal amount of emphasis on acceptance
testing.
I also see unit testing failing in cases where it's a checkbox item on
a project schedule. Just saying that we're doing unit testing says
nothing about the quality of the tests. So I like to see a test fail
once in a while as it tells me that the test is actually testing
something that could break. I also like to open the tests up to
review by users of my code and folks with more testing experience to
see where I might improve the quality of the tests.
Finally, a common question I hear revolves around what to do about
legacy code on a project that doesn't have unit tests. It frightens me
to hear that some managers want to get to a certain percentage of test
coverage for all legacy code. Unit testing legacy code can be
successful if done tactically around sections of code undergoing change
or containing bugs. But when unit testing is taken as an all-or-nothing
approach, it's neither practical nor economical.
In what ways has unit testing been successful on your project, and
where has it failed to deliver the results you expected? When is the
last time one of your unit tests unexpectedly failed? How was that
feedback helpful? What approaches are you taking to gain confidence
to change legacy code economically? I'd enjoy hearing your
responses on your blog or via email.
A while back, Mike Gunderloy of Application Development Trends
interviewed me for his Five Questions column, which was distributed in
a newsletter. With Mike's permission, I thought it would be fun to
post the interview one question at a time over several weeks. Think
about how you'd answer each question differently. Here's the second
one:
Q: If you go into a completely disorganized development shop, which
practices do you try to get them started with first?
A: Since developing software is such a high-touch human
activity, I suspect the disorganization would stem from a break-down
in communication. So I'd start by concentrating on practices that
foster better communication.
First, I've had good success helping teams deliver smaller sets of
features early and often. The act of delivering working software, of
any scale, is a powerful communication technique. For starters, we
have to know what it is we're trying to deliver and whether what was
delivered is what was expected. That means we need tests to help us
check that we built the software right and built the right
software. Thus, the more often we deliver something, the better
chance we have to converge toward being organized as a team.
Each release also offers multiple points along the way to communicate
what's going on. For example, building and testing the software
continuously throughout the day is an inexpensive form of communication
that advertises the health of the system and helps avert integration
problems downstream. Yet, far too many projects don't practice
continuous integration.
Small releases also communicate how efficient we are as a team. If
after a few weeks we aren't able to deliver a proportional number of
features, then we get an opportunity to assess what's slowing us
down. Optimizing may involve breaking high-level requirements into
smaller tasks, automating time-intensive chores, or finding ways to
eliminate waste in the process.
So I'd start with small releases supported by unit and acceptance
testing, and set up a continuous integration process to throw up red
flags when things go awry. I'd also look for ways to automate
repetitive project procedures to conserve time and reduce errors.
Have you tried these practices on your project and if so, how
have they helped you keep organized? What other development practices
have you found beneficial? How were you able to sell those practices
to your manager and others on your team? I'd enjoy hearing your
responses on your blog or via email.