Building the new MailChimp.com

Out with the old

In preparing for MailChimp’s recent redesign, we wanted to change the way we manage the site and its content. MailChimp is growing fast, and that was becoming all too obvious behind the scenes of our website. Our creative department moves quickly, and the tools that were supposed to help us were actually slowing us down. We wanted a system that would be modular, scalable and—most importantly—fast. Here’s how we did it.

Meet Frank

We needed an extensible platform that let us rapidly build and deploy new pages. Using Frank, an open-source static site generator, we put together our own system optimized for developer happiness and a clean workflow. Frank allows us to develop locally using our favorite templating tools, and then serve static HTML in production. We can extend Frank by writing our own DRY helper methods in Ruby, which we then call in our templates. For instance, we declare unique meta information, written in YAML, in each page of the site. We then dynamically generate HTML meta tags using one of our helper methods, cutting out repetitive tasks. All of our content is kept in version control, and performance is swift—no queries run on each page request, because as we all know, static HTML is web scale.

Legos, OOCSS and Sass

Rebuilding the site from scratch gave us the opportunity to address our existing code bloat. Aaron Robbs worked diligently to ensure that design elements were uniform across the site. This allowed us to write lean, scalable and reusable modules, and minimize code bloat. We built on Nicole Sullivan’s OOCSS framework to arrive at a solid CSS foundation for effortlessly coding new pages. Each new page is built using predefined modules, like legos, which are stacked to create new layouts. Sass provides everything we wish CSS had: variables, nested declarations, selector inheritance and user-defined mixins.

HAML for markup

HAML’s template inheritance reduces boilerplate work, letting us add new pages without duplicating layout code. Its lean syntax keeps our code consistent and organized. Most importantly, HAML lets us call our own Ruby helper methods inline. We use these to turn YAML data into HTML, to dynamically assign state to navigation items, and to render commonly-used snippets of code.

JavaScript modules with require.js

To organize the JavaScript we use RequireJS, a modular script loader. We implemented a page-specific JavaScript module, which maps each page’s unique HTML id attribute to a function call. Between RequireJS and page-specific function calls, the JavaScript stays neatly organized, and we know where to find code when it needs revision. Finally, all JavaScript is minified with the Google Closure compiler before deployment.

Deployment

Deployment is handled with our own script, which exports the site to static files, then minifies the CSS and JavaScript using the Closure Compiler, and sends the site to staging. From there we ensure everything is as it should be, then push to production.

The new system lets us quickly and easily add and modify content. We no longer edit code in a textarea in the browser, but instead in our favorite editors. By extending Frank, we’ve created a site-management tool we’re happy with.

That’s a lot of separate systems (plus the app) that all share the same basic design. It would be interesting to hear how you manage sharing assets among them and preventing a website update from wrecking havoc in the app, or blog, or knowledge base, or api docs, or, well, nevermind — you get it.