74

So I am new to agile, but not test-driven development. My professors in college were all about the idea of tests then code then tests. I am not sure I understand why. From my perspective it is a lot of upfront cost that will most likely be changed as your code evolves.

This is how I imagine TDD and why it confuses me. If I were to build a house as a TDD contractor.

  1. Give me all of your specs (stories).

  2. Get approval on the specs.

  3. Break down all the specs into inspection I think I will need (see into the future).

  4. Call an inspector to look at those points and tell me right now I am failing the inspection (gee thanks).

  5. Start building the house.

  6. Call the inspector back out daily (passing 2/100).

  7. Oh shoot, there was an issue with my understanding and now I need to add 9 more inspection and change 27 of them.

  8. Call inspector passing 1/109.

  9. Damn it. Why doesn't the inspector like this one... oh I updated that method name...

  10. Build some more.

  11. UGGGGHHHH MORE CHANGES let me update the damn inspector. Oh I am failing no s**t.

  12. Am I done yet?

Okay, that may be outlandish, but I just do not see how I should know all my methods and how things will work until my code is there. 99% of the time I have to go back and update a unit test any ways and add more as I go. It just seems backwards.

What seems more appropriate is DDT or development-driven testing which is a thing the community has all but forgotten about it seems.

From my understanding DDT for a house would look like:

  1. Give me all of your specs (stories).

  2. Get approval on the specs and break them out.

  3. Start a unit (the foundation).

  4. Take notes (comments) of some tricky logic.

  5. At the end before beginning the next unit have the inspection (create a test).

  6. Fix any issue found and inspect again.

  7. Approved this unit move onto the next.

If we are all being honest doesn't that sound more human and centered on the developer and business? It seems like changes can be made faster and without the overhead TDD seems to create.

20
  • 60
    The glaring disconnect for me is the idea that you can have 100+ failing tests before writing the code that starts passing them. As @Telastyn says, there should be no more than a few failing tests at a time. "Tests then Code then Test" doesn't mean writing all of the app's tests before writing any code.
    – Eric King
    Aug 3, 2016 at 15:41
  • 33
    Metaphors are an antipattern! People will spend more time explaining why your metaphor does not fit the subject, rather than addressing your actual concern. In this case your actual concern seem to be you think you have to write all tests up front.
    – JacquesB
    Aug 3, 2016 at 16:54
  • 21
    As a side-note here, TDD is commonly used in agile projects but I think it's important to distinguish between agile project management and agile development practices. There isn't a very strong relationship between the two. You can use most agile development practices regardless of the project methodology and vice-versa. It's often forgotten that agile, at it 's core, is really about adapting your approach as needed to achieve the best result and not about a prescriptive list of things you must do. In other words, Agile != Scrum + TDD.
    – JimmyJames
    Aug 3, 2016 at 17:17
  • 35
    For the record, comparing software development to building a house is pointless. The studies have been done. The results are in. The answer is clear. You simply do not build software the same way you build a house. The. Two. Are. Different.
    – riwalk
    Aug 3, 2016 at 19:10
  • 14
    Agile is all about fast feedback loops, TDD is just one particular type of feedback loop
    – jk.
    Aug 3, 2016 at 19:22

10 Answers 10

83

One of the benefits of a TDD approach is only realised when you also do emergent design.

So in your first analogy, you wouldn't write 100 tests, as there's no possible way that you'll know what your software will look like.

You write one test. You run it. It fails. You write the smallest unit of code to make your test pass. Then you run your test again. It passes.

Now write the next test, repeating the process above.

This might seem like a wasteful approach at the very beginning, when it's obvious what your code is meant to do, but the great thing with this approach is your test coverage is always high, and the code design is cleaner this way.

As a method, it goes hand-in-hand with pair programming; one pair writes the test, the next writes the code to make it pass, then writes the next test, and so on.

I even use this approach when writing a new class; the first test is a call to initiate the class constructor. But I haven't yet written the class, so it fails. Next I write the simple, empty class, and my first test passes.

Once you get into the mindset, it is very difficult to not be in it and code the "old fashioned" way.

I'd recommend working in a good Agile environment to learn this, or reading a few good Agile books (Clean Code and Clean Coder are both very good) to better understand.

27
  • 46
    The term "Emergent Design" makes it sound like you can grow a software design by making tests pass. You can't. Aug 3, 2016 at 16:35
  • 28
    @nerdlyist: Don't forget about design, though. You still need to design software; good design doesn't just naturally emerge from red-green-refactor. TDD encourages good design, but it doesn't create it. Aug 3, 2016 at 16:36
  • 19
    @RobertHarvey, I completely disagree with your "The term "Emergent Design" makes it sound like you can grow a software design by making tests pass. You can't" statement. Having done just that on a number of occasions, I can assure you it can be done.
    – David Arno
    Aug 3, 2016 at 17:01
  • 12
    @DavidArno: Do you begin with a requirements specification in hand? How do you translate that specification into a sensible architecture? Do you reinvent it each time with tests, or do you have previous architectural principles in mind? Nobody does this in the blind; there's nothing at all magical about writing your tests first, other than it forces you to make your code more testable. Aug 3, 2016 at 17:02
  • 46
    @DavidArno I think your objection stems from not giving yourself enough credit as an experienced developer/architect. Because you already know what module X looks like intuitively, your tests will be driving your development in a good direction. An inexperienced developer with few to no intuitive notion of what a module should look like before writing the tests will build a well-tested, crappy module.
    – svidgen
    Aug 3, 2016 at 17:47
86

Software is not a house. Intuition is good, but understand that it isn't always correct.

Break down all the specs into inspection I think I will need (see into the future).

This isn't accurate. In TDD, you're describing how you want to use the code. The specs say "There must be a house, with a way to enter it." The test then says "Hey, I want to have a front door, with a knob." This is far less seeing into the future than starting with the implementation of building a doorframe, knob, keylock, etc. (or so the argument goes).

Call the inspector back out daily (passing 2/100).

This isn't correct. You're not writing tests for the house. You're writing tests for the front doorframe, then making them green. Then tests for the door being solid, making them green. You should have maybe a dozen or so tests at most broken at any given time. Usually, it's closer to two to four.

Also, the "call the inspector out" analogy implies that it takes some amount of time for the person to come out and do their job. Running unit tests for a TDD iteration should literally take a few seconds.

It seems like changes can be made faster and without the overhead TDD seem to create.

The overhead is less than you seem to be implying. A few seconds to run the tests maybe a half dozen times is inconsequential to the overall development time.

The problem of dev first is sometimes when you get to testing, you find out that there is a big problem. Like you put the bed next to the toilet and nobody wants to live there sort of problem. Things that take longer to fix than any sort of TDD overhead. Things that TDD would have caught, since TDD forces you to use your code from the start and think about how to interface with it.

My professors in college were all about the idea of Tests then Code then Test.

All that said, TDD isn't that ubiquitous. Many places still do dev first and much of the purported benefits of TDD are overblown. What's important is that you make the tests and make them good. The order that you do the work is less important.

11
  • 18
    +1 just for the last paragraph. Your house examples really highlight how silly "religiousTDD" can be. Aug 3, 2016 at 16:22
  • 23
    "What's important is that you make the tests and make them good. The order that you do the work is less important." I am a big fan of Test-Driven-Development (TDD) and advocate for it often. However writing code is messy. For more difficult, less well defined problems I typically have to write some code first before I can understand what are the requirements. Then I can write the requirements and then write the tests. Aug 3, 2016 at 16:36
  • 1
    @TrevorBoydSmith wouldn't you be writing the documentation at that point not the requirements.
    – nerdlyist
    Aug 3, 2016 at 16:58
  • 8
    Because TDD puts in the perspective of the user of the code, [in best-case] it promotes better interfaces. For example, when I call open_door I shouldn't have to pass a flag for toilet_flushed; so I don't write my test that way and therefore my code doesn't have these "rough edges." Code written entirely without sufficient regard for how it is called often has weird interfaces or assumptions/preconditions.
    – brian_o
    Aug 3, 2016 at 17:44
  • 3
    @TrevorBoydSmith to put a name to it, I've heard that called "Spike & Stabilize" and yes, it's a handy technique when discovering how to do something you don't know how to do yet.
    – RubberDuck
    Aug 5, 2016 at 16:46
13

The similarities between building a physical thing and writing software are pretty minimal.

That said, there's one massive distinction worth pointing out:

There's a difference between "authoring a test" and "executing a test."

In the example of building a house, the requirements and tests do precede the physical buildout. And portions of the test suite are run continuously -- by multiple agents even! When the builder picks up a 2x4, he immediately and automatically "tests" the unit against his notion of "what a sound 2x4 looks like." He doesn't author requirements after he picks it up; he runs pre-existent checks on it.

Likewise for an assembled wall, an electrical box, the plumbing, etc -- the tests/requirements already exist; they get run implicitly and automatically by the trained eyes of everyone on the job continuously. Another suite of pre-existent tests are executed when the inspector visits. If the units were not built to pass those pre-existent test, they fail.

And likewise for the structure as a whole. The plans pre-exist the buildout. At every step of the way, the engineers are working towards a pre-existent set of conditions that the structure will ultimately be tested against when the buildout is complete.

That said, not every physical project needs to be preceded by a huge suite of tests. If you go to your workshop and start putting wood together for a toybox or something, letting your intuition and creativity guide you, that's not rigorous TDD woodworking. In that case, you're basically relying on the physical laws of the medium and your rough expectations to validate the work (i.e., "if it compiles and it works, it's good!").

And that's OK. Not everything needs to be preceded by rigorous tests.

tl;dr

Even though construction != writing software: Construction does operate in a test-driven fashion. The "passing" conditions for every unit do precede their buildout.

Don't conflate "executing tests" with "writing tests."

Not everything needs to be TDD.

9
  • I get code != physical its an analogy. But this actually clears up a little more for me. As my other comment point out I am wondering if this create the test first hinders the desire to go back and make larger changes now?
    – nerdlyist
    Aug 3, 2016 at 16:10
  • @nerdlyist In a way, yes. But, if your tests are checking the "right" things, it's a "hinderance" you want.
    – svidgen
    Aug 3, 2016 at 16:14
  • 4
    Going back to the house analogy: If your client suddenly wants to swap in a different style of door, and it doesn't have the same dimensions, requirements around the door and opening dimensions will change, and the work require to change those "tests" should mirror the work required to make the implementation change. But, there are a lot of tests that won't change: The door must open and close, lock, and be P% airtight in the opening when closed, etc... Lots of tests that don't change that "hinder" physical changes appropriately.
    – svidgen
    Aug 3, 2016 at 16:21
  • 1
    If I could +1 again I would that last bit is helpful to consider. Not everything needs a test. Also, rereading it made me think maybe I am fusing TDD unit tests with integration and regression testing. The workers automatically testing is units the inspector is integration and regression testing is done when making larger changes.
    – nerdlyist
    Aug 3, 2016 at 16:53
  • 1
    @nerdlyist Integration and regression tests can be done test-first too. Doing so doesn't quite fit the "TDD dogmatists" development cycle, but the result is largely the same: You end up with testable code, with minimal extraneous code, and tests that actually validate what they claim to. Testing after you write the code can make accomplishing any or all of those those things a bit harder. Not at all impossible, but potentially more difficult.
    – svidgen
    Aug 3, 2016 at 18:02
11

You have fallen into the trap of believing the nonsense idea that writing software is analogous to building a house. It isn't. It's more analogous to creating the architects drawings and the structural engineers calculations.

Now with real houses, the architect creates those plans up front. Then you call in the builders, who start building, run into problems, have to amend things, get building control in, who want changes, etc. Then at the end, the architect comes back and charges you more to update his drawings to reflect what happened. This is a crappy way of doing things, but houses take a long time to build and are expensive, so it's the only practical way.

Things are better for software engineering. The equivalent to the building the house is having the compiler turn your code into an compiled unit of some sort (library, app, web app etc). It's very fast and cheap to do this hundreds of times a day. As a result, it makes no sense to repeatedly rebuild the house as you add features, and only call in the inspector (QA) at the end to test it. Instead, if you automate those checks, you can have the inspector re-inspect everything every time you rebuild.

Whether you follow strict TDD, or a more test-orientated approach of writing some code, then some tests, doesn't really matter. I prefer the first approach, others the latter. Pick the one that suits you. The important thing is that you create those checks as you go along. They help later when you want to change code around by warning you of breaks in functionality elsewhere when you change something.

3
  • 1
    I see you've dealt with Building Control then... :)
    – Jules
    Aug 3, 2016 at 16:54
  • 5
    "This is a crappy way of doing things, but houses take a long time to build and are expensive, so it's the only practical way.": It is true that in software you can rebuild very quickly, but if you make a completely wrong decision at the beginning you may need a big rewrite later. Incremental design does not always catch this kind of problems: you move in small steps until you find yourself in a cul-de sac and you have to go back. There is not silver bullet.
    – Giorgio
    Aug 3, 2016 at 19:57
  • 2
    @Giorgio -- big rewrites happen because single decisions are reflected in many places in the code. When the decision changes, then the code changes in a lot of places. Continuous refactoring mitigates this problem, by squeezing out duplication and limiting the amount of code reflecting a single decision. Good test coverage supports continuous refactoring. Aug 5, 2016 at 1:36
7

First and foremost the upfront cost is not as high as you think it is. Yes, you spend more time addressing testing than if you do no testing. But if you do a "test after" method what are you really wasting? Let's say TDD takes 10 hours, and DDT takes 6 hours. Your "extra" upfront costs are only 4 hours. Now if you apply a code metric or requirement like 90% coverage, then your TDD and DDT become even closer in costs.

You will write less buggy code with TDD. Even if it's just because you have spelled out the requirements as a test, at the end of the day you can prove that your code is doing exactly what you wanted it to do. Now maybe you wanted it to do the wrong thing, but that's not a bug that's a change request. This is important. It's easier to "sell" a product that is working, but could work differently/better, then it is to sell a product that is perceived as not working. With TDD it's literally impossible to pass the test and write not working code. It is possible that you didn't understand the requirements, and that you wrote the wrong, but working code.

TDD is better the older the code base gets. Try refactoring without a test suite, or with a poorly implemented one. Even a simple change can introduce bugs. Having a test suite with good coverage ensures that as the product evolves it continues to function as it should. It also helps to highlight conflicting business rules (that happen over longer periods).

You don't know it doesn't work. Without a test suite you don't know if your code is working the way you think it is or if it just appears to be working.

var foo = function(in) {
    if(in == 0) {
      return true
    }
}

Now all over your application you call if(foo()){ doStuff() } What happens when I fix foo?

var foo = function(in) {
    if(in === 0) {
      return true
    }
}

You should be refactoring and DRYing your tests too. A good test suite is not hard to maintain. With well written atomic tests, I've rarely had to go back and change more than 1-2 of them at a time. When there have been larger changes to the test suite it's a giant red flag that something is not right.

I just do not see how I should know all my methods and how things will work until my code is there.

Well, you're not supposed to. You're supposed to write a test that tests that some unit of work is done. If you feel like you're testing things that you can't possibly know about then you're thinking too big, OR testing is too small.

For example, you need to know that a door closes, and locks. I would test door.close() and door.lock() and that door.open() returns false when the door is locked. That is it. If your tests are door.lock() sets a flag in the database. Then you're testing too small. The test doesn't need to know how door.lock() works, just that it does.

Now if you're writing a test that says house.isSecure() returns true when all doors and windows are locked. Without looking at doors or windows first then you're thinking too big.

Finally, You may be looking at too big a unit of work. When you get your list of requirements, you should organize them so you're working on the smallest unit. Write the test for just that unit, then the code, then rinse and repeat.

In essence, your understanding (the list) of how TDD should work is off. You should never have 2/100 passing. You should have 1/1 passing, then 2/2 passing, then 3/3 passing, then 4/4 passing, and so on.

A revised list for you

  1. Get all the specifications
  2. Pick one specification
  3. Test it
  4. Code it
  5. Test it
  6. If tests pass move on to 7 else go to 4
  7. If you have done all the specs, go to 8 else go to 2
  8. Review the specifications with the consumer, and add new specifications where needed. If done correctly you shouldn't have to change any tests at all. Just add new ones. Sometimes requirements gathering can fall apart and you have to add tests that conflict with earlier tests, but you should rarely have to change tests.
3
  • 2
    I like this answer because it highlights the real advantages of TDD - making legacy codebases manageable. Many people who have only worked on the greenfield phase of a project don't see the benefit of TDD because it looks like it's just extra work. It really pays off when you have to upgrade and maintain an existing codebase. I wish that in school they would give you a project, then as soon as you get it working request a bunch of feature changes. That would more closely mirror reality and demonstrate the value of TDD.
    – thomij
    Aug 3, 2016 at 21:24
  • 1
    I like this answer also. Note that we tend to forget just how much time we actually spend manually executing tests: edit, compile, step through to manually debug, repeat. TDD automates much of this. Aug 4, 2016 at 1:03
  • The thing that jumps out at me here is that it's important to note that when you write a unit test in TDD you're not writing a test for a piece of the client functional spec, you're writing a test for the behaviour of the unit as you - a programmer - have defined it in your brain, i.e. "this class should raise an event when X happens, let's write a test for that." This vague "your tests are your spec!" rhetoric is great when you already get TDD but to someone out of the loop it raises more questions than it answers.
    – Ant P
    Aug 4, 2016 at 8:37
4

There are some keys that I feel the other answers are missing.

Three Advantages

First, the cost of error and cost of change is so incredibly different between software and a house that some rules may not apply. For example, the cost of testing a physical structure is so high that you need a high degree of confidence of it working so as not to waste testing. With software, if you can run a suite of unit tests in 1 - 5 seconds, then we have different options at our disposal.

Secondly, the purpose of executing a test that you expect to fail before writing the code-under-test is to verify the test itself. Sure it can seem silly or wasteful. But I've seen enough unit tests written in a way that will always pass, even when the code-under-test is broken. That can easily happen when you write the code-under-test, test it manually, then write the unit test. If you write a unit test, see it fail, then when you write the code needed to make it pass, and it passes, you know your test is sound. If the code-under-test regresses, there is a reasonable chance your unit test will catch it.

A third advantage to TDD, not often mentioned, is that the resulting code size and complexity is often an order of magnitude smaller. I have always prided myself on preferring simple and concise code. Until I started practicing TDD. TDD showed me that what I would have done prior would be excessive code. Why does this happen? Because you write a test, then write code to make the test pass. When the test passes, you are done with it. If you are in this mind set, it is difficult to accidentally write "extra" code.

(Extra code has been a problem I have observed in a product I used to work on. Severe problems coming from code that nobody asked for, but some developer thought it would be cool.)

Cost Analysis

So in some ways, you are right. We could not get away with this strategy when building a house. It would be too expensive. But software isn't a house. Software is cheap.

An analogy with a house is the labor of assembling the house versus a software compiler.

In a non-TDD world, developers still iterate. We follow a code -> compile -> run -> test cycle. We're already in a model that deviates substantially from building a house. If your construction people build a door frame, then build a door, then have to rebuild the frame because the door is too big for it, you'll have a cost problem. Thus, you spend more time up-front to ensure you get everything perfect. In programming, most projects can be compiled in seconds or minutes, so it doesn't matter if something is imperfect early on. The cost of thinking trivial matters through ahead of time typically outweighs the cost of recompiling. Thus, we recompile all the time.

TDD is the same principle, just rotated so the test goes up front. If the testing can be made super cheap (so it all runs in seconds), then the cost of thinking through the big picture, perfect, overall solution in a single big-bang coding iteration outweighs the cost of refactoring.

Except...

There are some things in programming where these arguments don't hold up. That is the purpose of architecture. Identify and plan up-front concerns that will be more expensive to change later. For example, you wouldn't pick a database on the fly without thinking about your needs, start building, and simply argue that you can change it later. You need to think it through.

1
  • 1
    Great point on verifying the test! Also: when building a house, it's HARD to move a wall (and this leaves scars). With software, moving code around is relatively easy - provided you have automated test to catch any unintended changes. Aug 4, 2016 at 1:01
4

I used to wonder about this a lot until I did a few projects of TDD. There is a very succinct and comprehensive explanation that popped to me while I did this:

When you write code you have to have some way of making sure the code does something meaningful. So you test your code. You can do ad hoc testing. However, testing works better if you think about how to test before you start doing things. So you design the test strategy before you go to testing.

Now since you are thinking about your testing strategy you might as well automate, at least a part of it... And behold you have some level of TDD. The fact that you write code till you pass the test is just normal. That's what you do anyway, write code till it works. It's just now easy to blast the tests.

For reasons beyond scope you don't write the entire thing in one go. So you don't design the tests in one go either. But basically that's what it is. Just better planning of testing, you don't always write test up front. Sometimes you add more as you progress and find bugs you didn't anticipate or make the test more robust later. And sometimes you may find yourself not designing tests, but find manual testing laborous so you do the tests later.

So TDD is just an extreme way at looking at how you validate your work.

4

While this question already has an accepted answer I believe I have something to add, coming from a no-written-test style of design (all tests performed manually by "testers" following a test procedure) to TDD. These are just my personal observations, though I believe they're fairly universal.

When you're writing something new, something you've never done before, there is no significant difference between TDD and not doing TDD.

Generally what you'd do is write a small piece of code to explore an idea then add some hardcoded bits for "testing" and then compile and/or execute it. If it works you'd delete the hardcoded stuff and generalise the code by adding parameters, instance variables etc.

Think about it. That's exactly the same amount of work as TDD. The only difference is in TDD you'd write the "testing" bits separately in another file and not delete them at the end. In TDD you keep your testing code.

Of course, TDD being slightly more organised means that there is a bit more work figuring out how to separate the testing bits of code from your real code. But if you've written unit tests before you'll learn how to modularise your code for testing.

2

Why is agile all about the test-driven development (TDD) and not development-driven test (DDT)?

Just chirping in here because I find that the question suggests a fact ("agile is all about TDD") which I find rather objectionable. All answers seem to take this fact as granted. They are good answers if you assume agile is primarily about TDD (a.k.a., testing on the unit level).

https://en.wikipedia.org/wiki/Agile_software_development#Agile_methods lists a good dozen or more different development models.

I'd offer especially Behaviour Driven Development and Feature Driven Development as food for thought. Completely different beasts which also can lead to all the benefits of basic TDD but are a far cry from a simple red-green-refactor cycle.

So my answer ist:

  • "DDT" (a.k.a., writing tests after or "on top" of the implementation) does not work for real-life-reasons; as soon as you get time or money pressure, the tests go out of the window; and just having tests for the benefit of having tests is rather meh anyways, IMO.
  • Agile is not all about test-driven development (TDD) if you interpret that term as basically meaning "unit tests for all building blocks/classes" (which, at least according to Wikipedia, is the case). TDD is just one possibility of doing agile development.
  • There are other methods, like BDD or FDD, which do a full-stack approach. You still write your scenarios up front, you still have a red-green-refactor cycle, and you still only implement until your scenarios are green, but your "tests" by definition excercise the whole software (by acting like user interaction) and never only one single unit.

I'd rather have an application with complete BDD/FDD coverage and no unit tests than one with complete unit test coverage and no full-stack tests.

(TDD has its place of course, for example in APIs, but that's not what we are talking about here.)

Again, I'm not trying to downtalk all other answers here, just pointing out that the question is formulated rather narrow, and the field has much more to offer.

3
  • I knew of the other but at the time writingthis ddt just seemed to make more sense. Care to elaborate on why TDD is better for API? How would using it on say a web client with MVC differ?
    – nerdlyist
    Aug 4, 2016 at 16:58
  • 1
    In APIs it is hugely important that they follow a very detailed contract; each method call must behave very predictable for the users (which are other programs) to use it correctly. This is where unit testing really shines. OTOH, in an application, it is most important for the features your humans users need to work as intended. Sure, your "internals" better be correct as well, but it is more important to have a good coverage of "end to end" functionality (i.e., from the UI right into the DB and back) instead of testing each individual method (which the human end users won't see anyways).
    – AnoE
    Aug 4, 2016 at 21:23
  • Of course, all is in different degrees here - it may make sense to have a smattering of unit tests here as well if you should have very complicated methods/classes somewhere (for example: calculating distances between geocoordinates); but the bulk (e.g., in business applications) is the overall workflow.
    – AnoE
    Aug 4, 2016 at 21:24
0

Although you don't see it written this way often, much of the reasoning behind agile is that re-writing code is better than writing it well the first time. Every time you re-write code you improve the code and improve yourself. Getting it "Right" the first time tends to be slower and more brittle.

The house analogy isn't all that bad, but you have to think about how long we've known about house building vs how long we've known about software engineering--also the complexity of software engineering is closer to building a long bridge or 20 story tower than a house. We should also consider that with new languages and tools being built it's like every builder wanted to build the building with completely different shapes, sizes and materials. Complete chaos.

However, inspecting is not a good analogy to code testing. In software we aren't even to the point where we HAVE decent inspectors (Except your peers of various skill levels). We also don't have regulations to inspect against except, perhaps, some mostly-arbitrary "coding standards" (which is more like testing the color of your paint and your lawn layout than the structure).

Test-first is more like you build a wall then you apply some pressure to it to ensure stability before lifting it and placing it on your house. It's like measuring the window to ensure it will fit into the hole you left before trying to place it.

If you had to build a series of bridges without our centuries of previous architecture knowledge, patterns, regulations and math that we currently have to prove our bridges will work before we build them, you'd probably be testing and rebuilding your bridges a LOT.

Finally a non-analogy point--with software every time you are allowed to re-write a section of your code you improve both your code and your skill significantly. Take every chance you can to re-write code. TDD can be a great excuse.

Not the answer you're looking for? Browse other questions tagged or ask your own question.