Skip to content

Instantly share code, notes, and snippets.

@jordelver
Created October 2, 2012 12:51
Show Gist options
  • Star 7 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save jordelver/3818839 to your computer and use it in GitHub Desktop.
Save jordelver/3818839 to your computer and use it in GitHub Desktop.
Functional TDD: A Clash of Cultures - Kent Beck

Functional TDD: A Clash of Cultures - Kent Beck

https://www.facebook.com/notes/kent-beck/functional-tdd-a-clash-of-cultures/472392329460303

I have been taking Bryan O'Sullivan's excellent Haskell course and noticed something during the homework: TDD wasn't working for me, at least not as I apply it in object languages. This has forced me to take a step back and rethink what is really essential about TDD and what is an artifact of the languages I have been using.

A warning: I'm only on week two of the course. I did quite a bit of functional programming in the Dinosaur Computing Era, so the style is familiar, but everything contained herein is subject to change. I'm mostly just thinking aloud (and hoping for contributed wisdom.)

When I use TDD with an object language like Smalltalk, Java, or PHP I typically start programming with a trivial case--a List with no elements, for example. Working through it encourages me (sounds better than "forces") to think about the metaphors I am using and style of the API. From there I move on to tests that encourage me to write the logic at the heart of the new code. When I can't think of any more tests that could fail, I'm done.

In Haskell, though, starting with the null case seems actively misleading. The romance of Haskell seems to come when composing solutions to smaller problems results in a solution to a larger problem. Handling the null case first gets me off track. Thinking about case analysis leads me to decomposition at the exact moment I should be thinking about composition.

At the same time there is TDD baby I don't want flying out the window with the object-oriented bathwater. I love (am addicted to, really) the feeling of confidence that comes when a comprehensive suite of tests passes. I like having a stream of bite-sized problems to solve (some day I'll write about using this as a treatment for depression). How can I retain what I like and discard what no longer fits in a Haskell world?

TDD can be described operationally as red -> green -> refactor. Within that structure there is subtle wisdom about which tests to write and which to skip, what order to write tests, and when and how much to refactor. My current confusion has led me to identify a handful of principles that underlie TDD and that I don't want to lose, however I end up programming:

  • Double checking. If I think through a problem two different ways and arrive at the same answer, it's much more likely the right answer than if I only think one way. I need to keep some form of double checking. (Haskellians have assured me that type checking is sufficient double checking. I've already written programs that type check just fine and produce wrong answers, so pencil me in as skeptical.)

  • Solution decomposition. I need to be able to work on a part of a problem at a time without having to hold the whole thing in my head at once. Having solved part of a problem I need proof that it is and remains solved.

  • Automatic verification. I need the computer to check whether results are correct. Green should mean, as closely as I can approximate, "Ready to serve nearly a billion users."

  • Outside in. The program's externally visible behavior is more important than its internal structure (leaky abstrations notwithstanding). I want to start my search for a solution from the outside most of the time.

One of the great things about experiencing a new culture is rethinking assumptions. I remember my first week in Switzerland reading an FT article about how Americans think it's rude to stereotype based on national origin but that Europeans use stereotypes as a useful approximation. "Rude!" I thought, "It's just WRONG!" Then I realized I wasn't in Kansas any more and it was time to figure what was really important to me and what was just the result of my lack of exposure. I feel a bit of the same dislocation now. I'll keep you updated. If you have any advice from the other side, I'd appreciate hearing it.

@ae-mo
Copy link

ae-mo commented Jan 12, 2020

Seven years later, it would be interesting to see how this has evolved. Did TDD make its way into functional programming?

I stumbled upon this while I was looking for a TDD book that uses Haskell, but no luck so far. Because of this I'm not very hopeful but I thought I would just ask anyway.

@dickykmrlh
Copy link

I too struggle to do TDD on Clojure..

@samlaf
Copy link

samlaf commented Mar 16, 2022

Weird. He answered the opposite in 2011 on quora: https://qr.ae/pGLO0B

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment