Sunday, July 25, 2010

Regarding Coding Style Goals

I'm currently creeping my way through a Javascript book. It's taking longer than I would like since it's not high enough on my priority list at the moment, and because it's summer. In the interest of keeping things rolling, I thought I might write about code aesthetics today. Everyone who programs has a slightly different preferred coding style. Here are a few of the things that I love to see when reading code and strive to do when writing it. Take a moment and think about general coding practices you like. Now you can be amused by how similar, or different, our priorities are.

When I'm reading code, I love seeing things that improve my ability to grasp both what the code is doing and where that piece fits in the larger whole. Descriptive naming is a huge help, and it goes beyond just what you call your functions and variables. I enjoy seeing complex Boolean tests broken into logical parts using descriptive Boolean variables. Meaningful constants in place of literals, especially numeric literals, are a joy to read.  Naming in libraries can help their users understand not what they are but their focus as well. Whether I prefer seeing a pattern like FileOpenFileRead, and FileClose to OpenFileReadFile, and CloseFile in a function library depends on what the library is for. The naming should reflect the usage pattern. If the library is focused on file I/O, I like the File part first. If it's a generic I/O library that provides similar operations across a large type of targets, put the operation name first and the File/Socket/PrintBuffer part next. I usually name GUI widget variables using the style of typePurpose, resulting in names such as labelTitle, and buttonStartCountdown, to make them easier to find both in graphical designers and the code. Similarly, I like to reflect class hierarchies in their naming. For example, think about an abstract socket class and two concrete subclasses implementing UDP and TCP sockets. I prefer the naming to help me see not just what the classes represent, but their relationships too. So, I wouldn't call them AbsSocketTcpSocket, and UdpSocket. Instead, I'd call them SocketSocketTcp, and SocketUdp, or something along those lines. Note the effects on auto-completion with this scheme: typing the base class will give you the subclasses because the name directly reflects the inheritance relationship.  And you can't talk about clarity without mentioning comments. Comments that tell why something is being done the way it is are often more important than comments that tell what is being done. And of course, misleading, incorrect, and out of date comments can quickly destroy your code's clarity.

Having similar things work similarly seems obvious, but I'm sure you've seen code that just doesn't do it. If the existing methods in a class report errors by throwing an exception, I don't want to add a new method that uses a return code, and vice versa. I like seeing consistent parameter ordering in related routines. Using I/O library example from above, I'm going to be much happier if all of the routines take their target identifier in the same relative position in the parameter lists than if some of them have it first, others last, and a few somewhere in between.

Having, and enforcing, coding style conventions is a big deal. They help keep you reading code rather than having to stop and check if the indention is misleading or if there is some significance to that one variable using underscores instead of being camel cased. And I doubt anyone likes having to change their editor's tab/indention settings every time they change what they are working on. It's just one more niggling little thing to forget. Personally, I'm a huge advocate of the generic conventions put forth in the second edition of Code Complete. To paraphrase a recent political slogan, yes we can use the same coding style across all languages.

Simplicity is a big pet peeve of mine. The KISS rule has real benefits. Writing working code is hard enough when you can keep the model in your head, and my memory is poor enough that I really hate extraneous noise. I strive to keep the noise down when I can with these personal rules. Avoid routines that do nothing but call one other routine, they can be an indication of poor design. (Language specific things such as compiler chaining and faking default parameters get a pass on this. Sometimes.) Don't create a whole new class when a method will do. An abstract class with only one subclass wastes programmer and compiler time. Really think hard about inheritance. Using true subtypes should reduce the complexity of the code. If it isn't, I may be coming at it from the wrong angle. Would composition be a better fit than inheritance? Can I use conditional statements instead, or will that cause me headaches later? Write classes/routines for specific tasks unless you already have a concrete reason for them to be more generic. Try to keep paths between where data is stored and where it is used as short as possible (ideally this would be handled within a single class/set of routines).

I tend not to follow this rule in my writing, but I do try to in my coding. The less code there is, the fewer places you have to check later to find defects. I try to follow the DRY rule. Comments that just restate code are always annoying. Plus, I have a pathological hatred of redundant header comments. (Why do I need to write the name of the routine in a comment right above the syntactic definition of that name!) Brevity speaks to design in a very similar way as simplicity, for instance not adding a transformation layer to code when you can correct the data differences to not require the transformation in the first place. It's worth noting that as code ages, it gets harder and harder to maintain brevity in the face of normal development accretion.

There are real tradeoffs between these goals, and in general I have listed them in my order of preference. I'd rather the code be clear than brief, and prefer consistent to simple. Striving for all of them at once is one of the things that makes programming fun (and frustrating). Actually achieving them all produces what a colleague once referred to as really sexy code.

No comments: