There’s an interesting thread going on in the Yahoo TDD group started by Jay Flowers about introducing TDD to a large organization, and an interesting spawned thread about TDD without OO. I made a tangential post last week that’s referenced – How much design before unit testing, and how much design knowledge before TDD?
I’m not necessarily the best person to ask about this because my experiences haven’t been typical. More than anything else, the critical factor is an organization or team of developers that is open and willing to doing TDD. Management support would be nice, but in the end it’s the developers who are going to make it succeed or fail. I had it relatively easy because my introduction to TDD came as a consultant with ThoughtWorks, one of the leaders of all things Agile. A key factor for me joining my present employer was their desire to adopt Agile processes. The support for TDD was there from day one, at least from development management. Add in a group of developers who all believe in TDD, or at least willing to give it a try, and you can achieve a pretty smooth adoption rate.
Coming in and laying down the law, “You will do TDD starting now!” probably isn’t going to fly. Actually, I’ll say it more strongly — TDD won’t take without some kind of consensus from the developers.
You might not have it that easy, but then again, the wealth of free information and TDD lore that’s available on the web and blogosphere dwarfs the information that was available way back in 2003 when I was writing hopelessly tangled tests.
A team bootstrapping itself will probably struggle at first. For best results, you’re going to have to get some coaching to the TDD newbies. Most people, myself included, struggle at first with TDD when you start encountering nontrivial enterprise development tasks like persistence and integration. Brown bag sessions (especially if the team takes turns presenting) and training will help, but for my money, you want a sprinkling of people who can coach TDD and get them paired up with the folks who are new to TDD. If you don’t have anybody who can coach, it might be worth the cost of bringing in an external TDD coach to work hand in hand with the team members. Regardless of the experience level that your team has, I’d very strongly consider adopting pair programming as a way to disseminate knowledge. One of the advantages of pairing is the propagation of tricks — IDE shortcuts, ReSharper features, and TDD idioms for testing code. For example, I learned how to use NMock for unit testing with external dependencies by pairing with someone who was familiar with NMock. As a direct result, I immediately got faster. Even part time pairing will help.
Going in to TDD, you’re going to want an open-minded attitude about the way you code. In other words, start with an assumption that you will have to change the way you code and design software. I certainly wouldn’t say that TDD is the silver bullet for perfect software designs, it’s more like a white glove test that finds all of the tightly coupled dirt and gunk in your design.
Learn Unit Testing First, or Go Straight to TDD
Jay Flowers talks about two camps in his organization, one camp who wants to concentrate on doing unit testing first before moving to TDD while a second group wants to go directly to TDD. My vote is actually on going straight to TDD. Most of the challenge in writing automated unit tests is writing code that can be tested. Putting an emphasis on writing the unit tests first keeps testability (and hence a strong focus on loose coupling) in the forefront of a developer’s mind. Retrofitting unit tests to existing code is hard, period.
OOP as a prerequisite for TDD
On the Yahoo thread I linked to, several folks are challenging my opinion that TDD requires OOP by sharing positive experiences of doing TDD and Continuous Integration with VB6. I’ll take their word for it, but doing TDD with VB6 reminds me of seeing an elephant fly in Dumbo. You can write almost-OO code with VB6 (minus true inheritance), but as I recall you fight against the language quite a bit. VB6 wants to be procedural.
Let’s pretend functional programming doesn’t exist (because I don’t know enough about it anyway) and that SOA is largely an orthogonal concept to OOP. I’m on record as saying that a solid understanding of Object Oriented Programming is essential for succeeding with TDD on nontrivial applications. I wouldn’t hesitate to recommend TDD to someone who is new to OOP, but sooner or later that same newbie will be held back if they’re not a strong OOP developer. To defend that assertion, let’s go back to some first causes:
- I want to be able to quickly write small unit tests that can be coded in rapid order to maintain flow
- External dependencies can make unit testing much more difficult and/or laborious, not to mention slower
The two primary ways to create testable code is to be religious in assigning responsibilities to different parts of your code and isolating external dependencies behind swappable interfaces. In both cases I think OOP has a far better story than purely procedural programming. OOP allows you to use techniques like Dependency Injection and Mock objects to replace external dependencies with fake objects that behave in a known way. Using best OO practices leads to code that is cohesive and loose coupling, exactly the kind of code that is easier to unit test. What can you do with procedural programming? Function pointers? You’re certainly not going to be able to do the same kind of interaction testing we use with OOP, and that’s an awfully important tool to leave behind.
The real enabler of TDD is writing code that exposes seams to unit test in small chunks. As long as you can accomplish that goal, you’re going to be fine. I just think that coding in an OO style gives you many more tools to create testable code. If you can stay perfectly in the realm of state based testing and keep your functions small and relatively independent, I can see you being able to use TDD with procedural code.
Just for background, here’s an older post on State vs. Interaction Testing. You’ll want to be able to do either, and know when each is most applicable.
P.S. I think doing TDD is actually a great way to learn OOP. You get immediate feedback on your OO structure.