The other day, Uncle Bob Martin wrote an interesting blog about estimation. The problem he used as an example was a simple line break algorithm. The typical way of implementing something like that withTDD involves building up your solution in small steps, maintaining state variables to keep track of where you are as you traverse the text. I'm pretty sure that maintaining indices as state is a major cause of grief as people move toward a solution, so I started wondering.. what would a pure functional solution to this problem look like and would you get to it in small steps?
Here's what I ended up with:
If you don't know Haskell, this is sure to seem cryptic. In a later blog, I'll explain how it works and I got to it.
No doubt other Haskellers will chime in and offer more direct solutions, but the code above does solve the problem, and the fact of the matter is that I did not use TDD to arrive at it. At least not the TDD where 'T' stands for "Test." Instead, I drove the design using type signatures. It's actually a very nice design technique. You start with the type signature of the function that you want to write to solve your problem (in this case lineBreak) and you drill down, refining type signatures for the functions that you need to make the original function work, keeping an eye out for functions which already exist.
This may seem to be plain old top-down structured design, but I think there are some differences. For one, it seems easier to see things as a linear flow of transformations rather than a tree of invocations. I'm still not sure whether that is a real distinction.
Oh, and the estimation? The design took longer than I expected, but that's par for the course, isn't it?
Michael, thanks for the post!
I'm new to haskell too but I've caught myself recently doing something similiar. https://github.com/zmoazeni/3load/blob/master/src/Strategies.hs#L77 and https://github.com/zmoazeni/karkeze/blob/master/src/Parser.hs#L53
Even when the function signature wasn't necessary, I found it was helpful to clear up mental inconsistencies.
Posted by: Zmoazeni | April 27, 2012 at 12:45 PM
Nice post!
Eric Meijer uses similar approach in his series on MSDN: http://channel9.msdn.com/Shows/Going+Deep/Lecture-Series-Erik-Meijer-Functional-Programming-Fundamentals-Chapter-1
I can't remember which chapter it is in though.
Posted by: Mark Thomas | April 27, 2012 at 02:25 PM
Like types, a test is a proof about the program. The main distinction is that tests, as opposed to types, are ad hoc and with very limited scope -- though some times can be very limited in scope as well, when you get to advanced types such as those in Agda or Coq.
So Type-DD and Test-DD are are very similar. Uncle Bob's first is very adamant, for instance, that you should write the smallest test possible that fails, and that not compiling is failing.
In Test Driven Development, the only distinction would be that you'd first write a test to the effect that you have a function called lineBreak that takes a String and returns a String, fail compilation, and then write the declaration.
Posted by: Daniel Sobral | April 27, 2012 at 02:39 PM
I like that. Still, your code took as much though (if not more!) and doesn't change anything UncleBob said about estimation. Estimation is still hard, and always will be.
I'd rather maintain the Haskell code though.
Posted by: Rojepp | April 27, 2012 at 03:23 PM
From the post I don't understand how Type Driven Development relates to TDD. For me it would be helpful to see. the single steps (Screencast, http://CodersDojo.org etc.).
Posted by: Stefan Roock | April 28, 2012 at 01:35 AM
Nice example; Add a requirement for correct hyphenation if wordlength is greater than the line lenght.
Also, it'd be interesting to compare different approaches for solving this as efficiently as possible by using concurrent programming.
Posted by: Mika | May 01, 2012 at 12:01 PM
But still you didn't test at all while developing?
I'm a novice in Haskell, but I need a lot of tests before nailing down my functions. I'm using GHCi to manually testing them, but for sure I'd like to have a kind of testing framework, probably more like fitnesse than xUnit
Posted by: Uberto | May 01, 2012 at 02:33 PM
I'm glad your saying this. If I had a nickle for everytime I was blasted for even suggesting that these kind of type systems and test driven development had some overlap in facility to aid incremental design, well, then I could probably pay you to say it for me. In short, thanks for blogging about this even though strongly typed functional programmers have been saying this for years.
--James
Posted by: James | May 06, 2012 at 03:57 PM
great....
thanks for the info :)
Posted by: pakaianindonesia | May 08, 2012 at 02:17 AM