Monthly Archives: February 2010

Our customers are asking for richer interfaces and user experiences. And so we – and by “we” I mean the Rails development community – are writing more and more JavaScript. We’ve gone from ignoring JS (using RJS server-side) to rendering JSON and writing our own jQuery plugins.

But in this transition some of us left our objects & design patterns on the server. Just because you’re writing a click handler in JavaScript doesn’t mean it couldn’t, or shouldn’t, be a method on an object.

If you have a long-lived page, its data are clamoring for object orientation. That data needs to be loaded, reloaded, and paginated via AJAX calls – why build that code (or that interface) more than once?

What about APIs that you’re accessing via AJAX? Wrapping an API in an object means you can more easily mock out the actual service in test and keep all the parameter logic separated from your data models. Or even more exciting, you can reuse your API code on the server (thanks for the timely example, Dion!).

JavaScript already has objects, but how do you organize your code in a more object-oriented way?

I’m a fan of a more Pseudo-classical approach to my JavaScript. (Sorry, Mr. Crockford, but I’m spending nearly all my time in Palm webOS these days and Mojo new‘s my objects). I’m not a fan of Prototype.js’sClass.create – $super is awkward, puts too much responsibility on the coder, the errors you get when you forget one are confounding, I don’t need to rename my constructor…the list is a bit longer, but you get the idea.

Instead we use JavaScript prototypes a lot like Ruby’s Classes – objects that implement common “class”-wide behavior. We setup an inheritance graph between child & parent prototypes – much like Google’s Closure. And we explicitly call functions on parent prototypes when we need “super”.

The result is a set of techniques that behaves enough like Classical inheritance for us to be productive. More importantly, we like it and the code we write with it – if there’s demand, I’ll write up an example.

Defining objects for purposes of encapsulation, abstraction and ease of testing (no matter the technique) is not only possible in JavaScript, they (surprise!) offer all the same benefits they do in other languages: less code that’s more robust and that you don’t mind extending & maintaining.

Why else is this important now? THE FUTURE.

Writing HTML5/RIA/MobileWeb applications in JavaScript is different than Rails/MVC web development. In order to make our code manageable we’ll need and want to crib from the object-oriented patterns of desktop client development.

This morning Yehuda Katz posted a response to my previous post, Technique for extending a method from a module, showing how a more modular organization of the Person class would allow for a solution that does not require a crazy meta programming hack. The idea is that by extracting the method we want to decorate into an ancestor class, Ruby makes it a lot easier to do what we want.

Previously I was aware that there were other ways I could structure the host class to make the module’s job easier but I did not try that because but I was writing the code with the knowledge that I would only be in control of one side of the equation, the module. The host class was going to be written by the end-user of the Rubygem the module was to be packaged in. Since I did not want to try dictate how the end-user structured the host class I ended up adding a lot of complexity to the module. The goal became how to write the module in a such a way that the class would “just work” upon including Teacher without requiring any additional steps to be taken. Asking the user to create an AbstractPerson class that contained their initialize method and then creating a subclass felt like an obtrusive request to make through a README that would ultimate negatively impact the user’s experience with the library.

Shortly after I put that blog post up I got this tweet from Josh Susser:

I was trying to solve how to decorate the initialize method from a mixed-in module. My real problem however, was that I was trying to modify the behavior of the host’s initialize from a module which is a good way to get into trouble. I am now of the opinion that if the module does need to be instantiated in some way, a good solution is to provide a initialization style method that the host class can call.

An added benefit of this approach is that initialize_teacher can be called from anywhere, and doesn’t have to happen within Person.new. This explicit instantiation violates my original goal of being unobtrusive to the user but it sidesteps the can of worms that the original approach has. One obvious problem that was likely to come up was the case where the module’s initialize needs to take a parameter. Once that happens it is not longer completely transparent to user. Even worse is if the host class’s initialize needs to take it’s own parameter. At that point it falls apart completely.

Credit to Austin Putman for suggesting this in a comment on the first post. Also thank you to Yehuda Katz for his informative post on writing modular ruby code.

I was recently presented the problem of appending to the initialize method from a module that was being included. To do this it would need to override the class’s initialize method with my own but keep the functionality of the original initialize method.

Whenever I need to do something in Ruby that I know will require some experimentation I like to move outside of my application and reproduce the problem in a simple way. For this problem I created a Person class that mixes in a Teacher module.

The goal is to get the following output when a Person object is created:

> Person.new
initializing teacher
initializing person

The basic program fails as expected; Teacher.new prints “initializing person” because Person’s initialize is trumping Teacher’s. Our immediate goal is to replace Person’s initialize with Teacher’s but in a way that preserves the original initialize method. By using alias_method we can create a copy of the original initialize method that we can call later.

This solution is the simplest thing that could possibly work, unfortunately it also has one major limitation. For it to work the call to include Teacher in Person has to come after Person’s definition of initialize. This is may be fine in situations where you have total control over the Person class, but what if Teacher is going to be part of a library you are distributing? Asking your users to place the include line to your module in a specific spot is unacceptable.

To make this work we need to be able to capture definitions of the method we want to redefine even after our module has been included. This sounds like a good time to use Ruby’s method_added hook.

module Teacher
def self.included(base)
base.extend ClassMethods
base.overwrite_initialize
base.instance_eval do
def method_added(name)
return if name != :initialize
overwrite_initialize
end
end
end
module ClassMethods
def overwrite_initialize
class_eval do
unless method_defined?(:custom_initialize)
define_method(:custom_initialize) do
puts "teacher initialized"
original_initialize
end
end
if instance_method(:initialize) != instance_method(:custom_initialize)
alias_method :original_initialize, :initialize
alias_method :initialize, :custom_initialize
end
end
end
end
end

Whoa! As you can see a lot of complexity has been added to Teacher. However, what it’s doing is actually really cool. Here is the breakdown:

What self.included is doing:

The ClassMethods module containing overwrite_initialize is added to base (Person).

overwrite_initialize is invoked.

method_added is defined on Person at the class level.

What overwrite_initialize does:

If a method called custom_initialize does not exist it defines one. custom_initialize runs Teacher’s initialize logic and then defers to Person’s initialize.

If the current initialize method is not our custom_initialize method then initialize is preserved as original_initialize and a copy of custom_initialize is made to replace initialize.

What method_added is doing:

Watches for new methods with the name “initialize”.

When an initialize method is defined method_added calls overwrite_initialize to put the chain from custom_initialize to this new initialize method in place.

What is particularly nice is that this implementation is flexible enough to handle multiple redefinitions of initialize. This is important because a subclass of Person may also define initialize. It is not perfect though—if the initialize in the subclass of Person calls super the program will go into an infinite loop where custom_initialize and the subclass’s initialize call each other indefinitely. If anyone has a suggestion on how to get around this please post a comment or fork the gist on Github.

Interesting Things

If you are testing with jasmine, it’s a good idea to include your CSS files in the test runner. This prevents, for example, issues where you’ve hidden an element in the CSS and expect it to be visible in your JavaScript. If you are using Sass, then you should regenerate your CSS from the Sass before running the jasmine tests. The current version of haml-edge updates the sass command-line tool with an update command. On one of our client projects, we added the following to our jasmine_config.rb file:

Interesting Things

RailsPlugins.org is asking that all Rails plugin developers register their plugins on the site. This will both help determine the set of plugins that are ready for Rails 3, and also provide a comprehensive directory of plugins.

Interesting Things

Bundler is now at version 0.9.x. The 0.8 to 0.9 release included many improvements and large internal changes. Everyone should probably upgrade, but be aware that this may be disruptive to your project, as the bundle command has changed names. You should be aware of this before upgrading. Yehuda has posted a comprehensive blog post about using Bundler that is worth reading. Since Bundler is in beta, it will probably keep changing.

There is some question about what state of a DOM node is shown in the Safari console when console.debug is called. Is it the state of the DOM node from exactly when the call was made, or is it some later state due to Safari asynchronously displaying the console messages? We are going to do some research and will update at a future standup.

Edit:

It sounds like the Safari issue occurs when logging a reference. Mentioned workarounds for the Safari issue include:

explicitly logging the variables that you are interested in; i.e., console.log(obj.a, obj.b)

Interesting Things

A project reported that GemInstaller failed when installing Rails 2.2.2, because it attempted to list the remote Rails 3.0.beta gem. There’s a bug open and awaiting more info, but since this is not reproducible on RubyGems 1.3.5, it may be due to an old RubyGems version not handling prerelease gems properly.

Pivot David Stevenson introduces Remarkable and Contextually, testing tools that can be used on top of RSpec. Remarkable is tool that makes testing common ActiveRecord and ActionController functionality more declarative, making tests shorter and more legible. Remarkable is used heavily in Contextually, a role-based testing framework that simplifies testing the behavior of controllers against a variety of roles. David shares his experience and metrics from using these tools on a recent project.

Isaac Hall of Recurly describes many of the hidden challenges in managing recurring billing online. He offers step-by-step tips, tricks, and firsthand experience on how to better architect and more easily deploy billing in your application.

If you’re using Jasmine to test your JavaScript code and you miss the shared examples functionality you used in RSpec, you can achieve the same result by just using a plain old function. Name your function something like “mySharedBehavior” and call it in each of your describe blocks that share the behavior. Jasmine will execute the function and print your results just as if you repeated all the shared examples in each of your describe blocks. Be careful not to modify the scope of the function that contains your shared examples (Jasmine needs to control the scope).

Javascript tests are good, but manually-maintained HTML fixtures are painful. It’s time consuming to keep fixture markup in sync with the actual markup produced by your app. Despite best efforts, deviations arise, leading to bugs and false positives in tests.

For the past few months on Mavenlink, we’ve been pre-generating real-life fixture markup and making it available in our javascript tests. Results have been positive.

The basic approach is simple:

1) Pre-generate real-life markup using any convenient mechanism.

2) When javascript tests run, load the pre-baked markup into the DOM for access by JS code.

For #1, we use a small set of RSpec controller specs that exist solely to generate fixtures. For #2, we retrieve fixture markup from our Jasmine server via ajax, and inject it into the DOM with jQuery. While our approach leans on the various bits of our stack, any part of it could be swapped out to adapt to different tools.

We create a workspace, hit the WorkspaceController‘s show method, and save the full text of the response’s <body> element to a file. This spec lives in a file with others like it, separate from the real controller specs. We have about a dozen of these specs, all in the same file.

We added save_fixture() and html_for() to ControllerExampleGroup to help with fixture generation. This gist has implementation details.

Our javascript tests sometimes require that we load different versions of the same page. We generate a different fixture for each version, giving them meaningful names like ‘busy-workspace-page’ and ‘empty-workspace-page’.

When we change markup consumed by our javascript tests, we re-run the controller specs that generate fixtures. Changes are picked up the next time we run our javascript tests. Fixture generation is hooked into continuous integration, so our javascript tests see the latest markup when running in CI.

Loading fixtures into the javascript test DOM

On the javascript side, fixture loading is handled by the code in this gist. Of note:

We use two methods for making fixture content available to our tests. loadFixture() inserts the fixture markup into the DOM for use by code that accesses the DOM. readFixture() returns fixture content as text; we use it to test our ajax callback methods.

Within the same test run, we cache fixture text in javascript to avoid multiple requests to the server for the same markup. Across test runs, we ensure our markup is fresh by appending a cache busting timestamp to our request path.

loadFixture() inserts markup into the #jasmine_content div. Then we examine the DOM, do stuff to it, and inspect it again. toHaveSelectedTab() is a custom Jasmine matcher. Jasmine matchers are super easy to write. We love them.

You may be wondering how we’ve established our event bindings. jQuery’s html() method, used within loadFixture(), executes any scripts in the markup passed to it. If you’ve bound events in your fixture markup, within a $(document).ready() or not, they will execute when you call loadFixture(). This is really nice, because it means the same mechanism used for binding events in real life is also used within tests, keeping our tests that much closer to reality.

If, on the other hand, you bind events not within fixture markup, but instead within a script loaded once per suite globally, you’ll have to invoke your event binding code explicitly before each test.

Speaking of event bindings, you’ll need to clean them up properly between tests. For example, jQuery live events are bound to document. We clear them in a global beforeEach():

Any events bound on elements within #jasmine_content are cleared out by jQuery when we call $('#jasmine_content').empty(), which also wipes the DOM clean between our test runs.

Results

Managing html fixtures like this has been a big win. In a recent team retrospective, consensus was “I can’t imagine doing it any other way.”

Building fixtures for tests is often simple as writing a 5-line controller spec. Maintaining fixtures just means re-running the specs, or perhaps enhancing the specs with additional data. We don’t see any production bugs from fixture markup vs. real markup discrepancies, and we spend very little time dealing with the fixtures.

We sometimes forget to re-generate fixtures after we change our markup, but, by now, realizing our mistake is a reflex action.

Test speed was one of our concerns going into this. Loading the fixtures takes time, of course. In practice, the runtime hit is dwarfed by the time saved by automating fixtures.

We have 224 javascript tests, and 200 of them load an html fixture. Our suite runs in 38 seconds in Chrome on a 2.4 GHz Core 2 iMac. (Other browsers are considerably slower). Of that 38 seconds, 9 seconds are spent loading fixtures and re-binding events.

We end up running our tests on fairly large DOM. We could probably save some running time by more narrowly focusing the markup that we generate and load. However, we haven’t felt it worth the additional development overhead. Additionally, running tests on our full DOM has an advantage – it exposes event handlers that conflict with each other.

Other gotchas

Nested describes are another great feature of Jasmine. It can be difficult, though, to keep track of where you’ve called loadFixture() within your hierarchy of describes. We sometimes found that we were calling loadFixure() twice in the same spec. To prevent that, we now keep track of how many times loadFixture() is called within a single test, and fail the test if the count exceeds 1.

At one point, we noticed that our javascript suite was consuming hundreds of megabytes of memory as it executed. We traced the problem to two jQuery plugins. Each time we loaded a fixture, the plugins claimed memory that never got freed. Now we mock out the plugins where we’re not explicitly testing them.

Isaac Hall of Recurly.com describes many of the hidden challenges in managing recurring billing online. He offers step-by-step tips, tricks, and firsthand experience on how to better architect and more easily deploy billing in your application.