We’ve spoken already of the test driven development (TDD) mental game. Now it’s time to consider the situation on the ground.
The main TDD disabler we’ve already met: a broken or too-slow build/run/result flow. If your team has that issue, throw all your weight at it, and do not try to launch TDD itself.
It’s very important that the team’s initial experiences with TDD are not blocked by externalities. Whether its easy or hard to roll the first few microtests, the difficulty needs to be focused on the pre-TDD code, not the process itself.
If you have a disabler, your coaching story is clear: we can’t do TDD until we fix it. Once the disabler(s) are cleared, we need to turn to the various factors that don’t quite stop the show: the inhibitors.
An inhibitor doesn’t block TDD, it just makes it harder to apply.
(Don’t relax: if you pile a few of them on, you’ll long for a good old-fashioned disabler, because it would at least have kept you off the TDD road until you tackled it.)
Inhibitors are usually about technique.
(And still don’t relax: you can’t simultaneously introduce 82 slightly different variants of technical solutions.)
Let’s take one detailed example, then sketch a few others with their related solutions.
The Promiscuous Database
The promiscuous database is an inhibitor I’ve found very common, especially in IT shops. It’s easy to spot: just grep the source for “SELECT” and inspect the results. In a typical nightmare, virtually every source file will contain explicit SQL.
(Sometimes there is some awful framework in place, that makes the grep not look so bad, because the actual SQL is in some bizarre xml file. Same problem, different grep.)
The promiscuous database does its damage by forcing all microtests to rig up the database and then connect to it. How do you spell heartache?
Moving The Database Out
The solution is straightforward: extract each SQL statement, or each hardwired database statement, into a separate class named for the intention of its calls. Now we can easily use a hand-rolled or automagic fake.
- Name the class for its intention, e.g. GetOutstandingLoans, not ComplexSQLCmdWithThreeParameters.
- Pass the parameters in the constructor.
- Return typed containers.
- Discover, don’t pre-implement, shared code to pull up.
- Consider a hierarchy based on command return-type rather than ‘tables touched’
- You may want to use a factory approach for getting the actual command.
- You certainly want some way easy way to slip a fake in. This can be done at the caller’s constructor, or just use a factory method that can be overridden.
- Wonderful side-effect, it often shows you more dup than you thought was present.
I hope this solution isn’t too telegraphic. If so, holler at me in the comments. The real point here is that we’re talking about learning and using programming technique to solve most inhibitors.
Readily != Painlessly
It is readily possible to solve the promiscuous database using coding technique. But readily doesn’t mean painlessly in the beginning.
Everyone who’s got work in the caller-class has to be able and willing to do these extractions. It can be done, but until a few tries are under a noob’s belt, it will feel like a useless formalism.
This is the general tenor of working against TDD inhibitors.
Let’s sketch a few more inhibitors and their solutions.
The Very Large GUI Of The World
GUI classes that do frighteningly complex work are the bane of any team working legacy TDD.
The problem here is tremendous and obvious: you can’t test the functionality without launching the GUI itself. Say goodbye to rapid feedback.
The answer is easy, or easy-esque: create a class whose lifetime is exactly coterminous with the GUI class, then rework your GUI class so that all non-graphical work is done by the shadow class. Turn the GUI class into a specialist who removes GUI-isms before passing on to worker, then puts GUI-isms back in on the way out.
The Hardware Distraction Layer
Direct calls into the hardware are everywhere. This is a hallmark of the embedded scene. Look for globals.
Solution: You need an adapter that fronts just the calls that this particular client needs. Work to make that adapter really hide the underlying dependencies. Once done, you can readily fake the adapter as needed.
The In-House Framework Of Universal Despair
The colossal ass-hattery known as “our in-house framework” is often an inhibitor par excellence.
The framework provides needed services, such as a database connection, that we don’t know how to get access to without launching the framework.
In this case, usually we’re seeing significant work done in a class that derives off of something from the framework. The trick here is just another variation on the theme of ‘take away frameworkisms on the way in, and put them back on the way out’.
Coaching On Inhibitors
The meta-pattern for inhibitors is simple.
Coach two or three teammates through the process of working around a given inhibitor.
This will give you two key advantages: the ability to show multiple instances of ‘problem-solved’, and the support of the teammates who actually lived through the solution.
So? Use lottery learning, or some other meeting, to introduce the problem and its solution. Show them the two or three. (Without the show you’re just being an abstract chatterer.)
In early days, just make the team aware you want to be tripling any time that problem comes up.
Ultimately, early days pass, and you can say with some confidence that your whole team knows how to finesse the solved problem.
After that time, and only after it, the team can raise their standard of excellence to say “files like this are hereby declared TDD’able”.