Have you ever heard about spaghetti code? It simply is a messy code you don’t want to work with. However, most of the time it is not something you get from someone else. Instead, you were the author of this atrocity, and now you struggle to understand what you wrote. If you felt that way even just once, today we can change it. In this post, I will explain my tips on how to avoid spaghetti code.
If you are reading this, chances are you are already a programmer. You already know how to code, even just a little bit, and you are smart. You are already having concerns about how to write clean code. Well, this guide on how to avoid spaghetti code is the right one for you.
Tips on how to avoid spaghetti code
Like many things, there is not a step-by-step recipe on how to avoid spaghetti code. Instead, we have a list of best practices you can follow. Ideally, you should use them all, because if you do your code will be awesome. Trust me, the quality of the code matters, but we will also see why later.
So there we go, some tips in no particular order.
- A function does one thing only
- Make self-contained functions
- Split your files
- Use a consistent naming convention
- Use docstrings
- Implement tests
- Long variable, short variable…
- Use comments!
- Use source control (git)
A function does one thing only
I have come across this easy-to-fix error many times. Each function in your code should do just one thing. If that’s not the case, you have a problem you want to work on. Of course, the same is true for methods in all your classes, including the static ones.
Have you ever found a function that does different things based on one or some of its arguments? Bad design pattern. Each function should do just one thing, and take as argument only the parameters that are strictly needed for elaboration.
// Bad
function processData ($method, $a, $b) {
if ($method == 'multiply') {
return $a * $b;
}
return $a + $b;
}
// Do this instead
function multiplyData($a, $b) {
return $a * $b;
}
function addData($a, $b) {
return $a + $b;
}
How to fix
Create multiple functions, each with its own purpose. When fixing this error, you should first write the purpose-specific functions. Then, you should replace your all-in-one-messy-function so that it calls your new functions. After that, check all your code where your all-in-one-messy-function is used, understand how, and then replace it with the correct one.
Make self-contained functions
If your functions are not self-contained, your code is the worst spaghetti ever. What do we mean by that? It means having a super-huge function that does a super-huge and possibly complex task. Quite bad. How to avoid spaghetti code in this case? Identify the sub-tasks. Once you do, you can create a function for each subtask. Repeat the process until all your functions are small enough and do just one thing: get some data in, process it, and return the result.
To make this clear, imagine you have a function buildHouse
, that actually creates a house. Having that function by itself is not a problem, but if it contains a huge amount of code we have an issue. Instead, in this function we should call several other functions, like layFoundation
, buildWalls
, createPiping
and so on. In turn, each of those functions may call other functions. For example, the layFoundation
function may call excavate, pourConcrete
and so on. This repeated as many times as you need, until the functions where you actually execute the code are quite small.
How to fix
Identify huge functions, and split them into chunks. Focus on optimizing the parameters you pass to each of your new sub-functions. Then, repeat the process until you are comfortable with the size of functions, and you are sure they are self-contained. Ideally, more than 50 lines of code in a function are a bad thing. There are exceptions to that, but keep it as a thumb rule on how to avoid spaghetti code.
Split your files
The smaller the thing you have to deal with, the easier it is. This is true in many aspects of life, and it is true in code, for functions but also for files. Having a large file is generally bad, having multiple smaller files is way better.
So split your code among multiple files.
How to fix
Define a limit for yourself. In general, it is good to have just one thing in each file. Typically, this translates into a class. Having a file containing multiple classes is a bad thing. Fixing is easy because the split is quite easy, you just need to move your classes away into dedicated files.
Furthermore, if the language you are using supports namespaces, packages or similar groups of files, use that.
Use a consistent naming convention
Naming is everything, from variables to functions to classes. There are many best practices on the naming convention you should follow, and they vary language by language. Ideally, you should adhere to the best practices for the language your using. In this way, any new developer will be familiar with your code structure.
However, this is a nice to have, the great improvement comes from having a consistent naming convention. In other words, it doesn’t really matter if you adhere to the standard for your language or not. It matters that you adhere to any standard and stick with it.
How to fix
If you are starting with brand new code, take time to read and understand the best practices you should use it. Obviously, do that before you start writing any code! Instead, if you already have some code, if it has an established naming convention follow it, even if it doesn’t adhere to the best practices.
Start using best practices only when you are willing to switch all your existing code to it.
Use docstrings
This step on how to avoid spaghetti code is great to make your code easy to maintain. However, this is best applied when you already have self-contained functions. So, if you don’t have them yet, fix that first.
Docstrings particular comments you have at the beginning of your functions, methods, or even classes. They define what the function does, what are its parameters, its return values, and what are possible exceptions it may throw. Most IDEs inspect your code and show you the docstring when you are calling the function, so you can quickly have code reference at hand.
Below, an example of docstring in PHP. It is very similar to many other languages.
/**
* Create a new processor object
*
* @param array $object The configuration to build the processor
* @return Processor The created processor
* @throws RuntimeException in case the array is misconfigured
*/
function createProcessor(array $data) {
// ...
}
How to fix
Understand what is the syntax for docstrings in your language and use them. Below some easy references.
- Docstrings for Java
- Docstrings for C#
- C++
- Python
- Javascript (awesome article by Stephen Charles Weiss, a must-read)
- PHP
If you are using yet another language, don’t worry – Google will have the answer for you!
Implement tests
This is the most time-consuming practice, but it will avoid blowing everything up when modifying your code. Hell, if your code is really messy you may want to consider test its overall input-output first. Then, once you have the tests done, you can start tweaking the code and do that with confidence as long as you don’t break the tests.
In case you are not familiar, tests are simply other functions that run your program and check how it works compared to expected results. So, if your program changes the way it works, your tests will fail.
Any good code has tests, so if you don’t have any you have something to work. And the classic excuse “but this can’t be tested!” is what it is, just an excuse. In the end, everything can be tested.
How to fix
How to avoid spaghetti code here? Get yourself some patience and start writing tests. If you are not sure how to start, there are many great tutorials out there. Just search for “unit test” followed by your favorite language.
Long variable, short variable…
This is another little trick that can help turn your code around. In most languages, you are pretty much free to name your variables in any way you want. This is good, but as always, you need to be consistent.
A good way to name variables (but also functions, classes, everything…) is to give them a name that clearly describes what they should contain or do. So, a variable named “a” is not a good one. Instead, a variable named “invoiceId” is great.
And now the concept of long and short variable kicks in. The more places you use a variable in, the more it must be clear what it is. Thus, explain it better with a longer name. If instead, your variable is just used within a function, you may opt for a shorter name. Shorter names are fast to write, longer names are fast to read.
Use comments!
This is another great tool on how to avoid spaghetti code. Comment everything, but comment wisely. Comments should provide an explanation of something that is not obvious in the code, otherwise, they just mess things up.
However, if you are not sure, it is better to err on the side of commenting a little too much than commenting a little too less.
Ideally, in-line comments should provide quick insight into what is happening line by line. Multiline comments should provide a more detailed explanation of the context or the function as a whole, possibly as docstrings.
Ditch commented-out code!
Okay, I don’t need this, but who knows, instead of removing I will just comment-it-out. Sounds familiar? Sounds bad to me. Comments are for humans to read, they are not a place to store code you may not need anymore. Remove all comments that are not meant to be read by a human.
But how do I keep that code that I will need in the future? Read on…
Use source control (git)
Source control is a system to have your code always available, versioned. This means you can see how your code changed over time. And I am not only about the files that have changed: I am also taking about line-by-line differences.
If you are not using git now, you simply aren’t a professional developer. Change that. Start using git today. Doing so is easy and free. The easier platform to start to do that is GitHub, which is free (and has a paid version you don’t really need).
Why avoiding Spaghetti Code?
Enough about how to avoid spaghetti code, now it is time to understand why. Why would you want to put all this effort into making beautiful code? Why do that if the code is already working?
Well, because eventually, you will need to change your code. It might be you, or it might be someone else, but you will have to touch that code again. And, the more you touch it, the more you risk breaking it. Eventually, you will get to a point where it is more convenient to re-write your code from scratch, rather than modifying it. This is known as technical debt, when you write code so fast and so bad you will need to spend more time in the future whenever you want to edit it.
At some point, things will be unsustainable. And, if you are thinking you will never touch this code again, think again. The code will not be touched again only if it fails to do what it should do. And, with spaghetti code, you are setting yourself up for failure! Write clean code.
In Conclusion
Hopefully, you now know how to avoid spaghetti code, and you understand why it is important. With all this knowledge, you are ready to make the world a little bit better by writing better code.
It might sound counter-intuitive at the beginning, but if you are a true programmer, you will enjoy writing beautiful code and start to hate touching spaghetti code!