Wednesday, August 5, 2015

Kata: Print Diamond in Clojure

Yesterday we did the Print Diamond kata in the Clojure Developers Barcelona group.

I paired with Rafa Gómez. We managed to complete a recursive solution to the problem using our usual mix of TDD and REPL-driven development.

Later, we showed our solution and realize that, even though, it worked fine, we had to improve the names of some helper functions we had created to make our solution easier to understand.

After that, Samuel Lê, presented on the whiteboard (we couldn't connect his laptop to the projector) a completely different and very elegant approach.

I'll try to explain it:

Say, for instance, that you're trying to create the diamond for D.

You first create the following sequence repeating the string "DCBABCD" as many times as lines there are in the diamond:

Only one letter is allowed to appear in each line of the diamond.

Let's represent this in a table:

Now the only thing we have to do to get the correct diamond lines is to substitute by a space (we used an underscore to make it easier to visualize) every letter of the line that is different from the allowed letter for that line:

This is a very elegant approach that only uses sequences functions.

When I got back home I redid the kata again using both approaches: the recursive one and the one that Samuel had explained on the whiteboard.

These are the tests I used to test drive the recursive code (sorry I can't show the REPL history because I haven't found where Cursive saves it):

I'm using an underscore instead of a space to make the results easier to visualize.

and this is the recursive code:

Then I deleted the recursive code and started playing in the REPL to build a new solution following Samuel's approach and using the previous tests as acceptance tests to know when I was done.

Once I had it working again:

I refactored the code a bit introducing some helpers to separate responsibilities and make the code more readable and renamed some bindings.

This is the resulting code:

You can find all the code in this GitHub repository.

As usual the Clojure meetup and the conversations having a drink afterwards have been both great fun and very interesting.

We also met Alejandro Gómez which is writing this great ClojureScript book and has recently moved to Barcelona.

Tuesday, July 28, 2015

Using pattern matching in the Binary Search Tree Clojure solution

A member of SCBCN coded a beautiful solution in F# for the Binary Search Tree kata.

I wanted to try using pattern matching to get to a similar solution in Clojure.

So I watched Sean Johnson's Pattern Matching in Clojure talk and read a bit the documentation of clojure/core.match.

My intention was to use defrecord matching, but I couldn't make it work.

Later I found out in an answer to this StackOverflow question, Pattern matching on records in Clojure, that this feature hadn't been implemented yet.

So I followed the advice given in StackOverflow of using map pattern matching and coded this version of the Binary Search Tree:

Even though is not as nice as the F# one, it reads very well and allowed me to get rid of the value, left and right private helpers and all ifs.

Then I tried another thing that Sean Johnson had mentioned in his talk.

I coded another Binary Search Tree solution using the defun macro which creates functions with pattern matching like in Erlang, or Elixir

This is the resulting code using defun:

which also reads very nice.

Sunday, July 26, 2015

Applying property-based testing on my binary search tree implementation

Some weeks ago I did the the Binary Search Tree problem from Exercism in Clojure.

I used TDD using some of the sample tests that Exercism provided and some other that I added.

These were the tests, after deleting some redundant ones:

And this was the binary search tree code:

I was just testing a few cases.

To gain confidence in my solution and play a bit more with the exercise, I decided to apply a bit of property-based testing on it.

So I added the clojure/test.check dependency to my project:

and added a new spec to the tests:

The in-order-traversal-of-bst-sorts-elements spec is checking the in-order-traversal-of-bst-sorts-elements-property 100 times.

For each check, the generator creates a random vector of integers and checks if the result of calling in-order on the binary search tree created from the vector is equal to the sorted vector.

The macro clojure.test.check.clojure-test/defspec allows to integrate clojure/test.check with clojure.test, so that properties can run under the clojure.test runner.

Midje, the test framework I'm using, can also detect and run clojure.test tests.

Ok, after running the tests, this is what I got (formatted so it fits without a lot of scrolling):

There was a case that was failing.

A really nice thing about clojure/test.check is that it tells you the smallest case that makes your code fail. See the value of the :smallest key inside the map associated to the :shrunk key of the map in the output.

I had forgotten to write a test for the empty vector!

So I added a new failing test for that case:

and modified the code to make it pass:

Now the tests were all passing:

At this moment, I could have deleted all the unit tests and kept only the property-based ones, because the former were now redundant.

I chose not to do it, because I really like the readability of midje's facts.

In this case, I've used property-based testing to thoroughly check my solution after I had finished doing TDD. I wasn't wearing the TDD hat when I used it, I was just doing testing.

I think property-based testing and TDD can complement each other very nicely.

Another way to combine property-based testing and TDD is using the capability of clojure/test.check of giving you the smallest case that fails to help you choose the next test to drive your code.

Jan Stępień talked about this in his talk in last EuroClojure conference:
Another thing to consider is that the smallest case that makes the code fail given by property-based testing may not always correspond to the test that allows the code to grow in a small and easy to implement step.

I think that chances are that many times it might be, though.

Another thing to explore :)

Interesting Talk: "Interaction Driven Design"

I've just watched this great talk by Sandro Mancuso: This is an update and enhanced version of his previous talk: Crafted Design.