Much of what a senior developer does boils down to writing good code. Here are seven tips that make that easier.
It is commonly said that a developer should “always code as if the person who ends up maintaining your code will be a violent psychopath who knows where you live.” Senior developers take this quote to heart. So how do you actually do this?
Well, books have been written about that, but I want to share a few practices here that you can do starting today to write good code and be a better developer. These tips represent some of the more valuable lessons I’ve learned over the years of regretting the code that I wrote. After all, the worst coder I know is me six months ago.
Senior developers are fanatical about the details
No one likes a tedious pedant, but a good senior developer will risk being one to make sure that her code base does things in a consistent manner. A good senior developer establishes clear, understandable, and sensible rules and sticks to them like glue. She is fanatical about indentation, using a linter or a code formatter to make sure code is consistently formatted. She is fanatical about variable casing, even if her language is case-insensitive. She always uses braces around statements even if they aren’t required.
Basically, good senior developers know that if they take care of the little things, many of the big things will take care of themselves.
Senior developers name things well
The old joke is “There are two hard things in software development: cache invalidation, naming things, and off-by-one errors.” Yes, naming things is hard, but if you think more about how to avoid bad names, you can get most of the way towards the practice of naming things well.
First, remember that trying to conserve a few keystrokes is a horrible reason to choose a name. Short and abbreviated variable names are a vestige of a bygone era where terminal windows were 80 characters wide. Don’t abbreviate anything. Go ahead and type out grossWeight
instead of just gw
and netWeight
instead of nw
. You’ve got nothing to lose, and if you are worried about keystrokes, let IntelliSense do the work for you.
Along with not abbreviating anything, be sure to name things as completely as possible. Why name a variable length, when you can be more complete and call it lengthInCentimeters
?
Really, there’s zero downside to a long, clear variable name that describes the variable’s exact purpose.
Senior developers always use explaining variables
Inexperienced coders want to take shortcuts, and they may not even realize they are doing it. So sometimes they’ll write something like this:
```
function checkAccess(userRole: string, isAuthenticated: boolean, isAdmin: boolean, hasSubscription: boolean, isGuest: boolean): string {
return ((isAuthenticated && userRole === "member") ||
(isAdmin && !hasSubscription) ||
(isGuest && !isAuthenticated && userRole === "guest") ||
(isAuthenticated && userRole === "premium" && hasSubscription))
}
```
Now I don’t know about you, but my poor little brain has a hard time keeping track of more than about two boolean expressions at once. Instead of just figuring it in your head and writing out the first thing that comes to mind, it is infinitely better to take things step by step and break out each boolean expression with a name, piecing it all together into a single value, and using that in the if
statement:
```
function checkAccess(userRole: string, isAuthenticated: boolean, isAdmin: boolean, hasSubscription: boolean, isGuest: boolean): string {
const isMemberAndAuthenticated = isAuthenticated && userRole === "member";
const isAdminWithoutSubscription = isAdmin && !hasSubscription;
const isGuestAndNotAuthenticated = isGuest && !isAuthenticated && userRole === "guest";
const isPremiumMemberWithSubscription = isAuthenticated && userRole === "premium" && hasSubscription;
const hasAccess = isMemberAndAuthenticated ||
isAdminWithoutSubscription ||
isGuestAndNotAuthenticated ||
isPremiumMemberWithSubscription;
return hasAccess;
}
```
Note how those explaining variables make the whole boolean expression easy to follow. Using explaining variables can also make it easier to see what is what in the debugger, too.
Always choose to take things one step at a time and use an explaining variable so your code is clear and easy to follow.
Senior developers code against abstractions
Writing good code is about creating functionality. A good senior developer knows that the way something gets done can always be improved upon, so she will always code against some type of abstraction instead of a concrete implementation.
The idea is that a “radical new implementation” could be found at any time, and if you entangle yourself in a concrete implementation, it will be challenging to leverage the new solution.
But if you define an interface and code against that, you can easily “plug in” a new implementation without missing a beat.
Senior developers make and test one change at a time
It takes a few trips of spinning your wheels, but eventually you will learn that if you make more than one change and then test the new code, you can never be sure which change is the cause of problems that arise.
Keeping with the idea of doing one thing at a time and being slow and deliberate, wise developers methodically make one change at a time and see the effect of that single change before moving forward. This is particularly important in larger code bases with vast interdependencies, where making a change “over here” can have unforeseen effects “over there.” If the unexpected happens, you want to be able to know immediately which change caused the issue.
Senior developers ensure there is only one place to do anything
The maintainer of good code should never have to puzzle over “which of these three INSERT
statements is the one updating the database here?” There should be one and only one place where that kind of thing happens.
A senior developer never just writes code to do things in random places. If you have configuration settings, there should be one and only one place to read and write those configuration settings. If you need to update the state of a customer, you don’t just write the code in place. You use the code for the Customer
object to do it.
And if you need to change the behavior of any part of your application, there should be only one place that needs to change. If the same thing is happening in three different places, then a change to desired behavior means a change in all three places. Three places to change means two too many places where things can go wrong.
Senior developers don’t let anything get big
Big things make for bad code. Big classes and big methods are anathema to good code. We’ve all seen “God classes” and monster methods that are hundreds (thousands!) of lines of code. A good rule that I like to follow is never allow anything to have more than three code collapse lines.
IDG
All those vertical lines? Not good.
I’ve also heard it said that if you can’t see an entire method at once in your editor, it’s time to refactor.
The most basic thing to do in this case is to use “guard clauses,” or what is often called inversion. Deeply nested code often happens because there are a lot of nested if
statements. But if you invert the if
statement to “bail out if things aren’t right” rather than “keep asking if you can continue” pattern, you can avoid a lot of the brain-clogging boolean situations. Oftentimes, inversion can actually remove all of the nesting levels in a method.
The other strategy is to always extract code to smaller methods, so that no code block ever gets too big. Senior developers aren’t afraid of lots of small classes and methods. And of course, all those classes will be descriptively named, right?
Senior developers don’t comment their code
I saved this one for last because I know many developers get bent out of shape at this notion. I am, though, quite adamant on this point. I’m a firm believer that 99.9% of comments are an indication of bad code, bad naming, or a lack of explaining variables. If you feel the need to comment your code, it is almost certainly because your code is not clear and easily understood. If your code is not clear and easily understood, then it needs to be rewritten until it is. (Naming well and using explaining variables will help.)
In addition, comments are not physically attached to the code they refer to, and can actually go adrift, causing no end of confusion.
When is it appropriate to comment your code? Often there is code that has been optimized to use a strange or uncommon algorithm, perhaps for performance reasons. Situations like this—where there is a good reason to write non-obvious code—call for a code comment.
OK, so this list of guidelines is far from exhaustive. But if I were mentoring a junior developer, these are the seven practices that I would emphasize. They aren’t hard to do, but they are based on hard-won knowledge that is arrived at by experience. And unfortunately, it is often experience with bad code that makes a senior developer a great developer.