TDD work is the epitome of working smarter instead of harder. It is
orderly and precise. You begin the programming for any
small unit of production code by writing a unit test
for it that specifies and validates it. (You use a member of the
xUnit family of unit test
frameworks, standalone if necessary, but ideally integrated into
a refactoring-friendly IDE.)
You compile and run your test.
It fails. You then write and compile exactly enough code
to get that test to pass. Finally you refactor
the test code and production
code, as necessary. You are then done with that little task. Time to move
on. And this is the rhythm of the work, all day: a little test,
a little code, a little refactoring.
You get in the habit of knocking out tasks one after the other.
You make tremendous progress in a day, all of it demonstrated and
protected by
your tests. The sheer speed of TDD work can be astonishing.
Each new successful test proves that you are making orderly, safe
progress. This frees you to try new things, to experiment more with
design, refactoring, and performance adjustments. If you make a
mistake, your tests will catch you; you can always back out the
last thing you did to return to a robust build.
Every few minutes, you run all of your tests for all of the classes you are working on.
This could be hundreds of individual tests. This has interesting implications!
The entire suite needs to run in just a few seconds (like, less than 5 seconds is nice).
Otherwise, you just wouldn't keep doing it.
For so many tests to keep running so fast, they and their objects under test must
all be in memory. No slow interactions with external resources, such as disks,
networks, or databases. This means you have to systematically
eliminate dependencies between tested classes and such external resources, using
good OOD, and using fakes and mocks.
Mocks simulate external resources for you. They are like instrumented, remote-control
crash-test dummies. They
interact with objects under test exactly as you instruct them to, and they
collect results for you. In addition to letting you run your tests lickety-split, this
also enables you to simulate pathological circumstances
like network failures or database crashes.
This sounds like a lot of extra work, but you need only create a mock
once for a given resource. And in languages with reflection (like Java), you can
create mocks to spec dynamically. Fakes and mocks are more than worth the effort.
Hundreds of times each day, they repay you for creating them.
A surprising aspect of TDD work is how little time you spend in
the debugger. The tests you write give you so much insight into
your code, and prevent so many bugs, that you can work for weeks,
literally, without a single visit to the debugger. You just don't
have the need to manually step through code and snoop around watching
variables. Your tests catch all that stuff.
Finally, with TDD and refactoring you never have that nagging feeling that you
must eventually go back and "pay your code debt" -- clean up this
or that smelly section. You pay your small debts as you go, so the
code is always kept in a state of simplicity and clarity.
When you go home at the end of the day, you are truly done with
that day's work.
Programming is a creative act. It's supposed to be fun. When was the
last time it was fun for you?
TDD is indeed more fun, and more than a bit addictive: you
end up relying on seeing that little green bar in xUnit every few
minutes, reassuring you that all of your tests are still running
clean. You find yourself running the tests every few minutes even if
you haven't touched the code. It's just reassuring. Strange but true!
To experience TDD for yourself, check out Adaption's TDD
training courses.
|