Obviously, You're Not a Golfer

August 19th 2010

JavaScript is production code and should be treated just like your server side code. It helps define the user experience of your web application, so it’s important to write robust JavaScript. In the past, web applications were essentially server driven front ends for databases. JavaScript was used to add a little polish to these front-ends. But with HTML5 gaining traction, web applications are becoming rich client-side tools available not only to web browsers, but to mobile devices as well. JavaScript will play a much larger roll in your day-to-day development of web applications in days to come.

TDD and JavaScript

For the longest time, I didn’t use TDD when developing in JavaScript. At the time I only needed to use JavaScript to do minor DOM updates. Eventually I had to code forms that included business logic. As the complexity of the code increased, the likelihood of my code being altogether broken increased as well. I had to re-evaluate how I was using JavaScript.

For a majority of my professional development career, I’ve practiced Test Driven Development for all of my server side code. TDD is something I feel very strongly about. I write better code when I practice TDD. It makes me think in advance about how to design my code. My code becomes more modular as complexity increases, which makes it easier to maintain. Most importantly though, TDD give me confidence about my code. So why didn’t I originally feel the same way about TDD with Javascript?

The root cause was that I didn’t understand the language. Being a Rubyist, I’d treated JavaScript much like ruby. I’d become accustomed to the hand holding that the Prototype framework provided since it was included with Rails. My code was a mess and it would take me significantly longer to develop in JavaScript than Ruby. So I broke down and bought (I hate purchasing technical books for specific technologies) JavaScript: The Good Parts. It was very insightful and for me it was shocking to see how incredibly incorrect I was about how to use JavaScript.

Now I’m able to think and code in JavaScript. I then applied the same principles of test driven development to my JavaScript work-flow. I tried a few testing frameworks (JSUnit, and ScrewUnit) but eventually settled on JSpec.

JSpec is a behavior driven development framework based on RSpec. Snice I do all of my unit level testing with RSpec, JSpec was a comfortable fit for me. It has a DSL to define specifications (before, after, describe, and it blocks). And also a matcher library to add some syntactic sugar to your assertions.

…let’s go bowlin'!

The following is JSpec in action. It uses the Ron Jeffries' bowling game as an example. This is generally the first bit of TDD a developer sees. It explains the general red-green-refactor workflow of TDD, and stresses the importance of keeping your code clean.

To begin a JSpec project needs to be created.

First, install JSpec and set up the project:

The library file and its spec file get renamed to something that has meaning. The test runner also needs to get updated to reference the renamed files:

Now, start the spec watcher:

This starts a process that detects changes in the spec or implementation files then opens a Firefox tab that runs all specs for the project.

There needs to be a place to hang the code, so the initial test will ensure that the library exists.

It fails with “ReferenceError: BowlingGame is not defined”. Make it pass by adding a factory to generate a BowlingGame object:

Then create a spec to excercise the game logic. The simplest game a player can roll is all gutterballs:

And this fails with “TypeError: game.roll is not a function”. So define the methods under test on the BowlingGame lib:

And the spec passes. The next simplest game is one where the player rolls all 1s.

In this iteration I extracted the “player rolls” part of the describe blocks into a shared describe block. The output still has “player rolls” in it. I also pulled the for loop into the “roll_a” helper located in the spec.helper.js file. This file gets loaded before any of the specs run.

Now make the spec pass:

So far the design is simple. There is an accumulator variable that gets incremented by the number of pins felled for a roll.

The next case to test is when the player rolls a spare:

This fails with the message “expected 15 to eql 18”. Now the design needs to change. In order to detect that the player rolled a spare, the code needs to be able to look forward and backward in the history of rolls.

This design changes satisfies the previous specs, but it doesn’t satisfy the case that exercises a spare. It needs further refinement.

In this iteration, the score is calculated by frame (like any good bowling game should). This allows for the game to detect if the player has rolled a spare. It can also look ahead to calculate the bonus for the spare.

Now to test for a strike:

And it fails with ‘expected NaN to eql 28’. There’s an indexing error. And the fix:

Success! Now for the grand finale, the perfect game:

Our game logic satisfies this case. We’ve made some manly code! Even if JSpec isn’t a good fit for you, at least give some form of TDD a try. The final code for this exercise is available on my github account.

blog comments powered by Disqus