Having worked as a "heads down" coder for 15 years, I’ve worked in many code bases, some welcomed me with beautifully laid out architecture or had implemented custom frameworks that handled 90% of the business use cases out of the box! Others were a patchwork of ideas held together with hard work and a bit of luck.
Why readability matters
Most developers will eventually be tasked with fixing a bug or adding a new feature to an unfamiliar system. This is usually far more difficult than clean sheet development as the developer is confined by the system they’re working in.
Most developers have heard the term Tech Debt, poorly designed systems which require extra steps to complete simple tasks or the reliance on outdated systems which need to be replaced.
Code fragility is another issue most developers face, fixing a bug or adding a feature becomes a nightmare cycle of creating additional bugs for every code change with no reasonable fix other than hacking something together or re-engineering larger sub-systems.
Let’s explore a few things to look out for while coding...
Function naming:
Say my name!
One of the hardest things in software development is the naming of methods, functions, and variables. Don’t be scared to give a long descriptive name; these can by-and-large take the place of comments in your code, if done in a thoughtful way; allowing you and other developers to move more quickly and confidently through code.
Functions/Methods performing one action:
Do one thing, and do it well!
It is generally up to developer or team discretion as to what a single action is. The determining factor is less important than implementing a good strategy to break large complex code into small bite size chunks.
Single actions make naming easier by narrowing down what the method/function does.
Code re-usability:
Do you see a pattern?
Over time, you’ll notice repetitive actions or bits of code which would be great to pull out as an extension method, class library or into a utility file. The coding standards you and/or your team follow will determine the best location, but generally shared code should only be as accessible as needed. This reduces naming conflicts and removes unneeded options when using IDE’s with autocomplete.
Magic strings & numbers:
abracadabra!
Developers will run into situations where hard coding a value is a better use of their time over making it configurable through other means. Some developers will inline the value in code, e.g:
if (person.Id == 12)
{
}
This doesn’t give any context as to what the number 12 represents; depending on the skill of the developer, this could take anywhere from seconds to hours to determine. Like most things in software development, this problem has a few solutions; one would be to pull the magic number out into a variable such as var admin = 12, or the developer can pull this whole statement out into a method named IsPersonAnAdmin(). Either method gives instant context as to what the number 12 is referencing.
Coding standards, code style:
Where being diverse is not a strength
My first boss had a rule “I shouldn’t be able to tell who wrote the code by reading it”, the sentiment being everyone working in a code base should do their best to follow the implemented coding style and standards with any future changes.
Developers have multiple tools at their disposal to enforce coding style. Setting your IDE to auto-format on save is a great way to be sure all files follow whatever standard you and your team come up with.
Coding standards are something more likely to be caught during a merge request or peer review. Some IDE’s will help enforce coding standards by bringing attention to the issue or by breaking the build, if set to do so.
Terse code:
Shorter code, not necessarily a good thing!
As we refactor code we might run into a situation where we can shave off a few lines of code by using inline variables or using newer techniques to condense code. On the surface that might sound amazing! But what are we losing in readability?
If there are no performance gains or legibility concerns, there is nothing wrong with verbose code. Just remember, the time saved in future development typically outweighs a smaller file.
Hide complexity:
How do you eat an elephant?
Compartmentalizing code hides complexity by turning large tasks into bite size chunks, this allows developers to focus on each problem one at a time.
Most tasks have obvious steps; and these steps are a great place to start breaking our code into methods/functions on our quest to implement single responsibility. Each step will likely have a set of steps themselves, these steps should be further broken down into reusable chunks of code. Continue this process until each method/function can be given a single action as a name which describes what that bit of code will accomplish.
Comments:
What about comments?
Every tool has its uses and comments have a place in our code just as much as the if statement does. Comments can be used to add more context to obscure or complex code in a human readable format.
A.I
Hello Dave…
We’ve all dabbled with A.I to generate code and the results are generally a mix bag.
One thing that would improve generated code greatly is being contextually aware of what it’s being asked, institutional knowledge carried by developers will never be answered correctly by a prompt.
In Closing:
Finally!
None of the information I’ve gone over today is groundbreaking, new and likely not the first time you’ve heard it. But when we feel the time crunch and doing things “the right way” is the first thing that gets cut to make a deadline, know that this will delay future features. As an example, we’ve all hard coded a value to ship a feature out the door only to spend 3 hours late on a Friday 6 months afterwards trying to figure out what the value denotes! Now imagine the developer who runs into that value 3 years from now after you’ve already moved on, because I’m sure you’ve been there as well.
Thank you for reading!