DEV Community

Cover image for Don't Let the Domains Touch! The Professional Way to Avoid The Switch Smell
Doogal Simpson
Doogal Simpson

Posted on • Originally published at doogal.dev

Don't Let the Domains Touch! The Professional Way to Avoid The Switch Smell

We love if/else chains.

They are the first logic gates we learn. They feel safe. They feel logical. But as our systems grow, massive switch statements often signal that we are missing a critical abstraction.

We’ve all seen it: The "God Function." A single function that holds implementation details from five different, unrelated domains. It can do everything, contain anything, and as a result, it breaks every time we change anything.

Here is how to move from a brittle "Switch Statement" mess to a robust, polymorphic design.

The Junior Trap: The "Kitchen Sink" Logic

The most common place this smell appears is in notification systems. You need to send a message to a user, but you support multiple channels: Email, SMS, Slack, and Push.

The Junior developer writes a function called sendNotification. Inside, they throw every piece of logic required for every channel.

The Reality:
When you mix domains, you create risk.

  • To change the Email subject line, you have to open the file that handles SMS authentication.
  • If you make a typo in the Slack logic, you might syntax-error the whole file and bring down the Push notifications.

This violates the Cognitive Budget. You are forcing yourself to understand the entire notification infrastructure just to fix a typo.

The Pro Move: "Don't Let the Domains Touch"

A Professional Junior uses encapsulation. We ensure that no single class or object is aware of the logic of multiple domains.

We use Polymorphism. This sounds like a terrifying Computer Science degree word, but it just means: "Making different things look the same from the outside."

If an object looks like a Notifier and acts like a Notifier, the main system doesn't care if it sends an SMS or a carrier pigeon.

The Code: The Notification Refactor

Let's look at a function designed to handle user alerts.

// Before: The Brittle Logic

This function knows too much. It knows how to format an email subject, how to validate SMS length (160 chars), and how to talk to the Slack client.

// THE "GOD FUNCTION"
function sendNotification(user, type, message) {
  switch (type) {
    case 'EMAIL':
      // Email specific logic mixed in here
      const subject = `Message for ${user.name}`;
      emailClient.send(user.email, subject, message);
      break;

    case 'SMS':
      // SMS specific logic mixed in here
      // Logic relies on 'message' being raw text
      if (message.length > 160) throw Error("Too long!");
      smsClient.send(user.phone, message);
      break;

    case 'SLACK':
      // Slack specific formatting
      const slackBody = { text: message, channel: user.slackId };
      slackClient.post(slackBody);
      break;
  }
}
Enter fullscreen mode Exit fullscreen mode

The Scenario: Your boss runs in. "We need to add Discord support!"
The Fear: You have to crack open this massive, tested function. You risk breaking the SMS logic just to paste in the Discord code.

// After: The Polymorphic Strategy

We move the logic into small, focused classes (strategies). The sendNotification function no longer cares how the message is sent, only that it is sent.

// 1. The logic lives in small, focused classes
class EmailNotifier {
  send(user, message) {
    const subject = `Message for ${user.name}`;
    emailClient.send(user.email, subject, message);
  }
}

class SmsNotifier {
  send(user, message) {
    if (message.length > 160) throw Error("Too long!");
    smsClient.send(user.phone, message);
  }
}

class DiscordNotifier {
    send(user, message) {
        discordClient.postToChannel(user.discordId, message);
    }
}

// 2. The main function is now boring (and safe)
// It accepts any object that looks like a notifier
function sendNotification(notifier, user, message) {
  notifier.send(user, message);
}

// Usage:
const smsStrategy = new SmsNotifier();
sendNotification(smsStrategy, currentUser, "Your order is here!");
Enter fullscreen mode Exit fullscreen mode

Why This Wins

1. Zero Regression Risk

When the boss asks for "Discord Support," we don't touch sendNotification. We don't touch SmsNotifier. We just create a new file: DiscordNotifier.js.
The old code remains safe, tested, and boring.

2. Cognitive Budget

When I am working on SMS bugs, I only open SmsNotifier. I don't see the Email logic. I don't see the Slack API keys. I can focus entirely on the problem at hand without filtering out noise.

Pro Tip: Boring is beautiful. We strive for code that is so obvious it looks boring. When the solution is obvious, bugs have nowhere to hide.

Stop writing functions that know everything. Distribute the logic to the small, simple places where it belongs.


Stop writing code just to please the compiler.

This article was an excerpt from my handbook, "The Professional Junior: Writing Code that Matters."

It’s not a 400-page textbook. It’s a tactical field guide to unwritten engineering rules.

👉 Get the Full Handbook Here

Top comments (0)