Code Smells: What They Are and How to Fix Them

A "code smell" is like the "check engine" light in your car. It doesn't mean your car has broken down, but it's a warning sign that something might be wrong under the hood. In software, a code smell is a surface-level indicator of a potential design flaw.

Recognizing these smells is the first step toward writing cleaner, more maintainable code. They are not bugs themselves, but they are hints that a piece of code could be improved through refactoring. Let's look at some of the most common ones.

1. Long Method

  • Symptom: You have a function that has grown too long. It seems to be doing too many things, has lots of conditional logic, and requires you to scroll to see the whole thing. It's hard to name because it does so much.
  • Cure: Extract Method. Break the long function down into smaller, well-named functions, each with a single responsibility.
// ๐Ÿ‘Ž Bad: This function is doing validation, calculation, and formatting.
function createInvoiceSummary(order) {
  // validation
  if (!order.id || !order.customerName) {
    throw new Error('Invalid order data');
  }
  // calculation
  const total = order.items.reduce((acc, item) => acc + item.price, 0);
  const tax = total * 0.07;
  // formatting
  return `Invoice for ${order.customerName}: $${total + tax}`;
}

// ๐Ÿ‘ Good: The logic is broken into smaller, more focused functions.
function validateOrder(order) { /* ... */ }
function calculateTotal(order) { /* ... */ }
function formatInvoice(order, total) { /* ... */ }

function createInvoiceSummary(order) {
  validateOrder(order);
  const total = calculateTotal(order);
  return formatInvoice(order, total);
}

2. Duplicate Code

  • Symptom: You see the same (or very similar) lines of code in multiple places. If you need to fix a bug in that logic, you have to remember to fix it everywhere.
  • Cure: Extract Function/Consolidate. Unify the duplicated logic into a single, reusable function or class. Don't Repeat Yourself (DRY)!
// ๐Ÿ‘Ž Bad: The validation logic is repeated.
function saveUser(user) {
  if (!user.email.includes('@')) throw new Error('Invalid email');
  // ... save user
}
function saveAdmin(admin) {
  if (!admin.email.includes('@')) throw new Error('Invalid email');
  // ... save admin
}

// ๐Ÿ‘ Good: The duplicated logic is extracted into a shared utility function.
function validateEmail(email) {
  if (!email.includes('@')) throw new Error('Invalid email');
}

function saveUser(user) {
  validateEmail(user.email);
  // ... save user
}
function saveAdmin(admin) {
  validateEmail(admin.email);
  // ... save admin
}

3. Large Class (or "God Class")

  • Symptom: You have a class that knows too much and does too much. It has a huge number of methods and properties, and it handles many different responsibilities (e.g., data access, business logic, email, logging).
  • Cure: Extract Class/Single Responsibility Principle. Break the "God Class" into smaller, more cohesive classes, each with a single, clear responsibility.
// ๐Ÿ‘Ž Bad: A single class that handles everything for a user.
class UserProfile {
  getUserFromDb() { /* ... */ }
  displayProfile() { /* ... */ }
  updatePassword() { /* ... */ }
  sendEmail() { /* ... */ }
}

// ๐Ÿ‘ Good: Responsibilities are segregated into different classes.
class UserRepository { /* Handles database interactions */ }
class UserView { /* Handles displaying the profile */ }
class UserAuth { /* Handles password changes */ }
class EmailService { /* Handles sending emails */ }

4. Mysterious Names

  • Symptom: You can't figure out what a variable, function, or class does just by reading its name. You see cryptic abbreviations, single-letter variables, or vague names like proc or data.
  • Cure: Rename. Give things clear, descriptive names that reveal their intent.
// ๐Ÿ‘Ž Bad
function proc(d) { /* ... */ }

// ๐Ÿ‘ Good
function processDailyReport(dailyReportData) { /* ... */ }

Code Smells are Opportunities

Don't be discouraged when you find code smells in your workโ€”everyone writes them. The key is to see them not as mistakes, but as opportunities to refactor and improve your code. Like tending a garden, addressing these smells as you find them keeps your codebase healthy, clean, and a pleasure to work in.