In Midje's readme, I showed this fact:
(fact (numerical-reverser 103) => 301)
One way to implement
numerical-reverser would be to convert 103 into a string, reverse it, and then parse that string into an integer. String reversal is easy, right?
Well, actually, it doesn't seem to be, not using the Java API. My thought process might go like this: "There's no
reverse function for String?! Wait, there's one on StringBuffer? So I have to move the string into a StringBuffer, reverse it, then
toString it? That's crazy. Clojure's
reverse works for vectors, I see, but it gives me a seq. How do I turn that back into a string?... Man, this is not what I want to be thinking about right now."
What I want to do instead of that thinking is what
Abelson and Sussman dubbed "[[programming by wishful
thinking|http://dsoguy.blogspot.com/2007/01/programming-by-wishful-thinking.html]]" in their masterpiece [[Structure and
Interpretation of Computer
that style, while writing
numerical-reverser, I'd say to
myself "I'm going to assume a function
string-reverser exists. That'll make it easy to write
numerical-reverser. When I've finished that, I'll implement
string-reverser if it happens not to exist. Long journeys are made from small steps."
The Midje fact that makes that coding test-driven would look like this:
(fact (numerical-reverser 103) => 301 (provided (string-reverser "103") => "301"))
And the code could be written like this:
(defn numerical-reverser [n] (String/parseInt (string-reverser (str n))))
Actually, Clojure rips you out of the lovely world of wishful thinking a bit early. Because
string-reverser doesn't actually exist, you have to declare it to keep the compiler from spewing a huge stack trace at you. I like predeclaring wishful thinking functions like this:
That's the same as
declare, but it fails more informatively if it's ever called.
In the object-oriented world, this style is well described in Freeman and Pryce's Growing Object-Oriented Software, Guided by Tests. My original goal for Midje was to repaint that style onto the functional landscape, where we can think of test-driven design as building a web of interrelated facts.
Last edited by marick,