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

Monthly Archives: June 2012

Wiley Kestner

WWDC && More

Wiley Kestner
Friday, June 15, 2012

Helps

  • Standup is back in the Lounge today

Hang on folks, we’re iterating again…

  • Recommendations when writing a migration

This is in regards to a migration which involves a large amount of models.

One option is to clone the models you care about (into a different directory).

Another option is to do the schema change and the data migration as a rake task that is unit testable.

It depends whether this is a one-time event or if it’s a boundary you’re going to cross back-and-forth.

Interestings

  • JSON Deep Clone in 1 line

def JSON.deep(object)
JSON.parse(object.to_json)
end

Events

  • Yoga @ 6p – all welcome
  • 0 Shares
  • Share on Facebook
  • Share on Twitter
Mark Rushakoff

Simplifying View-View Events in Backbone using the Mediator Pattern

Mark Rushakoff
Thursday, June 14, 2012

In most single-page apps, you will inevitably end up having multiple views on one page at a time.
It usually starts out with just one view, and then that view needs to bind to events on a subview, and then the subview gets its own subview who will also trigger events that affect the top-level view…

When you have one view that ties to one model, the standard way to set up the binding in Backbone looks something like

MyView = Backbone.View.extend({
  initialize: function() {
    this.model.bind("change:someProp", this.render, this);
  }
  // ...
});

You might later find yourself binding view events in the same way:

MySubView = Backbone.View.extend({
  events: {
    "click li.foo": "fooSelected"
  },

  fooSelected: function(e) {
    this.trigger("foo:selected", new Foo({id: $(e.target).data("fooId") }));
  }
  // ...
});

MyView = Backbone.View.extend({
  initialize: function() {
    this.model.bind("change:someProp", this.render, this);
    this.subview = new MySubView();
    this.subview.bind("foo:selected", this.addFoo, this);
  },

  addFoo: function(foo) {
    var fooView = new FooView({model: foo});
    fooView.bind("someOtherEvent", this.render, this);
    this.$(".foos").append(fooView.render().$el);
  }
  // ...
});

This can get out of hand rather quickly in several ways:

  • You have to add a lot of code to your view to just to wire up the events properly, and your view has to be very aware of specific subviews
  • If you have three or more levels of views, then the views in the middle may need to “forward” events between subviews and parent views
  • You can end up binding the same method to the same event on subviews of the same class
  • To test that the events are configured correctly, you will need to instantiate all of the necessary subviews in your tests

In my experience, one of the cleanest solutions to this problem is to apply the mediator pattern.

(To be fair: it would be better if we could avoid needing a mediator altogether, but that is often not a realistic goal.)

The Mediator Pattern

Concept

The mediator is a centralized object (often a singleton) whose public API looks roughly like:

  • subscribe(string channel, function callback)
  • publish(string channel, arguments)
  • unsubscribe(string channel, function callback)

Even though your views are still coupled together through their layout hierarchy, your event logic is coupled completely around the mediator.
The good news is that your view events just became enormously easier to test.

Testing

The naive way to test view events before introducing a mediator may look something like this, in Jasmine:

describe("the subview", function() {
  describe("the foo:selected event", function() {
    var spy;
    beforeEach(function() {
      spy = jasmine.createSpy();
      subview.bind("foo:selected", spy);
    });

    it("is triggered when clicking on a li.foo", function() {
      subview.$("li.foo:eq(0)").click();
      expect(spy).toHaveBeenCalled();
    });
  });
});

describe("the view", function() {
  describe("the foo:selected event", function() {
    beforeEach(function() {
      spyOn(view, "fooSelected");
      view.subview.configure();
      view.render();
    });

    it("calls fooSelected", function() {
      view.subview.trigger("foo:selected");
      expect(view.fooSelected).toHaveBeenCalled();
    });
  });
});

It looks fairly simple when written this way, but in the real world, getting your views all set up and rendered may be significantly more complicated.

After introducing a mediator, you only need to test the interaction between your view and the mediator.
If you write some custom matchers, your tests can look as clean as this:

describe("the subview", function() {
  describe("the foo:selected event", function() {
    it("is triggered when clicking on a li.foo", function() {
      expect(function() {
        subview.$("li.foo:eq(0)").click();
      }).toPublish("foo:selected");
    });
  });
});

describe("the view", function() {
  describe("the foo:selected event", function() {
    it("calls fooSelected", function() {
      spyOn(view, "fooSelected");
      Mediator.publish("foo:selected");
      expect(view.fooSelected).toHaveBeenCalled();
    });
  });
});

Existing libraries

There are a decent number of libraries out there that do mediation and only mediation.
Surveying some of the libraries listed on microjs turns up several:

  • Mediator.js
  • smokesignals
  • Radio.js
  • callbacks.js
  • MinPubSub
  • js-signals

A quick Google search will turn up even more libraries:

  • Postman

But we’re already using Backbone…

Exactly!
You don’t need any external libraries because Backbone already provides everything you need to implement the mediator pattern.
Backbone.Events is what provides the existing bind/unbind/trigger functionality, which is everything you need to make your own mediator.
In fact, they even briefly mention this concept in the Backbone docs:

For example, to make a handy event dispatcher that can coordinate events among different areas of your application: var dispatcher = _.clone(Backbone.Events).

If you do choose to use the mediator pattern, here are some other extensions to that basic pattern that may be helpful:

  • Consider what you want your mediator to do when the same function is bound twice to the same event name.
    In some cases this is correct and it should call that function twice, but in other situations that is a programming error.
    Consider also when the function is the same but the context differs.
  • Sometimes a bindOnce function is handy – unsubscribe immediately after invoking the callback.
  • Make sure that both in the app (”between” pages) and in your tests (between specs) you unsubscribe all existing subscriptions so that you don’t leak references to objects that you are no longer using.
  • Depending on how you implement your mediator, you’ll probably want to write a custom matcher for your test library as well.
  • 0 Shares
  • Share on Facebook
  • Share on Twitter
Wiley Kestner

Pairing blog posts (Wednesday && Thursday)

Wiley Kestner
Thursday, June 14, 2012

Helps

  • WED: Packaging a Rails app

A client needs to create a packaged version of their Rails app which can be installed on a machine that does not have internet access nor root access. Any recommendations for how to build a portable ruby, with gems? JRuby? Tokaido?

  • WED: Add a banner to jasmine runner

We have multiple jasmine test suites that we need to switch once in a while but sometimes we run the wrong suite by mistake. Is there a way to have a banner to identify which jasmine suite is running? Like having the project’s name on it?

  • WED: Patience with growth, esp Tuesday lunch
  • THUR: Jasmine!!?

PLEASE ROLL THIS FORWARD TO WEDNESDAY’S WHITEBOARD.

We wrote a Jasmine matcher that returned an object (or undefined) expecting the truth-iness of that value to determine whether the matcher succeeded.

When running in Chrome, that was fine. But when we ran headless via chromedriver it resulting in the following error:

Failure/Error: fail out unless spec_results['result'] == 'passed'
RuntimeError:
  TypeError: Converting circular structure to JSON

Changing our matcher’s return value to !!object (making it true/false) fixed it.

WHY!!?

  • THUR: Force download dialog on opening file in development

We’re using thin/rack as a rails dev server. We want to force the browser to open a download dialog for certain file types (.txt) that it wants to open and display itself. We’ve found that we need to set "Content-Disposition: attachment" in the headers, but how do we set the headers in thin/rack? We don’t serve the files through Rails.

Interestings

  • WED: We have a GIANT thank you card for Frederika, it is with HR if you would like to sign it
  • WED: Paperclip …#url + :filesystem != URL

Using the :filesystem storage option in Paperclip, the #url method returns a relative path, not a url. I consider this false advertising, but that’s out of my control. If you change the :url option to include a host, e.g. http://localhost/, you must also edit :path, otherwise the default :path (where :filesystem will store the images) will be public:url (that is, Rails.root/publichttp;/…)

  • WED: Rails SQL injection

Apparently the parameters hash can be exploited to select form arbitrary tables. This is fixed in 3.2.6, 3.1.6, 3.0.14 and a patch is available for Rails 2. See the following links for details:

http://seclists.org/oss-sec/2012/q2/504

http://weblog.rubyonrails.org/2012/6/12/ann-rails-3-2-6-has-been-released/

  • WED: David G. OOO 6/14-6/20

Please follow up with Danny Burkes for any issues.

  • THUR: Capybara "within" block

"within" scopes page to whatever elements are inside the within selector, but does NOT scope page.body or page.source.

  • 0 Shares
  • Share on Facebook
  • Share on Twitter
Alex Kwiatkowski

[Standup][NY] 06/06/14: Convincing your boss to use ruby

Alex Kwiatkowski
Thursday, June 14, 2012

Help

  • Dirk & Mick met a bloke at the pub last night. He was trying to convince his boss to use ruby by binary searching a date sorted text file. Some suggestions were:
    • use sed and awk instead
    • ‘system’ out to sed and awk
    • There is a nice blog post about why GNU grep is so fast. He may be able to get some ideas from there

Events

  • Ember.js meetup tonight – “Views and View Helpers”
  • 0 Shares
  • Share on Facebook
  • Share on Twitter
Onsi Fakhouri

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
Kris Hicks

git config rerere.enabled true

Kris Hicks
Wednesday, June 13, 2012

There have been times where I performed a rebase and had to resolve conflicts as part of the rebase, and then decided to abort the rebase for one reason or another. Without rerere the next time I went to perform the rebase I’d end up having to resolve at least some of the same conflicts I had previously, which is annoying.

This is where rerere comes in. It stands for reuse recorded resolution.

What rerere does is save the resolution of a conflict so that it can be re-applied later if it sees the same conflict again. When Git sees the conflict which it already has a resolution recorded for, it will apply the resolution automatically for you, and give you the opportunity to accept the resolution as applied, or change it.

Turning it on can be done two ways: set it as a configuration parameter using git config rerere.enabled true, or use it only when you think you might need it with git rerere both before and after the resolution of a conflict.

A more verbose explanation of rerere exists in Scott Chacon’s Pro Git.

  • 0 Shares
  • Share on Facebook
  • Share on Twitter
Wiley Kestner

Now on your mobile device!

Wiley Kestner
Tuesday, June 12, 2012

Helps

  • Google Dev Conference Happy Hour

There’s a Google dev conference at Moscone on June 28-29, and they have a careers fair concurrently which we’re attending. As a result we would like to do a Pivotal office tour, a brownbag talk, and happy hour from about 4pm that Thursday 6/28. Need about 6 pivots

  • jruby resque workers

We have java libraries that we need to run in a resque worker. Any patterns for doing this. Just run the workers as jruby. The whole project?

Interestings

  • Pivots and Clients don’t need tickets to tech talks
  • You need reset_column_information

If you have a migration that changes the columns on a model and a migration later that uses said model, you need to reset_column_information or Rails gets confused and won’t write your columns.

  • Please remember to turn in your 401k rollover form by the end of June to HR.

Events

  • WWDC Dev Lounge 4p-7p
  • CocoaHeads breakfast meetup Wed @ 07:30am

Yet another WWDC meetup

  • 0 Shares
  • Share on Facebook
  • Share on Twitter
Alex Kwiatkowski

Standup 6/12/2012: MySQL security flaw

Alex Kwiatkowski
Tuesday, June 12, 2012

Interestings

  • There is a MySQL brute force security flaw in some releases that have been distributed with linux (http://arstechnica.com/information-technology/2012/06/security-flaw-in-mysql-mariadb-allows-access-with-any-password-just-keep-submitting-it/)

Events

  • NYC.rb meetup tonight
  • 0 Shares
  • Share on Facebook
  • Share on Twitter
Ronan Dunlop

Leftronic – not just a pretty face

Ronan Dunlop
Monday, June 11, 2012

Leftronic has produced a really nice clean dashboard to view all your company’s data in one place. Real-time data beautifully organized and rendered. View info from Google Analytics and Adwords, Zendesk, Amazon Web Services, New Relic, Salesforce, Pingdom, Mail Chimp and more on one customized screen.

Most importantly they’ve made it easy to integrate Pivotal Tracker immediately with a ready to use template.
Check out their blog post to get the overview – but for the real meat – go right to their tutorial

  • 0 Shares
  • Share on Facebook
  • Share on Twitter
Ronan Dunlop

tenXer, Jeff Ma’s new company, makes velocity personal

Ronan Dunlop
Monday, June 11, 2012

Congrats to our friend Jeff Ma and his latest enterprise tenXer for being written up in the New York Times.

tenXer tracks activities from your Pivotal Tracker, GitHub, Phabricator, Google Calendar, and Gmail accounts and provides statistics about your performance. To put it in terms our users are more familiar with, it’s about visualizing your “life Velocity”. You can read more on the benefits of tenXer on the tour section of their site

Thanks Jeff and the gang at tenXer for choosing to integrate with Tracker right out of the gate. If like us at Tracker, you use most of the services tenXer connects to already, there is really no good reason not to get a tenXer account today.

  • 0 Shares
  • Share on Facebook
  • Share on Twitter

Topics

  • agile (780)
  • rails (113)
  • testing (88)
  • ruby (83)
  • ruby on rails (70)
  • jobs (62)
  • javascript (55)
  • techtalk (44)
  • rspec (38)
  • ironblogger (32)
  • productivity (30)
  • activerecord (29)
  • gogaruco (29)
  • git (28)
  • nyc (27)
  • rubymine (26)
  • bloggerdome (23)
  • mobile (22)
  • process (21)
  • pivotal tracker (20)
  • cucumber (20)
  • jasmine (19)
  • design (18)
  • ios (18)
  • webos (17)
  • objective-c (17)
  • android (16)
  • palm (16)
  • "soft" ware (16)
  • fun (15)
  • tracker ecosystem (15)
  • ci (15)
  • cedar (15)
  • rails3 (14)
  • performance (14)
  • bdd (14)
  • gem (13)
  • css (13)
  • tdd (13)
  • selenium (12)
  • goruco (12)
  • bundler (12)
  • meetup (11)
  • railsconf (11)
  • nyc-standup (11)
  • capybara (10)
  • mac (10)
  • mojo (10)
  • chef (10)
  • api (10)
Subscribe to Community Feed
  1. ←
  2. 1
  3. 2
  4. 3
  5. 4
  6. 5
  7. →
  • 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 >