Shipping with Rails

Disclaimer: Each projects has its own pain points. Not all my projects have been automated to the same level (so you don't have to expose my flaws Joshua/Henrik).

Last year I visited Joshua in Victoria, BC. We talked about @WiiMe's success and progress on other projects. He proceeded to yell at me for wasting time. His point was clear: If you haven't shipped it you haven't done anything (paraphrasing and de-profanitized).

Timothy's post Cycle Eaters argues that you shouldn't ship your website - it should ship itself. All the tasks involved with shipping wasting your time and should be automated.

Back in the dark days of SVN, I got into a situation where Henrik and my code had diverged by over 100 commits. Deploy his changes required a multi-day process of painful conflict resolution because SVN sucks at merging/conflict resolution. Had we used git/(your favorite DVCS), Henrik would have multiple branches with changesets that did one thing each (fixed a bug or added a feature). I could have deployed individual branches as they were ready even though some commits/branches weren't ready.

bringing userscripts.org up to date

Using the wrong tools/processes can ruin your ability to ship. Here are ways I minimize wasted cycles building Rails based websites.

Do use Capistrano

This should be your first step. Every task required for a deploy should be done for you in this script. Capify-ing a generic application takes a few minutes, then start adding custom snippets for your unique requirements. Restarting workers, configuring sphinx, combining css/js into all.css/all.js, symlinking media, clearing cache, ...

Deployment should not require logging on to a server.

Do have automated tests

Manual testing sucks. You or another team member will forget to check something. A subtle change will break other things in unexpected ways.

While there are arguments if you should have 100% test coverage, most can agree that automated tests are a good idea. If you are new to testing, don't try to boil the ocean by spending days writing tests. Your first impulse when writing tests will be to over-engineer, leading to yet more complexity. Your tests should be be straight-forward and test one aspect of your code. You will need to learn to write maintainable tests, just as need to write maintainable code.

The next time you are fixing a bug is when you should write your first time. You should write a simple and targeted test that fails because of this bug. Then when you fix the bug, you will know that this failure will not happen again if the tests are run after every commit.

Do have metrics/analytics

As a developer we tend to think about bugs in terms of exceptions (code that blows up for semantic or syntactic reasons). Perfect code on a site that users don't understand is a problem. Defining important site usage metrics will let you know what you should be monitoring. Automatic collection and alerting you when deviations occur let you know when something bad (or good) has happened.

First you should have a dashboard which lets you see what is happening now, in the last 24 hours, last week, ... User sign ups, uploads, downloads, metrics that help you know if people are using your site.

If you are hacking you might not notice a sudden dip in the dashboards. That is where pingdom is useful. By implementing the equivalent of IsItChristmas.com and having pingdom check every minute, you get notified if suddenly: there are more than 10 exceptions in a minute, if no users have signed up recently, if no-one has viewed a user profile recently, ...

Do have automatic backups

Not only for disaster recovery, database snapshots are useful for development. Having an automated mechanism for loading a database snapshot (or if not possible a generated subset of it) allows you interact with a real version of the site. I upload my database snapshots to S3 every 12 hours, and have a rake command to download and load them (thanks Henrik!).

Do tunnel/stage work in progress

Making it easy for others to look at changes without having to come to your computer is required.

This can be accomplished by tunneling requests to an intranet/internet accessible server (jesse.domain.tld) to your development environment (via ssh). Simple port-forwarding adds lags, but it allows people to experience instead of seeing some images/text (which are usually misinterpreted)

When port-forwarding to your laptop isn't enough (lag or data isn't enough), having a staging environment on your services which is easy to deploy to

Staging involves a few more steps, so you should automated it to a single rake task which: push the current branch to a remote staging branch, creates a new database based on the recent snapshot, then a normal deploy with migrations of the staging branch. All this is done can be done via rake stage.

Do have a deploy branch

Don't put anything in the deploy branch that cannot be deployed. If business (partner requirements) or technical (complicated systems changes) reasons require a delay, then adding those changes to the deploy branch will only further complicate issues if you need to deploy another change while waiting. Also developers will periodically want to grab the current deployed changes and add them to branches that aren't ready yet. Having to worry if the deploy branch is merge-able is a pain.

If you aren't using branches, you should switch to a revision control system that allows them. (I recommend git, but use what works for you)

Do not wait to deploy

Combining automated tests and metrics gives you confidence that if something goes wrong you will be alerted.

Any time you merge change into the deploy branch it should be deployed. If the developer knows that pushed a change will be on the site in a few minutes

pushr allows automated deployment via triggered via a post-recieve web-hook on github. After github receives your changes, it sends a message to your instance of pushr to attempt a deploy. Pushr then does a capistrano deploy with migrations. Your capistrano script will run the automated tests and deploy only if tests pass. Pushr will then notify you via jabber/irc/twitter, but you will be off working on another task.

Your turn

How do you automate shipping?


Share/Save/Bookmark

Published

Thu, 12 Feb 2009

View Comments


Want more like this?

Subscribe via RSS
or by email:

New Relic