When is Ugly Code Beautiful?

Dec 03, 2019 | Sarah Reid

This article was inspired by a talk I watched at Rubyconf, 2019 titled: The Fewer the Concepts, the Better the Code

How readable is the code we write? How well is someone else able to read it? Who is our audience, both now and in the future? It could be ourselves two months from now or perhaps a fellow colleague.

Martin Fowler once said:

"Any fool can write code that a computer can understand. Good programmers write code that humans can understand." (link)

More often than not we think the humans Fowler refers to are skilled programmers who work in the same language I do. But what if I am the only engineer who knows Golang well enough to maintain that one legacy application written in Go? How do I write Golang in a way my fellow engineers can easily understand?

This question was the topic of David Copeland's 2019 RubyConf talk "The Fewer the Concepts, the Better the Code."

Take these two chunks of code as an example:


class Order
  def total
    items.map do |item|
      item.price * item.quantity


class Order
  def total
    result = 0
    for item in items do
      result = result + (item.price * item.quantity)
    return result

Both snippets accomplish the same result, but are written differently. Which one is better? The answer is it depends.

To some, the second code sample may seem uglier than the first and would probably get bad marks from linters like Rubocop. However, for a programmer coming from another language the second snippet will be easier to understand for two reasons:

  1. CODE SAMPLE 1 requires knowledge of class, def, .map, ||, *, .reduce(), &:+, as well as Ruby's implicit return. Whereas CODE SAMPLE 2 requires knowledge of fewer concepts: class, def, =, for, +, *, return.
  2. CODE SAMPLE 2 not only has fewer concepts, but the concepts used are almost identical to those used in many other programming languages.

The goal Copeland urges us to strive for is not to write ugly code that is cumbersome and simplistic. Rather, to remember the audience we’re writing code for might not be programmers exactly like us. We must consider the impact our code will have for programmers who are less experienced or come from an entirely different programming language.

Here at Doximity we primarily develop in Ruby on Rails. We use the syntactic sugar that Ruby and Rails have built-in, and we love it. We would proudly write CODE SAMPLE 1 and commit it to our codebase because we know our fellow engineers are Ruby on Rails experts. If a fellow engineer is a beginner, we’ll take the time to teach them the concepts we’re using in our code instead of simplifying it. There is no harm in this approach since the other programmers maintaining this code, in terms of Ruby on Rails expertise, are like me.

However, if we were maintaining a legacy application written in Java, we would likely create change sets that are more similar in style to CODE SAMPLE 2, with fewer concepts that are simpler to understand for someone with a Ruby background.

I too share Copeland's thoughts here. We must consider the potential diversity of the audience reading our code and employ the appropriate mix of elegance and simplicity. The result will be code that is more easily maintained and tailored to the changing needs of our company.

Thanks to Hannah Gambino for the illustration.

Be sure to follow @doximity_tech if you'd like to be notified about new blog posts.