80 character line limits
There’s nothing more irritating when trying to grok code than scrolling around to see the entire line. It’s a mental context killer. While any text editor worth its disk space has the option to wrap text automatically, chances are your code will be read in an environment that doesn’t. This includes CLI programs (like diff and less) and web-based source viewers like Github. Don’t make people scroll, it’s mean.
At some point in computer history, somebody (
arbitrarily?) created an 80 character line limit for code. It’s formally documented in the Python Style Guide, and I think it’s totally awesome. This has two benefits. First, as I mentioned, you eliminate the need to horizontally scroll. More substantively, this promotes code simplicity. When you restrict yourself to 80 characters before a line break, you’re more likely to break statements up into smaller chunks. I don’t like clever code that crams a bunch of nested function calls into lines like this:
This is painful to read. There’s so much to parse mentally, and I might even have to scroll. I’d much rather read each meaningful chunk line by line, and then see how it all comes together:
1 2 3 4 5 6
While I can add line breaks to the original one-liner to make it conform to the 80 character limit, the limit annoys me into breaking things up into shorter, more obvious statements. I want to be annoyed into this, it makes my code more readable in the long run.
Strict-ish typing with annotations
The Google Closure Compiler has a lot of rules regarding code annotations. These are necessary to allow the compiler to perform the “Advanced” compile-time optimizations, and it blows up when there is a type error. The annotations serve to clearly communicate to the compiler what the expected inputs and outputs of every function are.
It turns out that taking the time to explicitly declare the input and output types of a function to communicate to the compiler have a nice side effect: The types are also explicitly communicated to humans! Let’s take an example of some magical code:
1 2 3
Simple enough, but what if we do this:
Whoops. If the client of this code assumes that
addNumbers will do any typecasting for them, they will get unexpected results. However, if we explicitly annotate the function, we leave very little open to interpretation:
1 2 3 4 5 6 7 8
Much better. Very clear, very explicit. We can even take this a step further and add some documentation for the poor soul who has to read this code in the future:
1 2 3 4 5 6 7 8 9
Now, you by no means have to get this detailed with every function that you write. If a function is simple and obvious enough, I often just annotate the types and omit the documentation text. Just be pragmatic about it.
All of the cool kids seem to really hate the
Well, I really like the
new keyword. When I see
new in code, I read it as “make a new instance of the following.” Here’s an example of why I like this clarity:
This is simple enough, but
kitty could be anything.
Cat could be giving us a
number, for all we know. I prefer this:
You may prefer to just capitalize your constructors, but I feel that using
new helps to clearly communicate that a function is actually a constructor.
Compilers are totally awesome. Generally speaking, you shouldn’t deploy production code unless it’s been compiled with tools such as the Google Closure Compiler or UglifyJS. For my open source projects, I prefer UglifyJS. I actually get better compression with Closure Compiler, but UglifyJS is easier to develop with. UglifyJS also has a few really awesome features. One that I’ve fallen in love with is code pre-processing with compile-time defines. This feature is a throwback from the C world, and probably other compiled languages that are older than I. In any case, using defines lets you tailor your compiled binaries to fulfill various requirements. For example, you can use defines to tailor a build for mobile platforms that need different code than desktop platforms.
I’m using defines for Rekapi’s testing hooks. There are some methods that I want to expose for my unit tests, but I don’t want to expose them in the compiled code that gets sent to users. It’s just wasted bandwidth and CPU cycles to parse it. Here’s how I set it up:
1 2 3 4
1 2 3 4 5 6 7 8 9 10 11 12
Kapi._private has references to a bunch of methods that will never be used publicly, but need to be exposed for testing.
KAPI_DEBUG is a global variable (eeek!), but is only present in the source code, not the compiled binary. This is thanks to my build.js script:
1 2 3 4 5 6 7 8 9 10
This tells UglifyJS to set
false when it is compiled. Because my debugging code is wrapped in conditional that tests the boolean value of
KAPI_DEBUG, it is marked as unreachable code and not included in the binary. Perfect!
Something to note: At the time of this writing, this feature is poorly documented, but a Pull Request is pending.
I code like an old man
new, and love a nicely architected inheritance chain. I don’t do these things out of obstinance, but practicality. I suggest that you adopt whatever coding style results in code that is readable to others.
I write code that is boring, because boring code is readable code. I would contend that readability generally has more impact on the success of a project than micro-optimizations and stylistic experimentation. If that means writing like a C coder in the 80’s, then so be it.