HomeThoughts and MusingsThomas M. Tuerke on Design • Coding in Style
 

Coding in Style


Coding in Style

Code serves one purpose: to communicate intent. It does so to two audiences: the compiler that will reduce the code to machine instructions, and the hapless souls who will have to look at your code in the future... namely test developers, maintenence engineers, and the hiring manager for your next job. So good code is code that clearly communicates intent, both to the computer (so you don't introduce bugs) and to future humans (so they don't, either.)

The problem is, most coding standards don't attempt to improve the reliability of the code (except by the vague definition of "improving readability"—an attribute I call into question.) No, most coding standards are sorry things listing a bunch of superficial cosmetic issues like how deeply to indent, and where to place braces and parentheses. I almost never see a standard that says what to do, and follows it with an explanation why it is a Good Thing that such a practice is done.

In fact, I would argue that most coding standards—being purely cosmetic in nature—result in worse code rather than better, simply because eyes become lazy by seeing the same stuff all the time. And productivity often suffers, too. If all developers are ever exposed to is code written to one particular style, those developers will be completely out of their element when looking at a new piece of code, and let's face it: it will happen.

Imagine that you've managed to get all the developers on your team goose-stepping to one particular set of standards. Is that goodness?

Probably not.

  • Can you share code with other teams, "borrowing" something they've already written and tested? If you do, will you risk breaking that code (sending you back to square one testing-wise) by renaming all those identifiers and altering the whitespace and curly-brace positions?
  • What about Open Source? Third Party software? Will you rewrite that to "conform" to "standards" or will you leave it as it is? You know you're eventually going to have to look in that chunk of code. Have you budgeted for the additional testing effort, realizing that you've invalidated a significant chunk of the testing that has already been done on that code.

Unless and until the One True Style (which each developer assumes is the style they happen to use) is universally adopted, there will be a multitude of styles. Some folks will insist that identifiers follow lower_case_and_underscore convention, others ProperCase, others still camelCase, and this whole contingent over here will insist on piHungarianNotation. Some standards mix liberally, one convention for member variables, another for methods and functions, another still for class names. Microsoft has an elaborate naming scheme for its APIs, which it recommends. And then there's the bunch of developers who bristle at that: "yuck. it's too much like Microsoft's."

Let's face it: we're not going to agree on silly minutua, and quite frankly, I don't think we need to.

That said, I think there's a lot more to coding style than following a bunch of superficial regulations. I think that using a particular indentation style simply because founder Joe Codewonk said so is not a good enough reason, unless there is a clear material (read: not hazy, ambiguous, hand-wavy) benefit. Every single element of a shop coding standard should stand up to scrutiny. If it doesn't, it shouldn't be part of the standard.

Does each rule:

  • Catch specific kinds of coding errors in the compiler? (list which)
  • Catch specific kinds of logic errors at runtime? (list how)
  • Communicate intent to the subsequent reader? (describe how)
  • Make debugging and maintenance easier? (list how)
  • Make the code easier to reuse with a minimum of fuss? (list how)

Yes: note that each rule is required to justify its existence by listing how it contributes to the greater good of the code—and not just by allusions to "improved readability". And yes, note that by requiring to justify its existence, periodic review is sometimes necessary. Certain coding stipulations may be mandated by shortcomings of the environment, (I'm thinking "yoda notation" to overcome C-style languages' misuse of assignment for equality operators, or certain limitations in an editor or other development environment.)

As long as we're quibbling over capitalization, spaces, and curly braces, we're missing the point of coding standards. But once we get into styles of coding that transcend the cosmetic and materially result in better code, then we'll really be coding in style.


Replies: 2
RE: Coding in Style—Improved Readability
- Thomas M. Tuerke

Much of what is accepted as "improved readability" is really just laziness.

I'm currently involved in a project where I've collaborated with three separate groups, each having its own coding style. In fact, in the past twelve months I've had to delve into areas of code that adhered to about five or six different coding styles.

In no instance did the names of things, or indentation, or bracing improve or detract from readability. Admittedly, they were different but one was not inherently more "readable" than any other. This gives lie to the claim that these cosmetics improve readability. They don't.

What did improve readability was the liberal use of comments, describing what the intent of the code was. (Some pretty sorry comments really just mimicked the code in human terms: that was a waste.) Then there were vast wastelands where there wasn't a single comment visible on the screen.

What significantly decreased readability:

  • The extensive use of C++ #defines for complex (as in multi-statement) operations. Debugging through these was tedious.
  • The extensive use of templated types (and STL is a particularly bad offender here, in spite of its performance claims.)
  • Long, meandering functions that tried to do too many things. Some should have been factored into named sub-functions.
  • Overloaded methods that weren't logically related. A fundamental design principle is "same form => same function" so you would think that three overloads with the same name would do the same thing, but with three different kinds of arguments. Not so.


RE: Coding in Style
- Thomas M. Tuerke

Here are some non-cosmetic practices.

C and C++ have this construct where assignment is just another operator, and can be mixed in with other operations. This is cool, but the source of trouble, considering that the assignment operator is the equal sign (=), and the equality operator is the double-equal sign (==). As such, you can easily use one when you meant the other, as in

 if(theSky = "blue") // ...

which probably isn't what you meant. Therefore, some coding standards mandate that you use what I refer to as yoda notation ("backwards it is, yes!") where you reverse the operands so that the compiler won't let you do an assignment.

 if("blue" = theSky) // ...

will simply fail to compile, not letting you get by with = when you meant ==. Now, I'll say I really don't care for yoda notation, but the fact remains: you can't mis-use the assignment operator with it, and that results in better code, so if you're using C or C++, it's probably a good idea to use. (C# thankfully doesn't suffer from that problem, so yoda notation isn't as important there... but if you jump between C++ and C#, then it may be a good habit to maintain.)

Another code rule states that the break in a switch's case statement should always appear outside of any curly-brace block, as in

 case foo:
 {
   // ...
 }
 break;

as opposed to

 case foo:
 {
  // ...
  break;
 }

The reason for this is subtle but important. As the code between the braces grows (which happens in production environments) you might find it necessary to apply more logic, possibly as a condition (don't laugh or roll your eyes, this actually happened...) and somebody may (that is, did) quickly solve the problem like this:

 case foo:
  if(someCondition)
  {
    // ...

As you can see, if the block ends with the break inside, the break suddenly is conditional (and if someCondition is false, the next case, if any is executed instead. Yes, the maintenance programmer should have been more careful. Yes, the body of the case should probably be factored. Yes, object-oriented design says that switches are evil. But in spite of all that, they persist. So it makes sense to write code that is hard for somebody else to jeopardize. The original author allowed the error to happen as much as the later developer made it happen.