Uncategorized

Test-Driven Development – Part 1

I’ve found Test-Driven Development (TDD) to be pretty much revolutionary in my own software development efforts. Yet I find it is often very poorly explained, and explanations focus too much on the technical aspects of the technique, instead of the ‘philosophy’ or principle behind it. I place a lot more value on principles and philosophies over practices, since often practices can’t be implemented exactly as described, whereas there can still be a takeaway from the philosophy.

In my opinion, TDD is unfortunately named, since it confuses people. The intent of TDD really has nothing to do with testing. Testing is merely the mechanism through which one gains the primary benefits.

My primary TDD mantra is ‘TDD’s not about testing, its about specification’. In my interpretation, TDD has 2 primary benefits:

  1. It forces you to specify the problem you’re trying to solve very narrowly, and very explicitly.
  2. It promotes a loosely-coupled, modular design, since testable designs are generally loosely-coupled by nature.

Most people will state that the aim of TDD is a large proportion of test coverage and automated regression tests. This is not true. Both of these goals are readily achievable without doing test-first TDD; i.e. they can be easily achieved by writing tests after writing code. Test coverage and automated regression tests are very nice by-products of TDD (when its done correctly), but to my mind they are certainly not the primary benefit nor aim of TDD.

I’d like to explain the first of these primary benefits of  TDD with a non-software related, everyday (somewhat contrived) example. (I’ll need to think of another contrived example to explain the second.) The reason for a non-software related example is I want you to be able to explain the concept to a non-technical person, like your mother or your CEO (or maybe even your team lead 😛 ).

Imagine that I get a crazy idea in my head that I want to become more ‘eco friendly’ in my day-to-day life, and contribute less to global warming. My statement of intent, or vision may be something like ‘I want to make a personal contribution to the lessening of global warming.’ This statement makes one warm and fuzzy, but on its own, its quite difficult to implement. I call this my strategy.

Good management textbooks and courses will tell you one has to implement strategy through strategic objectives. So in order to implement my strategy of being more eco friendly, I come up with the ‘strategic objective’ of reducing my daily carbon emissions.

After some thought about this objective being a little ‘hand-wavy’ and hard to measure, I can refine it by phrasing it as ‘I will decrease my daily commute petrol usage by 10% by the end of this month’. The objective now is measurable, and has a concrete time frame. I have a concrete goal towards which I can work, and measure daily progress (my car has a trip computer which indicates current and average fuel consumption). I can easily see whether I have met (or exceeded) this goal next time I fill up my car.

I have progressed from the warm-and-fuzzy but somewhat hand-wavy statement of ‘I want to do my bit to decrease global warming’ to something tangible to which I can work towards. I know when I have achieved my goal, without a shadow of a doubt, and I can prove it. I can now brag to my friends about how wonderful I am, and maybe I can even get a tax break or something.

Now that the example is concluded, I’d like to point out some things about strategic objectives that I learned at university. Strategic objectives (SOs) must be phrased so that they are measurable, and have a time frame. It says only what must be achieved, but not how. The fact that its measurable means that you know when its done.  You don’t know how to do it (that comes later, at the tactical and operations levels), but you know when its achieved.

If an SO is not measurable, it is considered bad and must be rephrased and rethough. This is akin to designing the SO and implicitly the fulfilment of the SO.

So, an SO is a statement of intent, its a description of a requirement. In x months’ time, we must have sold y units. The fact that it is measurable means  you know when you’re done, but you can also manage it, analyse it, report on it etc. If its not measurable, rephrase it.

If an SO is not a strong enough statement of intent,will those members at the tactical and operations levels  – who don’t operate at all at the strategic level – be able to interpret it and implement it?

If an SO is not measurable, how can you prove to your board that the strategy has been fulfilled?

The testing aspect of this example is simply asking oneself: ‘its now x months down the line, have I sold y units? Its a yes or no answer. Its comparing the actual outcome to the desired outcome.

This example is not test oriented at all. We don’t create strategic objectives in order to run a somewhat trivial test at the end of the prescribed period. The SO exists as a direction, as a statement of intent, as a specification of the where the business needs to be at some point. Sure the measurment aspect is a big part of the SO, but we don’t write SOs for the sake of measuring them.

TDD is no different. The point of TDD is not to write tests. TDD uses the test as a mechanism for feedback. Are we done yet? You can know if you’re done only you know where you’re supposed to be. I don’t know if I’ve made a meaningful contribution to decreasing my emissions until I’m at the petrol pump. A company doesn’t know if its fulfiled its strategy until it can prove it sold x units by a certain date.

TDD forces you to make that end-goal explicit, and to start with that end-goal. Businesses don’t write down strategic sales targets after they’ve made the sales. They start with the target, then put measures in place to achieve that target. TDD in software development is the same.

Start with your end-goal, stated in the form of tests, usually unit tests. You then know where you going. You can then start to decide how you’re going to get there.

To use another example, developing without TDD is like driving around with a sat-nav device, ending up somewhere, and post-haste setting that point as your destination.

Unfortunately, the examples I’ve discussed here don’t really explain the second primary goal of TDD, a loosely-coupled design. I will try think of an example for this benefit and blog it.

Some more notes:

1: As mentioned, businesses start with strategy and strategic objectives, and implement through tactical and operational implementations. They don’t run for a couple of months then retrofit their strategy to where they land up. One can state that ‘its more important to know where you’re going, than how to get there’.

One might also be able to state that ‘its more important to know where you’re going, than actually getting there’. This statement arises from the following: according to agile principles, one delivers the highest value tasks first. Since TDD tests are written before the code to satisfy them, one might argue that the test is more important than the code written to pass the test.

This can be reinforced by considering software product maintenance. The majority of these efforts is spent in understanding the code written by other developers. TDD tests can be a shortcut to understanding the intent of the code.

Also, as businesses changed, an application’s code is likely to change too (as should the TDD tests). Essentially, the intent of the code (conveyed by the test) is likely to outlive the code itself.

2: Behaviour-Driven Design (BDD) is an evolution of TDD, which basically has the notion of ‘executable specifications’ as its holy grail. Instead of developers having to interpret the end-goal presented to them in some type of specification and translating that into code, the customer of the software (business) should be able to codify their specifications in a language as close to their own natural language which can be executed as code.

3: Good TDD tests should be statements of intent. This is often what is meant as ‘tests documenting the code’.

3 thoughts on “Test-Driven Development – Part 1

  1. Well done. Great insight into the mechanics of defining and measuring objectives, and digging beyond the surface of understated TDD.

    For me, I still struggle with the idea that these objectives have already been formulated, and these approaches only serve to measure their success, however strict.

    The evolution of BDD narrows this gap in terms of scenario specifications, but its seems that when TDD comes in, the hard part is done. You have already decided that saving fuel is the way to go. Why didn’t we choose to recycle old news papers instead? Or both?

    That leads me to believe that TDD is more about keeping a leash on dev teams, and a way to make future ideas and implementation economical. Can I afford foregoing these niceties to save time and adoption costs, or am I missing the picture and can’t afford not to?

    I look forward to your thoughts on loosely coupled systems, where the separation of concerns lends itself to the higher level of specification and decision making.

    Keep Blogging.

    1. Shew, you raise a few points in your comment. I’ll try address them all.

      “For me, I still struggle with the idea that these objectives have already been formulated, and these approaches only serve to measure their success, however strict.”

      To a degree, yes. The requirement has been specified by those upstream (hopefully as a user story). I guess I didn’t make it clear what level I was talking about. In my opinion, although the requirement is provided ‘from up on high’, the TDD specification of the requirement is purely technical, and exists in the developer space only. BDD for example tries to bridge this gap.

      The TDD tests should be formulated to support conditions of acceptance, which should be specified as part of the requirement (its not the developer’s responsibility to specify conditions of acceptance, he doesn’t understand the business domain).

      There’s also an issue of granularity of tests. BDD tests would typically exists at a feature level, whereas TDD tests would typically (in my opinion) exist at the class or method level (TDD tests test behaviour, which is manifest in methods).

      “That leads me to believe that TDD is more about keeping a leash on dev teams, and a way to make future ideas and implementation economical.”
      This is where the primary benefit of making the design decoupled comes in.

  2. Your description of TDD shows real great insight into its core intent.

    Using the metaphor of “becoming more eco-friendly” with an action of “reducing carbon emissions” helps drive the point home quite nicely of elevating testing to a outside-in view.

    Also, all objectives should typically have the quality of SMART where:

    S – specific
    M – measurable
    A – attainable
    R – realisable
    T – timely

    giving it the ability to identified, measured, envisioned, and quantified over time.

Leave a reply to Ahmed Omarjee Cancel reply