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
Robbie Clutton

Stop leaky APIs

Robbie Clutton
Wednesday, May 15, 2013

There are many blogs about how to expose an API for a Rails application and many times I look at this and am concerned about how these examples often leak the application design and the schema out through the API. When this leak occurs a change to the application internals can ripple out and break clients of an API, or force applications to namespace URI paths which I feel is unnecessary and ugly.

When the only consumer of application data models are the views within the same application then the object design can be fluid and malleable. Once an application exposes an API to more than one client, and especially if that client is on a different release cycle to the server, such as iPhone application, data models become rigid. Rails tends discouraged N-tier architecture to the benefit of development speed but APIs are contracts between a server and it’s client and can be difficult to change once they start being used.

Passing an object into the Rails JSON serialisation methods will work for a time, but relying on this will only get you so far. At some point a refactor will take place that will cause a breaking change. It could be something simple such as renaming a column, moving responsibilities from one class to another or adding extra meta-data to a response. Either way, adding this information into your model class starts to place more responsibilities into one place.

There are a few ways out of this potential issue. Let’s take a look at the classic blog application and its Post object. The Rails rendering engine will call as_json on an object if the request has sent the content-type of application\json to the server. Here we override the implementation from ActiveRecord to provide a stable, known version:

def as_json(options={})
    {
        author_id: author.id
        title: title
    }
end

A second option is to model the object explicitly and serialise the internal model into a public representation. We can duck-type the object to respond how ActiveRecord objects behave during a serialisation call. Although this can be seen as a step towards a N-tier architecture, it’s also a step towards service dependent abstraction:

class Api::Post
  attr_reader :post

  def initialize(post)
    @post = post
  end

  def as_json(options={})
    {
      author_id: post.author.id
      title: post.title
    }
  end
end

The benefit of doing this is a separation of concerns between your data model and the data presentation. An application model doesn’t need to know how it’ll be represented by an API, command line interface or any other outside communication mechanism. If an application were tending more towards HATEOAS for instance this separation could help resolve hyperlinks relevant to the interface. You may lose some of the Rails respond_with goodness with this:

respond_to :html, :json

def show
  post = Post.find(params[:id])
  respond_to |format| do
    format.html { @post = post }
    format.json { render json: Api::Post.new(post) }
  end
end

That can be regained with the help of a presenter:

respond_to :html, :json

def show
  post = Post.find(params[:id])
  @presenter = PostPresenter.new(post)
  respond_with @presenter
end

Where PostPresenter may look something like:

class PostPresenter < SimpleDelegator
  def as_json(options={})
    Api::Post.new(self).as_json(options)
  end
end

What’s the difference between this and putting the as_json method into Post directly? More control, separation of concerns with application modeling vs presentation and the big win is when breaking changes occur within the API. Now we can put version relevant information into new objects, or into the serialised class itself.

class Api::Post
  attr_reader :post, :version

  def initialize(post, version)
    @post = post
    @version = version
  end

  def as_json(options={})
    send("v#{:version}")
  end

  private
  def v20130505
    # version specific JSON
  end

  def v20121206
    # version specific JSON
  end
end

Through this we have versioning information in one place and through a request parameter of something like v=20130506 the application can handle multiple versions in one object. For me, this ultimately removes URIs like /v1/posts, but why is that important? The URI is an identifier which points to a resource and having v1 or v2 in the URI muddies the fact that the two identifiers are pointing to the same resource. Using a request parameter, much like pagination is handled, means we can ask for a representation of that resource rather than having to specify different resources. Then we can do away with needing controllers such as Api::V1::PostsController and just deal with Api::PostsController or even just PostsController and deal with the versioning within the object instead of the URI path.

  • 0 Shares
  • Share on Facebook
  • Share on Twitter
Ward Penney

A SASS with Bootstrap Workflow

Ward Penney
Monday, May 13, 2013

So you’ve decided to start a project with Twitter Bootstrap, but you want to use SASS (SCSS)? Well, this is the post for you. Here are some tips from my current workflow for starting a SASS with Bootstrap project. DISCLAIMER: there many ways to slice this cake. So please, take what you like and leave what you don’t!

A Typical File Structure

In the stylesheets source folder, I generally only have one primary SASS file, that imports all others. If you are using a Rack app, do not use sprockets directives here, just SASS.

Depending on your stack, you will have some place where you have a stylesheets/ folder. Within that folder, I typically set up a basic folder structure that looks like this:

  • application.sass
    • /libraries
      • _variables.sass
      • _mixins.sass
    • /vendor
      • _bootstrap.scss
      • _bootstrap-responsive.scss
      • bootstrap/
        • _accordion.scss
        • _alerts.sass
        • _breadcrumbs.sass
        • etc…
    • /components
      • _tables.sass
      • _forms.sass
      • etc…
    • /sections
      • _homepage.sass
      • _product_detail.sass
      • _style_guide.sass
      • etc…

./libraries/: contains only variables and mixins: SASS that does not render any actual CSS, but is used later. Why? You’ll find out later!

./vendor/: Vendor framework libraries. In this case, only Bootstrap is here.

./components/: SASS patterns intended to be used across the site. Pretty much everything in here will be devoted a section in the live style guide.

./sections/: Layouts and other page-specific stylings. Anything that is not intended to be used in multiple places in a versatile way.

Bootstrap Source

I like the Bootstrap source SASS not hidden in a gem because I can want to control exactly which features are included. You don’t want to be in a situation where it feels like you can’t deprecate or evolve away from Bootstrap because you don’t control it. So, here is what I do:

  1. Go to Thomas MacDonald’s amazingly well-maintained Bootstrap port to SCSS at https://github.com/thomas-mcdonald/bootstrap-sass

  2. Copy the contents of https://github.com/thomas-mcdonald/bootstrap-sass/tree/master/vendor/assets/stylesheets to your vendor folder described above

  3. Open up the bootstrap/bootstrap.scsss and comment out NEARLY EVERYTHING. Even the grid if you want to use a different grid. Uncomment features as you need them, when your user stories demand the functionality.

  4. Include the vendor/bootstrap file in your ./style.sass file, and BOOM you’ve got a full controllable Bootstrap source.

  5. When you need buttons, uncomment buttons. When you need wells, uncomment wells. Rinse and repeat.

  6. Replicate this process for the javascript also, only including what you need when you need it.

(Note, this method also works if you don’t have Rails, or a rack app that can use gems, this still works for you. Yes, you can compile SASS with Bower and Grunt. Check out Sam Richard’s style guide prototyping stack)

Extending the Grid

With Bootstrap, you may typically insert its class selectors and elements into your markup to compose the, but some peepz do not desire this for semantic, SEO and other reasons.

SASS offers an attractive way to remove the clutter with the SASS @extend directive, however it has two performance pitfalls:

  • In Development: Using it in SASS nesting (more than two levels) may significantly slow down your compilation time, especially if that element is being @extend-ed a lot.
  • In Production, overuse can can create so many selectors on one element that it can lag the browser significantly.

In Bootstrap in particular, it becomes tricky because you have to extend the grid class, as well as the wildcard class that applies the padding. For example, a Bootstrap element classed with .span3 will receive stylings from the .span3 selector, as well as a funky selector [class*=’span’]. For example, you can’t just do this:


.advertising-sponsor
  @extend .span3

This misses the [class*='span'] wildcard selector because @extend only scours literal selectors, not searching for anything that MAY apply. Therefore, you have to do this:


.advertising-sponsor
  @extend .span3
  @extend [class*='span']

The downside is the second @extend adds an extension to that target selector every time you use it, and a really long one if it is nested. Those hit the performance issues I described above, hard.

So, my process now is to create my own mixin that allows me to quickly pseudo-extend the grid class by calling the Bootstrap mixin that prints their styling. I place the following into my ./variables/_mixins.sass:

=bs-extend-span($spanNum)
  +grid-core-span($spanNum, $gridColumnWidth, $gridGutterWidth)
  float: left
  min-height: 1px
  margin-left: $gridGutterWidth

This essentially renders what bootstrap does for it’s span classes. This does duplicate CSS in the compiled result, but I have found that the performance impact of downloading more CSS pales in comparison to the pains suffered by @extend in development time, or in a more severe case, crashing or lagging the users’ browser.

Styling Bootstrap with Variables

Take a look at the ./vendor/bootstrap/_variables.sass. Notice how all the variables have !default after them? That means that SASS will NOT overwrite this variable if it is already defined. This allows you to create your own ./libraries/_variables.sass file, and include it in the load order before Bootstrap and effectively control those variables. This will be your primary way to style Bootstrap colors and such.

Using Compass or Bourbon with Bootstrap

Some people prefer Compass’ mixins. Some people like Bootstrap’s. Some like Bourbon’s. IMO, they are all good and I don’t mind using any, but it is a good idea to commit to one. For example, Bootstrap’s =Opacity() mixin takes a value from 0-100, while Compass’ function takes a value from 0-1. There is a variable order conflict with =transition(). I sometimes import pieces of compass, instead of the whole thing. For example, I like the ever-handy Compass =experimental() function. You can choose to import only specific files from Compass:

@import compass/css3/shared

Conclusion and Upcoming Topics

That’s it for now! Let me know if you have any topics you want me to expand on, or ideas for posts you want to see. I am currently doing a style guide using Groundwork-CSS, and hope to do a similar post later! Follow me on twitter for various nonsensical ramblings.

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

Storyation Workshop: How to get business stakeholders to create stories

Graham Siener
Monday, May 13, 2013

I read Lean From the Trenches last weekend and it was great.  Not because it provided black and white protocols for running an agile product development team, but rather because it showed how a real team operates under real conditions.

I want to focus this post on a quote from the book:

The definition of “ready for development” can be achieved only if all specialties work together to estimate features, break them into small enough deliverables without losing too much customer value, and to agree on acceptance tests.

Ready for development is an interesting concept — it implies that every business stakeholder that has input knows what the product owner needs to ensure a developer can deliver an acceptable story.  In my experience, this is usually not the case once a product is out in the marketplace and people from non-product teams (marketing, support, executives) have specific product needs.  This could look like promo code tracking to support a marketing campaign, or a data export to support your “data science” team.  Without a good process for getting these stories into the backlog, the result is an unhealthy IPM where the PM and developers have to divine what exactly the intent of a story is.

At one of my last companies, we had this problem in spades.  Even after introducing a Pre-IPM meeting, we still felt like the quality of the stories we presented to developers in IPM didn’t represent the time we had spent discussing them.  To add insult to injury, getting the story requester to accept a delivered story was like pulling teeth.  Once we did sit them down to walk through a story, rejection was often the result!

After reflection (and seeing this come up as a theme in several retros) we created a new weekly meeting called “Storyation Workshop.”  This session felt a lot like office hours, and we made clear the intent to only let high-quality stories into the backlog.  We (PM and Tech Lead) would do our best to interpret the needs for a feature and turn it into actionable stories.  We would also break out the necessary pieces from the nice-to-haves.  Make no mistake, though — the business owners were on the hook to bring justification for a feature and if it didn’t pass muster it lived in the Icebox for another sprint.

We were fortunate (as a company) to have support for keeping a healthy backlog and not jumping stories in the priority queue.  I saw many benefits to this new process:

  • All the other teams — marketing, professional services, customer support, data science — paid closer attention in IPMs and made sure that their needs were well represented
  • Acceptance happened more quickly after a story was delivered, and expectation alignment meant rejections went way down
  • Everyone got better at story writing as they started to grok how we broke down features and the logic behind it
  • More greenfield thinking popped up and made it into the backlog as actionable work

The first three were proof to me that we were missing a critical process in the arc of a story.  The last bullet (greenfield thinking) was a pleasant surprise.  It turned out that people were afraid of bringing a half-baked idea to IPM (rightfully so) but didn’t feel like they had the right forum to finish baking an idea.

Maybe this all sounds like common sense; if that’s the case congrats on having a healthy product development process!  For anyone struggling to deal with symptoms like these I suggest you try introducing a safe space for new ideas to come to light.  A Storyation Workshop could come in many forms, but you’ll know it’s working when you see more buy in from non-product team stakeholders and a faster cycle-team for their stories through the backlog.

As always, I’d love to hear if you’ve incorporated a similar technique into your agile product development process.

  • 0 Shares
  • Share on Facebook
  • Share on Twitter
Jonathan Berger

7 Best Practices for Facilitating Agile Retrospectives

Jonathan Berger
Monday, May 13, 2013

Facilitating a retro is a very powerful role; it’s almost akin to being a courthouse judge (and stenographer). By asking questions, recording testimony, and shaping the debate, you mold and influence your teammates’ feedback in a very vulnerable and trusting space. If the Product team sets goals (like a Legislature) and Development and Design teams implement them (like an Executive Branch), a retro is a chance to reflect, interpret, and set future direction—not unlike a Judiciary. In practice, that means it’s important to be especially honest and impartial, and to double-check that you’re doing justice to the team’s best interest and the speakers’ intent. Here’re a few patterns I’ve observed that help make the difference between a good retro and a bad one.

1. Explain and Enforce format

At the beginning of a retro, take a minute to explain what’s going on—even for a seasoned team, but especially for a team with new members. “We’re here to reflect and improve on process—this is a safe space, and we’re oriented towards exposing issues and taking action.” If the team isn’t explicitly aligned on why they’re in the room, they can’t get the job done. Speaking up is high value (it ensures the retro is properly oriented) and low-risk (it only takes a minute).

2. Write Everything Down Verbatim

A retro is about listening. Whoever takes notes ought to be respectful of the speakers voice. That means recording their thoughts as faithfully as possible, without interjecting opinion or commentary. If you do need to paraphrase for brevity, be as faithful to the original comment as possible—don’t insert your view, you’ll get your own turn—and confirm that your version does justice to the original. “You said ‘INSERT COMMENT HERE’ and I wrote ‘INSERT PARAPHRASE HERE’. Is that right? “

3. Categorize carefully

If you choose to categorize items, be very conservative about pre-judging what it is you’re talking about. Sure, you’ve spent the last 25 minutes talking about a few categories, but don’t jump to putting names on the buckets—that’s prejudice, and it shapes opinions. Group like items (“Are these two frownies related?”), branch out from there, and labels will emerge. Be careful that the buckets aren’t too broad to be useful; it can be tempting to draw connections among almost everything, but ideally you’ll be slicing things a little thinner, facilitating more focused action items.

4. Action Items Should Have Intent

Unclear Action Items are worse than useless. One trick is to ensure a verb is the first word of every Action Item. By definition, every action includes a verb, but sometimes the verb is glossed-over or shorthanded in the retro. Everyone in the room understands what’s meant, but afterwards that may no longer be the case. Make sure that Action Items remain actionable when viewed later.

5. Action Items Should Be Falsifiable

Be sure to frame Action Items in terms that can be assessed as “done” or not. “Refactor more” isn’t useful a useful task, because there’s no way to meaningfully tell whether it’s done. “Improve the User model’s Code Climate grade from an F to a D” is actionable, and lets the team take small, achievable steps towards improvement. Also: use Code Climate, Errplane, New Relic, Airbrake or other instrumentation services to help put objective measures on code quality, performance, etc.

6. Action Items Need a Single Responsible Party

Not two people. Not “team” or “all”. One person. When an action item involves the whole team, find a volunteer to be the cop and enforce compliance. If one person isn’t responsible, then no one’s responsible. Addendum: review Action Items. Print them up and put them on the team stand-up board. Cross them off as completed. Review the list at the next retro.

7. What Happens In Retro, Stays In Retro

The retro should be a safe place. Active members of the team should the be ones in the room; sometimes it’s helpful to include stakeholders that aren’t present for most of the week (but that’s a judgement call). Action Items may be displayed publicly, but it’s preferable to only share the raw notes with the people present.

These practices aren’t laws chiseled in stone; they’re hacks and ideas borne of observations of patterns and anti-patterns witnessed in many, many retros. Do you agree? Disagree? Have juicy, anonymized stories supporting or contradicting? Let us know (and share your best retro stories) in the comments.

 

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

Stop leaking ActiveRecord throughout your application

Robbie Clutton
Monday, May 6, 2013

Extending ActiveRecord::Base leaks a powerful API throughout an application which can lead to tempting code which breaks good design. Take the classic blog example where you may want to retrieve the latest posts by a given author. You may have seen, or even written code that gets the dataset you need straight into the controller or view:

Post.where(author_id: author_id).limit(20).order("created_at DESC").each { ... }

For me this is a design violation as well as breaking the “Law of Demeter”[Edit: Current Pivot Adam Berlin and former Pivot John Barker pointed out that chaining with the same object was not a Demeter violation]. The example above tells me structure of the schema that the calling class has no business knowing. It also makes testing using stubs ugly and encourages testing against the database directly. A test would have to chain three methods to stub a return value. It’s brittle, as in it’s susceptible to breaking due to changes outside of the class. For me it also fails from a narrative perspective in that it doesn’t succinctly reveal the intent of this part of the application.

If we were testing this and attempting to use stubs, we’d have to write something like the below. You can see how this is at best cumbersome, but also fragile.

where = stub(:where)
limit = stub(:limit)
order = stub(:order)

Post.stub(:where).with(author_id: author_id) { where }
where.stub(:limit).with(20) { limit }
limit.stub(:order).with("created_at DESC").and_yield(post1, post2, post3)

You may be forgiven for thinking you could chain the stubs like below, but the arguments are ignored and this just serves to highlight the breaking of the ‘Law of Demeter’.

Post.stub_chain(:where, :limit, :order).and_yield(post1, post2, post3)

I’d much rather see that as a message to the Post class.

def self.latest_for_author id
  where(author_id: id).limit(20).order("created_at DESC")
end

Post.latest_for_author(1)

If there were variations of the limit and perhaps offset, they can be passed as option parameters of as an options hash:

def self.latest_for_author id, limit = 20, offset = 0
  where(author: id).limit(limit).offset(offset).order("created_at DESC")
end

Post.latest_for_author(1)
Post.latest_for_author(1, 20, 0)

or

def self.latest_for_author id, options
  limit = options[:limit] || 20
  offset = options[:offset] || 0
  where(author: id).limit(limit).offset(offset).order("created_at DESC")
end

Post.latest_for_author(1, offset: 20)

In order to get the dataset the call looks like the following, and I think is more informative than using the ActiveRecord DSL directly.

Post.latest_for_author(author_id).each { ... }

Testing is also easier, as it puts more emphasis on the messages being sent to objects rather than a chain of calls having to be correct.

Post.should_receive(:latest_for_author).with(1).and_yield(post1, post2, post3)

There are a few advantages to this refactor:

  • Only the Post class knows about the schema
  • Any changes to the implementation of what latest_for_author are encapsulated in one place
  • The method describes the intent more than the implementation
  • Stubbing in the tests are easier as there is one clear dependency
  • Testing the database is encouraged only in the class hitting the database

One further refactor could be done here, and that is to move the query logic out of the Post class once more, but this time into a purpose built query Object:

class LatestPosts
  attr_reader :author_id

  def initialize author_id
    @author_id = author_id
  end

  def find_each(&block)
    Post.where(author_id: author_id).limit(20).order("created_at DESC").find_each(&block)
  end

end

Where using the class looks like:

LatestPosts.new(author_id).find_each { ... }

Here’s what Bryan Helmkamp has to say on query objects in his excellent write up on fat ActiveRecord models. Bryan here rightfully points out that once in a single purpose object, they warrant little attention to unit testing. Now is the right time to use the database to ensure the right data set is being returned and that N+1 queries are not being performed. This means that database testing would only occur within the class actually hitting the database and not the rest of application which has a dependency on the database.

All of these techniques discussed serve to improve the design of an application by preventing leaking responsibilities from one class throughout the rest of the application. I’m also not saying that developers shouldn’t be using ActiveRecord or even Rails, but to use the tools responsibly.

  • 0 Shares
  • Share on Facebook
  • Share on Twitter
Trace Wax

A user metric is a terrible thing to waste

Trace Wax
Monday, April 29, 2013

When it comes to user metrics, what should you log when you don’t know what to log?

Everything.

When you’re first getting an MVP site off the ground, you don’t know quite what you might want to track.  And might not have time to think about it.

If you log everything your users do, however, then weeks or months of data will be there for you when you need it most, to answer your questions right away.  That’s why I’m excited about companies like Heap are doing, logging every single user click.

For those without Heap invites, or if you’d prefer to use Kissmetrics, I wrote a simple gem to do the same with KissMetrics, for all your user clicks that hit your web server:   km_everything. It logs all controller actions by default, but you can set up a whitelist to give them more meaningful  and product-manager friendly names, or a ‘blacklist’ to prevent certain actions from being logged that aren’t meaningful and would use too much of your KissMetrics event quota.

Also, from what I’ve observed on KissMetrics, server-side metrics have proven more reliable.  Metrics recorded via Javascript can be off if the user closes their browser too quickly after taking an action.  Logging the metrics server-side also won’t take up any of the user’s processing power or show signs that remind them they’re being tracked.

Excited about our brave new world of meaningful ad hoc analytics with reams of user data, powered by ubiquitous metrics.  This data will then show us how to make our sites even better for our users.

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

Feature hydra: how many heads does your product have?

Graham Siener
Monday, April 29, 2013

Should a web and iOS project have one or two tracks/teams/IPMs?

I posted that question to our internal Q&A forum a few months ago.  We were kicking off a client on a large project, building multiple applications for web (incl. mobile) and iOS. We expected some disparities in functionality between the two but assumed the iOS client would be a subset of the website. The client dedicated a PM for each track and there were many shared resources across both projects (designers, UX, backend, other in-house integrations).  One interesting wrinkle that would be a driving factor: the web would be a backbone app driven by an API that another team was in the process of developing.

I was fortunate to get a variety of viewpoints from Pivots that had been through similar projects (hat tip to Onsi for his great answer that influenced this post!).  My hypothesis was that we should stick to one IPM, one standup, etc. and effectively stay as one team as long as possible.  Three months in, I wanted to share an experience report on what has worked and where we’re still improving.

Clear Roles

Having a PM for each platform meant we could effectively manage the user experience specific to the device.  Mark Pincus pushes for everyone to be the “CEO of Something” and this structure ensured that the PM was not a bottleneck as our development team ramped up to six pairs.  Having one designer meant our UI and UX felt consistent across platforms.  Do not take for granted that a user transitioning from one device to another will be disoriented by an inconsistent experience.  Be careful to watch out for communication issues between PMs, and make sure they’re both describing mutually compatible products. It’s possible to specify a feature in a way that’s subtly incompatible between web and iOS — try to catch these issues early!

Group Discussion

We started off with one IPM but this grew unwieldy (talking through, and pointing out, six pairs worth of work just takes time).  We decided to split into two IPMs but the anchor from iOS joined the Web IPM and vice versa.  We also ensured that these anchors were part of a pre-IPM process that delivered the broad themes and saved the larger IPM audience from unimportant decision points.

Own the API

As I mentioned, we started off with the expectation that we’d develop our front ends while another team worked on an API to expose their backend.  It only took a few weeks to realize this would create a lot of churn and we absorbed a layer of API that let us iterate quickly and optimize endpoints for iOS.

The web is an agile-friendly platform where rapid deployment is possible. iOS, thanks to Apple’s review process, is not. Tying minor tweaks on the web client to a (potentially non-backward compatible) full deploy of the API will almost certainly land you into trouble. You have to think carefully about backward compatibility with the iOS app; imposing a clear separation between the web client and the Rails API really helps.  Have (API-level) integration tests in both your iOS suite and your web suite that hit the API app. These integration tests represent the contract that your API agrees to satisfy.

Parallelization is Hard

Understand that parallelizability will be very difficult at the beginning of the project and at major milestones of each sub-project (iOS and web). Breaking stories into tracks of work helps to highlight this.  One consequence of two backlogs is a tight coupling of stories across two Tracker projects.  iOS features that rely on additions to the API are necessarily blocked until the API team can deliver them, and the PMs must negotiate the priority of these stories in relation to web-centric features.  We opted to separate iOS and Web work, but perhaps a more fluid team could better navigate these dependencies.

Build Product One Screen At a Time

We’re actively trying to improve the story mapping/ideation process for new features.  It’s helpful to develop high-level features for all platforms at the same time, but it’s unusual that a web-focused feature can be copied verbatim to iOS.  Similarly, who breaks the tie when the web and iOS PMs have a different viewpoint on functionality or user experience?  Having one ultimate product owner could potentially address this point, yet it’s unclear how they wouldn’t be a giant bottleneck for both teams.

Closing Thoughts

Building this much (this fast) is fun!  We stood up complete experiences across three platforms while rapidly iterating on functionality.  With a team of this scale it’s critical that you’re re-Incepting your project and including the whole team in roadmap discussions to create a shared product vision.

What did I miss?  What are some best practices you’ve discovered managing products across web and mobile?

  • 0 Shares
  • Share on Facebook
  • Share on Twitter
Jonathan Berger

Set your sights on the next Milestone with an Idea Board

Jonathan Berger
Monday, April 29, 2013

The Idea Board Technique

A typical Agile Inception ends with a fully fleshed-out backlog for the next few iterations, and some farther-off, coarse-grained, Epic-level ideas written on index cards. What to do with them? Some teams clip them together in a deck of cards that gathers dust and is rarely seen again. I prefer to externalize them on a foamcore board in a riff on a technique Thoughtworks calls an “Idea Board” or “Idea Backlog”.

Making the Idea Board

This is basically an Epic-level reverse-Kanban board that will work in concert with Pivotal Tracker. Create a few columns: “Now”, “Next”, and “Later”. Generally you’ll have 2-3 cards in the Now column, another 2-3 in the Next Column, and the rest (~20-40) in the Later column. The Idea Backlog can often fit on a half-foamcore board (4ft x 4ft), and serves a few uses:

  • it externalizes future epics so everyone 1) is reminded they exist, and 2) can see their relative priority
  • it gives Stakeholders a place to park long-term ideas, and feel that their contributions are included
  • it gives a big-picture view that tactical what-are-we-working-on-this-week systems have trouble displaying succinctly. This is great for strategic-level Release Planning meetings that I like to try to have every 3 or 4 weeks.

On a recent project, we had a bit of Priority Whiplash: every week, we’d go into an Iteration Planning Meeting (IPM) on Monday and agree on priorities. By Friday, someone on the team would say “Why’re we working on this?! What about that other thing?!”. We’d mention the agreed-upon priorities from a few days earlier, but inevitably someone would shake their head and say “I never agreed to that!”.

Idea Board to the Rescue!

We started using the Idea Board and bringing it to planning meetings. Having a tangible representation of the plan helped a lot. “Remember on Monday when we moved the Foo feature set into the Parking Lot to make room for the Bar feature set? I swear no one moved the cards since the last time we looked at this.” This helped a lot. It also really helped that when someone would say “I had a great idea! Let’s make a Baz feature!”, we could write “Baz” on an index card and stick it on the board. It may live in the parking lot for a while, but its visible and everyone is comfortable that we’re prioritizing the feature (rather than forgetting about it).

Some say a big drawback to a strategic paper-based system like the Idea Board is that over time, it falls out of sync with a tactical digital system like Pivotal Tracker. I think this is more a feature than a bug: when the Idea Board has one or two epics that are out of sync with reality it’s no big deal. When the whole board is a big lie, that’s a signal to the whole team that it’s time for everyone to re-asses the alignment between tactical steps and strategic goals: it’s time for a Release Planning meeting.

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

Single resource REST Rails routes

Robbie Clutton
Tuesday, April 16, 2013

REST principles by default is a fantastic convention within Rails applications. The documentation for how to route HTTP requests are comprehensive and give examples about photo resources within an application. If you’ve got photo and tag as first class resources of your application, Rails has you covered. But what if you are building an application with a focus on one type of resource, do you really want /resource_type as a prefix to all of your application paths? I certainly don’t and I’ll show you how to remove that without diverging from Rails core strenghts.

For better or worse, I’m always conscience of making sure applications I’m involved in have Cool URIs and sometimes that does mean fighting the Rails conventions. However Rails routing is very flexible and can provide me with the application paths that make me happy.

Take Twitter as an example. Every user has their username as a top level path, so instead of having /users/robb1e, they simply have /robb1e. When dealing with an application where there is one core resource it can make a lot of sense to strip the resource prefix. This can be achieved through scopes in the routing configuration.

Your::Application.routes.draw do
  scope ":username" do
    get '', to: 'users#show'
  end
end

Gives you routes which look like

           GET  /:username(.:format)                users#show

If you wanted to see the followers and followees of that user, you have two options. Return to the default resource or use HTTP verb contraints. I’ll show you both.

Your::Application.routes.draw do
  scope ":username" do
    get '', to: 'users#show'
    resource :following, only: [:show]
    resource :followers, only: [:show]
  end
end

This adds the routes

following GET  /:username/following(.:format)      followings#show
followers GET  /:username/followers(.:format)      followers#show

Alternatively HTTP verb constrains can be used to achieve a similar result.

Your::Application.routes.draw do
  scope ":username" do
    get '', to: 'users#show'
    get '/following', to: 'user#following'
    get '/followers', to: 'user#followers'
  end
end

This gives the paths

          GET  /:username/following(.:format)      user#following
          GET  /:username/followers(.:format)      user#followers

If you are trending into paths unknown, you always have the safety of tests to help you out. Both Rails and RSpec have ways to test your application routes.

One gotcha which using the default resource routing removes is clashing paths. If you decide to build an admin page and want to put that at /admin, that needs to be in the routes config before the scoped block and if a user has given themselves the name of admin then you may be in for some fun.

So the next time a need arises for an unconventional route, check the documentation, it’s probably possible although almost always warants thinking about.

  • 0 Shares
  • Share on Facebook
  • Share on Twitter
Trace Wax

See Your Work Product in Its Natural Habitat

Trace Wax
Monday, April 15, 2013

I took a day off of work recently, and learned more about what I was working on than in several months of coding.

My current Pivotal client project is CaseCommons, using web technology to modernize child welfare and foster care so social workers can spend more time with kids and families.  We’d just completed a large set of work about court hearings, and now I was attending one. I went to see my friends finalize their adoption of two little boys they’ve been fostering, with their wedding to immediately follow.

Everything I’d done and learned paled compared to seeing the judge and social worker speak about how the kids’ lives improved in my friends’ care. One of the boys was in a wheelchair a year ago, and now here they were joyously laughing and running in circles around their new parents as the adoption was completed and wedding vows were spoken.

I talked to the social worker at length and learned things I hadn’t yet come across, like how most adoptions are with extended family members, my friends were the exception. I also saw the clerk entering the details of the court hearing into their computer system, which looked like it hadn’t been updated since the 1990s but it still was blazing fast. They’re not using our product yet, which is much more streamlined. But they’ll expect it to be equally responsive.

Now, whenever I’m doing a feature or fix for social workers, I see Tania’s face as she hugs the children and speaks with my friends about the kids. When I work on court hearings, I see the clerk navigating so quickly to enter in all the many details.

I won’t always get to work on helping people help kids.  But when I move on to my next Pivotal project I can’t wait to set aside some time much earlier on, to look users in the eye and truly understand how what we’re building will make their lives better.

  • 0 Shares
  • Share on Facebook
  • Share on Twitter

Topics

  • agile (778)
  • rails (113)
  • testing (87)
  • ruby (83)
  • ruby on rails (70)
  • jobs (62)
  • javascript (54)
  • techtalk (44)
  • rspec (38)
  • activerecord (29)
  • productivity (29)
  • gogaruco (29)
  • ironblogger (29)
  • git (28)
  • nyc (27)
  • rubymine (25)
  • bloggerdome (22)
  • mobile (22)
  • cucumber (20)
  • process (19)
  • pivotal tracker (19)
  • 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)
  • tdd (13)
  • selenium (12)
  • css (12)
  • goruco (12)
  • bundler (12)
  • meetup (11)
  • railsconf (11)
  • nyc-standup (11)
  • capybara (10)
  • mac (10)
  • mojo (10)
  • chef (10)
  • api (10)
Subscribe to ironblogger Feed
  1. 1
  2. 2
  3. 3
  4. →
  • 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 >