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
  • Tools
  • Contact
    • Press Room
    • Press Releases
    • In The News
    • Press Kit
  • All
  • Labs
  • Standup
  • Tracker

Ember.js and SoundManager2

Luan Santos
Sunday, June 16, 2013

Continuing the experimentation with cool libraries and ember this time I’ll use SoundManager2, a really useful sound playing library for HTML5 and/or Flash that is compatible with most browsers out there.

It is not very hard to use and it has a pretty decent documentation, what I’ll show is a very simple usage of it that I plan to improve in the future, but this should give an idea on how to start at least.

My app has a Song model that contains a url property, there is a ‘songs’ route that lists the songs and a ‘song’ route that shows the player for a given song.

Let’s start by including SoundManager2 into our app, grab your copy from their website, the downloaded zipfile will have several folders, look for soundmanager2.js in the script folder and soundmanager2_debug.swf in the swf folder. You’ll want to change this to the nodebug version when you’re going production.

Once we did that we need to initialize soundmanager with our app. We do that by adding an initializer:

App.initializer({
  name: "soundmanager",
  initialize: function() {
    soundManager.setup({
      url: '/swf'
    });
  }
});

Note the ‘/swf’ path there, that’s where you put the swf file, update accordingly. This initializer will setup soundmanager with all the default options, you can override them by adding more properties to the setup function call. Please refer to the documentation.

Alright, now that we have everything in place we can use soundmanager to manage our sounds. I said that I have a route for each ‘song’ so let’s start by adding the template for that route.

<script type="text/x-handlebars" id="song">
  <button class="btn" {{action 'playPause'}}>{{playPauseLink}}</button>
  <button class="btn" {{action 'stop'}} {{bindAttr disabled="unstarted"}}>Stop</button>
</script>

This template has some stuff in it, let’s start by looking at the ‘playPause’ button, it’s content is a variable ‘playPauseLink’, we expect that to be either “Play” or “Pause” depending on the current state of the player, and it’s action is ‘playPause’ which will toggle the two.

Let’s take a look at ‘playPauseLink’:

App.SongController = Ember.ObjectController.extend({
  // …
  playPauseLink: function() {
    if (this.get('playing')) {
      return 'Pause';
    } else {
      return 'Play'
    }
  }.property('playing'),
  // …
});

Our controller have a property ‘playing’ which is a boolean for whether the song is playing or not, we use that to compute the play/pause link text with a binding, so it will stay up to date automatically. Now let’s see the playPause action:

App.SongController = Ember.ObjectController.extend({
  // ...
  playPause: function() {
    if (this.get('playing')) {
      this.pause();
    } else {
      this.play();
    }
  },

  play: function() {
    var sound = this.get('sound');

    if (this.get('unstarted')) {
      sound.play();
      this.set('started', true);
    } else {
      sound.resume();
    }

    this.set('playing', true);
  },

  pause: function() {
    this.get('sound').pause();
    this.set('playing', false);
  },
  // …

Now I’m showing you 3 methods, one is the actual action ‘playPause’, that will call either play or pause depending on the current state of the player, play and pause will set the ‘playing’ state accordingly. Play will either ‘play’ or ‘resume’ depending on whether the player has started or not, we use the property ‘started’ and it’s counterpart ‘unstarted’ for that purpose.

That’s all great but it will do nothing if we don’t load the sound first, we have to do that after soundmanager is ready and the template is inserted, let’s do that in our ‘SongView’ on the ‘didInsertElement’ callback.

App.SongView = Ember.View.extend({
  didInsertElement: function() {
    var self  = this;

    soundManager.onready(function() {
      self.get('controller').send('loadSound');
    });
  }
});

Note that we’re calling the ‘loadSound’ method in our controller once soundmanager is ready:

App.SongController = Ember.ObjectController.extend({
  // ...
  loadSound: function() {
    var self = this;
    var sound = soundManager.createSound({
      url: this.get('url'),
      onfinish: function() { self.finish(); }
    });

    this.set('sound', sound);
  },

Loading the sound is as simple as following the soundmanager’s documentation, create a sound passing in the ‘url’ property from our model. We set the ‘onfinish’ callback to reset the player once the sound is over. We’re also missing the ‘stop’ functionality that we have on the template:

App.SongController = Ember.ObjectController.extend({
  // ...
  finish: function() {
    this.set('playing', false);
    this.set('started', false);
  },

  stop: function() {
    this.get('sound').stop();
    this.finish();
  },

‘finish’ is just resetting the states, stop is calling stop on our sound object and then resetting the state by calling finish.

That is about the simplest play/pause/stop player I could think of using soundmanager, I published the full code for this simple implementaiton on this Gist. It has a little bit more to it like position/duration but it’s pretty much what I wrote above.

 

Library versions used in the post:

  • Ember.js: 1.0.0-rc.5
  • Handlebars: 1.0.0-rc.4
  • Ember Data: 0.13
  • jQuery: 1.9.1
  • SoundManager2: 2.97a.20130512
  • 0 Shares
  • Share on Facebook
  • Share on Twitter

Ember.js and Flot charts

Luan Santos
Sunday, June 9, 2013

Update (Jun 10th, 2013): Use custom view helpers and view bindings to make it simpler and more reusable.

Continuing to play around with Ember.js I wanted to draw some charts. I’ve used flotcharts with great success in the past but since it’s just a jQuery plugin it is obviously unaware of ember’s amazing data binding capabilities.

Flot requires you to pass in an array of datapoints every time you want to create or update a chart. You can’t use a bound variable in that array so we will have to use observers to manually update flot when our data changes.

Let’s create a flot view that we can re-use in our templates:

App.FlotView = Ember.View.extend({
  classNames: ['canvas'],

  didInsertElement: function() {
    this.renderChart();
  },

  chartUpdated: function() {
    this.renderChart();
  }.observes('datasets'),

  renderChart: function() {
    var canvas = this.$();
    if (canvas) {
      canvas.plot(this.get('datasets'));
    }
  }
});

We’re assuming here that this view is being added on a context where the controller has the property datasets. We observe that property for changes and we ask flot to update the chart accordingly. Here’s how you add that in your template:

Here we pass in our controller’s property datasets. We observe that property for changes and we ask flot to update the chart accordingly. Here’s how you add that in your template:

<script type="text/x-handlebars" id="charts">
  {{view App.FlotView datasetsBinding="datasets"}}
</script>

You can go further and make it cleaner by defining your custom view helper:

Ember.Handlebars.helper('piechart', App.FlotView);

And use it as simple as:

<script type="text/x-handlebars" id="charts">
  {{piechart datasets=datasets}}
</script>

For a simple line chart that datasets property should be something like an array of series [[[1, 3], [2, 14.1], [3.5, 3.14]], [[1, 3], [2, 8], [3.5, 2]]]. Refer to the flot documentation for more details on that.

Let’s say we have a controller like the following:

App.ChartsController = Ember.ArrayController.extend({
  datasets: function() {
    return this.map(function(chart) {
      return chart.get('dataset');
    });
  }.property('@each.dataset')
});

Here we’re creating the datasets computed property that depends on @each.dataset, that is, if the dataset property changes in ANY of the underlying models associated with this ArrayController this property will be updated and the observers (as the one we defined in the view) will be notified.

The dataset property on the model could be returning either one of the mentioned series or an object with more detailed information such as labels, color, etc..

That’s all the non-standard code you need for it to work, everything else is regular models and routes, the result is pretty nice and very responsive. You can also have your models pool for server changes for an auto-updating chart, and it’s definitely a very clean and straightforward implementation for something that would require quite a few events and callbacks if we didn’t have the sweetness of databinding.

I’ve published the complete example using pie charts (their datapoints are simpler) on this JS bin.

  • 0 Shares
  • Share on Facebook
  • Share on Twitter

Incremental refactoring

Luan Santos
Saturday, June 1, 2013

Refactoring is an extremely important part of the process of developing software. It’s what makes your code maintainable with the help of it’s equally important counterpart test suite. It is always good to go on refactoring mode after you made your tests green, but what if you miss it? What if you let it slip and they you have this snowball that will, before you notice, turn into an avalanche? How do you recover from it without compromising your process and your velocity?

It is important to spend time making your code more maintainable, it will make your velocity more consistent in the long run, but sometimes you can’t stop all the feature work at once to fix all the design problems you have, sometimes it is just too much, you have to start iterating. To do that you have to first define your pain clearly so you can get an idea of what you want.

Finding the problem might be a straightforward task, it may be right in your face screaming to be solved. But often times your team aquires the stockolm syndrome and then no one can see the problem anymore, that’s when a new member to the team is most helpful, the untrained eye can see the unseeable. Sometimes you know the problem is there and you just avoid dealing with it because your current code is “good enough”. Well, it is probably not good enough.

The problem with code is that there is always another way to do it, and while you think your way is better, your colleague might think otherwise, and you can always think of another way and another way that will seem better that your current solution. That said, you have to try and figure out what do you want to solve, finding the problem doesn’t necessarily mean that you know how you ideally want to solve it.

We’re talking about large design problems that have grown overtime, not a single messed up object or method that you can just extract out in a single coding session. If you feel like it is something you’re able to extract out in a short amount of time I say just do it. But if you feel like it is something that would take at least a few sessions you have to think about what steps you’re gonna take.

As I said, code can be written in several ways, so can your steps be defined. Think about your goal and figure out what is the smallest part you can enhance towards it. Do it. You will not have solved your problem, you will be closer but not quite. For example imagine you have a big object that has turned out into a method bucket that doesn’t quite make sense anymore, let’s say you want to extract each of the methods into it’s own class, extract one at a time then, and let your method bucket slowly turn into a meaningful object or even better, vanish.

The end of this story is very rewarding, this strategy allows you to do a major overhaul in your codebase with the costs of it amortized over several pieces of feature work. Try it out.

  • 0 Shares
  • Share on Facebook
  • Share on Twitter

Playing with Ember.js and Devise

Luan Santos
Sunday, May 26, 2013

I have been playing with Ember in and out since the beginning of 2012, you may have seen my two (obsolete?) libraries ember-facebook and ember-formbuilder. I wrote them out of real needs I had on projects back then.

I was away from ember since version 0.9.8 and ember-data I don’t even remember if it had a version number yet, and I started playing around with it again this last few weeks.

Right now there are not a lot decent resources of getting started with ember and unfortunately some of them are outdated. I am sure that this will get better and better now that the framework is stabilizing.

Anyway, I am working in a little project with a friend and we decided to use ember on it. First thing we implemented was authentication. This is a very simple problem with several solutions. We want to use devise. A very simple one is to rely on the devise’s engine and just make it a separate part of the app, after that you render the user’s session JSON on a metatag and parse it in ember. There is a very nice tutorial on how to do that by Alexander Zaytsev here.

Alternatively you can implement all the interface yourself and have a truly single page application, and it is not that hard. First thing you have to do is turn devise into an API by creating a few controllers. I am just going to show sign-up and login here.

Turning Devise into and API

For sign up let’s create our own users controller to handle registrations:

class UsersController < ApplicationController
  def create
    user = User.new(params[:user])

    if user.save
      render json: user, status: :created
    else
      respond_with user
    end
  end
end

It’s very simple, an API endpoint to create users using the devise’s user model and respond with the JSON for that user (you may or may not be using active_model_serializers here, but you should be).

Similarly we create a sessions controller to handle, well, sessions:

class SessionsController < ApplicationController
  def create
    user = User.find_for_database_authentication(email: params[:session][:email])

    if user && user.valid_password?(params[:session][:password])
    	sign_in user
    	render json: {
    	  session: { id: user.id, email: user.email }
    	}, status: :created
    else
      render json: {
        errors: {
          email: "invalid email or password"
        }
      }, status: :unprocessable_entity
    end
  end

  def destroy
    sign_out :user
    render json: {}, status: :accepted
  end
end

This one is longer, but it is also very simple: we find the user, we validate whether the password is correct and we then respond with either the basic user data and a successful status or an error message to be shown by ember with an errors status.
We are also adding the destroy action for loggout.

Don’t forget that you need to add theses to your routes.rb:

resources :users, only: [:create]
resources :sessions, only: [:create, :destroy]

Models

We are going to need two Ember models for this, one for our registration and another for the sessions, models in ember-data are extremely simple and there is not a whole lot to say about them.

App.User = DS.Model.extend({
  email: DS.attr('string'),
  password: DS.attr('string'),
  passwordConfirmation: DS.attr('string')
});

App.Session = DS.Model.extend({
  email: DS.attr('string'),
  password: DS.attr('string')
});

That is already enough for us to play around in the console and create users/sessions:

var user = App.User.createRecord({email: 'foo@bar.baz', password: 'password', password_confirmation: 'password'});
user.save();
var session = App.Session.createRecord({email: 'foo@bar.baz', password: 'password'});
session.save();

Routes

Let’s define our routes:

App.Router.map(function() {
  this.resource('users', function() {
    this.route('new');
  });

  this.resource('sessions', function() {
    this.route('new');
    this.route('destroy');
  });
});

The first two routes we have to add are simple and are just setting the content properties of their controllers. The destroy route is slightly more complicated:

App.UsersNewRoute = Ember.Route.extend({
  model: function() {
    return App.User.createRecord();
  },

  setupController: function(controller, model) {
    controller.set('content', model);
  }
});

App.SessionsNewRoute = Ember.Route.extend({
  model: function() {
    return App.Session.createRecord();
  },

  setupController: function(controller, model) {
    controller.set('content', model);
  }
});

App.SessionsDestroyRoute = Ember.Route.extend({
  enter: function() {
    var controller = this.controllerFor('currentUser');
    controller.set('content', undefined);

    App.Session.find('current').then(function(session) {
      session.deleteRecord();
      controller.store.commit();
    });

    this.transitionTo('index');
  }
});

This destroy route does not have a controller or view (at least not an explicit one), it basically unsets the content of the currentUser controller (check next section) then issue a delete request on the sessions controller of our API and redirect the user back to the root. Note that we are “finding” the session using the id of “current”, ember-data does not support singletons explicitly, so we have to work around that fact by doing that. You can read more about this here.

Current User

This part is based on the post I mentioned earlier by Alexander Zaytsev. It’s an object controller that will hold the existence (or not) of the current user session.

App.CurrentUserController = Ember.ObjectController.extend({
  isSignedIn: function() {
    return this.get('content') && this.get('content').get('isLoaded');
  }.property('content.isLoaded')
});

We’ll also need this initializer to populate it once the app is loaded.

Ember.Application.initializer({
  name: 'currentUser',

  initialize: function(container) {
    var store = container.lookup('store:main');
    var user = App.User.find('current');

    container.lookup('controller:currentUser').set('content', user);
    container.typeInjection('controller', 'currentUser', 'controller:currentUser');
  }
});

Here we’re asking or API for the current user with the same singleton strategy App.User.find('current'), the app is supposed to return either a successful message with the user JSON or an error. We now need a show endpoint in our users controller, as simple as respond_with current_user, don’t forget to add the show route in your resource on routes.rb.

Templates

We need two things here, we need a sign up form and a login form. Another thing we may want is navigation links. Let’s start with the forms. There is no point in logging-in if you don’t have an account right? So let us sign up!

<h1>Create an Account</h1>
<form class="form-horizontal user-form">
  <fieldset>
    <div class="control-group" {{bindAttr class="errors.email:error"}}>
      {{view Ember.TextField valueBinding='email' name='email' placeholder='Email'}}
      <span class="help-inline">
        {{errors.email}}
      </span>
    </div>
    <div class="control-group" {{bindAttr class="errors.password:error"}}>
      {{view Ember.TextField type="password" valueBinding='password' placeholder='Password'}}
      <span class="help-inline">
        {{errors.password}}
      </span>
    </div>
    <div class="control-group" {{bindAttr class="errors.passwordConfirmation:error"}}>
      {{view Ember.TextField type="password" valueBinding='passwordConfirmation' placeholder='Password Confirmation'}}
      <span class="help-inline">
        {{errors.passwordConfirmation}}
      </span>
    </div>
    <a href='#' {{action cancel}} class='btn'>Cancel</a>
    <button type="submit" {{action save}} class='btn btn-large btn-primary'>Sign Up</button>
  </fieldset>
</form>

 

Assuming you’re on rails and using the standard ember gems you should put this file in app/assets/javascripts/templates/users/new.hbs, ember will automatically pick it up if you follow it’s defaults.
I am using a bootstrap form structure here to show the inputs and error messages. Ember-data will automatically populate the errors property for you if you’re API is returning the right thing, which it is.

And our Login form:

<h1>Login</h1>
<form class="form-horizontal user-form">
  <fieldset>
    <div class="control-group" {{bindAttr class="errors.email:error"}}>
      {{view Ember.TextField valueBinding='email' name='email' placeholder='Email'}}
      <span class="help-inline">
        {{errors.email}}
      </span>
    </div>
    <div class="control-group" {{bindAttr class="errors.password:error"}}>
      {{view Ember.TextField type="password" valueBinding='password' placeholder='Password'}}
    </div>
    <a href='#' {{action cancel}} class='btn'>Cancel</a>
    <button type="submit" {{action save}} class='btn btn-large btn-primary'>Login</button>
  </fieldset>
</form>

This files goes into app/assets/javascripts/templates/sessions/new.hbs.
Very similar to the sign up form, in this case we’re only showing errors on the email field because we’re not specifying whether the email or password was wrong, sometimes you may want to do that, this is not our case here.

There you have it, a very simple sign up and login for that will just work. Right? No, we still have to define our actions, but we’re getting there. Note that we defined in both forms {{action save}} in our submit buttons, now we need our controllers to handle that.

Oh, and you may also want to add these navigation links somewhere:

{{#if currentUser.isSignedIn}}
  Logged in as {{currentUser.email}}
  {{#linkTo 'sessions.destroy'}}Logout{{/linkTo}}
{{else}}
  {{#linkTo 'users.new'}}Sign Up{{/linkTo}} |
  {{#linkTo 'sessions.new'}}Login{{/linkTo}}
{{/if}}

Controllers

Currently we have defined one controller that is the currentUser controller to control the active session, we now need to define controllers to react on actions on our forms, once again we’ll start with the signup form:

App.UsersNewController = Ember.ObjectController.extend({
  save: function() {
    var self = this;

    this.content.save().then(function() {
      self.transitionToRoute('index');
    });
  },

  cancel: function() {
    this.content.deleteRecord();
    this.transitionToRoute('index');
  }
});

When the user hits ‘save’ we tell the model to save itself this.content.save() and then we redirect the user to the root when we’re done. Everything else is being handled by ember and ember-data here behind the scenes, validation errors will automatically update the bindings in the template and will NOT call the ‘then’ callback.
When the user hits ‘cancel’ we just clean up the model this.content.deleteRecord() and redirect back to the root.

The sessions controller is a bit more complicated, let’s take a look:

App.SessionsNewController = Ember.ObjectController.extend({
  needs: ['currentUser'],

  save: function() {
    var self = this;

    this.content.save().then(function() {
      var userJSON = self.content.toJSON();
      userJSON.id = 'current';
      var object = self.store.load(App.User, userJSON);
      var user = App.User.find('current');

      self.get('controllers.currentUser').set('content', user);
      self.transitionToRoute('index');
    });
  },

  cancel: function() {
    this.content.deleteRecord();
    this.transitionToRoute('index');
  }
});

The ‘cancel’ action here is exactly the same as before, so let’s talk about saving. The first step is the same, we ask ember-data to ‘save’ our model this.content.save() and we hook into the ‘then’ callback. Since our create session endpoint is return a user’s JSON we’re gonna use it to populate the currentUser controller. At this point self.content.toJSON() will have the user’s email, but it may have more information as you application needs grow. We have to manually set the ‘id’ property on that JSON object since ember-data will not serialize it. We set it to ‘current’ to refer to our singleton currentUser.
And then we finally load that into a User object using the ember-data store. We then set the content of our currentUser controller to be that loaded user: self.get('controllers.currentUser').set('content', user).

And there we have it, if everything is wired correctly we should have a working signup/login/logout app. I hope it was as helpful for you as it was for me.

References

  1. Alexander Zaytsev – Using Rails & Devise with Ember.js
  2. Brian Cardarella – Building an Ember app with RailsAPI
  3. Jesse Wolgamott – API JSON authentication with Devise

Caveats

1. I had to add this line to my devise.rb file inorder to be able to get rid of the devise_for :users on the routes.rb file. That’s because devise won’t provide you with the dynamic helpers like current_user or user_signed_in? if you don’t call add_mapping, and devise_for calls that method underneath the hood.

config.add_mapping :users, {}

2. This strategy relies on cookies and sessions, if you’re going with this instead of using a auth token you should make sure your app is secure by having protect_from_forgery on. Then you will need to hack into ember-data’s ajax adapter to send the csrf-token on every request. You can achieve that with something like this:

$(function() {
  var token = $('meta[name="csrf-token"]').attr('content');
  $.ajaxPrefilter(function(options, originalOptions, xhr) {
    xhr.setRequestHeader('X-CSRF-Token', token);
  });
});
  • 0 Shares
  • Share on Facebook
  • Share on Twitter

Sidekiq Divide & Conquer

Luan Santos
Sunday, May 19, 2013

It happened on a project I was working on that we had to implement a divide & conquer algorithm using our background jobs processor, in this case we were using sidekiq. Implementing this using sidekiq can be quite challenging since all the workers are independent and they do not trigger any callback once they’re done.

Continue reading →

  • 0 Shares
  • Share on Facebook
  • Share on Twitter

Winning a Rumble

Luan Santos
Saturday, May 11, 2013

Last year before I joined Pivotal Labs me and my friend Raphael Costa participated in a brazilian Rumble, inspired by Rails Rumble ran by the folks from Startup DEV. It was a very interesting experience and I learned a lot from it. We won first prize, and I want to tell how we did that, and why I would change some things if it was a real project supposed to live more than 48 hours.

First, if you don’t know what a rumble is, a rumble is a developer’s competition where you have a very limited time to develop an app, your result is evaluated by some folks and the best app (according to their criteria) wins. In the case of Rails Rumble or Startup DEV rumble we had 48 hours over a weekend.

The plan

The plan can and should be draw before you start the rumble. When the clock starts ticking you have to laser focus in implementing everything you can.

First thing you need is an idea, it doesn’t need to be revolutionary it just needs to be implementable and easy. If it’s revolutionary, bonus points for you. Once you have an idea you have to describe in detail what is the featureset you are looking for.

When you have you featureset, you have to remove everything, EVERYTHING that is not absolutely required for your MVP, sort the features you removed in nice-to-have order in case you have spare time at the end.

Draw your mockups on paper and have them ready and attached to each story you selected as part of your MVP, if you have a designer, great, make him draw more detailed wireframes, if you don’t then you’ll have to use the tools the world provide you, such as bootstrap or foundation or whatever you prefer, do not waste time in things you are not expert in.

Split tasks based on capacity, in our team we were two developers, I had more experience with dev-ops (and we had to deploy our app to a VPS that was provided by the organization) he had more experience with UI/UX design, so I barely thought about how the app should look, and he barely used ssh.

Applying the plan

The basic procedure is: pick a story, assign it to you, implement it as quick and simple as you can, deliver it asap, move on.

Stay in sync, you have to know what’s happening with the other folks in your team, if your team is larger than 2, it gets more and more dangerous. You do not want to spend time resolving complicated merge conflicts so make sure the tasks are well parallelizable and that no one is stepping in no one’s toes. We had quick check-in (2 minutes, standup style) every 2 hours.

We knew what we were capable of, so we didn’t try to do anything other than that. If you never implemented a payment gateway, don’t try to do so in a 48 hour project, you will waste time and you won’t be able to finish. We knew how to TDD and we had paired before, but these were things that we were not used to do, processes not clear in our minds, we would have to learn it on the go and we would fail if we tried. When you try something new you will certainly spend time figuring things out. So because of that we didn’t even try, we did not test, we did not pair.

Commit often, commit every time, on every change. This avoids complicated merge conflicts and saves you a lot of times. Write decent SHORT commit messages so you team can understand what is that that you did just by parsing the message quickly. Pull often, see the log, git log --graph --oneline was the command we used to quickly parse messages, alias it to something simple, like gl, for example. Once you finish a feature, deploy it. Make sure everything works properly in your deployed environment.

We finished everything and more with about 2 hours to spare, in this 2 hours we looked for bugs, found some and fixed them. This spare time is essential specially if you are not TDDing, you will find problems.

What would I do differently

First of all, if you want your app to continue after the 48 hours you have to TDD, on the next day after the competition we looked at the code and it was only OK, it wasn’t bad or anything, but it was very hard to trust it and make changes because without any tests you have no confidence on doing it. The solution for us would be rewrite the app TDDing or backfill, and backfilling is very painful.

Skiping the tests is very risky, you may break everything without knowing, and that would make you fail, we took that risk and it worked for us. I wouldn’t do that again, I would TDD next time even if that means reducing the scope even more, it’s too hard to develop a real app without it.

Pair programming and TDD are things that make you very productive on the longer run, on a 48 hour crazy competition it might not be the best thing to do if you’re there to win and your team is only composed of two people. If you have a really small and simple featureset and your team has experience you can get away without it and it would be faster on this 48 hour streak. It is very likely that you will have to rewrite your app after tho.

I would pair if I had a team of 4, a single pair may not be the best for a 48 hour thing, you kinda need the parallelism on this short project. The ideal setup would be two pairs tho. More than 2 parallel developer stations would probably be a bad thing.

In conclusion

Participating is fun, we had a lot of fun, there were several good projects on the competition and it was awesome. If you ever have the opportunity to participate in one of these you should, it’s very tiring but it is worth it at least once. If you’re interested our project is still online at agrupe.se (it’s in portuguese, sorry, google translate).

  • 0 Shares
  • Share on Facebook
  • Share on Twitter

Vipe, a Vim command pipe

Luan Santos
Friday, May 3, 2013

When I’m doing outside-in TDD (and that is basically whenever I’m coding) I often process things as a stack. I write an acceptance level test, run it. It fails (hopefully), so I write a lower level test, let’s say, a controller test. It fails. I might need go further and write a model unit test.

When I finish the inner TDD loop (say, unit on a model) I want to “pop the stack” and run the controller one, having that done, I want to run the acceptance test again. Often times the inner part of the loop takes long enough that you might forget what exactly what you were doing before, lose track of the files you had and ask your pair “what was the feature again?”.

This is a general problem and I think every editor can have a tool to solve this. I couldn’t find it for the editors I use on a daily basis (Vim, Sublime Text or RubyMine, depending on who I’m pairing with). So I got something that we use here at Pivotal and implemented my solution on top of it for Vim.

The solution we have here was created to solve yet another problem, how to run tests from Vim asynchronously, that means, without blocking your editor. Most development environments have this functionality and I think it’s quite useful specially when pairing.

There are several ways to accomplish it in Vim, and we have been doing this using a unix pipe thanks to my coworker and good friend, Andrew Bruce.

The reason why I like this setup very much for pairing is because it raises the visibility of the test results, I like them always on screen so both can see it all the time regardless of how fast you can visually parse it, it looks somewhat like this:

Screen Shot 2013-05-02 at 1.17.12 PM

So you have you code in a window and your test results always visible. As a bonus, if you are on OS X and using iTerm2 you can ⌘ + Click a filename:line number to open the file in MacVim (Preferences -> Profiles -> Advanced, Open With Editor…, MacVim).

This is all very good and helps a lot. But I wanted a bit more, the first thing I noticed is that I kept wanting to run arbitrary commands that our “test_server” don’t support.

My fork of Andrew’s idea, vipe, is a more generic command pipe, that runs anything. With that I am able to send commands to the terminal and maybe map a key to it. For example :nmap ,t :Vipe ruby <c-r>%<cr> for simply running a ruby script with ,t. To do that I removed all the ruby/rspec/rails specific functionality from the original version and moved that into my personal vim config.

And then I implemented my most wanted stack of commands in Vipe. Running a command will automatically push it into the stack, you can simply run :VipePop and it will run the previous command, as simple as that. Similarly :VipeRerun reruns the last command.

And that’s about it, Vipe is a command runner for vim that has a command stack and allow you to run any arbitrary command you want, I haven’t spend so much time perfecting and I think there is space for improvement. I hope you find it useful.

  • 0 Shares
  • Share on Facebook
  • Share on Twitter

Pairing like a Pivot

Luan Santos
Friday, April 26, 2013

Pairing is an amazing activity if you and your pair can do it right, it is one of the things we value most here at Pivotal Labs. It is also one of my favorite aspects of extreme programming since it’s the thing that makes me learn, teach and grow everyday as an engineer.

Being good at it helps you and your pair enjoy the workday, keep motivated and therefore, productive.

During the last months I have learned a lot about pair programming and I am trying to perfect this everyday. I have noticed a couple things that I think can help a person be a better pair.

 

Continue reading →

  • 0 Shares
  • Share on Facebook
  • Share on Twitter
Luan Santos

Luan Santos
San Francisco

My name is Luan, I am a software engineer. One of the biggest joys in my life is typing things into Vim. I am addicted to soccer, Coritiba fan, the most victorious team in the world.
Subscribe to Luan's Feed

Author Topics

audio (1)
bloggerdome (8)
ember.js (1)
javascript (1)
soundmanager (1)
ember (2)
flot (1)
refactoring (1)
tdd (3)
api (1)
devise (1)
divide & conquer (1)
parallelism (1)
resque (1)
sidekiq (1)
mvp (1)
rumble (1)
outside-in (1)
vim (1)
agile (1)
pairing (1)
  • About
  • Case Studies
  • Team
  • Community
  • Careers
  • Tools
  • 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 >