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
Luan Santos

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.

I am going to use merge-sort as the example here since it is a quite simple application of the divide & conquer. I am not going to explain in detail how it works but it basically consists of splitting an array in two parts and them merging them sorted, recursively.

A very simple way of getting merge-sort to work on sidekiq is having one single worker that does all the job, note that I’m using two abstract service classes here SplitsArray and MergesArrays, imagine that things can go wrong inside of these services, since they are not controlled by us and can live somewhere in the internet, maybe, they can fail or be slow.


class MergeSortWorker
  include Sidekiq::Worker

  def sort(array)
    return array if array.count <= 1

    left, right = SplitsArray.split(array)
    MergesArrays.merge sort(left), sort(right)
  end

  def perform(array)
    SortedArray.create array: sort(array)
  end
end

If you think about this implementation, let’s say SplitsArray is a very flaky service and it fails once every few tries, do we want it to retry the whole worker from scratch? We can potentially be retrying this over and over again and maybe never see the result. That is exactly the problem we had and we needed each step to be independent. Not to mention that if we can parallelize this process to gain performance it’s another win.

So here is the initial idea, what if we have a worker to split arrays, and a worker to merge them? That could work right? Here is a pseudo implementation of that:


class MergeSortWorker
  include Sidekiq::Worker

  def perform(array)
    array = SortWorker.perform_async array
    SortedArray.create array: array
  end
end

class SortWorker
  include Sidekiq::Worker

  def perform(array)
    return array if array.count <= 1

    left, right = SplitsArray.split(array)

    left_sorted = SortWorker.perform_async left
    right_sorted = SortWorker.perform_async right

    MergeWorker.perform_async left_sorted, right_sorted
  end
end

class MergeWorker
  include Sidekiq::Worker

  def perform(left, right)
    MergesArrays.merge left, right
  end
end

And this is a visual representation of what it looks like when executing.

There is only one problem: workers are asynchronous and they do not have return values, so our code can’t possibly work like that, we have to store some kind of state to know when we’re done with a worker so we can merge back the arrays. There is no tool as of now to do that with sidekiq (couldn’t find anything for resque either) out of the box.

To solve this problem you can manually track the state of the job, thats essentially what we did in our case, we could end up with something like this:


class MergeSortWorker
  include Sidekiq::Worker

  def perform(array)
    SortWorker.perform_async TempArray.create(array: array).id
  end
end

class SortWorker
  include Sidekiq::Worker

  def finish(temp_array)
    temp_array.sorted = true
    temp_array.save
    MergeWorker.perform_async temp_array.parent.id
  end

  def perform(array_id)
    temp_array = TempArray.find array_id
    array = temp_array.array

    finish(temp_array) and return if array.count <= 1

    left, right = SplitsArray.split(array)
    temp_left = temp_array.children.create(array: left, sorted: false)
    temp_right = temp_array.children.create(array: right, sorted: false)

    SortWorker.perform_async temp_left.id
    SortWorker.perform_async temp_right.id
  end
end

class MergeWorker
  include Sidekiq::Worker

  def finish(parent)
    if parent.parent
      MergeWorker.perform_async parent.parent.id
    else
      s = Redis::Semaphore.new(:creating_sorted_array, connection: "localhost")
      s.lock do
        parent.reload rescue return
        SortedArray.create array: parent.array
        parent.destroy
      end
    end
  end

  def perform(parent_id)
    parent = TempArray.includes(:parent).where(id: parent_id).first
    return if parent.nil?

    finish(parent) and return if parent.sorted?

    if parent.children.present? && parent.children.all?(&:sorted?)
      left = parent.children.first.array
      right = parent.children.last.array
      parent.children.destroy_all

      parent.array = MergesArrays.merge left, right
      parent.sorted = true
      parent.save

      finish parent
    end
  end
end

The complexity of our workers grew considerably, but it is now fail proof and parallelizable, solving our previous problems and getting us somewhere closer to that graphical representation above. Note that we added the model TempArray to the equation, that is where we save our interstitial states.

We have knowledge about synchronization and thread safety all over the place now, we have that redis-semaphore gem to ensure it. Each worker is now trying stuff without the certainty of success, it eventually succeeds, tho. We are instantiating superfluos workers then giving up on them once we figure out the arrays “are not ready”, and it got much more difficult to understand what the code is doing.

The responsibilities of each worker are a bit shady right now because of the nature of the solution, it is definitely not ideal, but sometimes when you need a robust and efficient solution you have to make some sacrifices.

I still think this should be easier, I’m sure the code I wrote as an example here could be refactored to look nicer but still, this shouldn’t be such a pain to achieve, that is why I’m starting my own gem to solve this problem. More on that next week.

All the files I used for this are available on this gist here: https://gist.github.com/luan/5610299

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

Designing an API in Hell

Andrew Bruce
Sunday, May 19, 2013

Minitest, Ruby’s built-in testing library, has some great out-of-the-box features. One of these is test parallelization. Parallel testing is often added after a suite gets slow enough to hurt. That can be achieved using the parallel_tests gem, which takes advantage of today’s multi-core processors, or using custom solutions for dividing chunks of a suite across several machines. Arguably, test speed should be dealt with by making code design changes, but that’s another story: what interests me most about minitest’s parallelization is the constraints it places upon the design of stateful systems when TDDing from scratch.

You can turn on parallelization for a particular test case:

describe Server do
  parallelize_me!
end

or for all tests:

require 'minitest/hell'

As the name implies, the latter approach turns up the test pain level to 11, but it’s the kind of pain that can have positive effects. For ‘fun’, I started to use minitest’s parallelization on a side project, which has a stateful API backed by a relational database. Here are some of the decisions that were forced out by using parallel test examples.

Commitment to fast tests

I thought that running tests in parallel from the start of a project would make me lazy, causing me to neglect slow tests because they’d be running at the same time as others. Surprisingly, the opposite happened: the need to constantly rerun the whole suite to iron out nondeterministic conflicts encouraged me to fix slow tests early. I ended up being able to run the entire suite several times within a matter of seconds in order to check the tests’ ability to run in parallel.

Side note: this is an early-stage project, with a very low quantity of tests! It will be interesting to see how test speed increases as the volume of tests increases.

Avoiding test duplication

Since the unique constraints of my database could be hit by tests with the same fixture data running at the same time, I was encouraged to use more intention revealing test data for each example, avoiding foo and bar, which commonly litter a suite and make tests harder to read.

For IDs, I used Ruby’s SecureRandom library, which provides GUID and hex generation. I sometimes used hex generation when the user-supplied unique display name of something didn’t matter to the test.

Client-side ID generation

Although not strictly forced out from parallel tests, parallel testing got me thinking about how best to interact with the backend, which has a single database being served by multiple concurrent requests (just like any web server).

Using GUIDs instead of autoincrementing IDs can be a smart decision to make if you can (i.e. you don’t need human-friendly URLs), because it means your database server doesn’t need to worry as much about ensuring uniqueness, since the GUID algorithm effectively guarantees it.

TDDing my API from scratch, without external requirements, encouraged me to use GUIDs to simplify the design and to avoid bottlenecks at the database layer. POST requests canonically return the new URL of the resource you’re creating in the Location header of the response. So to test that a thing really got persisted I’d need to:

  1. POST to /items with a representation of the resource
  2. Grab the Location header of the response to get the new URL
  3. GET /items/:newid and ensure the response body matched the representation I sent

This seemed a very laborious process for storing some data. Much less work is:

  1. PUT to /items/:newid
  2. GET /items/:newid and ensure the response body matched the representation I sent

Since GUIDs can be treated as unique, it didn’t make much sense for the server to generate them.

Positive effect: the app would now cope with a distributed database system on the back-end, despite starting out on a technology that’s thought of as difficult to scale horizontally (SQLite).

Avoiding database resets

It’s common practice to wipe the whole database when starting a new example, or to run each example in a transaction and roll it back when each example finishes. I wanted real black-box tests, so I didn’t want to use transactions. Yet, deleting the whole database at the start of an example didn’t play nice with minitest’s parallelization, since data that one example required would be deleted by another.

The usual approach when using parallel_tests is to create a database for each process. However, since minitest doesn’t manage databases (nor should it) I chose to keep a single database and find a different solution.

I chose to sandbox all of the tests by creating new entities each time, and only checking for output that indicated that particular entity had been worked on. The product I’m working on is a Continuous Integration server, so I’d be creating CI projects (you might also know them as jobs) and expecting them to appear in an XML feed. The tests had to be OK with other data being present, since the other tests could be working too.

This approach precluded tests that checked that the number of records had increased by one, because in an otherwise acceptable “green” test situation they’d occasionally increase by more than one (another test added a record too), stay the same (another test deleted a record) or decrease (more than one had been deleted).

Constraints are fun

While I wouldn’t recommend going rogue like this on a client project, playing with constraints like truly parallel tests can get you thinking about your normal testing procedure. Some of the above decisions allowed for a much faster test execution time, and always having the assumption that other processes could be working on the database forced out some interesting techniques. Some of the techniques I had to avoid due to parallelization would normally necessitate different workarounds with their own drawbacks. For example, if you always assume the count of an ActiveRecord class will go up, you require exclusive use of the database. If instead you scope your queries to a parent entity, this restriction would be removed.

Hell isn’t so bad after all.

  • 0 Shares
  • Share on Facebook
  • Share on Twitter
Matthew Parker

Method Modeling: A Refactoring

Matthew Parker
Saturday, May 18, 2013

While working on AwesomeResource, I needed to implement functionality that would make the following test pass:


  it "creates readers and writers for any attributes passed in during initialization" do
    article_class = Class.new do
      include AwesomeResource
    end

    article = article_class.new("title" => "Fun")
    article.title.should == "Fun"

    article.title = 'Fun Times!'
    article.title.should == 'Fun Times!'

    expect { article.unknown_attribute }.to raise_exception
  end  

Simple enough. If you initialize an instance of a class that includes AwesomeResource, then you get attribute readers and writers for any hash keys passed in during initialization.

My first attempt at implementation looked something like this:


module AwesomeResource
  attr_reader :awesome_attributes

  def initialize(attributes={})
    @awesome_attributes = AwesomeResource::Attributes.new attributes
  end

  def method_missing(method_name, *args)
    if method_name["="]
      if awesome_attributes.has_key?(method_name[0...-1])
        awesome_attributes[method_name[0…-1]] = args.first
      else
        super
      end
    else
      if awesome_attributes.has_key?(method_name)
        awesome_attributes[method_name]
      else
        super
      end
    end
  end
end

Yuk. All those nested if/else’s didn’t sit well with me. Let me try to clean that up:


  def method_missing(method_name, *args)
    if method_name["="] && awesome_attributes.has_key?(method_name[0...-1])
      awesome_attributes[method_name[0...-1]] = args.first
    elsif awesome_attributes.has_key?(method_name)
      awesome_attributes[method_name]
    else
      super
    end
  end

The best I can say for this code is that it’s more compact. But is it any more readable? Hardly. In fact it’s worse.

Let’s take another look at the first implementation. The nested if/else blocks look awfully similar. Perhaps there’s a polymorphic model lurking there? But what are we modeling? If we were to wrap a class around those blocks, we’d have to be modeling a method. What would that look like? Let’s extract some classes:


  class AttributeWriter
    attr_reader :attributes

    def initialize(attributes)
      @attributes = attributes
    end

    def call(attribute_name, attribute_value)
      raise "Unknown Attribute" unless attributes.has_key?(attribute_name)
      attributes[attribute_name] = attribute_value
    end
  end

  class AttributeReader
    attr_reader :attributes

    def initialize(attributes)
      @attributes = attributes
    end

    def call(attribute_name)
      raise "Unknown Attribute" unless attributes.has_key?(attribute_name)
      attributes[attribute_name]
    end
  end

  def method_missing(method_name, *args)
    if method_name["="]
      AttributeWriter.new(awesome_attributes).call(method_name[0...-1], *args)
    else
      AttributeReader.new(awesome_attributes).call(method_name)
    end
  end

OK, I at least feel like I’m trying to write OO code at this point. There’s a bit of duplication between the AttributeReader and AttributeWriter classes. We could clean that up with template methods:


  class AttributeAccessor
    attr_reader :attributes, :attribute_name

    def initialize(attributes, attribute_name)
      @attribute_name = attribute_name
      @attributes = attributes
    end

    def call(*args)
      raise "Unknown Attribute" unless attributes.has_key?(attribute_name)
      execute(*args)
    end

    def execute(*)
    end
  end

  class AttributeWriter < AttributeAccessor
    def attribute_name
      super[0...-1]
    end
    
    def execute(attribute_value)
      attributes[attribute_name] = attribute_value
    end
  end

  class AttributeReader < AttributeAccessor
    def execute
      attributes[attribute_name]
    end
  end

  def method_missing(method_name, *args)
    if method_name["="]
      AttributeWriter.new(awesome_attributes, method_name).call(*args)
    else
      AttributeReader.new(awesome_attributes, method_name).call
    end
  end

Notice that we've moved the responsibility of stripping off the "=" off the method_name from method_missing down into AttributeWriter.

Hmmm... The base class is pretty abstract. How easy it this code to understand now?

Also, the body of the method missing now looks a lot like a factory method. While in Rome...


  class AttributeAccessor
    attr_reader :attributes, :attribute_name

    def self.from_method_name(attributes, method_name)
      if method_name["="]
        AttributeWriter.new(attributes, method_name)
      else
        AttributeReader.new(attributes, method_name)
      end
    end

    def initialize(attributes, attribute_name)
      @attribute_name = attribute_name
      @attributes = attributes
    end

    def call(*args)
      raise "Unknown Attribute" unless attributes.has_key?(attribute_name)
      execute(*args)
    end

    def execute(*)
    end
  end

  class AttributeWriter < AttributeAccessor
    def attribute_name
      super[0...-1]
    end

    def execute(attribute_value)
      attributes[attribute_name] = attribute_value
    end
  end

  class AttributeReader < AttributeAccessor
    def execute
      attributes[attribute_name]
    end
  end

  def method_missing(method_name, *args)
    AttributeAccessor.from_method_name(awesome_attributes, method_name).call(*args)
  end

I'm now starting to question this code. Is there a good trade off here between indirection and maintainability? I don't think the number of accessors are likely to grow (accessors have consisted solely of getters and setters since the dawn of OO). Between all of the refactorings, I think the first (with its minor duplication) was the easiest to understand.

Yet something still doesn't feel right. Let's look back at the very first code snippet. Notice the `AwesomeResource::Attributes.new` in the `initialization` method? Those are our bag of attributes (they're basically a hash with indifferent access). We keep passing it around to all of our Attribute* classes… perhaps some of this code should have lived there in the first place?


module AwesomeResource
  attr_reader :awesome_attributes

  def initialize(attributes={})
    @awesome_attributes = AwesomeResource::Attributes.new attributes
  end

  def method_missing(method_name, *args)
    awesome_attributes.accessor_for_method_name(method_name).call(*args)
  end
end

module AwesomeResource
  class Attributes < SimpleDelegator
	#...

    def accessor_for_method_name(method_name)
      if method_name["="]
        ->(attribute_value) { self[method_name[0...-1]] = attribute_value }
      else
        -> { self[method_name] }
      end
    end

    def [](key)
      validate_key_exists(key)
      attributes[standardized_key(key)]
    end

    def []=(key, value)
      validate_key_exists(key)
      attributes[standardized_key(key)] = value
    end

    private
    def validate_key_exists(key)
      raise "Unknown attribute" unless has_key? key
    end
    
    #...
  end
end

This feels right. We're now modeling methods with lambdas (Ruby's built in method objects). We've eliminated a tangle of nested if/else blocks without introducing too much indirection. We've maintained high-cohesion within the AwesomeResource::Attributes class despite the new methods.

  • 0 Shares
  • Share on Facebook
  • Share on Twitter
Ken Mayer

Sencha Touch BDD – Part 5 – Controller Testing

Ken Mayer
Saturday, May 18, 2013

Sencha Touch BDD

tl;dr

A multi-part series of articles on how to test Sencha Touch applications. It uses Jasmine for unit testing and Siesta for integration testing.

Part 5 – Controller Testing

Recap

Part 4 Introduced PhantomJS as an easy and faster alternative to headful Jasmine testing. Part 3 added jasmine-ajax so we can verify that stores and models react properly to back-end data. We also learned how to use stores to test views, without depending on a back-end server. In Part 2 I showed you how to unit test Sencha model classes in Jasmine. In Part 1 I showed you how to set up your Sencha Touch development environment to use the Jasmine JavaScript test framework.

It’s a control thing, but I will let you understand

Sencha Touch controllers usually live within the context of a single application object. Normally, this is handled for you when you invoke Ext.Application() in your app.js file. It creates a singleton object for you in the namespace of your application. For example, if you configured your application’s name to be ‘SenchaBdd’, then the application will be available as the .app attribute of the global SenchaBdd object, that is, SenchaBdd.app.

Unit testing should not have a running application, however. The point is that we are testing classes in isolation. There’s nothing isolated about an integrated, running, Javascript application. There is a relatively simple solution, however; You need to create you own “test” application object that you can then pass as a configuration option when you create controllers under test.

$ cat spec/javascripts/controller/MyControllerSpec.js
describe('SenchaBdd.controller.MyController', function() {
    var controller, app;
    beforeEach(function () {
        app = Ext.create('Ext.app.Application', {name: 'SenchaBdd'});
        controller = Ext.create('SenchaBdd.controller.MyController', { application: app });
        controller.launch();
    });

    afterEach(function() { app.destroy(); })

You may want to refactor the application creation and tear-down into a spec helper, to DRY out your tests.

Test behaviors, not events

It’s tempting to write a Jasmine test that tries to trigger an event in the DOM, then follow the event handling through the application. This is the road to hell. If you find yourself trying to simulate an event, please stop. That is what integration tests are better at doing. Controllers are classes like any other, and you should test methods in the same way. For example, let’s drive out a behavior where, when a user taps on the ‘Buy’ button our application sends a request to the back-end.

describe('SenchaBdd.controller.MyController', function () {
  var controller, app;
  beforeEach(function () {
    app = Ext.create('Ext.app.Application', {name: 'SenchaBdd'});
    controller = Ext.create('SenchaBdd.controller.MyController', { application: app });
    controller.launch();
  });

  afterEach(function () {
    app.destroy();
  });

  it('#newOrder', function () {
    var order = controller.newOrder();
    expect(order.$className).toEqual('SenchaBdd.model.MyModel');
    expect(order.phantom).toBeTruthy();
  });

  describe('#onBuy', function() {
    it('calls save on the order', function() {
      var myOrder = Ext.create('SenchaBdd.model.MyModel');
      spyOn(myOrder, 'save');
      spyOn(controller, 'newOrder').andCallFake(function() {
        return myOrder;
      });
      
      controller.onBuy()
      
      expect(myOrder.save).toHaveBeenCalled();
    })
  })
});

You might notice that I neither ‘tap’, nor do I test for a ‘POST’ ajax call. The former is better tested through integration tests. The latter is better tested in the model. All the controller need do assert that the model was saved. We trust external classes to function (because they’re tested, too, right?) Testing the #save method on the model follows the same process as testing stores, as I outlined in Part3. Another thing to note is that, under test, this controller does not have any views associated with it; Ext.ComponentQuery calls will return empty (undefined) results. This is to be expected in an isolated test, but may make for some head scratching when you first encounter it. If you must test something in the DOM, you should be writing an integration test anyway.

Ext.define('SenchaBdd.controller.MyController', {
  extend:   'Ext.app.Controller',
  config:   {
    views:   ['MyView'],
    refs:    {
      buyButton: 'myview #buyButton'
    },
    control: {
      buyButton: { tap: 'onBuy' }
    }
  },
  newOrder: function () {
    return Ext.create('SenchaBdd.model.MyModel');
  },
  onBuy:    function () {
    this.newOrder().save();
  }
});

As a personal preference, and make it easier to test and refactor, I have a #newOrder method that delegates to the model to create a new instance.

  • 0 Shares
  • Share on Facebook
  • Share on Twitter
Mark Rushakoff

git rebase vs. git merge: an agile perspective

Mark Rushakoff
Friday, May 17, 2013

At Pivotal Labs, we’ve been using Quandora for about 6 months as an easier way to archive and discover discussions about the hows and whys of consulting and software engineering here. Earlier this week, I asked my colleagues:

There are some git workflows that would have you regularly work in feature branches and then merge back into master only when the feature is ready for acceptance. However, on every project I’ve worked on at Pivotal, we have preferred to rebase and commit to master regularly.

Why prefer rebasing over merging?

I received some excellent answers.

Rasheed explains:

The more code diverges, the more difficult it is to integrate. If you want continuous integration, it’s a lot easier to do so on one branch, not many. It also drives out stories that are small, have the smallest actionable work, and are easy to accept. This leads to tight feedback loops.

Chad had some information to add to Rasheed’s answer:

Tight feedback loops are one of the things that Pivotal values.

We place priority on CI and small stories. This makes it easier to work on master – it’s not a big deal if it is accidentally broken, it’ll be easily fixed or reverted.

In my experience, we still do use topic branches when appropriate. E.g., in the middle of a story at the end of a day, or for a bigger feature that you don’t want to do in one commit, but would break mainline (master) with the intermediate commit. On my project, in this case, we usually merge –squash –no-commit onto master, to squash multiple commits on the topic branch into one commit on master.

Even in git, branching is still painful. The longer a topic branch lives, the harder it is to merge. Yes, you can rebase often, but that means you have to rewrite history to push the rebased changes to the server. This can cause confusion if the branch lives long and is worked on by multiple pairs or on multiple machines. So, it’s usually less net effort to just work on master, because we have good tests and can trust CI to quickly tell us if there’s any glaring logical merge conflicts that were missed. On teams without CI that rely solely on manual QA, this is much more of a risk and more expensive.

And Jacob, the director of our new Boston office, had this to say:

I’ve seen both patterns at Pivotal. Teams that rebase tend to be small and haven’t had a production release. Large teams have a quickly changing repo and feature branches make the history more readable. And teams that have released use feature branches to relegate incomplete code to a future release. They can also (in theory if not practice) easily roll-back an entire feature branch if something goes wrong in production.

Of course, as Rasheed mentions, trying to wrangle large unreleased changes causes all kinds of problems. Better to get faster feedback with smaller releasable features. If your team still feels it needs to have incomplete features in master, or needs to disable misbehaving pieces of the app, read up about feature switches and look into a tool like rollout or flipper.

So, it seems that in general, we tend to prefer rebasing because it helps facilitate some core concepts of agile software development:

  • Continuous deployment
  • Tight feedback loops
  • Small deliverables

Thanks to Rasheed, Chad, and Jacob for helping provide some great content!

  • 0 Shares
  • Share on Facebook
  • Share on Twitter
Cameron Cundiff

Lunchtime Drawtime!

Cameron Cundiff
Friday, May 17, 2013

Lunchtime Drawtime happens Fridays at lunch in the NYC office, where a handful of folks get together and perform some acts of creation. Sometime we have prompts; today’s was bodies of water.

Here’s what we came up with. Enjoy!

  • 0 Shares
  • Share on Facebook
  • Share on Twitter
Cameron Cundiff

How To: Use Skip Navigation Links for Better Keyboard Accessibility

Cameron Cundiff
Friday, May 17, 2013

For improved keyboard accessibility, use skip navigation links along with a coherent heading outline, ARIA landmarks, and a javascript polyfill for Webkit based browsers.

Why Use Skip Navigation Links?

It can be frustrating and fatiguing for folks with limited mobility to have to have to repeatedly tab through navigation links to get to the main content of a page. People who use screen readers face similar frustration when the page outline is not well defined. In order to address this issue, version 2.0 of the Web Content Accessibility Guidelines (WCAG 2.0) has specified a guideline for bypassing repetitive blocks of content. One technique recommended by the W3C is to include a skip navigation link at the beginning of the page, that changes focus to the first element after the repeated content.

How do I use Skip Navigation Links?

Add a link at the top of your body content whose href value points to the id of the element that wraps your primary content. Like so:

Disclaimer: The mechanism by which skip navigation links work had been broken  in Webkit based browsers for some time and has only recently been fixed. Until these browsers release the fixes, you may need to use a javascript polyfill to make skip nav links work.

What about ARIA?

Skip nav links are useful for users who use keyboard navigation only, but screen readers now support more sophisticated ways of navigating regions. Specifically, they support heading navigation and ARIA landmarks. You should take advantage of these features by using a clear heading outline and defining page regions.

Note: The last post I authored, Use ARIA Landmarks Instead of Skip Nav Links, presented a strategy that was predicated in part on the fact that skip navigation links have been broken in Webkit for the past three years. This bug has recently been fixed, so I was inspired to revisit the topic.

  • 0 Shares
  • Share on Facebook
  • Share on Twitter

Friday!

Pivotal Labs
Friday, May 17, 2013

Helps

Capybara "within" blocks and CSS pseudoselectors

We're running into an issue where :nth-child doesn't work with capybara CSS marchers. Oddly, the Xpath equivalents work just fine.

Halp?

Events

05/20: Agile Experience Meetup: Designer / Developer pair-cooking show

Robbie will be speaking and live-coding!

When teams integrate Agile and UX practices, the borders between designing and making become increasingly blurry, with siloed work replaced by cross-disciplinary collaboration. For our next Meetup, we'll combine a live pairing session with two talks on collaborating across roles and disciplines. How is pairing better than traditional collaboration? What are some pitfalls to be mindful of? Is it the right choice for your team? After their talks, we'll open up the floor for a panel-style Q&A.

RSVP at http://www.meetup.com/Agile-Experience-Design/events/116322382/

  • 0 Shares
  • Share on Facebook
  • Share on Twitter

Fear of Validation

Pivotal Labs
Thursday, May 16, 2013

Interestings

Negate a scope with ActiveRecord

Say you want to negate a scope.

scope :active, -> { where(active: true) }

You start by creating another scope:

scope :inactive, -> { where(active: false) }

Then the underlying column name changes, and you're forced to go back to two different scopes to update it. Ugh.

Wait!

You could have negated the first scope in the second scope!

scope :negate, ->(scope) { where(scope.where_values.reduce(:and).not) }

Now, use it:

scope :inactive, -> { negate(active) }

Boom.

  • 0 Shares
  • Share on Facebook
  • Share on Twitter

7 Minutes of Longest-Standup-Ever-Heaven

Pivotal Labs
Thursday, May 16, 2013

Interestings

FireSASS in Chrome (source maps)

If you're using SASS and ever wanted to see the original line numbers in your SASS files for debugging purposes, you've probably used FireSASS. Unfortunately, FireSASS is not available in Chrome.

However, you don't need FireSASS in Chrome, as SASS Source Maps totally work.

The following blog post will show you how to enable it.

http://fonicmonkey.net/2013/03/25/native-sass-scss-source-map-support-in-chrome-and-rails/

Events

05/20: Agile Experience Meetup: Designer / Developer pair-cooking show

Robbie will be speaking and live-coding!

When teams integrate Agile and UX practices, the borders between designing and making become increasingly blurry, with siloed work replaced by cross-disciplinary collaboration. For our next Meetup, we'll combine a live pairing session with two talks on collaborating across roles and disciplines. How is pairing better than traditional collaboration? What are some pitfalls to be mindful of? Is it the right choice for your team? After their talks, we'll open up the floor for a panel-style Q&A.

RSVP at http://www.meetup.com/Agile-Experience-Design/events/116322382/

  • 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 Labs Feed
  1. 1
  2. 2
  3. 3
  4. 4
  5. 5
  6. 6
  7. 7
  8. ...
  9. 228
  10. →
  • 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 >