Wednesday, June 29, 2011

I Don’t Have Time for Unit Tests

I’ve helped several organisations adopt Test Driven Development (TDD). The initial worry that almost everyone has, is that it will hurt productivity. It seems intuitively correct, because of course, the developer has to write the unit tests as well as the production code. However when you actually look at how developers spend their time, actually writing code is a small part of it. Check out this study by Peter Hallam from the Visual Studio team at Microsoft:

According to Peter, developers actually spend their days like this (while not reading Code Rant of course :):

  • Writing new code 5%
  • Modifying existing code 25%
  • Understanding Code 70%

If some technique allowed you to half the modifying/understanding parts of the job by doubling the new-code part, you’d now be taking only ~60% of the time you previously took to deliver a feature, almost doubling your productivity.

TDD is that technique. In my experience the productivity gains come from:

  • Allows safe modifications. If you break something when you modify some code, the unit tests fail.
  • Shortening the iteration cycle between writing/running code. No more need to step through your application to part where your new code gets exercised.
  • Mistakes in your code are shallow and obvious. No more need to step through code in the debugger, wondering which part of your application is broken.
  • Code is self-documenting. The unit tests explicitly show how the author expected the code to be used.
  • Code is decoupled. You can’t do TDD without decoupling. This alone makes the code easier to understand as a unit and much safer to modify.

Note that I’m just talking about feature-delivery productivity here. I haven’t mentioned the huge gains in stability and drop in bug-counts that you also get.

Now I don’t deny that TDD is a fundamentally different way of working that takes time to learn. Undoubtedly productivity may drop while a developer is getting up to speed. But in my experience the argument that a developer doing TDD is slower than a developer who doesn’t do it is simply not true.


Gareth Elms said...

I've recently started with TDD on a home project and I'm happy to say I agree with all your points here. Mistakes are indeed trivial because everything is decoupled. Combined with my first attempt at DDD after reading the Eric Evans book I've reached a new milestone in my abilities and it's all thanks to posts like this raising awareness and pushing TDD. It was tough at first but I would say it's worth it if you can step back and retrain yourself

jamiet said...

Totally agree with this Mike. I live in the SQL Server world and, slowly but surely, I'm getting my colleagues/clients into the habit of doing database unit testing.

We've recently banged out a functional BI system (containing >25 tables & >50 stored procs) in less than 3 months and I attribute that level of productivity to the fact that we did DB unit testing from day one. it wouldn't have happened otherwise.


Unknown said...

Well written code is what solves "understanding code" problem. With or without TDD. TDD itself plays small role - it's like bike training wheels.

Instead of writing tests I just don't write any code without knowing thoroughly how it will affect functionality around and system as a whole. And since my code is dead obvious - that costs nothing.

There are some other problems with this like high "bus factor" (what if I'm being hit by bus - who would replace me?) but for development speed - closely followed TDD would slow me down for 100%.

Also - .Net sucks for TDD. Mocking yet another HttpContext doesn't feel like any kind of accomplishment that adds business value.

amiralles said...

100% Agree!!

preet sangha said...

Well said Mike.

Can I just introduce another perspective please? For the past year I've been working in the equivalent of third line support for a complex product where customisations are at the level of writing .net code in c# and python. One of the most productive things we teach our customisation customers is the use of unit tests and decoupling code. The benefits to them are massive in terms of productivity.

They initially put up resistance as they're used to the unit testing manually approach however in time they come round to the benefits.

I spend the vast majority of my time understanding code and attempting low impact changes to a complex code base. Without automated unit tests this task becomes nigh on impossible in terms of the amount of manual testing for even small fixes.

Matt Honeycutt said...

@Unknown, I don't agree at all. I've been doing TDD for many years now, and I've noticed a huge boost in productivity. I think you are making some flawed assumptions in your comment.

First, except for trivially small applications that you never have to maintain, you can never be sure you know "thoroughly how it will affect functionality around and system as a whole." That's one of the reasons automated regression tests, like those produced as a by-product of TDD, are so important: we suck at accounting for how our changes may affect other code or how they'll impact existing requirements.

Second, I would assume you are indeed testing your code somehow as you create it (if not, please stop writing code now). You may be doing that by running the app and exercising the affected functionality integration-style, but you're still testing it. All TDD does is move that testing effort to the front, put your tests closer to the code you are changing, improve your design, and provide you with faster feedback. As a nice by product, you also gain automated regression tests, documentation, etc. So no, I don't buy at all that doing TDD slows you down unless you aren't testing the code you write in the first place.

Anonymous said...

I don't have time to read this, I'm too busy trying to understand this piece of code.

angry birds said...

i agree :D

ticktock said...

"If some technique allowed you to half the modifying/understanding parts of the job by doubling the new-code part", isn't this a contradiction?

If one doubles the amount of new code, then by deduction, one doubles the amount of time it takes to understand that double amount of code.