photo

Yours truly, writing a guest post on Datadog’s blog about the Couchbase integration we created awhile back:

… Datadog has become our exclusive performance monitoring and graphing tool because it strikes the right balance between ease of use, flexibility, and extensibility and provides our team with tremendous leverage.
We love the fact that the Datadog team decided to make their agent an open-source project. This makes it super simple to create your own custom checks and contribute them back to the community. We did just that six months ago when we wrote a new custom check for Couchbase.

Check it out

 photo

Responsive design

We are proud to announce the launch of the new Seattle Sounders FC site! This is the first site built by the MLS Digital team on our next generation content publishing platform. It was redesigned from the ground up to deliver a consistent, seamless experience across desktop, tablet and mobile devices.

Responsive Design

Over the last several years, we have seen a major shift in our traffic towards smaller screens (over 50%) and we foresee this trend growing. We intended to build a responsive site, but we took things one step further by prioritizing the mobile experience. All designs and CMS elements of the site were produced in mobile versions first, with the larger screen experience being created later. We opted to build our own custom Drupal theme using the excellent singularitygs grid system.

Content Screenshots

Content First

We understand the importance of content. Our new layouts for content display takes advantage of the larger screen space (when available) and adapts the experience for all screens. We removed the clutter and focused on content. The system uses a single content type to integrate video, news, blogs, and other content to simplify editing and placement. We use ‘posts’ to describe ‘news’, ‘articles’, and ‘videos’ then allow the editors to select a layout via a simple drop-down menu. We expect to add new, richer layout options for content in the near future.

Mobile Screenshots

Cloud Architecture

The new platform is hosted entirely on Amazon Web Services cloud infrastructure across multiple, active regions. Our architecture utilizes S3, VPCs, autoscaling, RDS, Elasticache and more and is automatically provisioned using Salt Stack. To learn more about the platform architecture read: Multiple Region Autoscaling Drupal in Amazon Web Services.

We are very excited for the future of the MLS CMS platform. Please share your feedback on the new site design and structure via the red feedback icon on the bottom of every page.

Hans Gutknecht - @hansyg
Justin Slattery - @jdslatts
Louis Jimenez - @LouisAJimenez
Chris Bettin - @chrisbettin
Amer Shalan - @pterodactylitis

 photo

Part 2 - Specifications

Welcome to the second installment of our three part series about the MLS API. Check out the last post if you missed it.

Until recently, the MLS API required verbose, repetitive code to define, sanitize, and validate new routes. As routes were added over time, we ended up with a variety of methods to validate route parameters and then transform them to the types required by the data lookup methods. The process was repetitive and prone to inconsistencies and copy paste errors, such as pagination parameters being cast to numbers in all but two routes.

To solve this problem, we created the respectify module. Respectify acts as a restify middleware and it allows us to define route parameters and corresponding validation requirements along side the the top level route declaration.

Here is how we would add it to our restify server:

var restify = require('restify')
  , Respectify = require('respectify')
  , server = restify.createServer()
  , respect = new Respectify(server)

// Add the middleware for sanitization / validation
server.use(respect.middleware)

Specifications

Building a spec can be apprached in many ways. The approach we took respectify was to define the spec directly in code as part of the route definition. We prefer writing code over the external JSON or XML configuration file approach. We felt that a code first approach allowed us to continue developing the API as we normally would, adding in extra information, as opposed to learning an entirely new system of route creation.

The result is a params object on the route that explains exactly what method parameters can be sent, and what valid values are. An example route might look something like this:

server.get({
  path: '/users'
, version: '1.0.0'
, description: 'user lookup route'
, params: {
    username: {
      dataTypes: 'string'
    , desc: 'username lookup'
    }
  , page: {
      dataTypes: 'number'
    , desc: 'current page'
    , default: 1
    }
  , pagesize: {
      dataTypes: 'number'
    , desc: 'page size'
    , default: 50
    , min: 1
    , max: 100
    }
  }
}, function(req, res, next) {
  // req.params will only contain properties as defined in the `params` object above
  res.send(200, ...)
})

In the example above, we defined three parameters, each with a data type, a description, default values, and, for number values, a max and min. Respectify allows us to add the parameter specification along side the route, giving us to use a single, predictable place (the route definition file) to modify parameters and validation for all routes.

Respectify can also be used to extract information about the route configuration at runtime. This data can be useful in many ways. We use it to drive automated documentation generation, a topic that will be covered in detail in the following post.

Here is a look at what respectify can give us back for route information:

[{
  "route": "/users",
  "parameters": [
    {
      "name": "username",
      "required": false,
      "paramType": "querystring",
      "dataTypes": [
        "string"
      ],
      "description": "username lookup"
    },
    {
      "name": "page",
      "required": false,
      "paramType": "querystring",
      "dataTypes": [
        "number"
      ],
      "default": 1,
      "description": "current page"
    },
    {
      "name": "pagesize",
      "required": false,
      "paramType": "querystring",
      "dataTypes": [
        "number"
      ],
      "min": 1,
      "max": 100,
      "default": 50,
      "description": "page size"
    }
  ],
  "method": "GET",
  "versions": [
    "1.0.0"
  ]
}]

This is really just the route object transformed into JSON, making it easy to access programmatically, or even to send directly to API clients.

Another interesting thing we can do is put the OPTIONS method to good use, sending back the route specification for any defined route.

Here is what that might look like as restify middleware:

server.opts({path: /.+/, version: '1.0.0'}, function(req, res, next) {
  var _method = req.method
    , router = server.router
    , methods = ['GET', 'POST', 'PUT', 'HEAD', 'DELETE']

  // Intended to represent the entire server
  if (req.url.replace('/', '') === '*') {
    return this.returnRoutes(req, res, next)
  }

  // Iterate through all HTTP methods to find possible routes
  async.mapSeries(methods, function(method, cb) {

    // Change the request method so restify can find the correct route
    req.method = method

    // Find the restify route object
    router.find(req, res, function(err, route, params) {
      if (err && err.statusCode !== 405) return cb(err)
      if (!route) return cb(null)
      return cb(null, respect.getSpecByRoute(route))
    })
  }, function(err, resp) {
    // Revert to the original method
    req.method = _method

    // Make sure a valid route was requested
    if (err || !resp || !resp.length) {
      return next(new restify.ResourceNotFoundError())
    }

    // Filter out all undefined routes
    var routes = resp.filter(function(x) { return !!x })

    if (routes.length) {
      return res.send(200, routes)
    }

    // No routes were found
    res.send(404)
  })
})

Now, for any route that exists on the server, a client may send an OPTIONS request to get the exact specification for that route.

There are many other use cases for respctify, but the largest benefit for us has been reducing boilerplate code our codebase and providing a clear path forward for future development.

In the next post, we will wrap up with one of life’s greatest joys: documentation. We will show you how respectify can save you time while improving the accuracy of your docs.

 photo

Today, we launched a completely redesigned and rearchitected mobile MatchCenter experience. Check out the MLS Cup MatchCenter, or any other 2013 match, on your mobile device to check it out. I had the great pleasure of leading design and implementation of the mobile website from scratch. I have been a developer for most of my career, but having obtained knowledge in the ways of User Experience and design for the last 5 years, I gave it a go. This was my first design project outside of personal projects, so please be gentle. Now then, I’d like to tell you a little about the design process, but first…

TL;DR Screenshots! Mobile Design Screenshots

Mobile First Design

Several months ago, we decided as a team that the mobile experience for our MatchCenter was not all that it could be. Mobile users are a major percentage of our website visitors, and we weren’t delivering the best to them. It was the byproduct of a desktop design that had been progressively hacked to work on mobile with responsive stylesheets. There was a laundry list of things that we didn’t like, and we concluded it was best to start over. That isn’t a decision we make lightly.

Starting over on the mobile experience allowed us to utilize what is called mobile first design. Essentially you start by designing the mobile website to your liking. If and when you decided to make your website responsive, you add onto the mobile design. This is in stark contrast to how most mobile websites are born, which is usually a tweaked subset of the desktop website. While it sometimes works, it usually doesn’t end up the way you would like.

Increasing the data pixels

Delivering a great experience on mobile is all about content. I’m a big fan of data visualization pioneer Edward Tufte, so I utilized one of his tenets to guide my design:

Decrease the non-data pixels

Essentially it boils down to getting rid of all the excess stuff. The chrome, the drop-shadows, the fancy annoying animations. The data is the content, and it should take the forefront and most of your pixels. Legends, labels, and axis may be necessary, but they shouldn’t distract from the important pieces.

You will also notice that several of the visualizations have morphed from the desktop version. I focused on immediate digestibility for all of the data. If you couldn’t figure out what was going in 5 seconds, then the visualization has failed. This meant things like the passing matrix had to go. The same data will definitely make its way back into the MatchCenter, but in a completely different outfit.

Code-sharing

Our MatchCenter runs on a Node.js based technology stack, which utilizes JavaScript as the language. This has many upsides, but one potential benefit is sharing code between the browser and the server. While this sounds great in principle, it is often hard in practice. The new mobile design actually accomplishes this goal. We use a new framework from Facebook called React to make that happen. Having a single place for all the rendering will reduce the bugs that make it into production, and eliminate differences between what the server renders and what you see in real-time while a match is happening. It also happens to be incredibly performant because of the virtual DOM it uses.

What’s next

This by no means the final form of the MatchCenter. We will continue to fix bugs, design new visualizations, and eventually take what we learned to the desktop version. Optimizing the real-time data is particularly important because that has a direct impact on performance and battery life of your mobile device. If you have thoughts on the new MatchCenter, please let us know on our feedback site.