Devlico.Us
CodeBetter.Com
RSS 2.0 via Feedburner
           Do you Twitter? Follow us @devlicious

Christopher Bennage

Our WPF book is now available!
follow @bennage on Twitter!
 


Solving Problems with TDD

I'm giving a talk on TDD at our local UG tonight, and under the influence of some recent posts here on devlicio.us, I just finished reworking my presentation. This post is an outline for the first half of my presentation.

The Problems

Code has entropy. That is over time it deteriorates. At least, that's the metaphor we developers like to use. What is really means is that the code becomes harder to maintain and extend as it is maintained and extended over time. Did you follow that? Our typical approach to maintaining and extending code causes the code to become fragile and rigid and thus harder to maintain and extend in the future.

There are three common difficulties that arise, maybe more, but I'm focusing on three:

  • Unchangeable Code
  • Unintelligible Code
  • Unnecessary Code

A portion of code becomes unchangeable when its deeply entwined and entangled with other portions of code that have different responsibilities. You can't change method X because we really don't know what that will do to Y and Z.

Code can become unintelligible for lots of reasons: abbreviated names, circuitous logic, enormous methods, confusion of responsibilities, use of php☺, etc.

Finally, unnecessary code is code that is not used by the system. It can be vestigial, or as often happens, it can be the result of feature anticipation. We thought this was going to be needed in the app, so...

The Solutions

There are some generally accepted solutions to these three problems.

In the case of unchangeable code, we can apply such patterns as Separation of Concerns (SoC) and the Single Responsibility Principle (SRP). For addressing unintelligible code, we have a number of techniques such as thoughtful comments, explicit naming, SRP again, etc. Finally, for unnecessary code we have the old axiom of You Ain't Gonna Need It.

Okay, so we know how to solve the problems. Or least, we know how to mediate them. So what? What does that have to do with TDD?

My proposition is this: solutions are without value unless they are applied.

Additionally, when a problem occurs over time, the solution must be applied over time.

The Analogy

I just started going to the gym. It's been about a decade since I did that, but I'm back. For the past several years however, I have been preaching to certain family members the value of exercise and healthy diet. I knew the benefits: stress reduction, longevity, improved sleeping, and just plain feeling better. However, I wasn't really doing either.

I had the problem and I believed in the solution and, in fact, I made attempts to employ the solution. Ultimately, I was unsuccessful. That is, until I committed to go to the gym three days week at a set time and with a workout buddy.

My point is this, we are human beings and despite being smart we frequently revert to doing "the easiest thing". Therefore, we ought to set up some sort of framework of methodology or discipline where the easiest thing is actually what we want to do.

Additionally, I have to keep on going to gym. For as long as I want to be fit, I will need to exercise. In the same way, for as long as I want my code to fit I will need to apply good principles.

TDD as a Discipline

I will argue that TDD is a discipline that enables the application of the solutions outlined above. Perhaps you apply those solution naturally. Perhaps you can benchmark 200lbs because of your genetic disposition. Bully for you. Go ahead and skip the rest.

Let's examine a few essentials of TDD and see if they really address the problems we outlined.

Test First

I'm an advocate of automated testing in general. However, I do think that writing your tests first yields additional value. Primarily, it helps you discover your ideal API. In other words, you can design your API up front such that it is more intuitive. More intuitive means easier to understand.

Secondly, testing first helps you identify dependencies early. You quickly discover that class X will need a Y and so you are forced to create seams in the application at the onset. This encourages SoC and SRP.

Testing Units

It took me a long time to understand the "unit" part of unit testing. The idea is that you decompose your problem into units, and deal with the problem one unit at a time. You could call this "test just one thing". Okay, well what is "one thing"? That is hard to tell and comes with experience. Nevertheless, the practice of trying to decompose a problem and identifying units leads you back to SoC and SRP again.

Just Enough Code

Another tenet of TDD is to write only enough code to pass the test. Our natural instinct is to anticipate. It is part of what we are as developer, and it is not a bad thing. However, like many strengths, it can become a weakness. By constraining ourselves to a single problem at a time we will end up with less code. It also forces us to be conscious about our anticipation and to ask if a given scenario is really necessary.

Conclusion

I know that there is much contention over the actual value of TDD as a practice, and I am not going to force it on anyone (unless I hire you and now you are warned). However, I have found it to be a useful discipline for helping me to overcome common problems and because of that I encourage it's use.



Comments

JoshG said:

Nice! As an additional point, Domain Driven Design (Eric Evans) contains many principles that address all those code issues, but in particular Unintelligible Code, as we bring the vocabulary in the code alongside the business. If they call it an SKU, we don't model a Product. It's much easier to find what has to change when the business makes a change.
# November 6, 2008 5:37 PM

Christopher Bennage said:

@JoshG thanks. Evan's book has been a big influence on my thinking as well. I was actually pitching Ubiquitous Language in the post-presentation conversations.

# November 6, 2008 9:48 PM

Dew Drop - November 7, 2008 | Alvin Ashcraft's Morning Dew said:

Pingback from  Dew Drop - November 7, 2008 | Alvin Ashcraft's Morning Dew

# November 7, 2008 8:38 AM

Emanuele DelBono said:

I talk about related argument about TDD for problem solving just yesterday in my blog. If you want you can read it here: http://blog.codiceplastico.com/?p=162 TDD save my life
# November 7, 2008 11:11 AM

Christopher Bennage said:

@Emanuele That's a good success story. Interestingly, some of the critical conversation after my presentation last night was regarding the efficiencies of solutions produced by TDD.

The criticism was that TDD can enable solutions that are wasteful. I think you nailed it though when you said "it met the customer's requirements". That's the key, what is the business value, what is the return on the time spent implementing the solution?

# November 7, 2008 11:22 AM

Emanuele DelBono said:

@Christopher The time spent to build the solution using TDD is the same if not minor to the time needed to build it without tests. And from now I have the tests that help me on every new requirements of modifications. Consider also that without tests you spend a lot of time with the debugger and in these type of application is very hard to find bug!
# November 7, 2008 12:56 PM

Arjan`s World » LINKBLOG for November 7, 2008 said:

Pingback from  Arjan`s World    » LINKBLOG for November 7, 2008

# November 7, 2008 3:31 PM

About Christopher Bennage

Christopher is a software developer and consultant at Blue Spire Consulting, a company he co-founded with Rob Eisenberg in 2006. He is a Christian, a marginal musician, and an armchair philosopher. His interests include programming, liberal education, science, truth, beauty, and a number of deceased British authors (C. S. Lewis, G. K. Chesterton, and most recently Owen Barfield.) He lives in Tallahassee, FL with his wife and three children and still prefers to play as the Night Elves in WarCraft 3. Check out Devlicio.us!

Our Sponsors

Proudly Partnered With