Friday, February 24, 2012

A tale of patterns, refactoring, and testing

I've heard it said that a good song is not so much written, as it is edited. The same is true of books, and surprisingly enough, code.

I'm in the process of creating the code that handles the "real-time" communication between the server and the browser for my game, using Socket.IO.

The first draft was mostly just a proof of concept. It followed the same structure of the many Socket.IO tutorials on the web, where you use Express to serve a web page which includes the client code. The server event handlers were all in the same file as the Express code. Of course, this is fine for proof-of-concepts, and tutorials, but it gets a little messy when your code gets more involved. My first task was to pull the code that handled communication into a separate module.

But what to name it? I wanted the module to expose the communication in domain verbs to the server. I kept thinking "I know there's a pattern for this - but what is it?" The name escaped me so I headed to the Internets. Oh, right - a "proxy".

After a little bit, I came up with this.
.
You may not have noticed but when I set up my NodeJs development environment, I forgot something really important. I didn't include any testing libraries! To rectify this I installed Expresso, and started creating some tests for the ClientProxy module. Only then did I realize that I needed to refactor. One of the warning signs that your code is doing too much at once is that your tests are hard to write. In this case it's pretty obvious - I've got an event handler factory object buried in the middle of my proxy code. Ouch.

That's why I love automated testing - testing drives design.

While refactoring, I noticed that I'd made a copy-and-paste error in my original code. See it? In lines 40-48 in the gist above, I tell Socket.IO to listen for 8 events, but only the "login" event handler would be invoked, no matter what event was fired.

Here's the ClientProxy, with the EventHandlerFactory passed in as a dependency, and the two tests.
.
When I run Expresso, it looks like this.
$ expresso
   100% 2 tests
$
Yay!

Quick Tip: Install NPM modules globally if you want them in your path

I installed the TDD framework Expresso using NPM.

npm install expresso

But when I tried to run the tool with the bare command expresso, the tool couldn't be found. Of course - it was buried down under the node_modules/expresso/bin folder, which wasn't on my path.

So I installed it globally, by using the -g flag.

npm install expresso -g

And that did the trick! Now all I have to do is type expresso at the command line, and it looks in my /test folder for any test modules, and runs them. Sweet.

Monday, February 20, 2012

Prepping for Node JS

I've got a philosophy about code (that is often valid in the wider world) that the context of an action is as important as the action itself. As much as possible in this blog, I'm going to attempt to share the context and tool-chain I'm using. In the next few posts I'll be exploring building a web app with Node JS. Before you can go out and write a line of code though, you need a dev environment. These are the steps I used to create mine. (I'm working from memory here - sorry. In future posts, I'll write things down as I do them.)
I decided not to run Node on Windows because I have a slight aversion to Cygwin. Also, I like the portability of a virtual machine. Theoretically, you can save the VM state, and move it to another computer, clone it to multiple computers, whatever.

Of course, a bare Linux installation is almost completely worthless. First, I gave my user sudo access (?!! You would think this would be a default. You would be wrong.), and installed the following:
  • Chrome
  • curl (because Node programmers aren't allowed to use a browser, y'know)
  • git (programmers should feel naked without some sort of source control)
  • NodeJS
  • NPM
  • MongoDB
  • CouchDB
Yes, I did download both MongoDb and CouchDb. I currently have zero experience with NoSQL databases, and I wanted to try these two out. Probably be using CouchDb the most though, because of the awesome stuff they're developing over at CouchBase.

So far, the NPM packages I've installed are
Most of the action in the upcoming posts will center around socket.io.

EDIT: I also installed Expresso, later. Can't forget testing!