5 Ways to Write Cleaner Code Quicker
Photo by Sarah Dorweiler on Unsplash

Cutting corners to meet development deadlines is common. But it will always come back to bite you. At some point, someone will come across what you have done and have to negotiate their way around it. They might spend two hours trying to decipher the logic, or, more commonly, they might just build on top and leave someone else to deal with it.

This is how projects die. Not through intentional sabotage or consistent abuse, but the evolution of a few shortcuts.

Don’t expect deadlines to change, no matter how unreasonable they are. Stakeholders don’t care about you. Find ways to write clean code quickly.

The following rules will help with that.

Use TDD

Photo by Green Chameleon on Unsplash

TDD stands for test driven development. It’s a method whereby you write tests before logic.

Consider the following pseudocode for a function.

if inputNumber = 0

return inputNumber

else if inputNumber = 1

return inputNumber * 2

else

return inputNumber * 10

To implement this using TDD, you would first write a simple test with a simple assertion. For example, we can see this function should return 0 if we pass 0, so we would write a test like the following (note: I’m using JavaScript for this, but it works in any language).

Now, you would write logic to pass the test. The simplest way to do this is to make the function return 0.

Since the test is passing, we can take the next assertion, i.e. the function should return 2 if the input is 1, and write a test for that.

This breaks because we’ve built the logic to only pass the first test. So now we write the minimum code required to make both tests pass together.

Repeat the previous process for the final assertion, where the function should return any other input multiplied by 10. It’s a good idea to write two or more assertions for something like this to increase comprehensiveness.

Make it pass again without breaking the other tests.

And done.

You’ll notice that we’ve changed how the function handles the 0 value. This is an important part of TDD. Every time you write code to pass another test, you refactor it.

TDD can be applied almost always, and is actually better for situations more complex than this.

TDD:

Ensures all your logic is covered, because you only write what is needed to pass the test

Practically writes the logic for you, because you break it down into simple, manageable steps, rather than trying to think of it all at once

Acts as clear documentation for your code

It is one of the best ways to write clean code quickly.

Avoid nested logic

Photo by Edvard Alexander Rølvaag on Unsplash

Here’s some pseudocode for a function that calculates redundancy pay.

if employee's age < 20

redundancyPay = 0

else

if employeeRole = management

redundancyPay = employeeTerm * (annualSalary * 0.05)

else

if employeeTerm <5

redundancyPay = employeeTerm * (annualSalary * 0.02)

else if employeeTerm > 10

redundancyPay = employeeTerm * (annualSalary * 0.04)

else

redundancyPay = employeeTerm * (annualSalary * 0.03)

And here’s a way we could write it.

You’ve probably seen code like this, and to be fair, it reads close to English. It’s also a relatively simple example. But imagine more realistic code, where you might have to mix in API calls or more complex logic. You can imagine this getting out of hand quickly.

The best solution is to avoid code like this altogether, i.e. commit to one level of nesting in a function. Anymore, and you break it out into a new function. Consider the following refactored code.

This code is cleaner and much easier to understand. It also wouldn’t take any longer to conceive of this code than it would the first example if you knew from the start that you didn’t want more than one layer of nesting. You might encapsulate all of these functions inside a file which exposes a single entry point. You can also test all of these functions individually, which will make your tests simpler, because they’ll only be dealing with a single part of the logic rather than the logic as a whole.

You might notice that I compressed the four parameters from the first example into a single employee object. This leads to the next rule.

Prefer functions with one parameter and one responsibility

Photo by Fabrizio Verrecchia on Unsplash

A function with multiple parameters is intimidating. There’s also usually a positive correlation between arguments and complexity.

Sometimes you can’t avoid having more than one parameter. But in most cases, you can probably do one or both of the following:

Create a data type to encapsulate related parameters

Rethink how many responsibilities your function has

Strongly-typed languages are great for the first point. In general, well defined custom data-types are a surefire way to make your program easier to understand and easier to maintain. But even with languages like Python and JavaScript, you should still prefer objects over separate properties when the data is related, because this at least puts a label on the data as a whole and helps readers understand how everything comes together.

But encapsulating parameters into one data type isn’t the right way forward if your function is also doing more than it should. Consider the following example, where we are building an employee record from some form input.

The calculateEmployeeFinancials function is doing multiple things. You might argue that this technically is a single responsibility of ‘calculating financials’, but it can still be broken down further. Generally, breaking your functions down as far as they can go is optimal, and takes no more effort than the alternative if you have it in mind from the beginning. It makes your code easier to understand and easier to test. Here’s a refactored solution.

This technique shines when you have more complex things happening, but even here it makes sense. These functions now only have one responsibility, and it’s easy to quickly identify exactly what is going on.

The buildEmployee function could perhaps be broken down too, but there will be times when you need to do a bit more complex logic. The idea is to break it down as much as you can and then put the pieces together like a puzzle to build your more complicated processes.

Be wary of fancy tools

Photo by Obi Onyeador on Unsplash

This one may be controversial. Most languages have succinct ways of writing things, but often the succinctness can come at the cost of clarity. Consider this if statement.

This code spans 6 lines, and it looks a little clunky. But it is clear. Now, consider this written as a JavaScript ternary expression.

This only takes up one line and it looks fancy. But it’s really not clear. There is a cognitive load that comes with an expression like this that you just don’t get with the regular if statement.

Ternaries aren’t bad. They can be good in very simple situations, like:

But any more complex than that and you’re playing with fire.

Favour procedural programming

Photo by Maxime Guy on Unsplash

Custom data types are great, but when you attach behaviour to them, they become objects. This is when things get complicated.

Objects are instances of classes. Classes are collections of properties and methods. Classes can own objects of other classes, which lets them invoke behaviour on other objects in the program. This already sounds complicated, but it gets so much worse.

When you have a bunch of objects flying around in your program, the data flow begins to look something like a spider’s web. An object might call out to another object, which then calls to another object, which calls back to the original object, which calls to a different object, which modifies some data on another object, and as a result creates an object which then goes off and makes an HTTP call. And so on.

When you have situations like this, it becomes very difficult to follow the flow of a program. Debugging involves trying to visualise winding virtual paths like in a labyrinth. And then there’s inheritance. Eugh.

Procedural programming has none of these problems. Procedural code simply runs step by step in a clear sequence. This doesn’t mean you can’t call other functions, but there is no concept of some other ‘entity’ like an object taking control of the execution or whatever else. It’s just step by step, all the way through. It’s much easier to follow, much easier to read, and much easier to debug.

Here’s a great video about this. Don’t watch if you’re an object-oriented enthusiast. Or do, actually.
['Lee Mcgowan']
['Coding', 'Programming', 'Software Development', 'Clean Code', 'Technology']