Tips for Writing Non-Spaghetti Javascript Code

Mohammed Adil
7 min readJan 21, 2023

--

Guys have you ever wondered what “Spaghetti code” mean?
Is it about writing code while you're enjoying your noodle meal or getting cursed by other developers for writing bad code?

Let's find out.

Spaghetti code refers to code that is difficult to understand and maintain because it is poorly organized and lacks structure. This type of code often includes a large amount of duplicated logic, convoluted control flow, and a lack of clear separation of concerns.

Spaghetti code is often the result of not following best practices for code organization, such as the DRY principle, or not using appropriate design patterns. It can also be caused by a lack of code review, insufficient testing, and a lack of clear coding standards.

Spaghetti code

Good code in JavaScript is code that is easy to read, understand, and maintain. It should follow best practices and conventions.

Good vs Bad

Good code and bad code can be subjective, but there are some general principles that can help distinguish between the two. Here are some examples of good and bad code in JavaScript:

Good :

// Good: Using const for variables that don't need to be reassigned
const name = 'John Doe';

// Good: Using arrow functions for clear, concise syntax
const greet = (name) => {
console.log(`Hello, ${name}!`);
};
greet(name);

// Good: Using clear, descriptive function and variable names
function getTotalPrice(items) {
let total = 0;
for (let i = 0; i < items.length; i++) {
total += items[i].price;
}
return total;
}
console.log(getTotalPrice([{ name: 'item 1', price: 5 }, { name: 'item 2', price: 10 }]));

Bad :

// Bad: Using var instead of let or const
var name = 'John Doe';

// Bad: Using anonymous functions instead of arrow functions
const greet = function(name) {
console.log(`Hello, ${name}!`);
};
greet(name);

// Bad: Using single letter variable names
function gTP(i) {
let t = 0;
for (let x = 0; x < i.length; x++) {
t += i[x].p;
}
return t;
}
console.log(gTP([{ n: 'item 1', p: 5 }, { n: 'item 2', p: 10 }]));

Good:

// Good: Using a utility function to format a date
function formatDate(date) {
return date.toLocaleDateString();
}
console.log(formatDate(new Date()));

// Good: Using the map function to create a new array
const numbers = [1, 2, 3, 4, 5];
const doubledNumbers = numbers.map(number => number * 2);
console.log(doubledNumbers);

// Good: Using object destructuring to simplify code
const person = {
firstName: 'John',
lastName: 'Doe',
age: 30
};
const { firstName, lastName } = person;
console.log(`${firstName} ${lastName}`);

Bad :

// Bad: Using a for loop instead of the map function
const numbers = [1, 2, 3, 4, 5];
const doubledNumbers = [];
for (let i = 0; i < numbers.length; i++) {
doubledNumbers.push(numbers[i] * 2);
}
console.log(doubledNumbers);

// Bad: Using a global variable instead of a local one
name = 'John Doe';
function greet() {
console.log(`Hello, ${name}!`);
}
greet();

// Bad: Using a long and complex function instead of breaking it down into smaller, more manageable functions
function processData(data) {
// Perform a lot of logic and calculations here
// ...
// ...
}

As you can see, good code is well-organized, easy to read and understand, and follows best practices such as using utility functions, map function, and object destructuring. It also uses clear, descriptive function and variable names, and follows standard conventions for indentation and spacing. In contrast, bad code is often poorly organized, difficult to read, and doesn’t follow best practices or conventions, such as using global variables, for loops, and long complex functions.

That's enough of JS.

Now let us see how to write cleaner and more efficient components in React.
In React, a component is a piece of code that represents a visual element on the page, such as a button, form, or list. Here are some examples of what a bad and good component in React might look like

Bad component:

import React from 'react';

class MyComponent extends React.Component {
render() {
return (
<div>
<h1>{this.props.title}</h1>
<p>{this.props.description}</p>
<button onClick={this.props.onClick}>{this.props.buttonText}</button>
</div>
);
}
}

This component can be considered bad because it has a lot of responsibilities. It renders a title, a description, and a button, and also handles the click event.

Good Component:

import React from 'react';

const Title = ({title}) => <h1>{title}</h1>
const Description = ({description}) => <p>{description}</p>
const MyButton = ({text, onClick}) => <button onClick={onClick}>{text}</button>

const MyComponent = ({title, description, buttonText, onClick}) => {
return (
<div>
<Title title={title} />
<Description description={description} />
<MyButton text={buttonText} onClick={onClick} />
</div>
)
}

This component is good because it follows the single responsibility principle. Each component is only responsible for rendering a specific piece of the UI, and they are all composed together in the parent component. This makes it easier to read and understand, and also makes it easier to test and debug. It also follows good practice of separating the button component and handling the click event in the parent component.

It’s worth noting that good and bad components can be relative to the specific use case and project requirements. However, in general, good components are easy to understand, test, and maintain and follow best practices, such as the single responsibility principle.

Popular Naming Conventions

In JavaScript, naming conventions for components and variables vary depending on the framework or library being used. However, there are some general guidelines that are widely followed.

For components in JavaScript frameworks such as React, it is common to use PascalCase (also known as UpperCamelCase) for the component name, e.g. MyComponent.

For variables, it is common to use camelCase (also known as lowerCamelCase) e.g. myVariable.

  • Components:
  • MyComponent (class-based component)
  • MyFunctionalComponent (functional component)
  • useMyHook (custom hooks)
  • withMyHoc (Higher-Order Component)
  • Variables and Props:
  • const myVariable = ''
  • const { myProp } = this.props
  • const [myState, setMyState] = useState('')
  • const myContext = useContext(MyContext)
  • Functions
  • handleClick (event handlers)
  • fetchData (asynchronous function)
  • getMyData (function to get data)
  • filterData (function to filter data)

It’s important to note that naming conventions are not strict rules and ultimately it’s up to the developer to decide what naming conventions to use, but it’s always a good practice to be consistent with the naming conventions in your project.

Follow the DRY Principle

Moving on.

DRY stands for “Don’t Repeat Yourself” and it’s a principle in software development that aims to reduce the amount of duplicated code in a project. In React, this principle can be applied in a variety of ways to make your code more efficient and maintainable.

Here are a few examples of how to apply the DRY principle in React:

  • Reusable Components: Creating reusable components can help you avoid duplicating the same code in multiple parts of your application. For example, you can create a Button component that can be used in multiple places throughout your application instead of duplicating the same button code in multiple locations.
  • Higher-Order Components: Higher-Order Components (HOCs) allow you to reuse component logic across multiple components. For example, you can create an withAuth HOC that checks whether a user is authenticated before rendering a component.
  • Custom Hooks: Custom Hooks allow you to extract and reuse component logic in a functional component. For example, you can create a useFetch hook that handles the logic of fetching data in multiple components.
  • Utility Functions: Extracting common logic into utility functions can help you avoid duplicating the same code in multiple parts of your application. For example, you can create a formatDate utility function that can be used in multiple components to format date strings.

Here’s an example of DRY and non-DRY code in React:

Non-DRY

import React from 'react'

const MyApp = () => {
const handleClick = () => {
console.log('Button clicked!')
}

return (
<div>
<button onClick={handleClick}>Click Me</button>
<button onClick={handleClick}>Click Me</button>
</div>
)
}

export default MyApp

DRY

import React from 'react'

const MyButton = ({ label, onClick }) => (
<button onClick={onClick}>{label}</button>
)

const MyApp = () => {
const handleClick = () => {
console.log('Button clicked!')
}

return (
<div>
<MyButton label="Click Me" onClick={handleClick} />
<MyButton label="Click Me" onClick={handleClick} />
</div>
)
}

export default MyApp

In the second example, the MyButton component is created as a reusable component and the handleClick function is passed as a prop. The same component is used multiple times and it follows the DRY principle by avoiding duplicating the same code multiple times.

The first example does not follow the DRY principle as the same code of the button is duplicated multiple times throughout the application, making the codebase more difficult to maintain and update.

What about code comments?

Are they important?

Comments are an important aspect of writing code in any language, including React. Comments are used to add explanations and notes to the code, making it easier to understand for other developers who may read or work on the code in the future.

In React, comments can be used to explain the purpose of a component or a specific piece of logic, describe how a component works, or provide information on how to use a component. Comments can also be used to provide context and background information, such as the reasoning behind certain design choices.

As a general rule, good code is self-explanatory and should be written in a way that makes it easy to understand without the need for comments. However, comments can be a valuable tool when used correctly to provide additional information and context to the code.

That's it, folks.

Let's all try to be non-Spaghetti Coders.

“Any fool can write code that a computer can understand. Good programmers write code that humans can understand”

— Martin Fowler

Developers after writing clean code

--

--