14

The situation: millions of lines of code, more than one hundred developers and frequent defects. We want to avoid repeating defects and we want to improve code design (who doesn't?).

Test Driven Development (first unit test, then code) sounds ideal: write a test case for each function.

But, with so much code written, how can TDD be implemented? Where do you start - with low level functions?

Or are we too late to start TDD?

2 Answers2

25

Start with Working Effectively with Legacy Code.

It's not really TDD if you're starting with legacy code - but all your coding can be TDD. As you tackle a new problem, write a test for it. If you can't, because the legacy classes are too difficult to test, then start writing tests for them, slicing off bits, and covering the bits with tests.

Refactor the Low-Hanging Fruit.

To avoid repeating defects: given an example defect, write a test that demonstrates it. It could be a relatively broad test that just simulates user activity; not yet a unit test. Make sure the test fails. Do your research; figure out why the test is failing. Now - this is important - before fixing the bug, write a unit test that demonstrates the bug. Fix the bug, and now you've got two tests, at least one of them fast, that protect you from regressions.

Carl Manaster
  • 39,912
  • 17
  • 102
  • 155
  • 4
    +1: The key here is to *not* try and comprehensively retrofit unit tests. – Richard Jul 08 '10 at 13:57
  • 1
    @Carl - nice summary. I particularly like how you've got a unit test & a system text out of the defect. – Reinstate Monica - Goodbye SE Jul 08 '10 at 14:50
  • @Richard - I'm puzzled - isn't that the opposite of what Carl is saying? – Reinstate Monica - Goodbye SE Jul 08 '10 at 14:51
  • 2
    @Mark, I think Richard and I agree; the key is "comprehensively". If you go through a legacy code base and try to cover everything before moving forward, you wind up getting nowhere (and with nothing to show for it). Tackle just the bits you need to work on; over time, your system becomes reasonably well-tested, and along the way, you're adding functionality (or at least removing bugs). – Carl Manaster Jul 08 '10 at 14:56
  • @Carl add something, also about adding tests to areas where you are adding new functioniality – Gutzofter Jul 08 '10 at 15:26
  • @Carl - yes, I understand now, thanks. And I agree - no point going through everything at once - stick to what is adding value. (After all - a study into Lean development showed that more than half the code we develop is never used!) – Reinstate Monica - Goodbye SE Jul 08 '10 at 17:17
  • 1
    @Gutzofter - definitely, otherwise you just add tests to legacy code... then your new code quickly becomes legacy code! :) – Reinstate Monica - Goodbye SE Jul 08 '10 at 17:22
2

Since Carl suggested one book I'll suggest another: Roy Osherove's Art of Unit Testing has a whole chapter on "Working with legacy code". I haven't read that chapter yet, but the first 5 chapters are excellent, and I'm looking forward to it.

orbfish
  • 7,381
  • 14
  • 58
  • 75
  • FYI I enjoyed Osherove's comparison of definitions for legacy code: "source code that relates to no-longer-supported technology" "any older application under maintenance" "code that works" "code that has no tests" (from Feathers's book) – orbfish Jul 08 '10 at 16:35
  • @Orbfish - Thanks for the tip. Perhaps when you've read it you'll come back and share some insights? – Reinstate Monica - Goodbye SE Jul 08 '10 at 17:21