What is the Spaghetti code?

Spaghetti code also referred to as the big ball of mud, is code without a definite structure and resembles spaghetti. This form of code is tightly coupled, hard to maintain, and refactor and a nightmare for the devs working on it. 

Spaghetti code is a software design anti-pattern found in applications where the delivery speed of application features is prioritized over code quality resulting in massive technical debt. 

Let’s understand this with the help of a real-world use case.

Spaghetti code use case – Online food delivery service

Imagine an online food delivery service comprising multiple business functionalities such as taking orders, routing those orders to the right restaurant and the delivery person, accepting payments, user memberships, inventory, and so on. 

The Spaghetti code for this application will have total discard for the software design principles and would have all the features coded tightly coupled with each other. The code will have no layers (controller, service, business, DAO, etc.), no use of SOLID OOP principles, no use of interfaces and modular design; rather, everything coded together like a big ball of mud. 

Spaghetti code

With an application having Spaghetti code, it would be overly painful to add new features since—first, the devs would have to figure out the code flow for a certain feature and then make the changes hoping the new code doesn’t break the existing functionality. 

This may result in an endless cycle of bug fixing with the spawning of new bugs due to the former bugs being fixed, which will eventually throw a wrench into the gears resulting in financial loss.

Why do we end up with the Spaghetti code?

There are several reasons, stated below, behind dev teams ending up with Spaghetti code:

  • Primarily due to the lack of time investment in code design during the initial phases of product development. Here in this article, I’ve discussed how important is knowledge of system design for developers.
  • Lack of developer experience. If the developers working on the code have little knowledge of software design, the code will end up being a big ball of mud. 
  • Several developers developed the project over the years, writing code in their style without following a definite structure, making the code look like Spaghetti. This is where programming frameworks like Spring come in handy as they help standardize coding structure.
  • The team always preferred delivery speed in contrast to code quality. Developers were happy to take the easy route without thinking much about leveraging OOP principles, design patterns and such. 
  • No team code reviews led by seasoned devs. If the code worked, it was pushed to the repo mainline. 
  • No regular code cleanups (Refactoring, rewriting, code quality checks, test coverage and such).

What can we do to avoid the Spaghetti code?

Use a layered architecture as opposed to stuffing everything in a single layer. 

Layered Architecture 

In most enterprise projects, you’ll find code split up into layers like the controller, service and data access layers. We can always add more layers to our code based on the requirements and the complexity of the project. 

When it comes to Java Spring enterprise projects, layered architecture is the defacto pattern that is leveraged. 

Layered architecture

In the layered architecture, also known as the lasagna code, every layer has its specific role; for instance, the controllers will handle requests specific to a certain business feature or domain, the service layer will execute the business logic, the data access layer will communicate with the database and so on. They communicate with each other via interfaces to keep things loosely coupled and abstracted.

With this, specific layers, such as the service layer, wouldn’t worry about what is going on in the controller or the DAO layer. It just does its job, that is, executing business logic and passing the data across the DAO and the controller. Having a layered architecture helps implement the separation of concerns. 

With this architecture, a change in a certain layer of the code won’t impact other layers much. The layers are isolated. This facilitates easy development and testing, keeping the code maintainable and extendable.

Hopping back to our online food delivery service use case, we will have the business functionalities like order management, order routing, payment, user memberships, inventory, etc., implemented as verticals in a layered architecture as opposed to having all these in a single layer in Spaghetti code.

domain driven layered architecture

End-to-end request flow in a layered architecture

Now, with the layered architecture, when a user searches for food items in their app, the request is handled by the inventory controller and then moves to inventory service and the inventory DAO and back. 

When they book an order, the request is handled by the order management (controller, service, DAO) flow. And when they pay for the order, the request is handled by the payment flow and so on. 

So, you see, the business functionalities are spread across the layers vertically. Anytime we need to update any business feature, we can do it without nudging the code of other business features much.

Why do I say much?

Because however, the business functionalities are separated in layers, they are not completely isolated. There is cross-communication between them, and in complex projects, this might again lead the code to become a big ball of mud/Spaghetti.

To tackle this, we either move to microservices or implement a modular monolith architecture. I’ve discussed that in a separate article here.

If you wish to master the fundamentals of web architecture and learn to design large-scale distributed systems starting right from zero, check out the Zero to Software Architect learning track that I’ve written.

Besides implementing a layered architecture, there are a few other ways to avoid ending up with the Spaghetti code

  • Always have code reviewed by seasoned devs before pushing it to the main branch. Always have team code reviews. Make this a rule of thumb. 
  • Educate junior devs on the importance of software design knowledge. Check out the best resources to learn software architecture and system design.
  • Practice domain-driven development with a thorough understanding of the domain. 
  • No disorganized and chaotic bug fixing just to make things work. This might create more bugs in the code. Focus on the root cause of the issue and understand if it needs any design changes as opposed to applying duct tape to the code to make it work. 

Recommended reads: Monolithic architecture explained in simple words | Web application architecture explained with a real-world example

Folks, this is it. If you found the content helpful, consider sharing it with your network for better reach. Check out the Zero to Software Architect learning track. I wish I had a similar learning product in the initial years of my career. 

I am Shivang. You can catch me on LinkedIn here. I’ll see you in the next write-up. Until then, Cheers!