Sunday, July 3, 2011

Beautiful code == poetry

This post is long and a little on the non-technical side, but I think the implications are very relevant to the readers. You might be somewhat pissed that I'm not talking about how sweet jQuery is, but here goes.

How many of us programmers just drool over clean, self-documenting code? I do. I literally strive to have my code look like elegant poetry, so much so that I spend a good portion of my time refactoring. Some might call that over-the-top. I call it an eye for detail. I believe code is like literature; you have to write it in a way so that others (and more importantly a future you) can immediately understand what you mean without getting bogged down with pathetic, obscure syntax or poor style. After all, code is not meant to be "write-once". Moreover, a few years down the line, you want to be able to look back on your code and say, "Whoa. I used to write amazing code even back then".

I try to take extreme care about naming my functions in just the right way. So whenever I read it later on, I know exactly what it does. I won't say I'm very good at it, but I believe I'm getting better.

The language syntax is crucial to how readable the code is. That is one thing Ruby does well. Let's see a contrived example:

a = [1, 2, 3] + [4, 5, 6] - [5]   # = [1, 2, 3, 4, 6]
b = "blah"
return true if a.include? 4 and not b.empty?

Another thing Ruby is good at: Domain Specific Languages (DSLs). They're an attempt to make non-geeks write code to get stuff done easily. As an example, consider this: rocket scientists are good at space-talk, but bad at writing code. What if we could create a program which exposes an API that looks like rocket science? It doesn't get any cooler. The scientist doesn't need to know Ruby, only the API. He can think in terms of space shuttles and takeoff times and things like that. For example, a rocket science DSL in Ruby might allow a rocket scientist to write stuff like:

shuttle.fill_tank 50   # tank up 50 liters
shuttle.launch_after 3 if shuttle.prepared? # 3... 2... 1... go!

You might say, "Wait a sec. Isn't that your regular object-oriented code?". Yes, but normally we create that for ourselves. A DSL's API is meant to be used by the users to write code.

A related example comes to mind. The other day my friend and I were working on a DSL for access control in a web application, which controls what user gets to access what part of the application. The most important thing in a DSL, as you might've noticed, is the API. Everything else is secondary. We needed to name a function which would take a condition, and a result to be returned if the condition was met. We thought up names like make_rule, but we weren't satisfied. After some brainstorming, we came up with an API like this one:

given :condition => user.admin?, :return => true

I feel the function name given is the most important thing in this API. It conveys the purpose unambiguously and reads like natural English. Any other name would've made it confusing or misleading. And remember again, some John Doe titled "Maintainer" at a company is going to be using this API directly, without being good at Ruby, that's why the nomenclature is so very important.

If you're more of a JavaScript guy, you should check out CoffeeScript. It's "a little language that compiles into JavaScript", with and Ruby and Python-inspired syntax. Imagine being able to write stuff like the following and have it run as JavaScript:

volume = 10 if band isnt SpinalTap
letTheWildRumpusBegin() unless answer is no

I've presented my (rather long) case. Let the comments fly.

UPDATE: We're finally done with the access control DSL, and the API now looks like this:

given :condition => { => :admin, => [:create, :show] },
      :return => true

isn't that beautiful? :)

If you like this article, consider following me and Rajat on Twitter.

No comments:

Post a Comment