Uncle Bob’s Bowling Game Kata, Clojure Style
The bullet points of Clojure are fairly simple:
- Build on the inherent power of Lisps in general, but in such a way that you’re not encumbered by decisions that were good 50 years ago but make no sense now.
- Embrace the host platform, the JVM (and even the CLR).
- Provide language level support for concurrency-oriented programming so that people can avoid the hell of concurrent programming in any of the imperative, lock based, OO languages on the plate today.
- Be (practically) functional.
It’s a Lisp
Lisp is this ultra-cool language designed by a guy named John McCarthy over 50 years ago which itself was based on the Lambda Calculus. Amazingly, he proved that you can create a language where every computable problem can be expressed in terms of just 7 primitives (quote, atom, eq, car, cdr, cons, and cond). As such, Lisp has been described as beautiful, elegant, concise, syntaxless, etc. and all of the negative corollaries you can imagine: obtuse, obscure, opaque. Doubtless, though, no one interested in Computer Science can not get goose bumps reading about all of computation being described in just 7 terms.
Lisp has this funny habit of continually coughing politely and reminding people that it was doing every cool new innovation in computer science since it’s invention. XML has been described as Lisp redone. Metaprogramming is just Lisp multimethods and ad-hoc hierarchies. Functional programming like Haskell? It’s just Lisp. Of course whenever that comes up there’s a large bevy of extremely smart people who calmly attempt to remind everyone that it’s not exactly true. Lisp didn’t invent every good idea known in computer science. What is true is that as programming languages become more powerful, they do begin to adopt features of Lisp and many other functional languages that Lisp has had for decades. They do so with different syntaxes and larger libraries, but many of the greatest ideas of computer science were expressed quite elegantly in functional languages like Lisp.
As such, Rich Hickey, who was a Lisp fan to begin with while not being able to afford to be a Lisp professional, thought it wise to attempt to reintroduce the language, especially since it has such potential power for use in todays concurrency-oriented world.
Embrace the platform
Where many Lisps have failed in the past has been in the area of libraries and platforms. I’ve never coded in Common Lisp, and the old saying is that “Every C program includes a poorly written and buggy implementation of half of Common Lisp”, but at the same time, since Lisp never really caught the imagination of the professional development community, new libraries are hard to come by. Compared to the explosion of Libraries for a poor language like Java, Lisp has always been somewhat left in the dust.
So M. Hickey decided that he’d solve the library problem, and the GC problem, and the System Call problem, and the etc. problem, by using the stunning piece of technology called the JVM as his platform. This means that at the expense of adding a couple of new primitives to McCarthy’s 7, he was able to provide amazingly good interoperability with Java, and thus open up the entire ecosystem of Java libraries to Clojure developers.
Many Clojure programmers like to say that Clojure does Java better than Java. And I’m inclined to agree.
A canonical example:
(doto (JFrame.) (add (JLabel. "Hello World")) pack show)
It’s important to note that the only special, Clojure, part of that
line is doto. Everything is purely Java Swing.
constructs a new JFrame, doto is a macro that is a little like the
with operator of languages like Ruby that allow you to avoid typing
the thing you’re operating on over and over and over again, the rest,
if you’ve done any Swing programming, should be familiar to you
because it’s just native Java calls.
The interesting thing here, for people who think that Lisp stands for Lots of Irritating Superfluous Parentheses, is that that code snippet beats Java, handily, for paren count.
Beyond being able to call Java from Clojure, all of Clojure’s core abstractions are defined in terms of Java Interfaces which mostly implement things like Collection. All data is the Object version of that data (i.e. ints are Integers), but can be coerced into primitive types for performance. That means that Java code written against the core Java abstractions (like all good code should be) can seamlessly interoperate with the Clojure data structures.
Java interop in Clojure rocks. Really.
Language level support for concurrency
I’ve never had the joy it sounds like programming concurrently in lock based languages personally, but reading through JCIP and listening to people who’ve done it extensively scares me enough that I never want to.
While Haskell may be the only possible truly functional language, Clojure strikes a better balance between the real world that does actually change and the functionally pure world that’s easy to reason about and model. Rich Hickey is not an academic by profession and he knows that when you’re programming most systems, you need side effects and you need state. Suffice it to say that where purity conflicted with practicality, M. Hickey sided with practicality most of the time. The persistent data structures and how they interoperate with change and transaction semantics is truly remarkable and easy to grok. At the end of this post I’ll link to some videos that are worth your time which do a much better job describing why Clojure’s concurrency primitives are the best concurrency story on the market today.
Because of pragmatic Dave’s efforts, software kata seem to be all the rage these days. I was actually introduced to them via Uncle Bob’s excellent Bowling Game Kata, which indeed is the subject of this post. Uncle Bob, in this case though, is the one who hit the nail on the head as far as the point of kata and how they should be thought about, over against Pragmatic Dave.
A kata is meant to be memorized. Students of a kata study it as a form, not as a conclusion. It is not the conclusion of the kata that matters, it’s the steps that lead to the conclusion. If you want to lean to think the way I think, to design the way I design, then you must learn to react to minutia the way I react. Following this form will help you to do that. As you learn the form, and repeat it, and repeat it, you will condition your mind and body to respond the way I respond to the minute factors that lead to design decisions.
So, what’s his basis?
Kata is a Japanese word describing detailed choreographed patterns of movements practiced either solo or in pairs.
One explanation of the use of kata is as a reference guide for a set of moves. Not to be used following that “set” pattern but to keep the movements “filed”.
A nice moving example (for however long it stays up) can be found in this clip from Fist of Legend round about 9 minutes 11 seconds.
A software kata takes the traditional notion of a short but thorough series of movements designed to tune your body to react in certain ways to a preconceived set of situations as well as to become used to moving in certain ways and translates it into a series of actions leading to the solution of a software problem.
It’s very important to realize that the ‘point’ is not the solution. If that were the point then ‘practicing’ a kata would make no sense. Once the problem’s been solved, why solve it again? Even more important is that no problem can be truly interesting and solvable in a short enough amount of time that you can practice it every day. Katas are short enough that you can spend 15 minutes in the morning ‘loosening up’ with one and actually get some benefit from it.
A kata a day keeps the debugger away
Uncle Bob and Stuart Halloway
Uncle Bob is an all around great dude who cares intensely about software, developers, and customers. His video from OREDEV about clean functions changed the way I thought about writing code. I read pretty much anything I can get my hands on from him. The reason I bother mentioning him at all is because he’s the one who designed this particular kata in Java.
Stuart Halloway is another of these luminaries who I’ve begun to come in contact with mainly because of my interest in Clojure. He’s one of the big name Clojure users and is a regular contributor not only on the Google Group but on the actual code base as well. His solution is what I ultimately based this kata on, with some minor tweaks..
The bowling game Kata is quite simple.
The problem is that we want to score a game of American 10 pin bowling.
The steps to memorize are these.
- A brief design session
- Set up your project
- Test 1: Score a gutter game
- Test 2: Score a game of 1 pin frames
- Test 3: Score a game of 1 spare frame, a 3 pin frame, and gutters
- Test 4: Score a game of 1 strike frame, an 8 pin frame, and gutters
- Test 5: Score a perfect game
Test 5 should actually require no extra coding. The way it was originally published was as a Java kata.
Now, Uncle Bob is getting into Clojure and he wants to translate his kata into it. This leads to some difficulties and some not too pretty code as it’s really his first foray into Clojure any way. He publishes it nonetheless and asks for feedback.
Stuart Halloway comes along and does a nice implementation of the kata solution and even publishes a wonderful little post about his thoughts while refactoring.
So why am I bothering writing this? Well, because I can’t find anywhere where this kata was published as a kata on the web and I figured I’d rectify that. Remember, the kata isn’t the solution, the kata is the process leading to the solution. For a kata to be a kata, you should be working in the same IDE and use the same file names, and literally do every single thing exactly the same as the kata you’re following. Do it a hundred times before you start looking for ways to improve it!
Here’s the kata, then.
I’ll give the high level steps. The easiest way to learn the kata the way I do it is to watch the video I’ll embed at the end.
A Design Session
- Bowling can be thought of as a sequence of rolls, some number
of which constitute the score of a certain frame.
- The total score, then, is the score of 10 frames, plus a certain number of rolls if the last frames require them, because they are a spare or a strike.
- We’ll need a score-game function which takes a sequence of rolls. We’ll throw in the rolls as an infinite sequence just for fun, even though that goes beyond our requirements.
- We’ll need a score-frame function to score each frame.
(reduce + (map score-frame (to-frames game-rolls)))
- We’ll need functions to determine if a particular sequence of
rolls is a strike or a spare.
- We’ll need a function to transform a series of rolls into a
series of frames that can be totaled up.
game-rolls => (10 5 3 0 0 0 0 ...)
(to-frames game-rolls) => ((10 5 3) (5 3) (0 0) (0 0) ...)
- Bowling can be thought of as a sequence of rolls, some number of which constitute the score of a certain frame. Example:
- Create a directory called bowling-game. I always do it on my Desktop because you’re going to delete it as soon as you’re done.
testdirectories under their.
bowling-game.cljin both of those directories.
- Create a
You’re first test!
Score a gutter game. At the end you have
(is (= 0 (score-game (repeat 0))))
(defn score-game [game-rolls] 0)
Score a game of 2 pin frames. At the end you’ve added
(is (= 20 (score-game (repeat 1))))
(defn score-game [game-rolls] (reduce + (take 20 game-rolls))
Score a game of 1 spare and a 3 pin frame. At the end you’ve added
(is (= 16 (score-game (concat [5 5 3] (repeat 0)))))
(defn score-game [game-rolls] (reduce + (map score-frame (take 10 (to-frames game-rolls)))))
Score a game of 1 strike, an 8 pin frame, and gutters. At the end you’ve added
(is (= 26 (score-game (concat [10 5 3] (repeat 0)))))
Score a perfect game. This simply runs.
Score a game of spares specifically of the configuration 0 10 repeating. My favorite.
(is (= 100 (score-game (cycle [0 10]))))
Format to your tastes. I find that because of how compressed Clojure code tends to be it benefits more than most languages that I’ve seen from good formatting practices.
Have a beer.
For the nitty gritty details of myself performing this kata, I present the following:
So there you have it. The Bowling Game Kata published as a Clojure Kata (not just a solution!).
If the common wisdom that I hear from almost every software luminary is true, I would absolutely recommend you learn new languages and for the best bang for your buck, make it a language as different from what you’re used to as Clojure almost certainly is.
Here’s some great clojure resources:
- Code Katas
- Clojure.org: Seriously awesome amount of content, and almost all of it well written.
- Introductions to Clojure
- Video Curriculum
- Books I’m Reading
- Programming Clojure by Stuart Halloway. I’m going to write a review of this as soon as I can. It rocks hard from start to where I’ve read so far. ;)
- The Joy of Clojure. I just finished this book and was a little less than impressed. However, it was still a good read and it was also the first book I read on Clojure so some of my less than impressedness might have come from simple unfamiliarity with the language.
- Books I’d like to read