Code is written once, but read many times. Given this truth, it makes sense to prioritize read-ability over write-ability. Readable code contains good variable names, uses appropriate abstractions and is understood easily. Many have waved the flag of ‘Clean Code’ for quite a few decades now.
What has helped me write code that I consider clear and readable is something I call Literary Programming. Not to be confused with Literate Programming. I would change the name of my concept but I’ve grown rather fond of it. Apologies in advance.
What I call Literary Programming is the deliberate application of structured grammar and story-telling into the naming, abstracting and composition of code. It is the conscious act of letting your code capture a narrative with your choice of words. Not leaving intentions and actions in a state of vagueness; method names should reflect what is actually being done within and the meaning of the return value, intermediate variables are encouraged.
Don’t overanalyze what I am trying to say. This isn’t a very strict set of rules. It may just be synonymous with ‘Good Code’ to you. It is a simple idea meant to inspire a little more scrutiny in you when creating APIs, choosing names, composing expressions and designing the structure of your application.
Here are just some ways you can make your more literary:
- Use abstractions to ‘shorten’ portions of code. Simple example: putting argument and configuration parsing in a separate function to keep the rest of the
mainas clean as possible.
- Put great care into class API design; as much detail as possible into method names. Prefer a name like processIncomingMessages() over process() or messages(). getOrCreateItem() over getItem() or createItem() for a method that will return an existing object if it already exists.
- Value consistency. One method shouldn’t be named bool error() while it’s counterpart is named bool isValid().
- Use intermediate variables to compose expressions. These variables serve as logic checkpoints for the future reader.
- Wrap complicated loop conditions into a boolean-returning functor. Take this call site as an example:
while (continueRunning(itemsLeft, maxItemsToProcess, error)).
- As mentioned before; good naming pays dividends.