Pivotal Labs

Main menu

Skip to primary content
Skip to secondary content
  • About
  • Case Studies
  • Team
    • Executives
    • Locations
      • San Francisco (HQ)
      • Boston
      • Boulder
      • Denver
      • London
      • Los Angeles
      • New York
  • Community
    • Blogs
    • Tech Talks
    • Events
  • Careers
    • Lifestyle
    • Principles & Practices
    • Benefits
    • FAQ
    • Apply
  • Contact
    • Press Room
    • Press Releases
    • In The News
    • Press Kit
  • All
  • Labs
  • Standup
  • Tracker

Cocktail: DRY up your backbone code with mixins

Onsi Fakhouri
Tuesday, July 24, 2012

I’ve continued to enjoy using Backbone.js to build single page apps. As I’ve seen more and more real world backbone I’ve started to develop opinions to augment the blissfully unopinionated little framework that could.

One of these opinions has turned into a mini-library: Cocktail adds functionality to Backbone’s extend to facilitate breaking up reusable code into mixins. It’s pretty straightforward:

  1. Define your mixin. Mixins are just plain vanilla JavaScript objects with methods and properties hanging off of them. Here’s a slightly contrived mixin that makes a view selectable:

    window.MyMixins = {};
    MyMixins.SelectMixin = {
      initialize: function() {
        this.model.on('change:selected', this.refreshSelect, this);
      },
    
    
      events: {
        click: 'toggleSelect'
      },
    
    
      render: function() {
        this.refreshSelect();
      },
    
    
      refreshSelect: function() {
        this.$el.toggleClass('selected', this.model.get('selected'));
      },
    
    
      toggleSelect: function() {
        this.model.set('selected', !this.model.get('selected'));
      }
    }
    
  2. Mix your mixin into your views. It’s a one-liner:

    var MyView = Backbone.View.extend({
      mixins: [MyMixins.SelectMixin, MyMixins.SomeOtherMixin],
    
    
      events: {
        'click .myChild': 'myCustomHandler'
      }
    
    
      initialize: function() { ... },
      render: function() { ... },
      etc...
    });
    
  3. That’s it! Instances of MyView will automatically inherit the behaviors and methods defined in SelectMixin.

Cocktail brings two simple things to the table:

  • it adds the special mixins:[...] notation to Backbone’s extend.
  • it automatically detects and handles method collisions. In the example above Cocktail will wrap MyView‘s and SelectMixin‘s implementations of initialize into one method and assign that method to the new, composite, class. The return value of this composite method is the last non-undefined value returned by the methods it wraps. All colliding methods are handled this way, as is the events hash (the events hashes all get merged together).

There are more details and examples at the repo. In particular, there’s an example for testing mixins with Jasmine — it goes over a pattern for writing shared behaviors in Jasmine.

  • 0 Shares
  • Share on Facebook
  • Share on Twitter

Coccyx: plug up those backbone leaks

Onsi Fakhouri
Wednesday, June 13, 2012

A number of projects at Pivotal have been using Backbone.js to build single page web apps. I’ve enjoyed using Backbone: it’s lightweight, unopinionated, helps encourage good separation of concerns between models and views, and reduces a fair bit of JavaScript boilerplate by bringing just enough framework to the table.

Unfortunately, it’s very easy to write Backbone code that leaks – especially in the view layer. A common backbone pattern is to set up some event bindings for a view:

var MyView = Backbone.View.extend({
    initialize: function() {
        this.model.on('change', this.update, this);
        this.someOtherModel.on('change', this.update, this);
        this.boundResizeHandler = _.bind(this.resizeHandler, this);
        $(window).on('resize', this.boundResizeHandler);
    },
    ...etc..
});

If your app needs to switch between several such views it is not enough to simply remove the view’s DOM and null out any references to the view. You must also unbind these event bindings in order for the view to be garbage collected. Moreover, if this view contains any subviews, you must also tear down all event bindings for all its subviews. If you do not succesfully clear out all bindings the view (and/or its subviews) will leak.

What’s worse: while there are some great tools out there to identify leaking objects, Backbone’s default constructor lists all objects as type child. This makes finding the leaky Backbone objects that are instances of MyView nearly impossible in Chrome’s heap propfiler.

Coccyx attempts to adress these problems by doing two things:

  1. Coccyx adds named constructors to Backbone. You no longer need to wonder which child is yours. By adding constructorName when you extend a Backbone class you’ll be able to easily tell which object is which in the console and the heap profiler.

  2. Coccyx implements teardown-able view hierarchies. You can easily build view hierarchies in which parents are aware of their children and can tear the entire structure down by calling tearDown() on a root node. tearDown() automatically unbinds any Backbone event bindings, cleans up DOM events and gives your view a chance to perform any custom teardown via a callback.

There are many more details at https://github.com/onsi/coccyx. Bug reports and pull requests are encouraged!

  • 0 Shares
  • Share on Facebook
  • Share on Twitter

[SF] Standup 4/26/2012: Hush Terminal, Hush

Onsi Fakhouri
Thursday, April 26, 2012

Help!

“How do I prevent the asset pipeline from concatenating all my javascript when running Jasmine tests?”

Max has an almost-there solution that he sent out to the mailing list:

module Jasmine
  class Config
    def src_files
      Rails.application.assets["application"].dependencies.map do |asset|
        "assets/" + asset.logical_path
      end
    end
  end
end

This only works if application.js requires all relevant javascript, and contains no code itself.

“I’m looking for a client-side JS syntax highlighter!”

  • Don’t use: pygments — it’s what GitHub uses and is server-side only.
  • Consider using: code mirror

Interesting?

That slowness when you start Terminal? It’s parsing through all your system logs to figure out when the last log-in occured. Speed up your terminal with

touch ~/.hushlogin

http != https — who knew? Turns out sending an AJAX post from a non-secured origin (http) to a secured end point (https) smacks agains the same-origin policy. Solutions?

  • Bring up and iframe pointed to https and AJAX post from there.
  • Or (better): Enforce SSL on the originating page.
  • 0 Shares
  • Share on Facebook
  • Share on Twitter

[SF] Standup 4/25/2012: Haproxymations

Onsi Fakhouri
Wednesday, April 25, 2012

Ask for Help

What’s the best way to think about redirects for API calls? e.g. You post to create an object, what should you get in return?

The crowd: Some concensus emerged around: send back a 201 with a location header pointing to the url for the object and a body containing the object itself.

Mongoid’s atomic operations don’t trigger hooks (before_save, after_save, etc…)

The crowd: Crickets…

haproxy, like nginx, can pass http connection through with the header ‘X-Forwarded-For’ set so that it is possible for the app to know the original client IP. But haproxy doesn’t have support for serving as an SSL endpoint, so https:// connections are proxied in tcp mode instead of http mode. And no headers can be added because the request remains encrypted.

Some solutions:

  • Terminate the SSL connection in front of haproxy. PIvots suggested doing this via an additional nginx instance. Online resources show how to do this using stunnel. (http://www.completefusion.com/ssl-load-balancing-with-haproxy-and-stunnel-on-debian/)

  • Use nginx as the load balancer and discontinue using haproxy, or find a load balancer that fully supports SSL.

  • Build HAProxy with TPROXY support. http://blog.loadbalancer.org/configure-haproxy-with-tproxy-kernel-for-full-transparent-proxy/

  • 0 Shares
  • Share on Facebook
  • Share on Twitter

A More Kosher Approach to Spork

Onsi Fakhouri
Thursday, December 1, 2011

Ask for Help

“Reloading of models under spork?”

From hybrid-cutlery expert Sobo:

Spork requires you to divide your spec helper into two phases, before fork and after fork.
Before fork, you want to do time consuming things like loading the Rails environment, so you don’t have to pay that cost on each test run.
If you end up requiring model classes or other volatile files before forking, then they won’t be reloaded for each test run.
This can happen, for example, when you use Devise route helpers, which touch the User constant during route evaluation.
This causes user.rb to be auto-required before fork.
Since the User constant is defined after forking, Rails won’t autoload changes to User, forcing you to restart the Spork server every time you change it.

There are two solutions:

  • The first is simply to avoid loading models or other code you want to auto-reload before fork.
  • If you must refer to models before fork, as is the case with the Devise route helpers, then put an explicit load (not require because it won’t load the file if it’s already been loaded) in your after fork block for the files that were loaded before fork.
    This will force them to be reloaded.

Interesting Things

  • It’s open season on open enrollment. SF will have an info session today at 12:30. Pizza will be served. Y’all have between now and December 9th to make changes.
  • Those with mohawks and staches in SF are encouraged to take a picture at the Vermehr e-mail station (closest e-mail station to the bathrooms).
  • 0 Shares
  • Share on Facebook
  • Share on Twitter

No really, you have to pick *one*

Onsi Fakhouri
Tuesday, November 29, 2011

Ask for Help

“Postgres SELECT * GROUP BY insists that all selected fields must either appear in the GROUP BY or be aggregated.”

Many agreed that this is, in fact, how a database should behave and that MySQL’s leniency on this matter is faulty. If you select a field that you don’t group by, you must tell Postgres how to combine the sub-set of values that fall in a given group into a single result (should it take the max? the min? the mean? the most purple?).

  • 0 Shares
  • Share on Facebook
  • Share on Twitter

SF Standup 9/16/2011: Schrodinger’s Cucumber

Onsi Fakhouri
Friday, September 16, 2011

Ask for Help

“I have a fresh install of Rails 3.1 and when I run specs with rake (with the development server running) it complains that the database is already in use.”

A chorus of replies: “I hate it when it says that.”

Looks like the test suite is trying to use the development DB. Try:

RAILS_ENV=test rake ...

It was pointed out that a call to rake that does not explicitly specify RAILS_ENV typically runs in development mode, detects that tests are being run, then switches to test mode. Any code that runs before the environment switch (in initializers, say) will run against the development DB.

“I have a large inherited cucumber suite that consistently fails on CI…. unless I screen share in and watch it. Why do I need to peek for my tests to pass?”

The likely answer: The very act of screen-sharing causes the test-suite to slow down. Use the setSpeed method in Selenium to force Selenium to take a breather between commands (the passed in value is in milliseconds).

Interesting Things

  • resque [ˈrɛsk] + JSON [jāsʌn] = surprise

    Ruby objects queued and dequeued by resque suffer a translation through JSON. What you put in may not be what you get out!

  • 0 Shares
  • Share on Facebook
  • Share on Twitter

The Vegetarian Version | It’s Pure and Good

Onsi Fakhouri
Friday, July 22, 2011

Ask for Help

“We’re trying to get the Google Docs API working on our project but we keep hitting unauthorized/bad request responses. Help!”

One thought: some ruby OAuth implementations are known to fail. Try shelling out and running a command line OAuth to make sure this isn’t an incompatibility with your ruby OAuth library.

Interesting Things

  • Ruby is slower than node.js.

    Two loops and a square root turns out to be a recipe for ruby slowness. The v8 engine wins again!

  • Ubiquitous Singaporean Chile (”Sambal Chilli”) now available – briefly – in the San Francisco lounge (courtesy of Nate Clark).

    To quote Nate: “It’s usually Shrimp based but this is the Vegetarian version which I find to be pure and good.”

  • Gogaruco sign up is now open.. and the early bird tickets are gone. Sign up soon!

  • 0 Shares
  • Share on Facebook
  • Share on Twitter

I Bless the Rains Down in Africa

Onsi Fakhouri
Monday, July 18, 2011

(Title: Standup 7/18/2011: I Bless the Rains Down in Africa)

Ask for Help

“I want a super-lightweight rack-based CMS/blogging setup. Any thoughts?”

Try out Toto a light-weight git-powered blog engine.

  • 0 Shares
  • Share on Facebook
  • Share on Twitter

Standup 1/14/2011: Key-Value-Fun

Onsi Fakhouri
Friday, January 14, 2011

Ask For Help

We’re running into a problem where MongoMapper is somehow setting the value of a ‘many’ relationship to null in the parent document, which then makes MongoMapper blow up when trying to load the parent doc from mongo. There’s an argument to be made that MongoMapper shouldn’t blow up, but it’s understandable that it’s confused when the key exists – here’s a spec demonstrating what happens when the null exists in
mongo: https://gist.github.com/779930

The big question is what is creating these values. All our inserts are through MongoMapper, so we’re blaming a bug we can’t reproduce in MongoMapper for the moment.

Interesting Things

How to fill up your Redis instance (part 2). Resque stores all records of failed jobs – including full backtraces – on Redis. Pushing a bug that generates lots of these can rapidly fill up your Redis instance. The solution? Send your Resque errors directly to hoptoad (which has better error management infrastructure anyway).

  • 0 Shares
  • Share on Facebook
  • Share on Twitter
Onsi Fakhouri

Onsi Fakhouri
San Francisco

Subscribe to Onsi's Feed

Author Topics

backbone (2)
javascript (2)
agile (12)
  • About
  • Case Studies
  • Team
  • Community
  • Careers
  • Contact
  • Labs
  • Events

Contact Us

contact@pivotallabs.com
+1 415-77-PIVOT
TwitterLinkedInFacebook

Pivotal Tracker

Tracker is the award-winning agile project management tool that enables real-time collaboration around a shared, prioritized backlog.
Visit pivotaltracker.com >