PatientsLikeMe Tech Blog

We’re a team of Ruby on Rails developers and UX practitioners at PatientsLikeMe, where patients share data about their treatments, symptoms, and disease outcomes.

Dealing with Git Merge Revisions

Zen and the Art of Git Chainsaw Maintenance

Git is pretty awesome and mind expanding, but I don’t think that anything is quite a mind-blowing as the first time you learn how to revert a merge. There’s a great explanation here: http://stackoverflow.com/questions/1078146/re-doing-a-reverted-merge-in-git

Basically, if you’ve merged a feature in by mistake, you can simply revert the merge to get back to a happy state. The mind bending comes when you decide that the feature is ready to be merged for real. While intuition might tell you to just git merge feature again, what you really want to do is “revert the revert”.

It makes sense, and it’s awesome, and it’s righteously scary in that wonderful way that only git can be.

At PatientsLikeMe we were familiar with this, but we hadn’t had a chance to do it in practice until last week. A branch was merged in prematurely and we successfully reverted.

The new wrinkle that I faced today was that the branch that was merged in and since reverted, is actually a long running branch and development continues on it. I wanted to merge master into this long running branch to stay up to date, but when I did that, I noticed pretty quickly that something was awry. 27 conflicts and a bucket of fail. Worse, my mergetool was consistently picking the wrong side of the merge.

Let’s go to the simulated instant replay, sponsored by GitX.

merge1
This is the state of the repo after we’re reverted our accidental merge.
merge2
Here is the repo with more work on both the feature and the master branch.

So, I’d like to merge master into the feature branch, but that leads to a sorts of erroneous conflicts. Why? Well, because git merge master asks git to merge the revert commit into my feature branch, that’s why. The revert commit essentially contains diffs that say to remove all the early work on feature branch. It makes sense to apply this to master, but it is a terrible commit to apply to the feature branch. It’s a bit like time travelling and accidentally killing your parents.

So what do we do? We know that we need to ‘revert the revert’ at some point. It turns out that there’s no reason not to do that immediately; we just need a new ‘shim’ branch. We’ll call it master_w_revert_reverted.

git checkout master
git checkout -b master_w_revert_reverted
git revert SHA_OF_THE_MERGE_REVERSION
git commit

git co feature
git merge master_w_revert_reverted

Voila! we’ve successfully merged our master branch into the long running feature and we’ve taken care of the ‘revert the revert’ going forward.

merge3

The next time we want to merge from master to the long running feature branch, or indeed from when we’re ready to merge the feature into master, we just merge as we would normally. Our days of reversion are over.

merge4

Until next time, happy merging!

Deconstructing My Favorite Sass Mixin

I originally set out to write a post about my favorite Sass mixins, but I realized I covered many of them in a previous post here. Instead I’m just going to review three of the CSS3-based mixins I frequently use and then go into deeper explanation of a mixin I just did for one of our analytics products.

First, if you’re not familiar with Sass or the complete awesomeness of Sass mixins, I recommend you start with the Introduction to Compass screencast. Wait, what’s Compass now? Compass is essentially pre-packaged Sass. Just check out the screencast. If you’ve been writing your own CSS by hand, you’ll be blown away. I promise.

Rounded Corners

So, let’s review those three mixins. Rounded corners are all the rage and Webkit and Mozilla are happy to make our lives easier by supporting border-radius. Internet Explorer is another story, but hey… there’s always Version 9! Here’s the mixin I use for rounding corners:
=border_radius(!radius)
  -moz-border-radius = "#{!radius}"
  -webkit-border-radius = "#{!radius}"
  border-radius = "#{!radius}"
Then, if you want to round a box, you just add:
.box
  +border_radius(5px)

That will generate:

.box {
  -moz-border-radius: 5px;
  -webkit-border-radius: 5px;
  border-radius: 5px;
}

How about variable corners? Easy as this:

.box
  +border_radius(5px 10px 2px 25px)

Not only does the latest versions of Safari and Chrome support the border-radius shorthand—they even support plain old border-radius (without the browser extension!). We’ll keep the -webkit-border-radius in there for older versions, though.

Drop Shadows

Who doesn’t love a drop shadow? Well, a nice subtle one anyway. Every default setting on a drop shadow I’ve ever seen made me cringe. It’s the type of drop shadow you see on a yard sale sign. But a subtle, soft shadow? Very nice. Here’s how we do it:

=box_shadow(!color, !values)
  -webkit-box-shadow = "#{!color} #{!values}"
  -moz-box-shadow = "#{!color} #{!values}"
  box-shadow = "#{!color} #{!values}"

Applying that to a .box will give you:

.box {
  -webkit-box-shadow: #CCC 1px 1px 4px;
  -moz-box-shadow: #CCC 1px 1px 4px;
  box-shadow: #CCC 1px 1px 4px;
}

What I love about these is not having to add all the vendor extensions every time I want to round a corner or drop a shadow. One and done.

Gradients, Heck yeah

What I love about this next one is how many images I can get rid of by replacing them with CSS gradients. Not only that, but through some IE-specific vendor extensions, you can actually get it to work in IE! Gradients are often a far more important design element than some corner rounding and shadowing, so that’s a big win right there. Here’s the guts:

=box_gradient(!top,!bottom)
  background-image = "-moz-linear-gradient(top, #{!top}, #{!bottom})"
  background-image = "-webkit-gradient(linear,left top,left bottom,color-stop(0, #{!top}),color-stop(1, #{!bottom}))"
  -ms-filter = "\"progid:DXImageTransform.Microsoft.gradient(startColorStr=’#{!top}’, EndColorStr=’#{!bottom}’)\""
  *filter = "progid:DXImageTransform.Microsoft.gradient(startColorStr=’#{!top}’, EndColorStr=’#{!bottom}’)"

That will render as:

.box {
  background-image: -moz-linear-gradient(top, white, #fcf5de);
  background-image: -webkit-gradient(linear,left top,left bottom,color-stop(0, white),color-stop(1, #fcf5de));
  -ms-filter: "progid:DXImageTransform.Microsoft.gradient(startColorStr=’white’, EndColorStr=’#fcf5de’)";
  *filter: progid:DXImageTransform.Microsoft.gradient(startColorStr=’white’, EndColorStr=’#fcf5de’);
}

The -ms-filter covers IE8 and newer while just plain ol’ filter has IE6 and IE7 covered. I saw some problems with them conflicting with each other in IE8, so I just added the * to filter so that IE8 and newer (and all other browsers) would ignore it. It looks a bit messy at first, but it’s a damn nice system that’s been working well for me.

I love those three mixins. I use them all the time. I bring them over to any new project I start (which seems to be a lot lately). I used them a lot while designing and building PatientsLikeMeInsights™, but Insights called for something a bit more… well, awesome.

Super Ultra Wicked Mega Dropdown

It all started with one dropdown. But as features were added to Insights, I added more dropdowns. Here’s what they look like:

Modify Categories Dropdown

Oh, but there’s more! We also had a bunch of plain ol’ form select boxes to choose which data you wanted displayed. But, our requirements made them difficult to keep using. Well, mostly it was IE’s shortcomings that made us need to seek alternate solutions. So, I refactored the dropdowns to work as select boxes, too. Like so:

Select Box Dropdown

When I first built these select boxes, I simply applied the regular dropdown styles, then overrode them with an additional set of styles. But I recently turned both into a mixin. You can pass a true/false argument into the mixin that dictates whether or not the dropdown is a select box. The resulting mixin is relatively epic, and here it is:

=lickable_dropdown(!select_box=false)
  +inline_blocks
  position: relative
  z-index: 3
  h3.toggle
    +inline_blocks
    +border_radius(3px)
    background-color: #FCF5DE
    color: #06c
    cursor: pointer
    border: 1px solid #E4C37C
    font-weight: bold
    *margin-right: 2px
    @if !select_box == false
      padding: 4px 10px
    @else
      width: 188px
      padding: 2px 6px
    span
      +inline_blocks
      margin-left: 2px
      width: 8px
      height: 6px
      background: url(/images/dropdown-arrows.png) no-repeat 0 0
      vertical-align: middle
      *margin-top: 4px
      * html &
        margin-top: 0
        background: url(/images/dropdown-arrows.gif) no-repeat 0 6px

  a.toggle
    color: #06c
    cursor: pointer

  .dropdown-container
    position: absolute
    top: 100%
    left: 0
    z-index: 0
    padding: 0
    margin-right: 0
    @if !select_box == false
      margin-top: -1px
    @else
      margin-top: 0
      width: 202px

    .dropdown-inner
      position: relative
      background-color: #FCF5DE
      border: 1px solid #E4C37C
      @if !select_box == false
        +border_radius(0 3px 3px 3px)
        +box_shadow(#CCC, 1px 1px 4px)
        +box_gradient(#FFFFFF,#FCF5DE)
        padding: 10px
      @else
        +border_radius(0 0 3px 3px)
        padding: 6px
        border-width: 0 1px 1px 1px
        margin-top: -1px

  &.active
    z-index: 5
    h3.toggle
      background-color: #FFF
      +border_radius(3px 3px 0 0)
      border-bottom: 0
      z-index: 2
      position: relative
      *padding-bottom: 5px
      span
        background-position: 0 -61px
        * html &
          background-position: 0 -56px

The markup for one of these puppies resembles this:

<div class="dropdown" id="modify">
  <h3 class="toggle">
    Modify Categories
    <span>&nbsp;</span>
  </h3>
  <div class="dropdown-container">
    <div class="dropdown-inner">
      … content goes here …
      <input class="update-table" type="submit" value="Update">
      <a class="toggle">Cancel</a>
    </div>
  </div>
</div>

So, let’s run through this really quickly, since I apparently love to use code samples:

=lickable_dropdown(!select_box=false)
  +inline_blocks
  position: relative
  z-index: 3

Just apply +lickable_dropdown(true) or +lickable_dropdown(false) to that container div (div#modify). These three lines will inline-block it, relatively position it (so the popup contents can be positioned relative to the container), and give it a z-index (this page is a z-index free-for-all!). What’s +inline_blocks? It’s a sweet mixin (that I didn’t write) that makes inline-block work in IE6.

  h3.toggle
    +inline_blocks
    +border_radius(3px)
    background-color: #FCF5DE
    color: #06c
    cursor: pointer
    border: 1px solid #E4C37C
    font-weight: bold
    *margin-right: 2px
    @if !select_box == false
      padding: 4px 10px
    @else
      width: 188px
      padding: 2px 6px
    span
      +inline_blocks
      margin-left: 2px
      width: 8px
      height: 6px
      background: url(/images/dropdown-arrows.png) no-repeat 0 0
      vertical-align: middle
      *margin-top: 4px
      * html &
        margin-top: 0
        background: url(/images/dropdown-arrows.gif) no-repeat 0 6px

All this for the toggle that triggers the popup! I have it as an h3, since it’s essentially a header for the dropdown contents. It can really be whatever you want. We have stuff you’d expect like borders, colors, cursors (to make it look like a typical link), and font weights. We’ve also got some inline_blocks and border_radius mixins going.

But here, we see our first if/then statement. If the dropdown isn’t a select_box, just give it some padding. If it is, give it different padding and also hard-code a width.

The stuff applied to the span is just to get that little arrow next to the h3 text.

  a.toggle
    color: #06c
    cursor: pointer

This is pretty simple. Just the “Cancel” or “Close” link at the bottom of the boxes. The “toggle” class (like with the h3) triggers the Javascript to show-hide the next div we’re going to cover.

  .dropdown-container
    position: absolute
    top: 100%
    left: 0
    z-index: 0
    @if !select_box == false
      margin-top: -1px
    @else
      width: 202px

This div is the one that we show and hide when we click the .toggle. It is absolutely positioned all the way to the left and at 100% from the top. Basically, this means the top of this div will be aligned with the bottom of the container div. We’ve also got another if/then. In this case, if it’s a select_box, it gets another hard-coded width. If not, we’re giving it a -1px top margin. Why? The select_box‘s toggle and content are the same width. The standard popup’s toggle is more tab-like on the top. This way, we can give it that tab effect by overlapping the tab over the content by one pixel.

This might be best illustrated with a song illustration:

Toggle Overlap

And finally:

    .dropdown-inner
      position: relative
      background-color: #FCF5DE
      border: 1px solid #E4C37C
      @if !select_box == false
        +border_radius(0 3px 3px 3px)
        +box_shadow(#CCC, 1px 1px 4px)
        +box_gradient(#FFFFFF,#FCF5DE)
        padding: 10px
      @else
        +border_radius(0 0 3px 3px)
        border-top-width: 0
        padding: 6px

This is where we see the three CSS3 mixins above. First, we’re going to relatively position this (so there can be some absolutely positioned content inside, if needed. Then we’ve got a border and background color. Now for some more if/then fun.

One last thing… when you activate a dropdown, the container element is given a class of .active. When a dropdown is active, the z-index is adjusted and the toggle gets some different styles:

  &.active
    z-index: 5
    h3.toggle
      +border_radius(3px 3px 0 0)
      border-bottom: 0
      z-index: 2
      position: relative
      @if !select_box == false
        *padding-bottom: 5px
        background-color: #FFF
      span
        background-position: 0 -61px
        * html &
          background-position: 0 -56px

First, on the toggle, I just rounded the top two corners, gave it a z-index that would cover the content by a pixel (to achieve the tab effect shown above), and axed the bottom border. Then, if it’s a standard dropdown, I changed the background color (to feed nicely into the gradient) and gave IE an extra pixel of padding. For the arrow span, I flipped the arrow upside down.

And there you have it. I hope this step-by-step example is useful for you in some way (be it to understand what Sass can do or to get an idea of how I build things with CSS). If you have suggested improvements, I’m all ears!

My Favorite Campfire Tips

We’re big fans of Campfire by 37signals here at PatientsLikeMe. Campfire is basically a group chat tool. We use it to stay connected, share files, and share ideas both when we’re all together in the office and when we telecommute a couple times a week.

We use Campfire so much that when I discover a new trick, it’s kind of a big deal. I though I’d share some of my favorites I’ve come across.

  1. Using Campfire with Fluid.app and Growl

    Let’s start with one I published right here. Since I always have Campfire open, it just made sense to run it in a site-specific browser (SSB) using Fluid.app.

  2. Drag and drop uploading

    You can easily share a file by browsing to it and clicking the upload button. Or you could just drag it to the chat screen.

  3. Formatted Tweets

    This one’s really slick. Basically, if you paste in the direct URL to a tweet, it will reformat it like this:

    Brogramming Twitter screenshot

    They’re still live, searchable text. They’re just prettier and save a click.

  4. YouTube clips in Campfire

    Similar to how Campfire reformats tweets, it will take a YouTube URL and show a preview image of the video. You do, however, need to play the video in a new tab/window as the image is an embedded video (although it looks like it).

  5. Type a person’s full name with just a few characters

    When I started at PatientsLikeMe, everyone was so formal in Campfire when addressing others. Posts would start with “Adam Darowski:” instead of just “Hey Adam”. Well, I finally figured out why. It’s this feature that will take something like “@Adam” and turn it into my full name.

  6. /play vuvuzela in Campfire

    Even those who didn’t follow the World Cup know what the vuvuzela is. If you want to play the ol’ plastic horn through Campfire, type:

    /play vuvuzela

    and laugh at your co-workers groans. This does have an excellent use though—if people are late for the daily standup, just play a vuvuzela and they’ll hear you from the next room.

  7. Campfire sounds: crickets, rimshot, and trombone

    I didn’t even know about this until after finding the vuvuzela feature, but it turns out you can also play crickets, rimshot, or—most importantly—the sad trombone. Seriously, no day of engineering is complete without a sad trombone.

That’s what I’ve got. Do you have any favorite Campfire tips?

Step-by-Step Blog Conversion to HTML5

Last week’s post, Migrating PatientsLikeMe to HTML5, documented the work Cris has been doing to bring the patientslikeme.com site into this brave new world of HTML5. The post has inspired me to, one by one, update all of our other sites as well. Most recently, Cris and I updated this blog—and we documented each step so you can easily update your own blogs and other sites. While this is a WordPress blog and some of the content here is WordPress-specific, much of it applies to all platforms.

So, let’s start HTML5in’!

Step 1: Change the DOCTYPE

This step is what actually makes your document an HTML5 document. HTML5 is so forgiving that you could just take an existing (valid) XHTML or HTML 4 page, change the DOCTYPE and it’d be a valid HTML5 page. HTML5 doesn’t care if you’re a stickler for self-closing tags, lower-case attributes, single or double quotes, whatever. It loves all.

So, to complete this easy-but-important step, change your DOCTYPE from something like:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

to

<!DOCTYPE HTML>

Pow. HTML5. Already. You’re like a paperclip.

Step 2: Make IE happy (not that it deserves it)

Out of the box, HTML5 tags such as <header>, <footer>, and <aside> (you know, the new ones) won’t be stylable in Internet Explorer 6, 7, or 8 because it won’t even render them. Luckily, adding the script below will make IE render these tags, which then lets us style them. As of the third developer preview for IE9, HTML5 is actually supported in IE.

<!–[if lt IE 9]>
  <script src="http://html5shiv.googlecode.com/svn/trunk/html5.js"></script>
<![endif]–>

This conditional comment targets all versions of IE before IE9.

Step 3: Clean up the <head>

Next, we made a bunch of changes to the <head> of the page. Luckily, we’re not adding anything. We’re just streamlining. Here’s what it looked like before conversion:

<html xmlns="http://www.w3.org/1999/xhtml">
<head profile="http://gmpg.org/xfn/11">
  <meta http-equiv="Content-Type" content="<?php bloginfo(‘html_type’); ?>; charset=<?php bloginfo(‘charset’); ?>" />
  <title><?php wp_title(‘|’,true,’right’); ?><?php bloginfo(‘name’); ?></title>
  <meta name="description" content="Members of the Product & Technology team at PatientsLikeMe blog about software engineering, user interface design, and user experience." />
  <meta name="keywords" content="software engineering, software development, ruby on rails, user experience, user interface design" />
  <meta name="author" content="PatientsLikeMe" />
  <link rel="shortcut icon" href="http://patientslikeme.com/favicon.ico" />
  <link rel="stylesheet" href="<?php bloginfo(‘stylesheet_url’); ?>" type="text/css" media="screen" />
  <link rel="alternate" type="application/rss+xml" title="<?php bloginfo(‘name’); ?> RSS Feed" href="<?php bloginfo(‘rss2_url’); ?>" />
  <link rel="pingback" href="<?php bloginfo(‘pingback_url’); ?>" />
</head>

We did a few things here:

The result is:

<html>
<head>
  <meta charset="UTF-8">
  <title><?php wp_title(‘|’,true,’right’); ?><?php bloginfo(‘name’); ?></title>
  <meta name="description" content="Members of the Product & Technology team at PatientsLikeMe blog about software engineering, user interface design, and user experience.">
  <meta name="keywords" content="software engineering, software development, ruby on rails, user experience, user interface design">
  <meta name="author" content="PatientsLikeMe">
  <link rel="icon" href="http://patientslikeme.com/favicon.ico">
  <link rel="stylesheet" href="<?php bloginfo(‘stylesheet_url’); ?>" media="screen">
  <link rel="alternate" type="application/rss+xml" title="<?php bloginfo(‘name’); ?> RSS Feed" href="<?php bloginfo(‘rss2_url’); ?>">
  <link rel="pingback" href="<?php bloginfo(‘pingback_url’); ?>">
</head>

Step 4: Utilizing the new HTML5 tags

Now we get to use some of the new semantic tags introduced, like <header> and <footer>. Let’s start with <header>. We simply changed this:

<div id="header">
…
</div>

to

<header>
…
</header>

And for the <footer>, we changed:

<div id="footer"> 
…
</div>

to

<footer> 
…
</footer>

The CSS updates were really easy. We basically had to change “#header” and “#footer” to simply “header” and “footer”.

There really isn’t any in-site navigation on this blog, so there’s no need for a <nav> tag. Also, the lack of a sidebar means no real reason for an <aside> tag (though we could use those within some posts).

Also, before I forget — when adding these new tags, you need to establish a display property for these new elements. Right now, browsers don’t really recognize them as block or inline, so it defaults to inline. We want them to be block-level elements. So, we added this to my stylesheet to get them all in one fell swoop:

header, footer, section, article, aside, nav, figure, figcaption { display: block; }

Next, we made use of the new <section> and <article> tags. We already had a <div id="posts"> as a container element for all posts. So, that’s a perfect candidate to become <section id="posts">. Likewise, within <div id="posts">, we have multiple <div class="post">s, each with a unique ID. These can become <article class="post">

So,

<div id="posts">
  <div id="post-143" class="post">

becomes

<section id="posts">
  <article id="post-143" class="post">

Styling, again, was easy to update because I had originally applied all styles to #posts and .post. Since the IDs and classes stayed the same, no CSS rework needed. Yay!

Each page also has a “no results” message in the event that you access a page and no posts are available (for whatever reason). I used to have these messages within a div.post, mostly for consistency. My div.posts are now all <article>s, so that doesn’t semantically make sense anymore. So, we instead used section#no-results for these.

Now the document structure is super clean. The home page looks like:

<html>
  <head>
  <body>
    <header>
    <section id="posts">
      <article>
      <article>
      <article>
    <footer>

I also turned the comments area on a single post into a <section>. The single post structure now looks like:

<html>
  <head>
  <body>
    <header>
    <section id="posts">
      <article>
      <section id="commentarea">
    <footer>

Oh so semantic!

Step 5: Add some new tags

We then shifted our attention to the new <time> tag. That can be used for timestamping content, such as <article>s.

Where I had

<li>Posted <?php the_time(‘F jS, Y’) ?> by <?php the_author_posts_link(); ?></li>

on each post, we changed it to

<li>Posted <time datetime="<?php the_time(‘Y-m-d’) ?>" pubdate><?php the_time(‘F jS, Y’) ?></time> by <?php the_author_posts_link(); ?></li>

Next, when we started this conversion, I didn’t even know about the <mark> tag. We decided to use it to highlight search terms in the Search Results page. We used the method described in this post.

Basically, we had to find this:

<h3><a href="<?php the_permalink() ?>" title="Permanent Link to <?php the_title(); ?>"><?php the_title(); ?></a></h3>

and replace the

<?php the_title(); ?>

with

<?php echo $title; ?>

and add this line before it:

<?php $title = get_the_title(); $keys= explode(" ",$s); $title = preg_replace(‘/(‘.implode(‘|’, $keys) .’)/iu’, ‘<mark class="search-excerpt">\0</mark>’, $title); ?>      

So, basically it all becomes this:

<?php $title = get_the_title(); $keys= explode(" ",$s); $title = preg_replace(‘/(‘.implode(‘|’, $keys) .’)/iu’, ‘<mark class="search-excerpt">\0</mark>’, $title); ?>      
<h3><a href="<?php the_permalink() ?>" title="Permanent Link to <?php the_title(); ?>"><?php echo $title; ?></a></h3>

Then give your <mark> tag a style, and you’ve got this:

mark tag in action

We haven’t figured out how to get the search term highlighted in post excerpts (admittedly, we also haven’t tried that hard). If you’ve got a tip, let me know!

Lastly, we added the <figure> and <figcaption> tags where appropriate. I was a bit unclear about when it was, indeed, appropriate. I mean, when is an image a figure? Are all images figures? Can anything else be a figure? Luckily, the W3C helps with this:

The element can thus be used to annotate illustrations, diagrams, photos, code listings, etc, that are referred to from the main content of the document, but that could, without affecting the flow of the document, be moved away from that primary content, e.g. to the side of the page, to dedicated pages, or to an appendix.
Emphasis is mine. Basically, if the image/code sample/etc. wouldn’t make sense on it’s own, outside of the blog post, don’t bother making it a figure.

Step 6: Search field

You can now explicitly state that a text field is a search field. My favorite part of that is the new placeholder attribute. This allows you to put text in the search field that will disappear once the user activates it. So far, only WebKit supports placeholder though. In fact, Firefox doesn’t display these search fields any differently yet. How it looks:

Search fields in WebKit vs. Firefox

Markup-wise, here’s the before:

<input type="text" value="<?php echo wp_specialchars($s, 1); ?>" name="s" id="s" />

and the after

<input type="search" placeholder="Search the Blog" value="<?php echo wp_specialchars($s, 1); ?>" name="s" id="s">

It’s not so bad!

If there’s one thing I realized when doing all this HTML5 conversion, it’s that it’s really not hard at all. So, go ahead and convert your blog. Let us know how it goes!

Migrating PatientsLikeMe to HTML5

After all the hype, the public spat between Steve Jobs and Adobe, and its rise to buzzword status, we here at PatientsLikeMe finally got around to looking closer at this thing called HTML5. Thanks to the excellent HTML5 For Web Designers by Jeremy Keith (a book that could only have been more perfect had it been inscribed with “Don’t Panic” on the cover in large, friendly lettering), we stopped worrying and learned to love this latest incarnation of our favorite markup language. As we near completion on our own HTML5 initiative, we just wanted to share some of what we learned along the way.

The year was 2005. A nascent PatientsLikeMe website sprouted from the efforts of a handful of participants. The doctype we chose: XHTML Transitional. Tags were well-formed, attributes were double-quoted, doctypes were too long to memorize, alt attributes were mandatory, and everything was lowercased. It was an orderly, if not altogether totalitarian rulebook for our markup needs.

HTML5, by contrast, is a libertarian wonderland. No more self-closing tags, no more repetitive boolean attributes, no more required quoting of attributes, and uppercasing of tags: allowed. As Jeremy Keith described it, the HTML5 spec was written to reflect what people are already doing out in the wild, instead of forcing them to change their ways.

But could this be a bad idea? Without the rigor of XHTML, could our little web shop potentially spiral into a state of markup anarchy that would make MS Office HTML look preferable? Fortunately, thanks to our existing use of Haml, the order I crave is already built into our app. To quote @doctorzaius:

“People who complain about Haml’s strict indentation are missing the point of Haml”

And this strict indentation makes for consistent, readable, and well-formed markup. Thanks to the abstraction that Haml provides, our switch to HTML5 from XHTML is handled with aplomb. All it took was changing the first few lines of our .haml layout from:

!!! 1.0
%html{:xmlns => ‘http://www.w3.org/1999/xhtml’, :lang => ‘en’}
  …
  %meta{‘http-equiv’ => ‘content-type’, :content => ‘text/html; charset=utf-8′}

to the more compact:

!!! 5
%html{:lang => ‘en’}
  …
  %meta{:charset => ‘UTF-8′}

And for the rest of the elements, because we have abstracted much of our markup into Ruby on Rails helpers, the change of the doctype automagically converts something like this:

<link type="text/css" href="/stylesheets/print.css?1281019285" media="print" rel="stylesheet" />

into this:

<link href="/stylesheets/print.css?1281019285" media="print" rel="stylesheet">

because we declared it with a helper, like this:

= stylesheet_link_tag ‘print’, :media => ‘print’
N.B. I haven’t yet found a Rails way to output boolean tag attributes the HTML5 way, yet, but things like <details open="open"></details> instead of the odd-looking, but more succinct <details open></details> are still legal.

A specific example

The XHTML way had a lot of strong opinions about the role of block level elements vs. inline elements and who could be the parent of what, etc. This, for example, is invalid XHTML because an inline element <a> should not be a parent of a block-level <h1> element.

    <a href="#">
      <h1>foo</h1>
    </a>
  

As told by the W3C validator:

The mentioned element is not allowed to appear in the context in which you’ve placed it; the other mentioned elements are the only ones that are both allowed there and can contain the element mentioned. This might mean that you need a containing element, or possibly that you’ve forgotten to close a previous element.

One possible cause for this message is that you have attempted to put a block-level element (such as “<p>” or “<table>“) inside an inline element (such as “<a>“, “<span>“, or “<font>“).

HTML5 now distinguishes not just between block and inline-level elements, but sectioning elements, heading elements, flow content and phrasing content, among others.

Now, freed from these XHTML shackles, we’ve done things like this for our research abstracts:

    	<article>
    	  <a href="http://www.patientslikeme.com/als/patients/find" id="als-genetics-search-engine">
    	    <figure>
    	      <img alt="ALS Genetics Search Engine" src="http://s3.amazonaws.com/patientslikeme/research_abstracts/21/als_genetics_small-thumb.jpg?1243454000">
    	    </figure>
    	    <h3>
    	      ALS Genetics Search Engine
    	    </h3>
    	  </a>
    	  <p>Search for ALS patients on a variety of parameters including known disease-causing genetic mutations (e.g. SOD1, ALS2, VAPB). Over time we will show patients with the inherited familial form of ALS (FALS) more information about their likely progression rates and publish our findings to the scientific field.</p>
    	</article>
    

We’re free to wrap the link around the <img> (seen here surrounded by this nifty <figure> element) and the <h3> heading — itself wrapped in an equally nifty semantic <article> element. By contrast, with XHTML we had to duplicate the link around the image and then inside the heading just to stay on good terms with the validator.

    	<div class="article-body">
    	  <a href="http://www.patientslikeme.com/als/patients/find"><img alt="ALS Genetics Search Engine" src="http://s3.amazonaws.com/patientslikeme/research_abstracts/21/als_genetics_small-thumb.jpg?1243454000" /></a>
    	  <a id="als-genetics-search-engine"></a>
    	  <h3>
    	    <a href="http://www.patientslikeme.com/als/patients/find">ALS Genetics Search Engine</a>
    	  </h3>
    	  <p>Search for ALS patients on a variety of parameters including known disease-causing genetic mutations (e.g. SOD1, ALS2, VAPB). Over time we will show patients with the inherited familial form of ALS (FALS) more information about their likely progression rates and publish our findings to the scientific field.</p>
    	</div>
    

Other changes were to convert our standard navigation elements from <div> to <nav>, our banner section to a <header> element, and our footer into a… wait for it: <footer> element.

One notable thing. A common pattern we’ve used is something we called a “callout”. Semantically. these fall under the <aside> tag. It’s great! I’m so excited to stop using so many damned <div> tags.

No offense, venerable and wise <div> tag.

Internet Explorer’d

So, how does this work in IE? Out-of-the-box, not so well. Any version of IE below IE9 doesn’t understand these new tags. But thanks to some clever and simple scripting, the HTML5shiv library tricks IE into recognizing anything assigned by document.createElement('<tagName>'). From there, just style the tags as needed in your CSS. The HTML5shiv script is hosted on Google Code and included by way of conditional comments for all your sub-IE9 needs.

Styling

Thanks to our use of Sass (Syntactically Awesome Style Sheets), this conversion to HTML5 was incredibly quick. Nested rules proved their mettle. Usually, it was just one change to the parent element of the selector and all the complicated conditional selectors became legit yet again. Sass FTW: Haters, take note.

I have yet to meet a developer who gives a shit about markup that likes SASS and HAML. 9:42 PM May 11th via web
We here at PatientsLikeMe really care about markup. Nice to meet you.

Forms

New input types available in HTML5 required us to install the Collective Idea HTML5 plugin to provide new Rails helpers for input types like search, url, email and number, among others.

This plugin also overrides other rails helpers like javascript_include_tag, stylesheet_link_tag, and empty form tags to prevent self-closing.

Validation

Another reason that this transition makes sense is that some of our engineers have already been using HTML5 features in our app. For example, the data-prefix attributes allow for the delivery of custom data to facilitate interaction with JavaScript. “But, wait”, said some party pooper (me), “that won’t validate as XHTML”. To which @monkeyatlarge replied:

“validation is so 1999″.

Touché, sir. It’s true that we’re not worried about blowing up an XML parser with every unescaped entity. But still, whatever one might think about the merit-badge you get for validating your markup, it is still useful for finding errors that can cause CSS to fail. With properly valid HTML5, we can use these useful new features and help ensure we’re not overlooking any big errors in the DOM.

What’s the point?

Good question. Why bother converting an existing site to HTML5? The principal draw for me is the new semantic sectioning elements, <nav>, <header>, <section>, <article>, as well as <footer> (which is actually considered flow content) — Divitis was really starting to get to me. Additionally, getting access to features like data- attributes and better support for aria- attributes while still validating is a nice bonus. Better semantics mean better potential support for accessibility devices, mobile devices, and, dare i say, search engines. But this is just scratching the surface. JS APIs, new multimedia elements, drawing with <canvas> and <svg> are the future and browser support is getting better all the time. In the meantime, development on our XHTML to HTML5 initiative is nearing completion and will soon see the light of day. Thanks for stopping by. And stay classy.

For more information on the full range of HTML5 capabilities, please see the excellent HTML5 Rocks presentation by Marcin Wichary and Ernest Delgado.

A more accessible checkbox

At South by Southwest in 2008, during a visit to the Knowbility.org booth, we got a demo of the JAWS screen-reader software using parts of our own PatientsLikeMe website. JAWS, along with NVDA and VoiceOver are some of the better known tools available for users with low-vision or visual-impairment — had we done a good enough job for an actual user to navigate our site using this assistive technology? This actual user, Fred Hunt, went through our homepage, our sign-up page, and our login page. What would he say? Fred’s verdict: pretty good marks overall, with one caveat: a deficiency in our implementation of checkboxes.

Take, for example, The PatientsLikeMe login form:

A screenshot of the PatientsLikeMe login form

The screen-reader reads the form elements in DOM order, so for the first field in the form, Username or Email, the reader would say something like:

username or email, edit text

Navigating further through the form, the screen-reader would then say:

“password, secure edit text”

Still makes sense. Further still through the form:

checkbox unchecked, remember me on this computer

Hold-up. That one didn’t make as much sense.

For this checkbox we have the swapping of the order of the control (a checkbox that is unchecked) and the question asked by the form (“do you want your username to be remembered on this computer?“) — a departure from the pattern as read in other form controls by assistive software.

This reversal of order might seem like a small difference, but it was enough for Fred to mention it. Since we operate a patient-focused website, it is very important to us that we provide the most accessible user experience for every user, regardless of ability. As such, Fred’s critique stung.

It’s obvious once you think about it: reading the associated text of the checkbox before the form control provides better context. What follows is how we got the screen-reader to say “remember me on this computer, checkbox unchecked“. Hopefully, this provides an improved user experience for users of such assistive technology.

Less talk, more markup

A common pattern seen in form inputs like radio buttons and checkboxes is a corresponding label tag with a matching for attribute with the input ID.

The structural markup for these controls can be seen in a couple of ways.

e.g., input, then label as adjacent sibling. A staple of user interface design.

<input id="remember-me" type="checkbox" />
<label>Remember me</label>

e.g., label as parent of input with label text following input.

<label>
  <input id="remember-me" type="checkbox" />
  Remember me
</label>

Makes you wonder why this differs from the standard layout for controls like text boxes, where the label always precedes the input? Aesthetics would be my guess*. With an array of radio controls of varying text length, the jaggedness would prevent the inputs from lining up were they at the end of the labels.

* Why this is a guess: Looking through the Apple Human Interface Guidelines and Windows User Experience Interaction Guidelines did not yield a single mention of the order of input and label for a checkbox.

Unfortunately, neither of the above approaches do anything to address the reversed order of label and input. So, we did it like this:

e.g., label as parent of input with label text preceding input.

<label for="remember-me">
  Remember me
  <input id="remember-me" type="checkbox" />
</label>

This technique requires some CSS intervention of the absolutely positioned kind to get it to look “normal”. Let’s take our approach of choice and add a classname of “accessible”.

<label class="accessible" for="remember-me">
  Remember me
  <input id="remember-me" type="checkbox" />
</label>

Now with the DOM structure in a good place for screen-readers, let’s fix up the visual presentation with CSS to match our expectations for how checkboxes and labels look in our web form.

label.accessible {
  position: relative;
  padding-left: 22px;
}

label.accessible input {
  position: absolute;
  left: 0;
  top: -3px;
}

Quite simply, we’re padding the left side of the label and positioning the input in that gap. This technique, of course, also applies to radio buttons. With very little effort on our part, we’ve made things a little easier for our screen-reader audience.

Using Campfire with Fluid.app and Growl

Campfire Screenshot

At PatientsLikeMe, we use Campfire by 37signals for our internal communication. We have a flexible schedule that allows us to work remotely part of the time, so it certainly comes in handy for keeping up with the rest of the team.

Campfire is a web app, so you can access it from any web browser. But it also has an API that allows third party developers to build Campfire clients. A couple popular ones I’ve seen are Propane and Pyro. I was drawn to the appeal of bringing Campfire outside of the browser, but I didn’t feel the need to get a third party app. Instead, I turned to my old friend Fluid.

Fluid is a Mac app allows you to create “site specific browsers” (SSBs). Why is that useful? Taking frequently used web apps (like your email, project management software, oft-used social networking tool, etc.) lets you quickly switch to that site as if it were an application running on your Mac. So, it’s in your Dock. The Dock icon notifies you of unread messages. You can command+tab to it. No sifting through tabs to find it. No losing it in a browser crash.

There are a couple extras you can add to your Fluid Campfire app, like Growl notifications and a nice application icon. But first, let’s get into how you set it up.

Setting up your Fluid app

Create an app with Fluid

  1. Download Fluid.app.
  2. Download a nice high resolution icon for Campfire from 37signals.
  3. Launch Fluid. Enter the URL of your Campfire account and the name of the app you’re creating. Here you can also turn the Campfire icon you just downloaded into the application icon.
  4. Create your app.

And that’s really it.

Setting up Growl notifications

Growl notifications in Campfire

Sometimes you just can’t read everything that goes by on Campfire. Campfire does allow you to search the archives for important terms like, say, your name. But if someone’s talking to or about you, you can easily monitor that real-time. Enter Growl.

Growl is a Mac service that will pop up little messages on your screen to notify you of certain events. There’s a script that allows you to set this up for your new Campfire Fluid app. Let’s do that.

  1. Install Growl.
  2. Install the script. Instructions are on the script’s page.

Now you can decide what should trigger Growl notifications. There are two options:

  1. Always, but stick on trigger: This will pop up every message in the chatroom, but they will close after a couple seconds (giving you just enough time to read it). When your term is used (like “Adam” in the example above), the message will stay on your screen until you manually dismiss it. This is the setting I use.
  2. Only on trigger: Will only pop up images when they contain the term you entered (again, “Adam” in the example above).

And that’s all there is to it. As the leading image in this post so perfectly demonstrates, Campfire is an indispensable communication tool for the Product & Technology team. This Fluid+Growl combination helps me keep a handle on things quite nicely.

CSS Tricks You Can Use Once You Ditch IE6

Not long ago, I tweeted:

Underrated CSS selector: input[type=text] { style: here; } (targets only inputs with the type=”text”, leaving radio buttons & submits alone)

That generated a response that went something like “not if you need to support IE6!”. Personally, I think an unstyled form element is perfectly acceptable for IE6. But this also got me thinking… what types of CSS tricks can we freely use once we don’t have to worry about IE6 anymore? IE7 is no superstar, but it does have support for more advanced CSS selectors and image usage.

I enlisted the help of my fellow sheet-stylist, Cris Necochea, to build this list:

  1. Transparent PNGs

    Right now, we have to export two versions of our sprite graphics—one for IE6 (a transparent gif with a white matte) and one for everybody else (a transparent png with all the alpha-channel sweetness you’ve come to love). This is annoying, tedious, and—with IE6 out of the way—no longer necessary (for some of us).

  2. Attribute Selectors

    Oh, I love these. Attribute selectors inspired the tweet that kicked off this post. Here are some examples:

    input[type=input] {
      width: 100%;
    }
    
    abbr[title=and] {
      font-family: Baskerville, "Goudy Old Style", Garamond, Georgia, serif;
      font-style: italic;
      border-bottom: none;
    }
    
    a[rel=external] {
      font-weight: bold;
    }
    

    What do each of these do?

    Want more? CSS-Tricks has a great resource on all the possibilities with attribute selectors.

  3. Child selector (>)

    You can use the child selector to select elements that are a direct child of another element. For example:

    div#header > ul {
      list-style: none;
    }
    

    That will target any ul that is a child of the div with the id “header”. This will not target any ul within div#header that is nested inside another element (such as another div). It has to be a direct child.

  4. Adjacent sibling selector (+)

    Let’s start with an example. This one is a bit tricky to explain:

    h1 + p {
      margin-top: 0;
    }
    

    This will take any p that immediately follows an h1 and remove the top padding. As the name implies, it must be an adjacent sibling. Note that the styles target the second element (the p), not the first (the h1).

  5. General sibling selector (~)

    This one is a lot like the adjacent sibling selector, but the siblings don’t need to be adjacent. So, take this:

    h1 ~ p {
      margin-top: 0;
    }
    

    What this will do is target any p that is the sibling of an h1. An example use case might be if you have a bunch of lists and each is separated by an h2. You could easily target either the lists or the headers without the need to add class names.

  6. :first-child, :first-letter, and :first-line

    :first-letter and :first-line are pretty self-explanatory. :first-letter is ideal for things like drop caps. :first-line can help you get that treatment where the first line of a block of text is a bit bigger than the following lines.

    :first-child is a bit more complicated—and powerful. Here’s how it looks in action:

    ul li:first-child {
      font-weight: bold;
    }
    

    This would make the first item in a ul appear bold. A more widely-used use case might be:

    ul li {
      border-top: 1px solid red;
    }
    
    ul li:first-child {
      border-top: none;
    }
    

    This would put a red border above each list item, but remove the border for the first item. This way the borders are only used for separation. Handy. (Note that :last-child is still not supported in IE7.)

  7. max-width, min-width, max-height, and min-height

    Because sometimes you just want to set a minimum. Now you can (without the need to jump through hoops of IE6 hackery).

  8. Class chaining

    This would confuse the heck out of IE:

    div.alert.warning {
      color: red;
    }
    

    This would find any div with both the “alert” and “warning” class names and color the text red. While you can debate whether or not class chaining makes for manageable CSS, it is at least a viable option now.

  9. Pixels for font sizing

    Everybody has their own favorite method of font sizing. Sizing with pixels has pretty much been frowned upon by the standards community for one major reason (among others)—IE6 wouldn’t let users resize type set in pixels. Without IE6, pixels now become an option along with keyword sizing and em sizing.

There’s nine. Got any more for me?

Manage Your CSS3 Tricks with Sass Mixins

Shortly after joining PatientsLikeMe last fall, I started working on our family of applications for partners. This was a unique opportunity to start on something essentially from scratch. Despite the fact that we know some major clients are tied to Internet Explorer 6, I took this as an opportunity to use a whole bunch of new CSS3 tricks. I know, IE6′s CSS3 support is beyond spotty. It’s nonexistent. But ask yourself: Do websites need to look exactly the same in every browser?

No, they don’t. They need to work in every browser. They need to be usable and maintain your company’s branding. But the fact that IE6 doesn’t like rounded corners doesn’t mean you need to spend an extra day creating background images with rounded corners. It just means that IE6 users should get straight edges. Let’s face it… IE6 users are used to things looking like crap. A sharp edge on a dropdown menu isn’t going to offend them.

In addition to embracing CSS3, I also continued my lovefest with Sass. A while back on my personal blog, I wrote up my first impressions of Haml & Sass (Haml is a markup language for generating HTML while Sass is a meta-language for generating CSS). Long story short, I’m still in love. In fact, I’ve fallen deeper because CSS3 and Sass are perfect for each other.

Why are they so perfect? Sass Mixins allow you to create a group of CSS rules you can re-use. In addition to reusing the styles, you can also pass variables and arguments into the mixin, making your CSS much more dynamic. Because many CSS3 tricks involve multiple lines that target specific browsers, this can be a big time saver.

Example time!

If you’re new to CSS3, I encourage you to check out css3please.com, a site that allows you to visually try out different CSS3 properties. The first CSS3 property that anyone tries is border-radius. Since border-radius is not officially supported yet, you can only render it through vendor-specific properties. For Firefox, this means adding -moz- to the beginning of the property while for Safari and Chrome that means adding -webkit-. All other browsers, so far, are all out of luck.

This would produce a 12-pixel rounded corner on all corners of a box:

.rounded {
  border-radius: 12px;
  -moz-border-radius: 12px;
  -webkit-border-radius: 12px;
}

Again, -moz- is for Firefox while -webkit- is for Safari, Chrome, and all other Webkit-based browsers. We also include the border-radius property with the assumption (hope?) that all browsers eventually support rounded corners without vendor-specific properties.

There are two ways you can apply those properties over and over:

  1. Keep adding them to every element you want rounded
  2. Add them to a "rounded" class and add that class to all elements you want rounded

Option #1 is obviously tedious and forces you to duplicate the same properties over and over—not ideal. Option #2 is promising, but forces you to include non-semantic class names all over the place (similar to our beloved “clearfix”). Also, what happens if you want the rounding to be 12 pixels in one place, 6 in another, and perhaps a weird mix in a third spot? You need to keep building classes for each of these situations (and those are bound to get non-semantic class names like "rounded12". Again, not ideal.

Using Sass, you can build the mixin once and pass arguments into it, therefore allowing you to modify the rounding values on a case-by-case basis. That, and there’s no pesky class names that muddy up your markup. You simply apply the mixin to the property you want rounded in your Sass file. Then when the Sass file compiles, it creates the correct properties for that element. It’s like magic.

Here’s the mixin:

=border_radius(!radius)
  border-radius = "#{!radius}"
  -moz-border-radius = "#{!radius}"
  -webkit-border-radius = "#{!radius}"

!radius is the argument we use to pass in the value. So, to apply 3-pixel rounded corners to an h1, you would write this:

h1
  +border_radius(3px)

Want 12-pixel rounded corners?

h1
  +border_radius(12px)

Want to round the left side, but not the right side?

=border_radius(!radius)
h1
  +border_radius(12px 0 0 12px)

Let’s take a look at a screenshot from one of the PatientsLikeMe applications and then see how it was put together.

Here’s the basic markup from that image (simplified to just the basic structure):


<div id="categories">
  <h3 class="toggle">
    Modify Categories
  </h3>
  <div id="categories-inner">
    …
  </div>
</div>

Of course, with Haml, that’s just:

#categories
  h3.toggle Modify Categories
  #categories-inner
    …

Much cleaner. So, let’s style the h3 and the inner div. I’m only showing the CSS3 mix-ins in the styling below (there are other styles, but they’re pretty standard). The h3 will get border-radius (but just the top two corners) while the div gets four mixins:

  1. +border_radius on all corners except top-left
  2. +box_shadow: A subtle drop shadow on the box
  3. +box_gradient: A gradient background on the box
  4. +box_gradient_ie67: A hacky solution for when you also want the gradient in IE6 and IE7

Here’s the Sass:

#categories h3
  +border_radius(3px 3px 0 0)
#categories-inner
  +box_shadow(#CCC, 1px 1px 4px)
  +border_radius(0 3px 3px 3px)
  +box_gradient(#FFFFFF,#FCF5DE)
  +box_gradient_ie67(#FFFFFF,#FCF5DE)

You’re already familiar with +border_radius. Here’s the +box_shadow mixin:

=box_shadow(!color, !values)
  box-shadow = “#{!color} #{!values}”
  -webkit-box-shadow = “#{!color} #{!values}”
  -moz-box-shadow = “#{!color} #{!values}”

There are two arguments: one for color of the shadow and one for the values (horizontal offset, vertical offset, and blur radius). Of course, this will only render in Firefox, Safari, and Chrome. But it’s a drop shadow. Those who use nice browsers deserve nice things. Those who don’t have no idea what they’re missing.

+box_gradient is the big daddy of all of these. I borrowed the cross-browser gradient implementation from css3please.com. Here’s how my mixin looks:

=box_gradient(!top,!bottom)
  background-image = “-moz-linear-gradient(top, #{!top}, #{!bottom})”
  background-image = “-webkit-gradient(linear,left top,left bottom,color-stop(0, #{!top}),color-stop(1, #{!bottom}))”
  -ms-filter = “progid:DXImageTransform.Microsoft.gradient(startColorStr=’#{!top}’, EndColorStr=’#{!bottom}’)”

Again, two arguments: one for the top color and one for the bottom color. I’m using all vertical gradients, but you can certainly do horizontal, radial, whatever. You would just need to introduce more arguments into the mixin. I’m just not an overly-argumentative guy. As you’d expect, -moz-linear-gradient works in Firefox while Chrome and Safari get their gradients from -webkit-linear-gradient. The frightening line that starts with -ms-filter targets IE8 (and I assume early betas of IE9).

But there’s actually a vendor-specific property that will work in IE6 and IE7, too. Yeah, I was shocked. I’ve placed that in a separate mixin so I only apply it at certain times (when it is a major visual element of the design). It looks a little something like this:

=box_gradient_ie67(!top,!bottom)
  filter = “progid:DXImageTransform.Microsoft.gradient(startColorStr=’#{!top}’, EndColorStr=’#{!bottom}’)”

I quarantined that one because on occasion it caused conflicts based on the fragility of other IE6-and-IE7-targeted hacks.

Put it all together and what’ve you got?

#categories-inner {
  box-shadow: #cccccc 1px 1px 4px;
  -webkit-box-shadow: #cccccc 1px 1px 4px;
  -moz-box-shadow: #cccccc 1px 1px 4px;
  border-radius: 0 3px 3px 3px;
  -moz-border-radius: 0 3px 3px 3px;
  -webkit-border-radius: 0 3px 3px 3px;
  background-image: -moz-linear-gradient(top, white, #fcf5de);
  background-image: -webkit-gradient(linear,left top,left bottom,color-stop(0, white),color-stop(1, #fcf5de));
  -ms-filter: progid:DXImageTransform.Microsoft.gradient(startColorStr=’white’, EndColorStr=’#fcf5de’);
  filter: progid:DXImageTransform.Microsoft.gradient(startColorStr=’white’, EndColorStr=’#fcf5de’);
  background-color: #FFF;
  position: relative;
  z-index: 1;
  margin-top: -1px;
  border: 1px solid #E4C37C;
  padding: 10px;
}

Huzzah! I loved Sass before. But now that it makes it so much easier to sprinkle in some CSS3 goodies here and there, I’m even more in love.

Questing

If you know anything about PatientsLikeMe, or our engineering team, then it is easy to understand the influences in our Rails Rumble entry, http://quest-for-life.org. This site started as an educational lecture I developed for my application as a JPL Solar System Ambassador. From there, it is easy to see PLM’s influence as we used social media to both teach and learn science.

quest-for-life

I had been thinking about this site for a very long time, and I was fortunate to have 3 great friends agree to help me build it as part of the Rails Rumble in time for the International Year of Astronomy. I’m very proud of our results and I’m looking forward to opening the site up to the Astronomy community.

What Worked

There were a bunch of things that worked for us in the competition.

  1. Quest-for-life has a nice constrained scope. We didn’t have to drop many ideas to present a complete vision. This was good for time and morale, no debates over what’s in and what’s out.
  2. Domain expertise is critical. Others have commented that a 48-hour competition is not the time to learn new technologies. It is also not the time to learn new problem domains.
  3. Location, location, location. I think that a lot of work can be done remotely, but in a 48-hour contest co-location is an asset. I can ask verbal questions, hurl insults (or encouragement) or smack talk the opposition without even leaving my editor. I can look around the room and see that somebody needs to get some sleep, or needs some help. And pairing to solve difficult problems is much more efficient when everybody is together.

What Could Be Better

  1. Know your tech. During the early planning stages we were waffling between clearance and authlogic for managing teacher sign-ups and authentication. We settled on clearance, which was great, but I don’t think we knew it well enough. It made some assumptions about the user model we weren’t aware of and that made for some difficult to unravel bugs at the end.
  2. Prioritize bug fixing as aggressively as you prioritize features. We had a bug in our “forgot password” code, relating to clearance assumptions (see above). Attempting to unravel that consumed about 2-hours late in the contest and ended up breaking an important piece of functionality that we weren’t able to fix in time. Fixing the password recovery bug wasn’t worth it. We should have just jettisoned the “forgot password” link.
  3. Sleep is important. There was a point Sunday morning where made negative progress because we really shouldn’t have been coding anymore.
  4. We practiced, and documented our server deploy, but we still ran into problems with gem versions. We also spent too much time trying to get cap deploy working only to find out that we didn’t have access to set deploy keys on git hub. Eventually this was provided on the Rails Rumble site but we had moved on by that point. We should have moved on sooner.

Wrap Up

This was a great experience and we’re already planning next years app. Congratulations to everybody who participated. There was a lot of great work done.