Skip to content

16 · 32 · 6 min

Fixing the function from page one

Back to the 200 line function. Here is what the four tools do to it.

Before

java
class NotificationService {
    void send(String type, String to, String body) {
        if (type.equals("email"))      { /* 20 lines of SMTP */ }
        else if (type.equals("sms"))   { /* 15 lines of gateway */ }
        else if (type.equals("push"))  { /* 25 lines of tokens */ }
    }
}

After

java
interface Channel {
    void send(String to, String body);
}

class EmailChannel implements Channel { /* the SMTP code, alone */ }
class SmsChannel   implements Channel { /* the gateway code, alone */ }

class NotificationService {
    private final Map<String, Channel> channels;

    NotificationService(Map<String, Channel> channels) {
        this.channels = channels;
    }

    void send(String type, String to, String body) {
        Channel c = channels.get(type);
        if (c == null) throw new IllegalArgumentException("unknown channel: " + type);
        c.send(to, body);
    }
}

What changed

Adding WhatsApp is now one new class and one entry in the map that builds the service. NotificationService is never edited again, which is why SMS stops breaking.

The SMTP code did not go away. It moved into a file where nothing else lives, and where changing it cannot affect SMS because they no longer share a function.

And it became testable

java
var sent = new ArrayList<String>();
Channel fake = (to, body) -> sent.add(to + ":" + body);
new NotificationService(Map.of("email", fake)).send("email", "[email protected]", "hi");
assertEquals(List.of("[email protected]:hi"), sent);

The old version needed a live SMTP server to test at all.

Fixing the function from page one