How many times have you heard something to the effect of "Now that's beautiful piece of work?" I heard it often when I was an undergraduate. In fact, I distinctly remember Dr. Homer Austin using a phrase like that to describe the Fibonacci sequence.
After graduation I became a computer programmer, not a mathematician. With that, the word "beautiful" dropped from my professional use, if not from my professional vocabulary entirely. Still, one thing that was made very clear to me in school was that beautiful solutions were good solutions. Applying that to software development begs the question--what is "beautiful code"?
Someone might suggest that commercially successful code is beautiful, but that doesn't really help much--a "killer app" might be a great app, but its code could be ugly. Many code programs contain comments along the lines of 'here be dragons', and the expression "Don't touch fooboggle, it's huge, it's ugly, but it works" is no rarity. These functions may work, but they aren't beautiful--all we have identified is the absence of software goodness. This makes me wonder: What elements of "beauty" is all that bad code missing? If that code were different, how would it be different to beautiful? What does beautiful code have that bad code does not? After some thought, I've come up with a few things that I have consistently seen in code that I would call beautiful:
- Beautiful Code is readable. Perhaps nothing is worse than trying to maintain software that does everything yet no one understands. This means that our functions shouldn't be too long and should accept a reasonable number of variables. What's "reasonable"? Military science (and chess, for that matter) teaches us that most people can only keep 3-7 variables in our head at the same time. When we get beyond that, we lose track of things, and that means we have forgotten things, which means defects. At that point, it's time to consider breaking our software into smaller chunks.
- Beautiful Code is Focused. Code should do one thing, and do it well. All the object oriented theory about model-view-controller is essentially an attempt to separate the user interface from the business logic from the back-end system. Mixing these up limits reuse and makes test automation look more and more like fantasyland. I will just say that we should strive for simplicity and generality--to do one thing and do it well. I would submit, however, that this subject is worth researching.
- Beautiful Code is Testable. A well-defined function, given specific input, should have a clear expected output. This makes sense, yet many functions are written with "out of bounds" behaviors that are undefined. For example, consider a function designed to take in a coupon_id and determine if that coupon is valid. You can write the function signature in pseudocode in two different ways:
- Option 1:
sub get_eligibility_of_coupon(coupon_id) returns boolean;
- Option 2:
struct eligibility_type(ok boolean, msg string, good_coupon boolean); sub get_eligibility_of_coupon(coupon_id, optional date assume sysdate) returns eligibility_type;
Assume a coupon_id is an integer. What happens in option 1 when you pass in -1? Or, for that matter, any value that isn't a valid coupon? Or Null? We don't know. To test option 1, we need to know some coupons that are valid or not valid as of right now. We probably have to write a query.
For option 2, we can create a list of coupons that are valid as of a certain date, then pass in that date. We can test all kinds of interesting scenarios like "what happens on leap years?" We can provide a different response if the coupon_id was invalid than if the coupon_id was just expired. In short, option 2 is testable. Murphy's Law applied means that testable code is better code.
- Option 1:
- Beautiful Code is Elegant. I've heard it said that the charlatan makes the simple seem hard to understand, and the genius makes the complex easy to understand. Elegant Code (like recursion) shows up when the complex program has a simple solution. When the specification is three pages and the code implementation is one. It's hard to grasp "elegance", but we've all seen bloated, bug-ridden code that was not elegant. If you're like me and can't clearly define elegant, then my suggestion is simple: When coding, remember buggy, junky code, and create software that is the opposite. Elegant code is powerful code. Perhaps that is why I like perl so much; it's very constructs allow me to build simple solutions to complex programs. As Antoine de Saint-Exupiry said so eloquently: "Perfection (in design) is achieved not when there is nothing more to add, but rather when there is nothing more to take away."
I am not suggesting that this is a complete list on how to make beautiful software; it is just a start, a jumping-off point. I think it makes a point: Instead of searching for some automated measure of our codes efficiency in (lines of code)/function points + (1/defect density) blah blah blah perhaps we should be striving for beauty in our work because we believe that beautiful things are better. Perhaps we should be building and weighing our own list of what makes beautiful code. In fact, you could submit that beautiful code should fail gracefully, or Design-By-Contract , or have a unity of design, or a dozen other things. Even without conclusion, the very discussion is healthy.
Why should we study software beauty? Well, think about the list above. Beautiful code tends to be smaller--so we can write more powerful software in less time. It tends to be testable, so we can improve it's quality and more confidently maintain it. Because it does one thing and is well-separated, beautiful code lends itself to re-use, which results in still more functionality delivered in still less time. In short, beautiful code is good code. If we write more beautiful code, we will be better programmers. When people try to compare personal improvement in art to improvement in software, that's about the best I can come up with.
The good news about code beauty is that it is a space that hasn't been explored much; there is plenty of room for us to make our mark on the body of knowledge.
Ronald Jeffries, Andy Lester, Dr. Paul Jorgensen, Scott Kiwilski, and Chuck Dreyer contributed to this article.
Matthew Heusser is Technical Project Manager at Priority Health, where he manages in-house, integration, and outsourced software projects. He can be contacted at [email protected].