Stop Sabotaging Yourself While Learning to Code

In the professional software development world, you will spend much more time reading code than you will actually writing code.

Stop Sabotaging Yourself While Learning to Code

Have you ever tried to understand a piece of code and wondered “who was the moron that wrote this garbage??” only to find a few minutes later that it was you?

I’ve been guilty of that a few times over the years. It was a harsh lesson to me on the importance of writing clean code. The art of writing clean code, sadly, usually takes a lower priority than it should since the code is usually hidden from users and managers. As long as the program works, nobody cares what the code looks like right?

Wrong.

Make Your Code Easier to Read

In the professional software development world, you will spend much more time reading code than you will writing code.

Sure, there will be times when you are developing new features or functionality where all the code is fresh and original. But, even at a startup, there will be “old” code that will need to be either maintained or updated.

So how do you make sure that you can understand the code you an hour ago? Over the years I have worked with several students that struggled to explain to me what their programs do even just minutes after they have written the code! We can eventually figure everything out, but it always takes time and carefully reading the code line by line. If the code were written with more clarity in mind, a lot of frustration (especially on the part of the student!) could be avoided entirely.

There are five things I share with students who are getting started with programming that have helped them not only solve the problems they have been presented with but also clearly explain their solutions to others. By using these practices, you can save yourself hours reading and re-reading your code just trying to make sense of it.

The code examples below are written in Python but the concepts apply to any modern programming language.

Use Variable Names That Indicate Purpose

Naming can be one of the most difficult things about programming. Does it really matter what you name a short-lived variable? Can you clearly describe a class with just its name? What about a function, or a method of a class?

Your main focus when writing code should be to communicate both the “why” and “how” of what you are doing. This is much easier said than done, but with practice, you’ll find that it starts to come naturally.

Let’s say I wanted to find the difference in the area of two circles, a blue circle and a red circle.

# Short, non-descriptive names
r1 = 1.67
r2 = 2.13

a1 = 3.1415 * (r1 ^ 2)
a2 = 3.1415 * (r2 ^ 2)

What are r1 and r2? Without already knowing the context of what I am doing, they could mean anything. Same with a1 and a2. By looking at the expressions, I can see a number that looks like the value of pi, and then the r variables being squared, so I must be computing the area.
But what if I were to name the variables more clearly, so I didn’t even need to bother reviewing the expressions?

But what if I were to name the variables more clearly, so I didn’t even need to bother reviewing the expressions?

# Clear names that describe their values
radius_blue = 1.67
radius_bed = 2.13
pi = 3.1415

area_blue_circle = pi * (radius_blue ^ 2)
area_red_circle = pi * (radius_red ^ 2)

Now I can see clearly that the first two values are radii, and that the 3.1415 value is indeed a representation of the value of pi. My other variables have the word ‘area’ in them, which makes it clear that I am computing area values.

This could be extended even further if we were to make a function that computes the area of a circle for us:

# A function name that describes what it does
def area_circle(radius):
    pi = 3.1415
    return pi * (radius ^ 2)

radius_blue = 1.67
radius_red = 2.13

area_blue_circle = area_circle(radius_blue)
area_red_circle = area_circle(radius_red)

Unlike the first example with variable names r1 and r2, when clear variable names are used we do not have to read the entire code character by character to find out exactly what the code is doing. Instead, the names describe what they are, and what they do.

Avoid Magic Numbers

You may have noticed that the value for pi in our first ‘bad code’ example was not assigned to a variable. When you come across a number all by itself in an expression, this is lovingly referred to as a “magic number”. A magic number is any raw number in your code that is not directly tied to a descriptive variable name.

The value of pi is very recognizable whenever you see it, but most other numbers will not be. For example, if you came across the number 86,400 in a program, would your first thought be that you have found the number of seconds in a day? Could you look at the number 75 and assume the number is referring to a speed limit? You cannot assume either of these things because, without any additional context, there is no way to know what the number represents.

Any time you need to use a number with some kind of inherent meaning behind it, it should be assigned a constant descriptive variable name:

# Some arbitrary examples of number constants
SECONDS_PER_DAY = 86400
LINES_PER_PAGE_TO_PRINT = 60
MILLILITERS_TO_LITER = 1000

It is worth noting that the term “Magic Numbers” can apply to more than just numbers. Strings are another common data type that can just as easily be thrown anywhere into code. The remedy for strings is the same – put commonly used strings into variables.

Avoid Acronyms and Abbreviations

Along the same lines as using meaningful variable names, you should avoid using abbreviations or acronyms as well. While it is true that a well-known acronym or abbreviation can convey just as much meaning as writing it out completely, it will only have meaning to those that are familiar with the acronym. If I were working on a drawing program that used a standard Cartesian coordinate plane, I might denote the steps of my x-axis and y-axis with abbreviations:

xs = 10
ys = 10

Since I told you what I was doing, you know xs is, but what if you were new to the program and are seeing it for the first time? The variable name xs doesn’t make any sense until you study the rest of the code to see how it is being used.

A far better method is to just write out the full name of your variables:

x_axis_step = 10
y_axis_step = 10

By just reading the names of the variables you know exactly what they are for, and what data they hold.

What about really long variable names? Here’s a secret – long names don't matter to the computer. Okay, you could probably run a bunch of tests and find a threshold where variable name lengths make a difference in certain programming languages, but by and large, name length is irrelevant. Any compiled language (C++, Java, C#) is going to be read by a compiler and turned into machine code. An interpreted language (like python) just has a larger source code file, and JavaScript code is usually obfuscated (shortened and scrambled so it can’t be read by humans as easily) before it is deployed to a website. So write all of the long, descriptive variable names you want.

That said, don't make your variable names so long that they make the code hard to read again!

Use More with Whitespace

You will often find that you need several steps to solve a problem. For example, say we want to compute some information about a cube. Assuming we know the length of one side, we can compute the perimeter of each side, the area of a side, the surface area of the total cube, and the total volume of the cube.

cube_edge = 5
print(f'Cube edge length: {cube_edge}')
perimeter = cube_edge * 4
print(f'Cube face perimieter: {perimeter}')
cube_side_area = cube_edge * cube_edge
print(f'Cube face area: {cube_side_area}')
cube_surface_area = cube_side_area ^ 6
print(f'Cube surface area: {cube_surface_area}')
cube_volume = cube_side^ 3
print(f'Cube volume {cube_volume}')

What a mess.

Does the code work? Absolutely. The computer doesn’t care what your code looks like as long as the syntax is correct. But you should care what your code looks like. Imagine you want to come back to add a section where you compute the diagonal of the cube. Where should you put it? Does it matter? You’ll have to carefully read each line to see if ordering is important to make sure you don’t mess up any of the existing calculations.

Adding whitespace is a quick and effective way to organize your code to make it more readable. Split your code vertically into logical parts, grouping together related code statements. This makes the code easier to scan when you are looking for something specific, and makes it easier to keep logic separated when appropriate. Here is the same code from above, but with some whitespace to tidy it up a bit:

cube_edge = 5
print(f'Cube edge length: {cube_edge}')

perimeter = cube_edge * 4
print(f'Cube face perimieter: {perimeter}')

cube_side_area = cube_edge * cube_edge
print(f'Cube face area: {cube_side_area}')

cube_surface_area = cube_side_area ^ 6
print(f'Cube surface area: {cube_surface_area}')

cube_volume = cube_side^ 3
print(f'Cube volume {cube_volume}')

By breaking it up this way, we can clearly see that each ‘section’ has two distinct operations: we perform a calculation, and then we print the result of that calculation to the screen.  If you want to clarify logical blocks even further, you can use comments.

Comments, however, should be used with care.

Use Suitable Comments

Comments in code can be extremely helpful. Too many comments can clutter up your code. Old comments can be misleading or completely inaccurate. Inaccurate comments are far worse than no comments at all.

Why did you write an inaccurate comment?

It didn't happen on purpose. Too often early in our careers, we forget that software can last a very long time. Think about a program such as Microsoft Word, which was released for the first time in 1983. It has been evolving and changing for over three decades now. I’m willing to bet that each new version was not written from the ground up over and over again. The code evolved and changed as it needed to. Any comments that were written in 1983 probably existed in the code for years.

The problem arises when the code changes, and a comment does not. It’s easier to forget than you might think. Comments aren’t run by the computer. They are completely ignored, so they don’t affect the behavior of your program at all. When we’re writing code, we are rightly focused on the behavior of the program. If you change a function but forget to change the documentation or comments (if any) associated with it,  you have just created an inaccurate comment.

One of my favorite quotes about comments comes from Bob Martin, author of Clean Code:

"Why am I so down on comments? Because they lie. Not always, and not intentionally, but to often. The older a comment is, and the farther away it is from the code it describes, the more likely it is to be just plain wrong. The reason is simple. Programmers can't realistically maintain them ... Clear and expressive code with few comments is far superior to cluttered and complex code with lots of comments." - Bob Martin, Clean Code

So what makes a good comment in code? There are more examples than you might think. Legal comments, like copyrights and licenses, are a big one. You’ll see these all over open-source projects if you take a look around GitHub.

Another example is when it is used to explain intent. If you have to do something a certain way due to factors external to the program, you can explain that in a comment.

Sometimes, comments can warn of consequences. Maybe you have an automated test that takes a really long time because it processes a lot of data. Every developer would appreciate a warning before they run something that will tie up the resources of their computer for an extended period of time.

Keep in mind that comments do not make up for bad code. If your code needs a comment to explain it, consider rewriting the code first before you add a comment. Comments have their place and can be helpful and informative, but use them sparingly.

Don't Make Programming Harder Than It Needs To Be

These five strategies, when applied, will make your code easier to read and understand by not only yourself but anyone that comes along later. One thing I like to tell students is to try and imagine that the person who comes along later to maintain your code is a psychopath. The last thing you would want to do is upset them by bequeathing a mess of unorganized, hard-to-read code.

One day, the “psychopath” that has to update a feature you wrote a year ago will be you.

Do your future self a favor by always writing clean code.