The eclectic musings of a bitter software engineer.

Code aesthetics

Sunday January 06, 2008 @ 04:36 PM (PST)

I’m not exactly the tidiest person when it comes to the physical world. I have two desks in my office at home; on top of one is a bunch of clutter and an LCD, keyboard, and mouse, so you might say it’s at least serving a purpose. The other desk serves no purpose other than forming the nucleus of another gigantic ball of clutter.

When it comes to code, though, I’m the most mind-numbingly anal perfectionist you’ve ever met. Ugly code—even if there’s nothing wrong with it aside from being messy—makes me depressed. It actually affects my mood. I can’t bear to look at it, much less work with it. The aesthetics of code have such a strong effect on me that I actively avoid languages that encourage or facilitate messy code and I try to avoid working with programmers who write messy code. I know this isn’t rational, especially if I want to continue to learn and grow as a programmer, but it seems to be hard-wired. I can’t help it.

One of my biggest pet peeves is when programmers fail to use vertical whitespace and descriptive comments to make their code more readable. Obviously you don’t want pages of blank space or comments on every line, but ideally whitespace and meaningful comments should be used to break up code inside a function into logical groups. This makes the code more readable in the same way that paragraph breaks make text more readable.

The following example is a more or less randomly-chosen snippet from a Ruby Flickr library I wrote a while back. Exhibits A and B are absolutely identical, except that B has vertical whitespace and comments, whereas A does not.

Exhibit A:

def sign_request(request, params)
  if @api_secret.nil?
    request.set_form_data(params)
    return request
  end
  params['auth_token'] = @auth.token unless @auth.token.nil?
  paramlist = ''
  params.keys.sort.each {|key| paramlist << key << URI.escape(params[key].to_s)}
  params['api_sig'] = Digest::MD5.hexdigest(@api_secret + paramlist)
  request.set_form_data(params)
  return request      
end

Exhibit B:

# Signs a Flickr API request with the API secret if set.
def sign_request(request, params)
  # If the secret isn't set, we can't sign anything.
  if @api_secret.nil?
    request.set_form_data(params)
    return request
  end

  # Add auth_token to the param list if we're already authenticated.
  params['auth_token'] = @auth.token unless @auth.token.nil?

  # Build a sorted, concatenated parameter list as described at
  # http://flickr.com/services/api/auth.spec.html
  paramlist = ''
  params.keys.sort.each {|key| paramlist << key << 
      URI.escape(params[key].to_s) }

  # Sign the request with a hash of the secret key and the concatenated
  # parameter list.
  params['api_sig'] = Digest::MD5.hexdigest(@api_secret + paramlist)
  request.set_form_data(params)

  return request
end

This function isn’t the least bit complicated, but Exhibit A sure makes it look like it is. Exhibit B, on the other hand, breaks it into meaningful chunks and uses comments to tell you what each bit is doing, so that a programmer unfamiliar with the codebase can see at a glance what’s happening without having to parse the actual code.

I probably spent an extra minute or two writing those comments and adding whitespace, but that up-front investment was well worth it when I found myself looking at that code again today for the first time in months and understood it instantly.

Do your future self and your fellow programmers a favor: comment your code and use whitespace to make it more readable. Only assholes and Perl programmers think cryptic code is impressive.

Comments

I have an inner conflict when it comes to this. My coder aesthetic actually prefers tighter (note - not cryptic) code without lots of wordy comments and needless whitespace. If you push enough whitespace in there, even the most elegant language will start to look as bloated as Java (ugh). At the same time, I know that deciphering that code can be a bit of a pain at times. So, when just hacking something together, I usually stick to something closer to example A and only put comments (without whitespace buffering) above especially non-trivial parts. If for some reason I think the code will have a long lifetime with lots of different maintainers I do something more like example B. I also am pedantic about top-of-file documentation - this is the most important place to document IMHO. I'm not sure there's a perfect solution for all contexts, and I'm not sure my hybrid solution really satisfies me either - but it's the best I've come up with.

Monday January 07, 2008 @ 12:27 AM (PST) Posted by Caleb

...first and second desk ;-)

And for the record: I totally adore tidy code... and i hope to master it in a couple of hmm - well i hope to master it some time!

Monday January 07, 2008 @ 09:25 AM (PST) Posted by Weasel

Tidy code, yes. That's what you get when you refactor your first batch of code, which is just meant to work. Be a proof of concept, if you will. Unfortunately, in the fracas of software development, there's not always time to tidy up everything after you get it to work. I am notoriously bad at documenting code I've written to implement boring standard interfaces, for instance.

I have to say to my defense that my code documentation skills have improved since the days of iPerForm, and most of my functions will actually fit on one page in printout - as opposed to five or six. perhaps the code itself hasn't gotten any less complicated to innocent bystanders, but then, the stuff I implement, these days, is also a bit more complicated than what we were working on, back in those days.

I do think I'm much better, now. That's what the nice doctor says, anyway. ;o)

Monday January 07, 2008 @ 01:25 PM (PST) Posted by GreyStork

Ryan, I totally relate on messy code affecting mood. When I see messy code, I feel physically sick and just want to go home and lie on my bed. Or escape to a beautiful code utopia.

Monday January 07, 2008 @ 04:24 PM (PST) Posted by Rohan

The article didn't really mention Ryan, but are you putting your comments down before you lay out the code, or do you go back and comment when you are done? I've seen both styles, and I tend to lean towards psuedo-comment-code first, and then make real code underneath it.

@Rohan: Messy code gets at me too. Mostly the lack of comments or explanation., though I am pretty annoyed about a lack of unit tests sometimes too.

If you don't have time to comment your code, did you have time to make sure it was good code?

Tuesday January 08, 2008 @ 09:24 AM (PST) Posted by Jakob Heuser

If I'm about to write a complicated (or not-so-complicated but very large) chunk of code, I'll often write the comments first as a way of working out the flow and then making sure I don't forget it. I don't do it religiously though; in general, if what I'm writing has a simple enough design that I can hold it in my head as I write the code, then I'll add the comments as I write rather than before.

One thing I usually don't do is sit down and design an entire application or library before I start writing code. Instead, I tend to design as I write, refactoring as necessary. I suspect it's not quite as time-efficient, but I find that the refactoring helps to cement the code in my head and help me keep a reliable overall picture of the codebase as it grows. This works better on personal projects than on collaborative ones, of course.

I do need to get better about writing unit tests, though. I suck at that.

Tuesday January 08, 2008 @ 10:13 AM (PST) Posted by wonko
Post a comment

Basic XHTML (including links) is allowed, just don't try anything fishy. Your comment will be auto-formatted unless you use your own <p> tags for formatting. You're also welcome to use Textile or Markdown.

Don't type anything here unless you're an evil robot:


And especially don't type anything here:

Copyright © 2002-2008 Ryan Grove. All rights reserved.
Powered by Thoth.