This is the third post in a series about my current Clojure workflow.
Having discussed Emacs setup for Clojure, I now present a sort of idealized workflow, in which I supplement traditional TDD with literate programming and REPL experimentation.
First, some questions:
The answer to (a) is, of course, by having good tests; and the best way I know of to maintain good tests is by writing test code along with, and slightly ahead of, the production code (test-driven development, a.k.a. TDD). However, my experience with TDD is that it doesn’t always help much with the other points on the list (though it helps a bit with (b), (c) and (e)). In particular, Rich Hickey points out that TDD is not a substitute for thinking about the problem at hand.
As an aid for thinking, I find writing to be invaluable, so a minimal sort of literate programming has become a part of my workflow, at least for hard problems.
Now for the workflow proper. Given the following tools:
then my workflow, in its Platonic Form, is:
“Writing” in each case above refers to updating comments and docstrings, as described in a subsequent post on Literate Programming.
Here are the above steps as a flow chart:
The workflow presented above is a somewhat idealized version of what I actually manage to pull off during any given coding session. It is essentially the red-green-refactor of traditional test-driven development, with the explicit addition of REPL experimentation (“REPL-driven development,” or RDD) and continuous writing of documentation (“documentation-driven development,” or DDD) as a way of steering the effort and clarifying the approach.
The utility of the REPL needs no elaboration to Clojure enthusiasts and I won’t belabor the point here. Furthermore, a lot has been written about test-first development and its advantages or drawbacks. At the moment, the practice seems to be particularly controversial in the Rails community. I don’t want to go too deep into the pros and cons of TDD other than to say once again that the practice has saved my bacon so many times that I try to minimize the amount of code I write that doesn’t begin life as a response to a failing test.
What I want to emphasize here is how writing and the use of the REPL complement TDD. These three ingredients cover all the bases (a)-(e), above. While I’ve been combining unit tests and the REPL for some time, the emphasis on writing is new to me, and I am excited about it. Much more than coding by itself, I find that writing things down and building small narratives of code and prose together forces me to do the thinking I need in order to write the best code I can.
While I don’t always follow each of the above steps to the letter, the harder the problem, the more closely I will tend to follow this plan, with one further modification: I am willing to wipe the slate clean and begin again if new understanding shows that the current path is unworkable, or leads to unneeded complexity.