Red Green Repeat Adventures of a Spec Driven Junkie

The Shape of Code

I heard Uncle Bob say this at a talk:

Programmers don't hate bad code, They get used to the shape of it.

When I first heard it, I laughed a bit… but now when I look at some old code, I know exactly what Uncle Bob meant and I cry.

Code starts to take on a shape as it grows large and/or old. The code works, but its shape starts to, as I like to call it, ‘snake’. Example from my recent code:

WINNING_MOVES = {
  top_row: (Set.new [0, 1, 2]),
  middle_row: (Set.new [3, 4, 5]),
  bottom_row: (Set.new [6, 7, 8]),
  left_column: (Set.new [0, 3, 6]),
  center_column: (Set.new [1, 4, 7]),
  right_column: (Set.new [2, 5, 8]),
  american_stripe: (Set.new [0, 4, 8]),
  british_stripe: (Set.new [2, 4, 6])
}

This block of code isn’t hard to read, but it takes some time to read.

The code starts at the top left and gets a little longer, where assignment starts to curve in and out in between variable and value, like a snake.

Code Alignment

I thought snaking code was just a natural process of all code bases over time and will be the eventual shape of code.

When I discovered code alignment, it completely changed my opinion about how the shape of code can become over time.

If the previous code is code aligned, it would look like:

WINNING_MOVES = {
  top_row:         (Set.new [0, 1, 2]),
  middle_row:      (Set.new [3, 4, 5]),
  bottom_row:      (Set.new [6, 7, 8]),

  left_column:     (Set.new [0, 3, 6]),
  center_column:   (Set.new [1, 4, 7]),
  right_column:    (Set.new [2, 5, 8]),

  american_stripe: (Set.new [0, 4, 8]),
  british_stripe:  (Set.new [2, 4, 6])
}

I find this code much easier to read than the previous version, even though both are exactly the same, only difference between them: white space.

At a glance, isn’t this block of code just pretty and approachable? I instantly feel the programmer who worked on this code before really cared, not only about the functionality, but also the code.

By aligning code well, the shape of code can be made better and kill off the code snake!

Improving the Shape of Code

One can improve the shape of their code today by applying the principles of code alignment.

So, instead of just creating code, which its shape will default to:

def start
  config_type = configure_type
  config_difficulty = configure_difficulty(config_type)
  display_x = display_config(Board::X, {})
  display_xo = display_config(Board::O, display_x)
  config = config_type.merge(config_difficulty)
  configuration = config.merge(display_xo)

  configuration
end

Start shaping the code so it is like this:

def start
  config_type       = configure_type
  config_difficulty = configure_difficulty(config_type)
  display_x         = display_config(Board::X, {})
  display_xo        = display_config(Board::O, display_x)
  config            = config_type.merge(config_difficulty)
  configuration     = config.merge(display_xo)

  configuration
end

I loved the way the code looks when it is aligned well. Coming back to work on aligned code felt better than unaligned, or ‘snaking’ code.

Code Alignment in the wild:

I’m not the only one who thinks like this, let’s look at some code that’s in the wild:

Rubocop

I have been using Rubocop religiously and even submitted a fix!. Looking at one part:

NODE_MAP = {
  AndNode          => [:and],
  ArrayNode        => [:array],
  CaseNode         => [:case],
  EnsureNode       => [:ensure],
  ForNode          => [:for],
  HashNode         => [:hash],
  IfNode           => [:if],
  KeywordSplatNode => [:kwsplat],
  OrNode           => [:or],
  PairNode         => [:pair],
  ResbodyNode      => [:resbody],
  SendNode         => [:send],
  UntilNode        => %i(until until_post),
  WhenNode         => [:when],
  WhileNode        => %i(while while_post)
}.freeze

source

Even with one variable name longer, KeywordSplatNode, keeping everything aligned makes the whole data structure is easy on the eyes.

Linux

When I look at one of the largest open source code bases out there, I found a great example:

copy_msqid_to_user(void __user *buf, struct msqid64_ds *in, int version)
  {
    switch (version) {
    case IPC_64:
      return copy_to_user(buf, in, sizeof(*in));
    case IPC_OLD:
      {
        struct msqid_ds out;

        memset(&out, 0, sizeof(out));

        ipc64_perm_to_ipc_perm(&in->msg_perm, &out.msg_perm);

        out.msg_stime       = in->msg_stime;
        out.msg_rtime       = in->msg_rtime;
        out.msg_ctime       = in->msg_ctime;

        if (in->msg_cbytes > USHRT_MAX)
          out.msg_cbytes    = USHRT_MAX;
        else
          out.msg_cbytes    = in->msg_cbytes;
        out.msg_lcbytes     = in->msg_cbytes;

        if (in->msg_qnum > USHRT_MAX)
          out.msg_qnum      = USHRT_MAX;
        else
          out.msg_qnum      = in->msg_qnum;

        if (in->msg_qbytes > USHRT_MAX)
          out.msg_qbytes    = USHRT_MAX;
        else
          out.msg_qbytes    = in->msg_qbytes;
        out.msg_lqbytes     = in->msg_qbytes;

        out.msg_lspid       = in->msg_lspid;
        out.msg_lrpid       = in->msg_lrpid;

        return copy_to_user(buf, &out, sizeof(out));
      }
    default:
      return -EINVAL;
    }
  }

source

What I find very impressive is the indenting is maintained, even through the if/else statements and this is 12year + 7year old code!

How to

Aligning code can be very mundane, especially doing it by hand. I would recommend hand aligning the first time, but getting editor support will save your sanity.

Emacs

Emacs can align anything based on a regex and it is built in. The command: M-x align-regex.

Vim

Has an external plugin: vim-easy-align which looks like it will align anything!

Visual Studio, Sublime, Notepad++, & Blend

For other popular editors, http://codealignment.com has great plugins

Conclusion

I thought the shape of code for an old code bases trended towards becoming a ‘snake’. Getting thick and windy for assignment variable and values.

After learning about code alignment, I see the shape of code can be pretty, even for very old code bases.

Now when I look back at my code that has been aligned, I love it. I just want to get in an code on it again. Present me thanks past me for taking the extra effort to align things, so present me can quickly see what’s going on without winding through it.

Start making code pretty today, future you will appreciate it! :-)