Designers sometimes use the word “refactor” in a loose way. I think they overhear the word from programmers without getting the precise meaning. This article will introduce the term to designers so they can gain the same advantages that programmers have from a clear understanding.

How do designers loosely understand refactoring? Many take it to mean “rearranging” a design or “adjusting without completely rethinking” it. Refactoring actually means something else. It means changing the way a design is built without changing the way it looks from the outside.

Here’s an example of a refactoring. Let’s say there is a list of elements on a page and we want a dividing line above and below each element. Below the list there is a copyright footer.

Sketch of a list of elements with borders

We could implement this design with the following HTML and CSS:

<div class="items">
  <div class="item">
    The text of the first item
  </div>
  <div class="item">
    The text of the second item
  </div>
  <div class="item">
    The text of the third item
  </div>
</div>
<div class="footer">
  &copy; 2011 Design by Me.
</div>
div.items { border-top: 1px solid red; }
div.items div.item { border-bottom: 1px solid red; }

This CSS renders a border on the bottom of every item. A top border is rendered on the container so that every element has a border above and below it.

All is well. Now suppose we start working on other pages in our project and we realize we want the copyright footer on every page with a border above it. We add a selector in our CSS that renders a border above the footer.

Sketch of the global footer

<div class="footer">
  &copy; 2011 Designed by Me.
</div>
div.footer { border-top: 1px solid red; }

The footer looks good by itself. But when we return to the page with our list of elements, we now have a double border.

One way to fix the problem is to special case the global footer on just this page. Here’s what that looks like:

<body class="list_of_elements">
  <div class="items">
     . . .
  </div>
  <div class="footer">
    . . .
  </div>
</body>
body.list_of_elements div.footer { border-top: none; }

Sketch of the list of elements with the double border removed

That special case for the footer fixes the problem, but I don’t love the code. The footer is a global element. It makes more sense to change the list of elements that only appears once than to change the global footer that appears everywhere.

So even though the design looks right, I’m going to change the code behind it. I’m going to “refactor” the styles so the borders on the list don’t interfere with the border on the global footer.

Here’s the refactoring:

Before

div.items { border-top: 1px solid red; }
div.item { border-bottom: 1px solid red; }
div.footer { border-top: 1px solid red; }

After

div.items { }
div.item { border-top: 1px solid red; }
div.footer { border-top: 1px solid red; }

The result looks like this:

Sketch of the list of elements with the double border removed

It looks exactly the same as before. But the code is different. That’s a refactoring.

Here’s a real example from our products. Each of our products has an Account tab with a block that displays your current plan and an arrow pointing to a recommended upgrade plan.

Screenshot of the fixed width account cards

The grey container was originally a fixed width. While we were designing the 37signals Suite, we decided it would be better if this block could stretch horizontally. We wanted the card and arrow elements to remain at their fixed widths but appear centered inside the grey container regardless of the container’s width. Here’s what happened when we stretched the container horizontally:

Wide account card container with broken arrow

Oops. The arrow didn’t come along for the ride. What’s going on here?

Have a look at the structure of the design.

Structure of the account card markup

There is an outer container called .cards with two cards rendered inside (embedded Ruby does the rendering) and an arrow between them.

      <div class="cards">
          <%= render :partial => 'account_card', :locals => {:plan => @account.subscription} %>
          <span class="arrow">
              <%= image_tag('upgrade_arrow.png') %>
          </span>
          <div class="upgraded_card">
            <%= render :partial => 'account_card', :locals => {:plan => @account.recommended_upgrade_subscription} %>
          </div>
      </div>
div.cards { position: relative; background: grey; etc… }
div.cards span.arrow {
  position: absolute;
  top: 78px;
  left: 249px;
}

When I inspected the CSS, it turned out the arrow was being absolutely positioned relative to the top-left corner of div.cards. That was fine when div.cards was a fixed width. But when div.cards comes wider, and the cards move to a new center point, the arrow doesn’t move with them. It’s fixed to the top-left of the container regardless of the container’s width.

The solution is to position the arrow differently. We want to position the arrow relative to the cards instead of the container so it will always be in the right place, even if the container changes.

Before I started changing the code, I reverted back to the original fixed-width design. I want to change only one thing at a time. Otherwise when the design breaks it’s hard to know which change did the breaking. Reverting to the fixed-width design also makes the change a true refactoring. The design should look the same before and after the change on the outside.

Here’s the new code (slightly paraphrased for this example):

      <div class="cards_background">
        <div class="cards">
          <%= render :partial => 'account_card', :locals => {:plan => @account.subscription} %>
          <span class="arrow">
              <%= image_tag('upgrade_arrow.png') %>
          </span>
          <div class="upgraded_card">
            <%= render :partial => 'account_card', :locals => {:plan => @account.recommended_upgrade_subscription} %>
          </div>
        </div>
      </div>
div.cards_background { background: grey; etc... }
div.cards {
  position: relative;
  margin: 0 auto;
  width: 590px;
}
div.cards span.arrow {
  position: absolute;
  top: 78px;
  left: 233px;
}

I renamed div.cards to div.cards_background and wrapped the cards and arrow with a new div.cards. The new div.cards has a fixed width equal to the width of both cards and the gap between them. The arrow is positioned absolutely to the top-left edge of this new div.cards. Now the arrow will go wherever the cards go.

When I reloaded the browser, the screen looked exactly the same as before.

Screenshot of the fixed width account cards

That’s a refactoring. The difference is that now when I stretch .cards_background out, the arrow will move along with the cards as intended.

Wide container with the properly positioned arrow

Refactoring is a good tool to have in your belt. It helps to consciously decide as you code whether you are changing the implementation of a design or the outward appearance of the design. I hope these examples give you a precise definition of what refactoring means.