Testing Client Side Javascript with Jasmine and Node.js

After having spent a long time trying to run javascript tests with Rhino, I've finally found something better. Rhino was never really fast enough for me. Spinning up the JVM just takes too long when you're running your tests continuously. A few seconds really makes a difference when you do something hundreds (thousands?) of times per day.

On top of that, testing frameworks like ScrewUnit (aside from being abandonware) have scoping issues that make tests very brittle...unless you run each one in it's own process...again back to the JVM startup problem.

Recently, I started playing around with the Jasmine testing framework for Javascript. It was really nice, but I wasn't convinced it was really going to solve the problems I was experiencing since they were mostly due to global namespaces and Rhino.

Enlighentment came, however, when I tried running Jasmine tests from within Node.js, using a patched version of mhevery's jasmine-node module. If you don't know, Node.js is a Javascript runtime environment based on the V8 engine. It's actually designed for server-side development, but I wondered if I could use it to run tests for my in-browser javascript. The answer is mostly, but the results were very compelling and I'm now doing this on all my web application projects.

Firstly, here's an example project that shows how I set things up.

To understand what's going on here, lets begin at the html. In index.html, we're not doing anything fancy. Just a few tags to load jquery and the javascripts in our app:

The interesting bits start to show up in spec/specHelper.js

specHelper.js is actually a proper node.js module, meaning that it explicitly declares it's exports. What it's doing, actually, is exporting the namespace for our entire application (as the variable 'app'). This means that in our specs:

We can create a completely clean copy of the entire application and store it in a variable that the tests can access. Jasmine's beforeEach function can recreate it before every single test. This means that we don't have to create a new Rhino instance for each test to get a clean environment. As a result, these tests run fast (hundreds of tests per second).

They run so fast, in fact, that I've been using Watchr to run them. Here's my Watchr script

This automatically runs all the Jasmine specs on each change. The tests run so quickly I haven't had the need to optimize it yet. I've been really happy with this setup (despite a few problems with jquery and env.js) and I'm hoping to improve it as the tools mature.

A Bit of Heresy: Functional Languages are Overrated

Lets talk about problems. As professional software developers, we get paid to solve problems. Sometimes we do this by writing code. Sometimes we do this by finding creative ways to avoid writing code. In either case, it's important that the problem drives the solution, and not the other way around.

Enter: The Concurrency Problem. Moore's Law is starting to run out. We've all gotten very used to using hardware to solve scalability problems, and up until now, that's been a relatively easy thing to do. But chip manufacturers are starting to hit physical limits of transistor size and density. Now, the only way to scale up is to scale out by adding more cores, and that means concurrency. "But concurrent programming is hard!", they say. "And we have an army of semi-conscious Java developers in our company that wouldn't know a semaphore from a telegraph line! Oh noes! What will we do?"

The current fashionable solution to this problem are functional programming languages. They are the next big thing. Languages such as Scala, Clojure, Erlang, and Haskell are supposedly going to save us from the dread intermittent bugs and horrible deadlocks intrinsic in concurrent systems built with object oriented or procedural languages. The implication in this argument is that functional programming languages are more thread safe because (depending on the language) they either shy away from side effects or find ways to eliminate it completely.

Well, I'm sorry, but I'm just not buying it.

Don't get me wrong. Concurrent programming in a typical object oriented language is hard. Really hard. I've slogged through enough of it to learn to just avoid it unless you really, really need it. Especially when you're dealing with shared state. Michael Feathers once told me that he thought if threads had never been invented, and someone had proposed them at a conference today, they'd be laughed out of the building. He may have been kidding, but honestly, I would believe it.

My problem with the functional programming cure to this problem is that I haven't seen a cure yet that's better than the problem. Maybe it's me. Maybe my tiny Ben brain just can't comprehend the magic and majesty of OCaml, but every time I've tried to learn a new functional language, it's ended it disaster. First with Erlang, and then Haskell, I've now had two aborted attempts to understand the supposed cure to the concurrency problem. The languages are just too complex, too terse, and absolutely full of academic shitheaddery. I mean, seriously, what the hell.

If your concern with the death of Moore's law is that you won't be able to afford/find skilled programmers to scale your systems using multicore processors, these are not the droids you're looking for.

But even if you're got a bunch of really sharp developers on your team, I'm not sure this is the solution either. Message based architectures (especially asynchronous ones) are good, pretty easy to understand, and easy to test. Shared state in concurrent systems is a pain, and you shouldn't do that. Interprocess communication is relatively easy through various methods. Whether you're using an object oriented, pure functional, or hybrid language, these things are true.  And while it might be possible to ignore thread safety problems by just working in a purely functional language, I think you're just trading one kind of complexity for another. And if you're working in a hybrid language, what assurances do you have, really, that your system is really thread safe? Indeed, the risk compentation effect might give you a false sense of security, giving you a system that actually had more concurrency problems that one written in a "dangerous" language.

I think the downfall of some of these languages is that they get wrapped up in being "functional" rather than focusing on solving a particular class of problem. They abandon convention and common sense for complex type systems and functional purity. You can have an actor model architecture without using a functional programming language. You can avoid shared state in any modern language (even JavaScript). These things are not synonymous with functional programming.

I think the future of computing is people. Lots of people. Web applications, social networks, and millions (billions?) of mobile devices interacting over the net. I think the majority of these problems can be solved with multi-process, message passing architectures. In the end, a large scale system might wind up with one core for every 10 users. Maybe less. If multiple cores are the new gigahertz, I would not be the least surprised if computing gets that cheap. All it would have to do is follow the trend of the last 40 years, just along a different axis. Really, the only barrier to a process-oriented approach in that case would be memory, and that may not actually be a limitation at all.

So I think the cases where a functional programming language are really the best solution to the concurrency problem are, in fact, rather rare. It's worth noting that even after Twitter raised eyebrows by moving their backend processing from Ruby to Scala, they "reverted" to Java for some of the concurrent operations:

initially we had a number of actors inside the system...over time as we ran more and more system tests on it, we found that actors weren’t necessarily the ideal concurrency model for all parts of that system. Some parts of the concurrency model of that system are still actor based....but for other parts we’ve just gone back to a traditional Java threading model. The engineer working on that, John Kalucki, just found it was a little bit easier to test, a bit more predictable. 

So I need someone to explain this to me. The state of the art in functional languages scare me a lot more than intelligently-designed concurrent programming, but everyone is hopping on the bandwagon, so I feel I must be doing something wrong. So, in typical fashion, I've made a heretical claim in the hopes that someone will show me the light and prove me wrong. Because I seriously don't get it.

Contract Tests in JUnit 4

As part of his talk on integration tests J.B. Rainsberger talked about how contract tests can be used to test the interaction between classes when using a mockist approach to developer testing. He wondered aloud if it would be possible to write these kinds of tests using abstract classes and JUnit 4. The answer is yes, with some caveats, as I demonstrate in the screencast below. Enjoy!

EDIT: If the embedded screencast below doesn't work for you, try this link.

Why I Always Ask To See Code

The quality of code is a reflection of the environment in which it was created. Chaotic environments usually create chaotic code. Professional environments usually create clean code. In my experience, it's one of the most reliable metrics that you can check before taking on a new client, employee or employer.

So ask to see code. Scan through it. Try to build and deploy it. Try to write a test. It only takes a few minutes and you can learn a lot.

Why I switched from TextMate to Vim

It wasn't because I was used to vim. I wasn't. In fact, aside from editing configuration files through ssh for the occasional sysadmin work I'm call upon to do, I'd hardly ever used vim before.

I started to investigate vim because I had hit a productivity plateau with TextMate. I had learned the majority of the useful shortcuts. I had installed all kinds of bundles, and even made a few. But I still had moments where I thought to myself "I'm wasting time with this", and I had no clear way to make them better.

I started to think that this was holding me back, not in the actual time it was taking, but in the way it affected how I write code. Programmers love efficiency. They tend to repeat actions that are efficient, and avoid those that aren't. As a result, your development environment has a direct effect on how you write code and what code you write. It encourages efficient actions and discourages inefficient ones. The problem is, what's efficient in your editor might not be the best thing for your codebase.

I wondered how I would write code differently if all my modifications had zero cost. If I could add methods, remove classes, rename variables and add new statements in the blink of an eye, I would make different choices about how I code...I don't think it would just be the same thing done faster. I might start writing more exploratory tests. I might use inline assertions more often. I might favor a failing test over firing up a debugger more often.

So I started worrying that inefficiencies in my work environment were encouraging me to take an approach that was, overall, less optimal. This has lead me to some pretty serious thought about what a truly optimal environment would be like. So far, I've come up with four properties of an ideal programming environment:

  1. Actions are accessible without switching contexts
  2. Feedback is immediate and relevant
  3. The environment is self documenting
  4. The environment is easily evolved

So the reason I switched from TextMate to vim, is that I think vim gets me closer to an ideal environment. Will it get me all the way there? I don't think so. I do think that I'm already more productive using vim (even after just a month of learning it) than I ever was with TextMate...and I'm still learning. I also think it's going to be a very long time before I hit a productivity wall like I did with TextMate. There's just so much to learn in vim.

Don't Get Blocked By A Broken Build

Lets examine the behavior of a healthy 3 person development team:

<Build failure alarm sounds>
Tim: Sorry guys, that was me!
<A few minutes pass>
Tim: Build's fixed
Steve, Bob (in unison): Thanks Tim!

Now lets examine the behavior of an unhealthy 3 person development team:

Bob: I just did an update and now the build is failing. Anyone know why?
Bob: Looks like Tim was the last to commit, does anyone know where he is?
Steve: I think he's in a meeting.

Bob: I guess I'm blocked then (heads to digg.com)

If Bob wanted to get around his block, he could fix the build himself and check in the change. Hopefully, he understands enough about what's going on to really fix it. And an email to Tim to let him know what happened would probably be a good idea as well.

Another option, rarely exercised, is to revert Tim's change to fix the build, and then email the team to let them know what happened. Really, it's nothing personal. Tim just make a simple mistake, he checked in when he wouldn't have enough time to check the build before going to his meeting. Now Bob (and the rest of the team) is stuck. If the fix isn't obvious, or will take a long time, the solution is simple: Just revert the commit.

Tim can recover his changes from source control when he gets back from his meeting and try again. If you can't (or don't) take responsibility for a broken build, and let everyone know that you're working on it, you should expect your commit could be reverted. Again, it's nothing personal...it's just the best thing for the team.

I think there's a sort of stigma associated with source control reverts. People think of it as destroying someone else's work. Sometimes this is hard, because often the thing that's breaking the build is a minor problem, and it's a mistake that we all make. But just as we've learned that refactoring isn't wasteful because it allows us to evolve our design, understand that reverting a commit isn't wasteful because it unblocks the team. And the changes don't go away...they're still in source control and easy for the original committer to recover. My suggestion is to keep this technique in your toolbox, and don't be afraid to use it. You should never be blocked due to a failing build.

MVC Isn't About Replaceable Parts

My continuing thoughts on MVC...

We separate models, views and controllers, because it decreases the cost of change. It does not, however, allow us to replace one these layers without changing the others. That's rarely practical. If it happens, that's great, but don't count on it. The same thing is true in thin clients. It's a nice idea to think that you can redesign your site simply by replacing your CSS and leaving your markup and javascript alone. Unfortunately, that's usually not the case.

We decouple our systems along these lines because over time we've found that these particular configurations create effective firewalls to halt the ripple effects of change. A harbor doesn't prevent all waves from rocking the boats, it just makes the big ones smaller. MVC and it's ilk make maintenance easier by reducing the cost of change, not creating a plug-replaceable system. Plug-replaceable systems are expensive and difficult to create, and you should only make one if you need it for a specific business reason.

By extension, if your domain causes changes to frequently occur in other parts of the system, decoupling those parts from the rest will decrease the cost. And while I'm not going to tell you to forget MVC (or Model-View-Presenter, or any other paradigm), be sure that the separations you create actually insulate changes that tend to occur on your particular project, and aren't just there because you think they should be.

Mouseless Firefox

Firefox's default keyboard shortcuts do a pretty darn good job of giving you everything you need to browse the web mouseless.

Backspace = Back
Shift + Backspace = Forward
Tab = Next Field (If you didn't know this one already...)
/ = Search Text
' = Search Links Only
F3 = Search Again

Once you've got a link selected:
  Enter = Open Link in current tab
  Ctrl/Cmd+Enter = Open Link in new tab
  Shift + Enter = Open link in new window

Spacebar = Page Down
Shift + Spacebar = Page Up
CMD + L = Jump To Location Bar (CTRL + L on Windows, I think)
Ctrl/Cmd+Tab = Switch tabs
Ctrl/Cmd+[1-9] = Select tab (1-9)
You can find the full list of firefox shortcuts here