Refactoring Horror: Turning Spaghetti Code into Gourmet Code
There’s nothing quite like opening up someone else’s code and immediately questioning your life choices. We’ve all been there—staring at a piece of spaghetti code so tangled it looks like it was written during a caffeine-fueled rage session at 3 AM. Today, I’m sharing a refactoring journey—turning messy, hard-to-read code into something even a junior dev could understand without breaking into a cold sweat. Before: The Spaghetti Here’s a gem I recently stumbled upon: function processData(data) { let result = []; for (let i = 0; i entry.items // Filter items within each entry to include only those with value > 100. .filter((item) => item.value > 100) // Map the filtered items to a new structure. .map((item) => ({ id: entry.id, // Include the parent entry's ID. item: item.name, // Include the item's name. value: item.value // Include the item's value. })) ); } What changed? Readable logic: No nested loops, and each part of the process is obvious: filter, map, done. FlatMap magic: Combining transformation and flattening into one neat operation. Declarative style: We’re describing what we want, not how to loop. After: The Gourmet Code Here’s the result of our cleanup: // Sample dataset: An array of objects, each representing an entry with an ID, status, and a list of items. const data = [ { id: 1, status: 'active', items: [ { name: 'A', value: 150 }, // Item A has a value greater than 100 (should be included). { name: 'B', value: 50 } // Item B has a value less than 100 (should be excluded). ] }, { id: 2, status: 'inactive', items: [ { name: 'C', value: 200 } // Entry status is 'inactive', so none of its items should be included. ] }, { id: 3, status: 'active', items: [ { name: 'D', value: 120 } // Item D has a value greater than 100 (should be included). ] } ]; // Using the filterActiveItems function to process the dataset. console.log(filterActiveItems(data)); // Output: // [ // { id: 1, item: 'A', value: 150 }, // From the first entry, item A meets the conditions. // { id: 3, item: 'D', value: 120 } // From the third entry, item D meets the conditions. // ] Now, instead of dreading the next time you need to touch this code, you can actually look forward to it. It’s concise, modular, and easy to understand. The Moral of the Story Bad code isn’t the enemy—it’s an opportunity. Every piece of spaghetti code is a chance to level up your skills, clean up the mess, and maybe even teach a junior dev a thing or two. So, the next time you stumble across a codebase that looks like it was built by a raccoon on a keyboard, don’t despair. Roll up your sleeves and turn that spaghetti into a Michelin-starred meal.
There’s nothing quite like opening up someone else’s code and immediately questioning your life choices. We’ve all been there—staring at a piece of spaghetti code so tangled it looks like it was written during a caffeine-fueled rage session at 3 AM.
Today, I’m sharing a refactoring journey—turning messy, hard-to-read code into something even a junior dev could understand without breaking into a cold sweat.
Before: The Spaghetti
Here’s a gem I recently stumbled upon:
function processData(data) {
let result = [];
for (let i = 0; i < data.length; i++) {
let temp = data[i];
if (temp.status === 'active') {
for (let j = 0; j < temp.items.length; j++) {
if (temp.items[j].value > 100) {
result.push({
id: temp.id,
item: temp.items[j].name,
value: temp.items[j].value,
});
}
}
}
}
return result;
}
At first glance, you might think, “Hey, this isn’t that bad.” But look closer, and it’s a nightmare:
-Nested loops inside an if statement. Classic.
-Hard-to-follow logic that merges filtering and transformation into one messy pile.
-Zero comments. Hope you like deciphering someone else’s brain dump!
The Refactor: Untangling the Mess
Let’s break this down into smaller, more focused pieces. The goal is to make it:
1 Readable: Anyone should understand the logic in a single pass.
2 Reusable: No repeating yourself, because DRY isn’t just for laundry.
3 Testable: Smaller functions = easier unit tests.
Here’s the refactored version:
/**
* Processes a dataset to extract items from active entries where the item's value exceeds 100.
* @param {Array} data - An array of objects, each containing `status`, `items`, and `id`.
* @returns {Array} - A list of objects with `id`, `item`, and `value` fields.
*/
function filterActiveItems(data) {
return data
// Step 1: Filter entries with a status of 'active'.
.filter((entry) => entry.status === 'active')
// Step 2: Flatten and transform the filtered entries' items:
// - Keep only items where the value is greater than 100.
// - Map those items into a new format containing `id`, `item`, and `value`.
.flatMap((entry) =>
entry.items
// Filter items within each entry to include only those with value > 100.
.filter((item) => item.value > 100)
// Map the filtered items to a new structure.
.map((item) => ({
id: entry.id, // Include the parent entry's ID.
item: item.name, // Include the item's name.
value: item.value // Include the item's value.
}))
);
}
What changed?
- Readable logic: No nested loops, and each part of the process is obvious: filter, map, done.
- FlatMap magic: Combining transformation and flattening into one neat operation.
- Declarative style: We’re describing what we want, not how to loop.
After: The Gourmet Code
Here’s the result of our cleanup:
// Sample dataset: An array of objects, each representing an entry with an ID, status, and a list of items.
const data = [
{
id: 1,
status: 'active',
items: [
{ name: 'A', value: 150 }, // Item A has a value greater than 100 (should be included).
{ name: 'B', value: 50 } // Item B has a value less than 100 (should be excluded).
]
},
{
id: 2,
status: 'inactive',
items: [
{ name: 'C', value: 200 } // Entry status is 'inactive', so none of its items should be included.
]
},
{
id: 3,
status: 'active',
items: [
{ name: 'D', value: 120 } // Item D has a value greater than 100 (should be included).
]
}
];
// Using the filterActiveItems function to process the dataset.
console.log(filterActiveItems(data));
// Output:
// [
// { id: 1, item: 'A', value: 150 }, // From the first entry, item A meets the conditions.
// { id: 3, item: 'D', value: 120 } // From the third entry, item D meets the conditions.
// ]
Now, instead of dreading the next time you need to touch this code, you can actually look forward to it. It’s concise, modular, and easy to understand.
The Moral of the Story
Bad code isn’t the enemy—it’s an opportunity. Every piece of spaghetti code is a chance to level up your skills, clean up the mess, and maybe even teach a junior dev a thing or two.
So, the next time you stumble across a codebase that looks like it was built by a raccoon on a keyboard, don’t despair. Roll up your sleeves and turn that spaghetti into a Michelin-starred meal.