Advice abounds for writing good code. But day-to-day, I live by just a few guidelines. These 5 essentials will transform your code into something you and your teammates can enjoy maintaining.
1. Self-documenting names
Good naming goes a long way toward understandable code.
- A name should describe what the thing is or its intent as clearly as possible.
- Don’t be afraid to be verbose if it’s the only way to improve understanding.
- Avoid acronyms, unless they’re universally accepted and well-known in the domain you’re coding in.
I always write code in at least 2 passes. I don’t stress over names during the initial draft. But by the time I’m doing a final edit before code review, I make sure the variable and method names I’m using are as descriptive as possible.
2. Right-sized classes and methods/functions
The ideal method length is debatable, but smaller is generally better.
As usual, our job as a developer is to bring our good judgement to bear and balance things. The code should be able to tell its story without an extreme amount of jumping around, and without page-long methods that mix details of several different concerns.
The general rule I use is to consider refactoring a method if it’s over 25 lines. But most importantly, if a method has multiple concerns in it, see if one of them can be packaged in its own method and given a self-documenting name.
A run of 50 lines of code is probably exposing details that aren’t as important for the reader to know vs the method’s overall purpose. Imagine splitting it into 3 methods, named in a way that essentially tells a story with a beginning, middle and end. Do this. Do that. And finally, return.
When it comes to classes, a class should strive to have a single purpose or responsibility. These things tend to grow over time, as maintenance work adds things bit by bit.
It’s usually not easy, but be on the lookout for themes or concerns that can be extracted out to its own class. For example, if your class makes use of an external API, the code related to that (invoking it and error handling) could be factored into its own “API client” class. This moves a non-essential concern out of your original class, and provides a simpler interface to the API as well.
3. Comments that tell why, not what
Some people frown on comments, but I don’t. They just need to be the right kind of comments.
Do your comments just repeat what the code is already saying? Instead, they should explain the why, the context that can’t be seen in the code itself.
Use context-providing comments generously. But whenever you finish writing a comment, ask yourself if there is some better variable or method naming that might eliminate the need for the comment.
Making your code supportable could mean different things depending on your project. At the minimum, think to yourself, “after I ship this code, if there is a problem, how will I know?”
What information will be most useful to you for debugging?
Your production environment should support some form of logging and monitoring.
Use logging to trace important state or key branches the code takes. You should be able to search the logs later and observe the general path and actions the code is taking. When you’re debugging an exception, these logs can be crucial to understanding the events leading up to it.
Sometimes your code will have cases that “should never happen”. These are good candidates for a log message or even throwing an exception.
Be careful to never log passwords or other secrets. Sometimes it isn’t clear where a log file ends up, within or outside your organization, and you wouldn’t want sensitive information to be exposed.
Exceptions and null checking
When it comes to unexpected errors, don’t hide them with empty catch blocks. It’s usually better for something unexpected to bubble up and be captured by a monitoring tool.
Maybe your code received some input it didn’t expect? A case you didn’t think of? Now that you have the exception in hand, and hopefully some logging, you can use this information to dig in and broaden your understanding of the system, and make adjustments to the code so the exception doesn’t happen anymore.
Is your code checking for null “just in case”? An unnecessary null check will cause the reader to wonder why… under what circumstances would this be null? They may be forced to scour the surrounding context to understand it.
In your internal code, only check for null if it has a clear and obvious meaning within the story the code is telling. For example, calling another method to find something and it returns null if it’s not found.
Providing a public API is different, and it may make sense for your implementation to check for and raise errors for invalid arguments.
This may seem shallow, but teammate-friendly code just looks nice. Yes, beauty is in the eye of the beholder, and perhaps with code, opinions range dramatically, but do your best to pay attention to the following:
- Consistency with surrounding code. When in doubt, just follow the conventions already in place, unless you’re looking to rework it all.
- Adherence to programming language and community norms. Many communities have a strong, well-accepted style.
- Thoughtful use of whitespace. Group related lines, like a paragraph in a story, then separate blocks with whitespace.
- Line length. Format longer lines so they wrap nicely, or use a well-named temporary variable to break things up.
- Spelling and formatting in comments. Yep, I’m one of those people.
These may seem silly, but the idea is to prevent any distractions to the reader as they try to understanding what your code is doing.
Many of these practices can be enforced by the linting tools available for your language.
There’s no such thing as perfect code. Our job is one of trade-offs.
Sometimes when I look back on code I wrote a year ago, I cringe. That’s ok! It means I’m growing and improving.
As you’re writing code, consider that the seemingly obvious today will not seem so obvious a month or year from now, when all the context you have built up in your head is gone. With that in mind, how will you name and structure things? What will your comments say?
The last thing you want is for your teammates to perform mental gymnastics to understand your code.
If nothing else, follow this Martin Fowler inspired, golden rule of coding: write code not for the computer, not even for yourself, but for your fellow teammates.