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
Will Read

XP on Ruby Rogues

Will Read
Tuesday, June 18, 2013

I had the pleasure of appearing on the Ruby Rogues podcast this week talking about how Pivotal Labs does Extreme Programing (XP). Accompanying me was ex-pivot Josh Susser, James Edward Gray, Avdi Grimm, and Charles Max Wood. I had more fun recording it than I would have imagined and the pivots here have enjoyed listening to it, I hope you will too!

  • 0 Shares
  • Share on Facebook
  • Share on Twitter
Brian Cunnie

Populating Null Keys using OS X’s PlistBuddy

Brian Cunnie
Tuesday, June 18, 2013

Abstract

Apple OS X’s PlistBuddy is a tool for modifying p-list (i.e. Property List, .plist) files; however, it has difficulty populating null keys (though little difficulty creating them). This blog post describes a method of using PlistBuddy to populate null keys by first creating & populating a placeholder key and then using the copy directive to populate the null key.

Creating the Null Key is Easy

Creating the null key is easy; use a double-colon (“::”):

/usr/libexec/PlistBuddy -c "add :: dict" /tmp/junk.plist; cat /tmp/junk.plist
File Doesn't Exist, Will Create: /tmp/junk.plist
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
  <key></key>
  <dict/>
</dict>
</plist>

Populating the Null Key: the Right Way

Populate the null key by first creating a placeholder key, populating that, and then copying it to the null key:


rm /tmp/junk.plist
/usr/libexec/PlistBuddy -c "add :placeholder dict" /tmp/junk.plist
/usr/libexec/PlistBuddy -c "add :placeholder:nullKeySubKey string 'hello'" /tmp/junk.plist
/usr/libexec/PlistBuddy -c "copy :placeholder ::" /tmp/junk.plist
/usr/libexec/PlistBuddy -c "delete :placeholder" /tmp/junk.plist
cat /tmp/junk.plist
....
<dict>
  <key></key>
  <dict>
    <key>nullKeySubKey</key>
    <string>hello</string>
  </dict>
</dict>
...

Things that Should Work but Don’t

In general, PlistBuddy will concatenate a double-colon (“::”) into one (“:”). So the key ::nullKeySubKey is treated as :nullKeySubKey, i.e.
/usr/libexec/PlistBuddy -c "add /usr/libexec/PlistBuddy -c "add ::nullKeySubKey string 'hello'" /tmp/junk.plist will not create a null key.

Attempts to trick PlistBuddy with an empty string (e.g. “”) won’t work, either. /usr/libexec/PlistBuddy -c "add :'':nullKeySubKey string 'hello'" /tmp/junk.plist will not create a null key.

Real World Example of Null Keys

The ~/Library/Preferences/com.apple.desktop.plist is a typical p-list file that contains a null key. First, we’ll convert the p-list from binary to XML using plutil, and then we’ll examine the XML to confirm that there is a null key:

plutil -convert xml1 ~/Library/Preferences/com.apple.desktop.plist
less ~/Library/Preferences/com.apple.desktop.plist
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
  <key>Background</key>
  <dict>
    <key>spaces</key>
    <dict>
      <key></key>
...
  • 0 Shares
  • Share on Facebook
  • Share on Twitter
Ward Penney

Bulletproof font-face syntax with SASS

Ward Penney
Monday, June 17, 2013

The Bulletproof font-face syntax effectively gives you broad browser support for your fancy (or austere) web fonts. However, using the Bulletproof font-face syntax with SASS carries a couple of gotchas. Reference this article when you are starting a new project and setting up the fonts.

TL;DR A handy mixin

Step 1: Use this:


//
// mixin for bullet proof font declaration syntax
//
@mixin declare-font-face($font-family, $font-filename, $font-weight : normal, $font-style :normal, $font-stretch : normal) {
@font-face {
font-family: '#{$font-family}';
src: url(font-path('#{$font-filename}.eot'));
src: url(font-path('#{$font-filename}.eot?#iefix')) format('embedded-opentype'),
url(font-path('#{$font-filename}.woff')) format('woff'),
url(font-path('#{$font-filename}.ttf')) format('truetype'),
url(font-path('#{$font-filename}.svg##{$font-family}')) format('svg');
font-weight: $font-weight;
font-style: $font-style;
font-stretch: $font-stretch;
}
}

Step 2: Write one line for each of your fonts you include:


@include declare-font-face('Gill Sans', 'Gill-Sans-MT-Pro-Light', 200);
@include declare-font-face('Gill Sans', 'Gill-Sans-MT-Pro-Italic', 400, italic);

Step 3: Party

The Tricks of Bulletproof font-face syntax with SASS

It uses SCSS syntax, because SCSS can do multi-line and SASS can’t. It’s fine if you use SASS syntax, just name this file .scss and @import it just the same.

The mixin has defaults for last three parameters (denoted by the colons in the method signature). This way, you don’t have to go out of your way to specify normal each time.

It uses the font-path inside of the url(…). That is because I have seen lots of bugs with complex file names for the font files, and the quotes guarantee the file will be found. Either rename all your fonts with no dashes or spaces or other weird characters, or use this trick.

This isn’t really a trick, but it is more convienent to put all font variants inside the same font-family. It just makes it easier to have everything as “Gill Sans” and change the font-weight: italic, rather than having “Gill Sans” and “Gill Sans Italic” and however other many variants you have.

The original trick: Originally developed by Paul Irish (Bulletproof font-face syntax) and more recently by Fontspring (The New Bulletproof syntax), the syntax gives you broad browser support for your web fonts. IE8 loads the first .eot file and is done, but it “tricks” IE9 by relying on a bug in the parser. It dies on the question mark in the second line, and doesn’t continue on to the other file formats (which don’t work in IE9, and would cause it to not display). The other formats are handled by Safari, Chrome and Firefox, and carry no such trickery.

Thank You

And be sure to follow me on twitter for new fancy posts!

  • 0 Shares
  • Share on Facebook
  • Share on Twitter
Graham Siener

When is done, done?

Graham Siener
Monday, June 17, 2013

When you get into the rhythm of pushing new features through the product development lifecycle, it can be addictive.  Theoretically every new push brings more customer value, so why not keep going?  Restated, when should you stop writing code and put your efforts elsewhere?

If you assume that you’ll never truly know (except in a vacuum), I think there are two main factors to consider:  First, every feature you implement requires justification to build and effort to maintain.  Second, if you are following lean principles it’s important to create valid experiments by measuring the viability of your current product, not one that is constantly shifting.

Let’s break that down.

Every New Feature Costs Something

Internalizing the lifetime cost of everything you build is critical to your [and your customers’] sanity.  A friend of mine recently endeavored to simplify her life by trying the 100 thing challenge.  Take a look at the three driving principles and you’ll see the parallels to product development:

  1. Reduce by reducing the number of our possessions for an extended period of time, we prove to ourselves that consumerism does not define us

  2. Refuse by refusing to go along with in the misleading lifestyle of consumerism, we form new priorities in line with personal virtue and what is best for the world around us

  3. Rejigger by rejiggering our lives through simplicity, we nurture better relationships with family and community and nature

If you ignore the preachiness, this can serve as a template for your product.  Don’t add new features just for the sake of it.  The best apps do something specific, and do it very well.  Refuse to add something that serves as a barrier between your customers and derived value just because it’s an emerging trend.  Lastly, by focusing on the relationship your customer has with your product, you’ll shift focus from business-centric to customer-centric interaction goals.

Your Product Should Sell Itself (Eventually)

The purpose of shipping early and often is to err on the side of learning too much.  If you’re launching a new product, chances are you’re only going after early adopters.  These people LOVE using unfinished products, since the chance of finding something that exactly addresses their wants/needs is high.  These initial customers probably try 10 new services a week.  Instead of chasing their wish list, you should figure out their common thread and target more of their peers.  Reach out to them and figure out which part of your value proposition they care about — this messaging should be clear and consistent throughout your marketing and product (i.e., product/market fit).  If you can tune this acquisition engine, you should see clear improvement in your cohorts without additional feature work.

Keep Building Tools

The caveat emptor to the above advice is that you can never have too many tools at your disposal.  While your product may be “good enough,” the instrumentation you use to measure your product are probably not.  Devote some dev cycles to email tracking, behavioral metrics and personalized drip campaigns.  Some might argue these are core product enhancements, even if they’re invisible (when done well).  If they are helping you attract and engage new customers, I think it’s a moot point — just make sure that you’re not spending your time building the perfect product at the expense of one that’s good enough.

  • 0 Shares
  • Share on Facebook
  • Share on Twitter
Robbie Clutton

To build a bookmarklet

Robbie Clutton
Monday, June 17, 2013

Building a bookmarklet provides an interesting challenge. It involves interaction a website your application does not control where that site could be anything with any number of dependencies on CSS or Javascript libraries. The first choice to make is trying to work with that website and probably setting an !important on every CSS selector used and hope that there’s no namespace or versioning clashes with any Javascript included; or use an iframe.

Iframes seem to have fallen out of favour in recent times but the sandboxed nature of the content inside an iframe mean the worries of CSS and Javascript clashes are gone. However this is replaced with a communications overhead of communicating between the host document and the iframe. I wanted to touch on some of the things our team did on a recent project to try and make this fairly seamless.

Getting into the DOM

A bookmarklet is a small piece of Javascript that a user can drag onto the bookmark bar and upon pressing the link the Javascript will run. Because there is no guarentee what site will be loaded and if that will have any number of Javascript libraries included it’s best to use plain old Javascript to create an iframe element and append it to the body of the document. Our bookmarklet also needed to have some javascript if for nothing else but to be able to dismiss and remove the newly created elements. This can be done through the creation of a script element and appending to the body just like the iframe itself.

Once the iframe and script tags are appended they are treated the same as any other element. The content is loaded and the script is executed. The next step is getting the window to talk to the iframe. As a convienence the domain with protocol and port of the iframe is stored in a variable for later use.

element = document.createElement('iframe');
element.id = 'example_iframe';
element.src = 'example.com?referrer=' + window.location;
document.body.appendChild(element);

script = document.createElement('script');
script.src = 'example.com/bookmark.js';
document.body.appendChild(script);

The location is also sent to the remote server to load the iframe so that it can also store that location for passing messages to the host.

At this point this Javascript could also append a script tag to a version of libraries that may be required for it’s own application to run. It could also test for the existance of that library before hand so it doesn’t bring down an incompatible version. For example, bringing in jquery:

if ($ === undefined) {
    var jq = document.createElement('script');
    jq.src = "//ajax.googleapis.com/ajax/libs/jquery/1.10.1/jquery.min.js";
    document.body.appendChild(jq);
}

Sending a message

The postmessage method is available to communicate bewtween the window and the iframe. The host window with a reference to the iframe can call postmessage with a string as a message and as a security measure the target location. We had stored this during the loading of the elements as described above.

iframe.postmessage('hello', 'www.example.com');

That message won’t get anywhere unless the iframe is listening for the message event on the other end.

// native Javascript
window.addEventListener('message', function(event){ … });

// jQuery
$(window).on('message', function(event){ … });

I’ve used the native Javascript above but really, once in the iframe itself the application has full control and could use JQuery or any other library at this point. Our application needs to listen to messages on both sides though so we needed the above to run in the host anyway.

RPC

Sending a message is all well and good but any non-trival application is going to have more than one function to run. We took influence from Remote Procedure Calls (RPC) to call functions within the host and remote sites. The message sent was stringified JSON with a very light ‘schema’ of the function to run and parameters to send to the function.

{   
    f: 'theFunction',
    params: {
        ...
    }
}

The recipient could then parse the string it knew to be JSON, extract the function to call and call it with any optional parameters also sent. This does create a binding between the host and the iframe but as the appliction controlled both sides we deemed it an acceptable risk. The function can be run from the window like so:

window['theFunction']();

// or from the event listener
var fn = JSON.parse(event.data).['f'];
window[fn]();

Dealing with namespaces

It was mentioned earlier that one of the goals of using an iframe was not to clobber any Javascript namespaces but we did end up including Javascript in the host and to avoid this we used an application namespace. However calling that as a property on the window would no longer work.

// doesn't work
window['my.app.function'](); 

// works
window['my']['app']['function']();

We looked to ElementalJS as an example of dealing with namespaced functions to parse the function.

window.addEventListener('message', function(){
    var fn = window; 
    var data = JSON.parse(event.data);
    var namespaced = data['f'].split('.');
    for (var i in namespaced) { 
        fn = fn[namespaced[i]];
    }
    fn(data.params);    
});

This is natually fairly crude, some defensive code could be added but this demonstrates the intent of the processing. Defense like making sure that function existed, or that ‘f’ existed in the data for the window could receive a message from another iframe.

Putting it all together

The bookmarket inserts two elements, an iframe and a script. The iframe has the source example.com?referer=bar.com. bar.com is inserted as a variable in the iframe Javascript code. The iframe inserted has an id of example_iframe

The host Javascript listens to the message event

window.addEventListener('message', function(event){
    var fn = window; 
    var data = JSON.parse(event.data);
    var namespaced = (data['f'] || "").split('.');
    for (var i in namespaced) { 
        fn = fn[namespaced[i]];
    }
    if (typoe(fn) === 'function') {
        fn(data.params);    
    }
});

The host also sets up a namespace and a function to be called.

window.example = window.example || {};

example.hello = function(){ … }   

When the iframe has loaded, it sends a ready message to the host

$(document).ready(function(){
    var data = JSON.strinify({f: 'example.hello'});
    parent.postMessage(data, referer); // referer set by server from the request param for the iframe
});

The host from the script loaded in the bookmarket has the example.hello function and it’s run. This in turn replies to the iframe.

var example.hello = function(){
    var iframe = document.getElementById('example_iframe');
    var data = JSON.stringify({f: 'example.world'})
    iframe.contentWindow.postMessage(data, 'example.com');
};

The iframe has an event listener which is the same code as the host, and runs the function example.world

var example.world = function(){
    // hello, world
};

Wrapping up

This has shown some of the techniques for a ‘hello, world’ bookmark with two way communication between host and iframe that uses Javascript namespaces. This was enough to get our application off the ground as the two way communication acted as a solid base to build upon.

  • 0 Shares
  • Share on Facebook
  • Share on Twitter
Andrew Bruce

The passing of time, and all of its crimes.

Andrew Bruce
Sunday, June 16, 2013

Programmers are constantly implementing time-related features, and accidentally including time-related bugs. I’m one of those programmers, and I would like to reduce the number of time-related bugs that I write. Some of them are small mistakes: time zone issues arise when running a test suite on a machine in a different time zone. These bugs are often fixed with consistent use of the time zone feature of a given time library. Others are more sinister, and lurk deep within the design of a system. They manifest in places where it’s tricky to get the system into a certain state because it is so heavily dependent on the current time. I propose that designing for the ability to set the current time from the outside of the system reduces the prevalence of timing related bugs, and has the happy accident of making code more reusable and testable.

How testing exposes this problem

Testing has many forms in the world of software. There are automated acceptance tests, unit tests, functional tests, enemy tests and so on. There are also tests carried out by humans. Sometimes referred to as ‘click testing’ or Quality Assurance, this kind of testing is an essential part of the process of delivering working software. At Pivotal Labs, it’s usually the Product Manager who has the final say about whether a feature is complete, or a bug is fixed. In order to evaluate whether a feature is ready, the PM exercises the area of the application in question, using the interface that a customer or stakeholder has been provided with.

When testing software with a mouse and keyboard becomes difficult, however, it often doesn’t get done. When it doesn’t get done, bugs introduced by diligent programmers, who test-drive their code, are missed and end up making their way into production.

After a few cycles of missing bugs like this, a team will look for ways to ease the pain of click testing their app. The programmers on the team might come up with clever, easy-to-implement solutions to this problem:

  • “We can manipulate the Time library to give us the time we want”
  • “We can change all of the data for a given account to pretend that it was created in the past”

When these sorts of techniques dig in, new problems arise. In the former case, you can end up with code that works when the fake Time library is used, but not when the real one is used. In the latter, you are committed to a maintenance chore: when a timestamp field is added, it needs to change along with the rest, and when the code that changes those fields gets out of sync with how things really change over time, more bugs arise. It becomes difficult to tell which bugs are genuine and which are a consequence of artificially shifting time data.

It’s usually programmers who propose the above solutions. We often think in low-level terms like libraries and direct data manipulation. From a Product Manager’s perspective, however, what’s really needed is a design change. One could imagine the user story presented to the team like this:

As a Product Manager
I want to travel in time
So that I can test, for example, that an account gets billed each month

Time travel sounds like science fiction. How could a user of your system possibly travel in time? It turns out that there are low-level solutions to this. For example, Timecop, which many of us at Pivotal have contributed to. If depending on the passing of time is your addiction, then Timecop is enabling you. It lets you easily manipulate time, usually for automated testing purposes. For example:

Timecop.freeze(1.month.from_now) do
  future_time = Time.now
  sleep 10
  future_time == Time.now # this is true
end

Here we’ve frozen time to pretend that it’s one month in the future. I can imagine some cases where this would be useful (not least in existing systems that are infected with code coupled to the current time), but in a lot of cases this is just wrong. Under what circumstance do you actually expect your code to be frozen in time? What are the consequences of testing code under these conditions?

Perhaps most importantly to the topic of this post, Timecop lets you forget about managing time at the unit level, and doesn’t encourage you to build time controls into your application.

I think there are better ways to get a grip on time that we should all consider before reaching for the magic wand. Let’s look at some real-world problems that can occur and then look at ways of building time control into an app’s design.

Examining the moment

Let’s think about the properties of the current time:

  • There is only one current time, unless you’re modelling multiple realities e.g. storylines about time travel.
  • Its value is always changing.
  • Everything is potentially affected by it.

So, the current time is a global, constantly mutating singleton. We know that the presence of global singletons is undesirable, because they are polluting. We also know that mutation ought to be contained, because mutable state makes our programs less predictable and harder to reason about. If a function deals with mutable state, then it might have different results each time it is called, even when it apparently has the same inputs.

Let’s look at a timing bug that can result from the fact that the current time has these undesirable properties:

policy = Policy.find(1)

if policy.current_state == :active
  notify_customer("You are still insured!")
end
# more code goes here
if policy.current_state == :inactive
  notify_customer("You are not insured. Hope you weren't planning on driving anywhere today.")
end

Imagine that the above code is within a web request. The request comes in at a certain time, and the customer wants to know whether their insurance policy is current. The code above is deep in the guts of a model somewhere, and gets called after the customer has been authenticated, their request has been authorized, and their account record has been pulled out of the database. Now it’s time to see what the state of the policy is, so we use a method someone wrote (current_state) that fetches the current time and returns a state based on whether the policy’s end date was before or after that time.

The customer sees this on their screen:

You are still insured!
You are not insured. Hope you weren't planning on driving anywhere today.

The policy could potentially be active on one line and inactive the next. This kind of bug gets worse when one line makes an external call if the object were in one state, and the next makes a conflicting call if it were in another.

I recently ran into a real bug similar to this on my current project, which was caught when an acceptance test I was writing would fail on one run and pass on the next. The temporary workaround was to memoize the method that checked the current state (current_state above). Unfortunately, this introduced even more mutable state, because memoization requires changing the state of an instance variable. The next programmer might wonder why fetching the current state works the first time he asks, but stays the same with consecutive calls.

current_nothing

The current_state method is guilty here. But what of? It has a hidden input, which is the current time. It’s not explicit, and that’s where the confusion lies. It wouldn’t make sense to have a method called current_something and have it take the time as an argument, because the prefix “current_” implies that it’s supposed to know what the current state is.

The internal functions of a program shouldn’t know this stuff. In most web apps, a request is made at a certain point in time, but it’s not important that the request takes some time. With most scheduled jobs, the job is run at a certain time, but it’s not important that the job takes some time (or if it is, it’s stored as metadata).

A name less prone to attracting this kind of bug might be state_as_of(time). If we force ourselves to pass the time as a parameter to all of our low-level functions, then we can:

  1. More easily unit test the basic correctness of the method without resorting to stubbing out the time with Timecop.
  2. Force out a decision to be made about what moment the lower-level methods should be operating on. Ideally the control would move as high as possible: to the controller level, or in the case of jobs, to the job itself, or to an environment variable.

A word about scheduling

Scheduled jobs are often concerned with when they think they’re being run, but a PM doesn’t want to wait for a month to see if, for example, the billing system is working. It’s important to give control over when a job thinks it’s being run to the PM or other person evaluating whether a system works. This might mean dropping your out-of-the-box scheduling interface for the purposes of feature acceptance.

Resque-scheduler has become very popular amongst developers as it’s easy to install and provides a cron-like syntax for declaring when jobs are run. It also provides a GUI for triggering scheduled jobs immediately. Unfortunately, there’s no way to set parameters for the jobs, so the time can’t be set. If you choose to heed the advice in this post and parameterize time, you’ll need to provide your own interface for passing the current time into the system. This is a good idea anyway. See GOOS for a good treatment of externalizing event sources, which goes even further than the suggestions in this post in many ways.

Making time a parameter to your jobs can often make the jobs more reusable. For example, I might want to invalidate all sessions in a particular time range because there was a system fault at those times.

A word about external dependencies

What happens if your external dependencies are dependent on the current time? Well, you’re going to have problems with that no matter how much control you build into your system. I would argue that the services should be wrapped, and the wrappers should allow the time to be passed in to fake responses if necessary. The acceptance (as in story acceptance in Pivotal Tracker) of your system doesn’t have to depend on the state of the other systems.

A word about customer-facing status pages

What if your customer needs to be shown what’s happening right now?
I think the trick here is to depend on the order of time, and not the passing of time. To move into the future, we should be reacting to events by adding data, not mutating it. A database can easily figure out what the latest order is, or what the latest billing cycle is. It doesn’t have to be a function of the current time.

If, however, it’s just too difficult to implement the functionality without checking the current time, it could be argued that the current time be a parameter passed in through the browser, available only in certain testing environments. I would resist this as far as possible, but think that it would be a preferable solution to mutating the state of the database.

  • 0 Shares
  • Share on Facebook
  • Share on Twitter
Jared Carroll

Everyday Git Commands in RubyMine

Jared Carroll
Sunday, June 16, 2013

As a long-time command-line Git user, I was hesitant to adopt RubyMine’s version control tools. But I decided to give them a try, and I’m glad I did. RubyMine’s version control tools make common Git commands more accessible and easier to execute. The addition of a GUI is great for tasks such as diffing a file, or viewing commit logs. In this post, we’ll look at performing everyday Git commands in RubyMine on OS X.

git-diff

You can view a diff of all your changes from the Changes tool window.

changes-tool-window

Press command + 9 to open the Changes tool window. Then press command + D to view a diff of all your changes.

view-diff

You can diff a single file by selecting “Compare with the Same Repository Version” from the VCS Operations popup. Press control + V to open the VCS Operations popup.

compare-vcs-operations-popup

git-commit

Press command + K to commit changes.

commit-changes

git-push

Select “Push…” from the VCS Operations popup, control + V, to push your local changes.

push-vcs-operations-popup

git-pull

Press command + T to pull in the latest changes.

update-project

git-log

To view the Git log, open the Changes tool window, command + 9, then navigate to the Log tab with command + shift + ].

git-log-changes-tool-window

To see the log of a single file, select “Show History” from the VCS Operations popup, control + V.

show-history-vcs-operations-popup

This will open the log in the Version Control tool window.

show-history

git-checkout

Revert changes by selecting “Revert” from the VCS Operations popup, control + V.

revert-vcs-operations-popup

git-blame

Determine who changed a file by selecting “Annotate” from the VCS Operations popup, control + V.

annotate-vcs-operations-popup

The committers will be displayed to the left of the editor gutter.

annotate

Don’t Abandon the Command-line

In this post, I focused on the most commonly used Git commands. RubyMine also includes support for more powerful Git commands, such as git-reset and git-rebase. However, I find their RubyMine GUI-based implementations slow and clumsy. As much as I want to stay in RubyMine, I find the best version control strategy is to use RubyMine for common Git commands, but turn to the command-line for the hard stuff.

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

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
Jonathan Berger

Talking Data Visualization with Sarah Nahm and Ian Johnson (transcription)

Jonathan Berger
Sunday, June 16, 2013

Talking Data Visualization with Sarah Nahm and Ian Johnson (transcription)

We were lucky to have two Data Visualists, Sarah Nahm and Ian Johnson from Lever, join us for lunch in Pivotal SF last week talk and about the current state of Data Visualization. Nina wrote a great summary of their thoughts. Here’s an (almost) transcription of the talk. In accordance with my notes policy, any errors, misstatements or shenanigans should be attributed entirely to me and not the speakers.

What To Do With All Your Data

Sarah: My approach is that Data Visualization is goal oriented; it’s not about being on a chart. A lot of people assume that a line chart is Data Visualization, but I think google search is Data Visualization. By building a service and they’re building a specific and powerful Visualization. There’s usually a form that data can take to hit a goal. It’s not about one answer, it’s about doing many. I’ma huge fan of unsexy Visualizations, like tables. Designing tables to be effective is hard; people tune them out. Designing for people’s attention is a huge part of Data Visualization. The second huge think is to think about how data transitions. Is this a button? A portal? Does it start another activity? All those things are design principles that figure into my thinking. Ian is totally different in an really awesome way.

Ian: I’ve learned a ton getting into this field. I came from math and didn’t know Data Visualization was a separate thing. I just had numbers and I could turn them into pixels and colors. From that perspective, any transfer or exchange is a way to turn one data into another. What do we want to accomplish? Goal oriented design has been a really big positive change for me to deliver things that work for people.

Question: Can you talk about [didn’t hear] something that came together?

S: The original question was about “how do you break out of business dashboards?”

Tim McCoy: Can you talk about the tension between using data to tell your story and how data builds the story?

S: Where Data Visualization is now is about showing the data. Insights is hard just not just of “big data” or because the datasets are hard. This has driven me to learns statistics; i highly recommend the Cartoon Guide to Statistics. Learning more about machine learning, getting more of a literacy about it; it’s way too easy to find a correlation and wave that around as an insight, but it’s not that simple. Designing something around data you can’t anticipate is hard. Designing around a story is about being acutely aware of when you’re smart, and trying to be dumb. The anecdote that pulls this together is that in our app—basically Lever is a hiring software that isn’t about finding as much as about managing the data problem. When you find the 300 candidates, you need to keep track of them; it’s a confined but messy data problem. We have a list of candidates here. The big Data Visualization is that there isn’t’ a dashboard; data should be ambient and a portal to get to what you want to look at.

We call this the filterlist—it’s a name that we picked and it just stuck.

As you filter the list, you see the Data Visualization filter and update. As you change criteria, the list changes. Something that was really hard about this is that these aren’t all you’ll ever have about these people, they’re portals to list. If you filter a list and the output is a list of people, but also, what’re lists that people really need? How else can we show this? “There are people I reached out 3 months ago, and I dropped the ball, and how do I get back in touch?” Last week I was doing something about time but it was really fuzzy and heuristics based. We invented “Last Interaction view” which are irregular but meaningful timespans (e.g. 1 week, 3 months) drawn as little airplane windows with sparklines below. This chart gave us so much grief; there’s nothing scientific about it. It kind of bugs people because we made all these decisions. But the user looked at it with the user eye, the user looked confused. But when you look at the sparkline, you see “oh, that time was busy; that other time wasn’t busy.”

The goal was to let people know that if you look at this, you’ll see the list of people you dropped the ball on 3 months ago. A scatter plot would be more accurate, but it ultimately didn’t translate to how people thought about it. All the other teammates were like “maybe we should cut it”, but Ian said “maybe it should be a sparkline, people think about it that way.”

Q: How do you start?

S: I always start with What It Needs to Be; that’s usually a text document. It’s so easy to be distracted. There’s so much fun stuff. We had all this stuff; 6 or 8 questions people needed an answer to about a candidate. It was all about focusing on that. Otherwise it’s too easy to do what’s fun or pretty.

Q: ? [didn’t hear]

S: A We usually get negative feedback, because its hard for people to think about data in context. Until they can see their own data, it’s hard to grok. This is really reductionist. It’s really minimal to try to not overwhelm people. Our style of this ambient, around all the time, makes it hard to not have your own data.

TM: yeah, I did a finance project and the most challenging aspect was that without real data, it’s a total mess.

S: Maybe you should talk about Chris S.
I: THis idea of fake data is extremely important; without data, you don’t have a Visualization. I try to be hard-line about this. We’re still really bad about creating data. People come to us with nothing. We have to comb through existing systems, spreadsheets, etc. We do paper sketches with existing data, some rough D3 sketches. Everyone who was higher-up than our client loved the data porn, but the client was like “where’s the stuff I want to see?” “Where do I get the answers to my questions”?

S: People using our product are beta testers at [REDACTED]. The only guy watching the data carefully; Ian did all sorts of lo-fi sketches of what visualizations might do. In many ways lo-fi helps, but that was just priceless in terms of interactivity, in terms of “what do I want to filter on?” or if there were a time-based graph I could see what formats I needed to export to. Prototyping is no new thing, but the nice thing about Data Visualization is that prototyping an interface around what the data can be is really important; it lets us put a play button on it. There’s something about the way an engineer throws a button on anything can be really helpful; it’s really awesome.

Q: How do you know when to up the fidelity?

I: Data fidelity should get high ASAP, even if its a sub-sample of the data. It should have the final structure.
S: You can never wait long enough to do visual high-fidelity. Clients know about Data Visualization; some good things and some naive things. They know the questions they want to ask, when they need it, etc. People have really terrible taste in charts; they think they know what they want, but they never break down what they really need. Once you get them to say “I want to email this to my boss”, it changes the deliverable from the fully interactive website to an animated gif. The more it does the work that people need; you can make it pretty later. If you’re thinking about the charts as vying for your attention against this list of what you’re trying to do, there’s a degree to which the visual styling needs to be environmentally aware, but usually I go visual too soon.

Ofri Afex: I need to explore many directions while I’m doing charts, otherwise I get too used to the initial approach and get locked in to my first choice.

S: I rely on my design partners; they’ll take a headline and common chart elements and make a bunch of visual styles right at the beginning. I think that’s really valuable. It has to mingle with the rest of the application. I still feel that the charts have to be what they have to be, and that’s locked in by the reductive design decisions you make.

Q: Wha?

S: We have to show these variables. We have this much space. We have this much sampling fidelity. We have this much interactivity. E.g. for lookup, tables are the best. Charts are meant to show relationships. For so many business products, lookup is the task that’s needed, but clients want pretty charts. Like I said, Google search is Data Visualization.

Q: The reality is that stakeholders need to buy in.

S: The current bar is so, so low. It’s fun to surprise people with how nice of a place they can live in. It all stems from scoping the problems they have to answer, and making them feel confident. That’s the UX side—accessibility and confidence. Todays’ tools are built for experts, but the need is getting democratized. Recruiters aren’t trained statisticians, but they know what questions they want to answer. In some ways, you make sure it meets those needs. Building for the next step: “what do you want to do once you know it?” is where current products tend to drop the ball. That’s where people get excited. On one screen, we did throw a bubble chart in just for visual sexiness and visual balance so it didn’t feel too dense or unplayful.

Q: ??? [couldn’t hear]

S: Many Data Visualization have elements that feel like whitespace: it’s a waste unless you’re thinking about principles like balance and designing people’s attention. The bubble chart is like whitespace; it gives people a chance to take a breath. It’s a signpost that says “we’re in a new part”.

I: This particular bubble chart—a bar chart would work better—but it’s not the main thing.

Q: I just want to dive in.

I: Anything you click on—there’s hover states, etc, you build filters—but there’s no external changes other than highlighters.

Q: How do you think about that problem?

S: We have three redundant ways to indicate a filter is activated. We’re nervous that users won’t know.

Q: Do you split test it?

S: We should probably test more. This is the thing we worked on most recently. we want to ship and see how people work in the whole system. What we’re kind of asking is “When people change the data, how do they see the change?”. The real time framework we’re building on is going to be this amazing way to manipulate things, we can affect anything on the page. The vision is that the delta of the data is as important as the new state; I’d love to show the ghost of the sparkline. The vision for the filtervis is to show that.
I: You can use the browser history API to show that stuff going back!

S: Questions around change over time are where people are doing interesting things. That seems to be top of mind. Tributary makes that easy. Dealing w/ that medium of motion and time.

Q: You talked about representing change over time. How do you attack the problem of representing change over scale, e.g. trillion-row database?

S: What does the user want? Do they want to get back to the big picture? There’s a natural inclination to set up data as a hierarchy, but the Visualization of the data need not mirror the data. Often data mirrors a company’s org-chart, but that need not be.

  • 0 Shares
  • Share on Facebook
  • Share on Twitter
Daniel Finnie

Coding while deploying with Git Deployment Directories

Daniel Finnie
Saturday, June 15, 2013

Two tenets of Pivotal are continuous integration and coding if you’re in front of a computer.  These goals can conflict when you’ve just wrapped up a story and are about to push to a staging environment – while your final tests and deploy are running, you can’t modify your Git working tree.  So you grab some coffee or check your email.

In the spirit of eliminating breaks enforced by devops, Dirk Kelly and Mik Freedman paired on a great way to run deploys in the background.  In essence, you create a separate Git repository on your development machine, we’ll call it deployer, that has your original Git code repository as a remote.  Your deploy scripts then run in background from the deployer directory while you happily code in your original directory.

If your deployment process is anything more than a push to GitHub, this saves a good amount of time.  If your project involves more than 1 pair, continuous integration and automatic deployment of all Git branches can alleviate the pain of long deploys.
Continue reading →

  • 0 Shares
  • Share on Facebook
  • Share on Twitter

Topics

  • agile (783)
  • rails (117)
  • testing (90)
  • ruby (86)
  • ruby on rails (71)
  • jobs (62)
  • javascript (59)
  • techtalk (44)
  • ironblogger (42)
  • rspec (39)
  • bloggerdome (34)
  • productivity (34)
  • activerecord (30)
  • rubymine (30)
  • git (29)
  • gogaruco (29)
  • nyc (27)
  • design (24)
  • mobile (23)
  • pivotal tracker (22)
  • process (21)
  • cucumber (21)
  • jasmine (19)
  • ios (18)
  • tracker ecosystem (17)
  • webos (17)
  • objective-c (17)
  • fun (16)
  • android (16)
  • palm (16)
  • ci (16)
  • "soft" ware (16)
  • bdd (15)
  • tdd (15)
  • cedar (15)
  • rails3 (14)
  • performance (14)
  • css (14)
  • gem (13)
  • mouse-free development (12)
  • selenium (12)
  • goruco (12)
  • bundler (12)
  • api (12)
  • keyboard (11)
  • meetup (11)
  • railsconf (11)
  • nyc-standup (11)
  • capybara (10)
  • mac (10)
Subscribe to Labs Feed
  1. 1
  2. 2
  3. 3
  4. 4
  5. 5
  6. 6
  7. 7
  8. ...
  9. 129
  10. →
  • 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 >