Close
Glad You're Ready. Let's Get Started!

Let us know how we can contact you.

Thank you!

We'll respond shortly.

LABS
What Powers Pivotal Tracker: Client side architecture

So what makes Tracker work? I will be doing a series of technical blog posts to explain that, starting with a deep dive into the client side architecture. In future blog posts I will highlight Tracker’s server side architecture and hosting environment, the external services Tracker uses and what major architecture changes we’re considering.

Basic principles

The client side architecture is the heart and soul of Tracker and is largely based on two user design principles. First, users should not have to “reload” the page or perform any action to see changes made by other users. Second, users should see the affects of their changes immediately without having to wait for the server to respond.

Tracker accomplishes these design principles by using a propriety based JavaScript MVC architecture built on top of a command queue. A change made by a user results in a command being enqueued and executed on the client and then sent to server. Commands update domain models which in turn notify their dependent views, which create, update and remove the html elements you see on the page.

Client Side Architecture Diaram

Keeping the client up to date

The client is kept up to date by periodically polling for changes. Changes are returned in the form of commands which are executed on the polling client the same way they were executed on the originating client which in turn update domain models that notify the views, which create, update and remove the html elements you see on the page. This client polling approach results in about 2k server requests per second at peak, with the majority of the traffic being handled by memcached processes sitting behind our nginx servers. Other than a few glitches here and there, this polling approach has worked well for us, but with ever-increasing traffic, we are getting closer and closer to its limits and we are considering moving to WebSocket/Socket.IO based push approach. I will dive into a deeper discussion of what we’re considering in future blog posts.

Merging changes

It’s important to merge changes from other people on the client without losing what a given user is in the middle of working on. This can be tricky, but here is how it works in Tracker. First, changes from other people are merged in as soon as a client receives them, paying careful attention not override the user’s local changes. Tracker keeps track of all of the user’s local changes so it can determine which of the incoming changes can be safely merged in. Second, Tracker ensures that all commands are executed in order. If the client was up to date before the change was made, the user’s changes are saved to the database, a command representing the change is inserted into the database and a successful response is returned. If the client wasn’t up to date, the user’s changes are not saved and and a list of “stale” commands are returned to the client. The client’s command queue then rolls back the command initiated on the client, executes the stale commands from the server, re-executes the original command and sends it back to the server. Rolling back a command entails undoing any domain changes that the command execution made.

Rich domain

Another important part of Tracker’s client architecture is its rich client-side domain. The rich JavaScript domain allows the client to quickly show how a change affects everything on the page. For example, moving a story into the current iteration may push stories below it into the backlog. Iterations on the client are dynamically recalculated on the client whenever any significant domain changes are made. This rich domain on the client also allows us to provide “what if” velocity change functionality, real time validation feedback, team strength and iteration length changes and more.

JavaScript libraries

As many of you have noticed, Tracker is currently using Prototype, YUI and jQuery libraries for various utilities and event handling, but we are in the process of moving completely to jQuery. We are also looking into the feasibility of replacing our proprietary MVC architecture with Backbone.js as well as looking closely at Socket.IO and node.JS. It’s possible that the next generation of Tracker will be built using combination of Backbone.js, Socket.IO and node.JS.

The power of TDD

As you can see, Tracker’s client side architecture is fairly complex. What keeps the code manageable and allows us to keep rolling new features out, is that we test-drive all of our JavaScript code, the same way we write our Ruby on Rails code. We currently have over 1600 JsUnit tests and several dozen selenium tests just for the “stories” page.

Stay tuned for more blog posts on the technical details behind Pivotal Tracker.

P.S. If you’d like to help us take this architecture to the next level, we’re hiring!

Comments
  1. Hugo Barauna says:

    Awesome post! I always was curious about Tracker’s internals, mainly the client-side part and how it’s integrated to the server side. Tks for the post, very intwresting!

  2. Sam Duvall says:

    Thanks for the post. I have a couple of questions.

    – What are you sending between the client and server for updates? JSON (my guess), JS that gets executed?

    – Which side generates the HTML skeleton, client or server? Does the server create a template that gets copied or does the client dynamically generate all the HTML itself (e.g. a new story comes in)?

  3. aur1mas says:

    Great article! looking forward to read more ;)

    I also a question: why have you decided to completely move to jQuery? Have you researched for any alternatives like mootools.js or completely moving to prototype?

  4. BTDT. Using COMET, http://github.com/cjheath/jquery.comet and an async_sinatra server (like the chat_server/bayeux.rb example there), you can get much lower latency in receiving messages from the server; basically zero. This server handles the back-end of a multi-user diagramming application written in Raphael, which is all built on the command pattern. For example, when someone moves a shape, the shape’s UUID is sent with the before and after position. If the server determines that in *its* timeline, the command occurred after that shape had been moved or deleted by another user, it sends a reversal of the rejected command (the command pattern requires that every action is reversable), then sends catch-up messages so this client has the latest from the server’s timeline. Pretty simple really, and works well. Because async_sinatra is built using Thin which uses EventMachine, there’s a minimum of context required for each long-polling client – no thread, just an open socket and the HTTP request&response objects (even those could be optimised if necessary). So it’s still pretty scalable. If it ever becomes a problem, I can horizontally partition diagrams to different servers. For my purpose, this is much more suitable than to make the jump to Node, since I have a large body of back-end code in Ruby which is involved.

  5. Mark Michael says:

    Hi Sam. Tracker only sends data back and forth. The client sends data to the server via CGI parameters and JSON is returned. All the HTML within the “panels” including the story HTML is dynamically generated on the client. Each of the view widgets know how to create their portion of the HTML on the page. For example, there is a “story preview” widget that’s responsible for generating the story preview line you see below.

    ![story preview](http://assets.pivotallabs.com/993/original/story_preview_line_2.png)

    Most of Tracker’s view widgets still create HTML elements by hand (document.createElement, element.appendChild, etc), but we are moving to a JavaScript template approach based on [John Resig’s Micro-Templating implementation](http://adiefatlady.posterous.com/john-resig-javascript-micro-templating-0) . We felt [jQuery Templates](http://api.jquery.com/category/plugins/templates) were a little to slow to use on the stories page.

  6. Mark Michael says:

    Hi aur1mas. We did consider going completely with prototype especially since we were already using it. We looked briefly a mootools.js, but didn’t think it gave us as much as jQuery or prototype, in the end we felt there was a larger community, more enthusiasm and plugin support behind jQuery than any of the other JavaScript frameworks. So far jQuery has turned out to be a good choice for us, we were able to use jQuery plugins to speed up the implementation of a number of Tracker’s recent features like resizing text areas and drag/drop file uploads.

  7. Muneeb says:

    Amazing stuff Mark.

    How do you maintain the views and models at the client side? And especially how do your link it up with the HTML elements?

    Do you use any libraries like Backbonejs or Knockoutjs ?

  8. Vincent says:

    Hi,

    Do you have any updates up what’s powering Pivotal Tracker in 2014?

    Thanks,

    V.

  9. Olli says:

    Hi,

    i’m also interested in the process of change of the pivotaltracker’s backend. Have you switched from Rails to the combination of node.js and socket.io?

Post a Comment

Your Information (Name required. Email address will not be displayed with comment.)

* Copy This Password *

* Type Or Paste Password Here *