Musing on TDD, Impulsive Developers and Aesthetics
March 17, 2015 § 1 Comment
I have to acknowledge a blunter truth about my relationship with TDD. That is to say I don’t do much TDD because a) I’m impatient, and b) I like to code impulsively. I strive to have the problem space booted up in my head and then walk around it arbitrarily, as Paul Graham has written about in his ‘the head’ article. When solving a problem I may start out with a vague idea of how the design will play out, but really I just want to try out a few rapid ideas, weighing up the various pros and cons as I go. I may use some tests, I may not.
My thinking is that TDD – as applied by the masses – compromises one’s ability to code intuitively against the problem space in their head. By formally marshalling the art of coding into a series of strict red/green chequerboard moves, your overall ability to think laterally about the problem is reduced.
At this point I must readily concede that the TDD conversation can’t be had without considering the technologies and languages involved. If you are doing battle with a traditionally large OO code-base, then TDD may be appropriate for a host of reasons. Primarily, it does keep you on the rails.
Being honest, can we admit that hacking on large OO systems can be a huge amount of fun? You get to lose yourself in a giant Sudoku. Design patterns, generics, some magical AOP code, what’s not to like if solving complex problems is your thing? The trick for many is to not to get lured in, however tedious that may be.
I do therefore hold respect for TDD in certain contexts. It’s like a puritanical response against the will of developers to get stuck into battles that we should probably be avoiding. TDD helps to keeps the mind clear, to keep it focused. There’s a world of dark and dangerous refactorings we could be doing if we let our inner impulses off the leash. Beginners may find TDD a useful tool to take incremental steps, and this indeed is a strong point in its favour, as discipline aids learning.
I just think that if you need TDD all the time to engage with a code-base, then it’s a smell of something being overly complex.
There is then the other the argument that TDD’d unit-tests are really just the same thing as REPL sessions, so therefore it’s unfair to attack them, that they are really just fulfilling the role of the safely walled-in playground. My view is that it sure doesn’t feel this way when I’m wrestling mock frameworks and spending hours of my life wiring stuff up, unless the playground is of the variety found in the Terminator 2 opening sequence. There’s a reason BeanShell sadly didn’t get widespread traction; you need a simpler language to make the REPL a pleasant experience.
My main overarching concern isn’t just the intuitive development approach though, as that’s largely horses for courses and is subjective to the individual. My main worry is about aesthetics, and the reason I’m pondering this is because Eleanor McHugh brought it up on a recent panel debated on TDD prompted by DHH’s article on “TDD is dead. Long live testing”.
It’s surely a worthy goal for code to be beautiful, to be aesthetically pleasing to the eye. Given developers will be spending years at a time patrolling a single code-base, it pays to have the code elegant and prideful looking. Beauty in code has a high correlation with simplicity, and it’s usually evident when a developer has thoroughly understood the complexities of the problem and has pinned down the right level of abstraction.
When a codebase has been dogmatically TDD’d, I think it ends up looking a little sad, as though the chunks of production code are being unfairly surrounded by unit-test SWAT teams. Everything is in a state of lock down, where you are restrained against making serious changes because the effort required to work with someone else’s tests is just too high. You then also have to suffer the moral quandary of considering whether to delete someone else’s test code, this isn’t trivial and so useless code has a habit of sticking around.
I don’t believe rigid TDD as applied by the masses is a good thing for aesthetics in code. I think it’s rather the opposite case, as going-through-the-motions unit-tests tend to take on opposing aesthetics. Through the eyes of a TDDist, one sees beauty in ensuring that every edge case is accounted for, and that every discreet piece of logic has a test. A TDD’d codebase can therefore be a sterile place. Well tested and functional, just lacking that human touch of grace and simplicity.