As you know from the previous blog, I’m following along the openSAP course Writing Testable Code for ABAP. We’ve just completed the week 2 and, sorry to say, it was a bit disappointing because of yet another “number in, number out” example. It felt like one of those “filler” episodes in the TV series that suddenly goes on to explore a subplot while a star actor goes to rehab.
We did learn about test-driven development (TDD) principle, which ABAP Unit Test is meant to support. The main postulate of TDD is that you create the tests even before you write any “real” code. So, you start with a test like “given X, Y is expected” and, naturally, it fails immediately because (duh) the code that is supposed to transform X into Y have not even been written yet. If to you this looks on a scale from silly to idiotic and bordering on insane, you are not alone. But any TDD apostle will tell you that this is not at all silly and, quite the opposite, a very effective methodology if only you fully embrace it and change forever the way you think about software development.
Fair enough. I’m not a stranger to the silly routines. For example, I always fasten the seatbelt in the car. No exceptions. Even if I only need to move the car out of the driveway, I still use the seatbelt. There is a fact-based evidence that seatbelts prevent serious injuries and death in car accidents. Even though the risk of having an accident while driving 5 meters at pedestrian speed is rather low, use of seatbelt simply become a reflex for me. Not to mention, it is the law in the state of North Carolina.
As any reasonable person, I like when there is factual evidence. But for some reason the discussions of TDD virtues seem to me less like scientists arguing about two different theories and more like the famous “electrolytes” dialogue in Idiocracy.
In this movie, humanity has become really dumb in future and it is visited by a time traveler, an average Joe from our times. The future humans have been using the drink called Brawndo (“The Thirst Mutilator”) instead of plain water to water the crops because the manufacturer told them that it “has the electrolytes” and that’s what plants need. The following dialogue occurs when average Joe suggests to use water:
“Joe: Okay, look. […] So why don’t we just try it, okay, and not worry about what plants crave?
Attorney General: Brawndo’s got what plants crave.
Secretary of Energy: Yeah, it’s got electrolytes.
Joe: What are electrolytes? Do you even know?
Secretary of State: It’s what they use to make Brawndo.
Joe: Yeah, but why do they use them to make Brawndo?
Secretary of Defense: ‘Cause Brawndo’s got electrolytes.”
There is no shortage of information how awesome TDD is. Honestly, I never even asked for it and somehow already know. Because this week has been slow and low at the openSAP camp, I went to Google to find the other side of story, i.e. the TDD criticism. Great thing about the Internet is you can easily find many facts and people who support your opinion. And then you can turn around and find just as many facts and people who support a completely opposite. 🙂
One of the top results in my Google search was a StackExchange question about the TDD disadvantages and it offers a great answer:
“Test-first assumes you are writing code that is:
– testable in a unit-test manner
– that what you are developing has an obvious approach and will not require extensive prototyping or experimentation
– that you will not need to refactor too heavily or that you have the time to repeatedly rewrite hundreds or thousands of test cases
– nothing is sealed
– everything is modular
– everything is injectable or mockable
– that your organization places a high enough value on low-defects to justify the resource sink
– that there is something of benefit to test at a unit test level
If your project does not meet those requirements you will have difficulty. The promoters of TDD have no good answers to this other to suggest that you redesign your product to better fall within those lines. There are situations where that is impossible or undesirable.”
Prototyping was mentioned in many other posts as an example of when TDD doesn’t seem to make sense. When met with such arguments, “the TDD zealots” quickly retract to “then don’t use TDD” but this starts sending the mixed messages.
Another StackExchange question on this subject might have as well been written by me: a solo developer struggling with the practical use cases.
The two most upvoted answers there (the second one being from Uncle Bob himself) do not really answer the question and go along the familiar lines of “how could you NOT love TDD?”. But slightly less popular answers offer more balanced and practical perspective. For example, there is an interesting comparison with gambling:
“Creating a test is a bet that the cost of bugs in a unit occurring and not catching them with that test (now, and during all future code revisions) is greater than the cost of developing the test. Those test development costs include things like payroll for added test engineering, added time-to-market, lost opportunity costs from not coding other stuff, etc.
Like any bet, sometimes you win, sometimes you lose. […]
Some types of bugs might be so unlikely to be made, or to make it out of any early sanity testing, as to be statistically not worth the time to create additional specific tests. But sometimes the cost of a bug is so great (medical, nuclear, etc.) that a company must take a losing bet (similar to buying insurance). Many apps do not have such a high failure cost, and thus don’t need the higher uneconomical insurance coverage. Others do.”
Development ROI is an important factor. Going back to my seatbelt example, what if it didn’t take just 2 seconds to fasten the seatbelt? What if it took 5 minutes? In that case you’d probably start skipping it when simply moving the car from one parking lot to another. (Side note: if you really want to enforce something it needs to be as effortless as possible. I guess that’s what ABAP Unit Test is meant to do for TDD in the SAP world. Not sure it succeeds.)
There are many other interesting articles offering different perspectives on TDD. This one examines it as a psychological phenomenon: is TDD a form of OCD (obsessive-compulsive disorder)? And this one analyzes the challenges of presenting TDD to the beginner developers.
If you have time to spend, you’ll easily find a full range of posts on how “TDD is the best thing that ever happened to software development”, “TDD is dead”, “TDD is not dead”, “TDD should die”, “why <something> is much better than TDD”. There is even a blog with peculiar title Almost, but not quite, Entirely Unlike TDD (by the way, it explains “code smell” term that confused the heck out of me in the week 1 of the course).
The latter blog features the quote “TDD is a learned skill…” But what if TDD is rather a tool? While discussing the openSAP course with the teammates, I mentioned that it reminds me of some recipes that involve melting chocolate. They start with long instructions on how to build a double boiler. To do that, you need a sturdy pan with just the right amount of boiling water and a heat-proof bowl that is just the right size to sit on top of the pan without touching the water. Then you slowly mix and melt chocolate in that bowl for undisclosed amount of time.
These are fine instructions if you are a kitchen maid in 1870s. In this century, we have microwave ovens that can melt the whole chocolate bar in 1 minute using just one bowl. Many professionals would claim that the double boiler method allows for better temperature control and avoids scorching the chocolate accidentally. Good point. From my experience though, as long as you check and stir the chocolate frequently, it’s hard to burn it and when it’s baked into brownies, not a single person can tell that I used a microwave.
Like with any tools, the real skill comes to finding the balance and best use of them. This is where “TDD or bust” is just as unreasonable as “we’ll just keep doing what we’ve been doing for the last 20 years the same way”. I feel another answer from StackExchange sums this up nicely:
“The biggest drawback I’ve seen is not with TDD itself but with practitioners. They take a dogmatic and zealot approach where everything must be tested. Sometimes (many times that is), that is not necessary. […]
A good engineer finds trade-offs and applies the right balance of when/where/how to apply test-first. Also, if you find yourself constantly spending much more time developing tests instead of actual code (by a factor of 2-3 or more), you are in trouble.
In other words, be pragmatic and reasonable with TDD (or anything in software development for that matter.)”
Amen to that.
P.S. There was sort of a hidden challenge in the previous blog and I’m surprised no one noticed that a slide about debugging featured the picture of a dragonfly. It’s not a bug and is, in fact, a beneficial insect because they are the natural enemy of mosquitoes. But I guess it’s a perfect allegory for TDD. 🙂
(Image source: Wikimedia Commons)