GuerillaPatch: An interface for monkey patching objects for Ruby 1.9 and 2.0

At RubyConf this week, the first preview of the upcoming Ruby 2.0 was released. One of the new features is refinements, a way of adding new behavior to an object that only takes place within a certain scope. This allows a safer way to extend existing objects without screwing up code that may be depending on the original behavior. A common example of this is ActiveSupport, which adds extensions to many of the core classes. With refinements, these extensions can be added to a refinement module, which can then be "used" in other namespaces without affecting the object globally.

This is a powerful new feature, but I was curious how best to write library code that uses it in a way that is interoperable with Ruby 1.9. I created a gem called GuerillaPatch which provides a single interface that will extend an object with a refinement if run under Ruby 2.0, and fall back to simply modifying the class globally if run under 1.9.

Install with gem install guerilla_patch. The source code and usage examples are available on GitHub.

jQuery is not an architecture

There is no question about the enormous positive impact jQuery has had on front end web development. It removes all the pain of the terrible DOM API and provides utility functions for just about everything small applications need. But when your application starts to grow, you need to structure your code in a more organized way to make sure things are testable, maintainable, and that features are discoverable to both new members of your team and your future self, who may not be able to discern the business logic of your application from looking at a slew of selectors and anonymous function callbacks.

Although jQuery has many facilities, its main purpose is as an abstraction layer to create a single, developer-friendly API that hides the ugliness of bad APIs and browser implementation quirks. Because most of its methods involve selecting, traversing, and manipulating DOM elements, the basic unit in jQuery is the selector. While this has the benefit of making DOM interaction simple and easy for beginners to learn, it has the unfortunate side effect of making people think that anything but very trivial amounts of JavaScript should be organized around jQuery selectors.

In a very simple application or basic web page, e.g. a WordPress blog, tiny snippets of jQuery or a plugin dropped into the page may be appropriate. But if you're building something with an amount of JavaScript even slightly larger than that, things will get difficult to maintain quickly.

jQuery is no substitute for good application architecture. It's just another utility library in your toolbelt. Think of jQuery simply as an abstraction of the DOM API and a way to think about Internet Explorer less often.

To illustrate just how backwards the jQuery-selector-as-basic-unit approach is for a non-trivial application, think about how it compares to the structure of an object in an object-oriented paradigm. At the most basic level, objects consist of members and methods – stateful data and functions that perform actions to manipulate that data. Methods take arguments on which they operate. In selector-as-basis jQuery, you're effectively starting with an argument (the selector), and passing it a method in the form of anonymous functions. This is not to say that object-oriented software is the only correct approach to writing software. The problem is that jQuery tends to make the target of an action the focus and not the action itself.

Ways to improve architecture

There are a few simple ways to improve the architecture of your JavaScript code beyond what is shown in most jQuery literature.

Namespaces

Use a single global object to namespace all your code. Use more objects attached to your global object to separate your modules by their high-level purpose. This protects you from name collisions and organizes the parts of your application in a discoverable way. When your application grows very large, this makes it easier for people less familiar with the system to find where a particular widget or behavior is defined.

window.FOO = {
  Widgets: {},
  Utilities: {},
};

Modules

Use function prototypes or the module pattern to create pseudo classes for your modules. All the intelligence about what your application does should be encapsulated inside these discoverable modules. Use clear, straight-forward method names. By extracting your event handlers and other functions into named methods, they can be unit tested in isolation for a high level of confidence that your system behaves the way you expect. It's also much clearer what the module does when looking at code you haven't seen in a while.

FOO.Widgets.CommentBox = function (containerSelector) {
  this.container = $(containerSelector);
  this.container.on("submit", "form", this.addComment.bind(this));
};

FOO.Widgets.CommentBox.prototype.addComment = function (event) {
  // More logic here...
};

// Many more methods...

Instantiate your modules

Initialize your modules by constructing new objects, passing in the appropriate selectors as arguments. Assign the newly created object to a property on your global object. A good convention is to use properties beginning with capital letters for modules, and properties beginning with lowercase letters for instances of those modules. Using this approach, you can have multiple instances of the same widget on one page with explicit control over each individual instance. This is useful both for interaction between widgets and for development in the web inspector in your browser.

Deferring initialization until a module is instantiated programmaticaly gives you great flexibility when testing. You can isolate the effect of your module to a particular subtree of the DOM, which can be cleared out in a teardown phase after each test.

FOO.comments = new FOO.Widgets.CommentBox(".comment-box");

Just the beginning

These are just a few very simple examples of ways to structure your code as your application starts to grow. For even better object-oriented abstractions, consider using a library like Backbone, which, although usually associated with Gmail-style single page applications, is also very useful for writing well-organized JavaScript that focuses on behavior and application logic instead of selectors tying it to the markup and heavy chains of callbacks.

Please don't use Cucumber

Cucumber is by far my least favorite thing in the Ruby ecosystem, and also the worst example of cargo cult programming. Cucumber has almost no practical benefit over acceptance testing in pure Ruby with Capybara. I understand the philosophical goals behind behavior driven development, but in the real world, Cucumber is a solution looking for a problem.

The fact that Cucumber has gained the popularity it has in the Ruby community is outright baffling to me. All the reasons to use it that people give are theoretical, and I have never seen them matter or be remotely applicable in the real world. Cucumber aims to bridge the gap between software developers and non-technical stakeholders, but the reality is that product managers don't really care about Gherkin. Their time is better spent brainstorming all the various use cases for a feature and communicating this either verbally or in free form text. Reading (and especially writing) Gherkin is a waste of their time, because Gherkin is not English. It's extremely inflexible Ruby disguised as English. The more naturally it reads, the more difficult it is to translate it into reusable code via step definitions.

There are basically two extremes of Cucumber:

  1. Writing Gherkin describing the feature at a very high level, and reusing few of the step definitions between features.
  2. Reusing step definitions, resulting in a level of detail described in the Gherkin which is not useful for any of the stakeholders.

Everything in between is just a bad compromise of one or the other.

Gherkin is really just glorified comments. If you simply write free form comments above Capybara scenarios, you can convey the same high level information about what the test is doing and what the acceptance criteria are, without any of the overhead, maintenance cost, and general technical debt of Cucumber. This doesn't allow for the real red-green-refactor cycle from the outside in of the BDD philosophy, but in my experience, developers tend to avoid the test-first approach with Cucumber simply because it's so painful to use. If you're not really following BDD practices, and your non-technical stakeholders are not reading or writing Gherkin, Cucumber is wasting your developers' time and bloating your test suite.

The one advantage Cucumber offers over simply commenting Capybara scenarios is that, by tying the "English" directly to the implementation, it's impossible for the "comment" to rot. This is certainly a danger, as a misleading comment is worse than no comment at all. However, this benefit comes at an extremly heavy cost. I would argue that it should simply be the discipline of developers to make sure that any time a Capybara scenario is updated, the corresponding comment is read through and updated as necessary.

Whenever someone writes a criticism of a particular piece of software, there is always a group of people who respond by saying, "It's just a tool. If it works for you, use it. If it doesn't, don't." While I agree in theory, this is where the effect of the cargo cult becomes real and damaging. Some guy somewhere came up with this idea that seemed great in theory, and everyone jumped on the bandwagon doing it because it sounded cool and it seemed like something they should do. After a while, people choose to use it just because it became the status quo. They don't see that all the reasons a tool like Cucumber seemed like a good idea, based on some blog post they read 3 years ago, are not in tune with the real, practical needs of their project or their organization. And once that choice has been made, everyone has to live with the increasing technical debt and slowed, painful development it creates.

Page 4