Skip to main content
CodeOath
← All posts

Architecture & Patterns110 min total · 26 parts

ACID, SOLID, and Design Patterns: A Complete Software Design Reference

Part 8 of 26 · ~2 min

Open/Closed Principle

Open for extension, closed for modification. A codebase should be able to grow new behavior without anyone reopening code that's already shipped and already trusted — the usual mechanism is giving the new behavior somewhere to plug in, an interface or a base class, rather than adding one more branch to a conditional that's already there.

ShiftDesk awards priority points for every completed shift — volunteers with more points get first pick when a popular Saturday slot opens up. Different kinds of shifts are worth different amounts:

// Violates OCP — every new shift kind means editing this method, re-testing
// every existing branch, and risking a regression in a case that had nothing
// to do with the new kind being added.
public int CalculatePriorityPoints(ShiftAssignment assignment, string shiftKind)
{
    if (shiftKind == "weekday") return 10;
    if (shiftKind == "weekend") return 15;
    if (shiftKind == "holiday") return 25;
    // every future shift kind adds another branch here
    return 0;
}
// Open for extension: adding an EmergencyCalloutRule means adding a new
// class, not touching CalculatePoints or any existing rule.
public interface IPriorityRule
{
    int PointsFor(ShiftAssignment assignment);
}

public class WeekdayRule : IPriorityRule
{
    public int PointsFor(ShiftAssignment assignment) => 10;
}

public class HolidayRule : IPriorityRule
{
    public int PointsFor(ShiftAssignment assignment) => 25;
}

public class ShiftAssignmentProcessor
{
    public int CalculatePoints(ShiftAssignment assignment, IPriorityRule rule) => rule.PointsFor(assignment);
}

A reader who already knows the pattern catalog will recognize IPriorityRule as Strategy, covered fully later in this reference — the principle describes the goal, and Strategy is simply the recurring shape people reach for to actually hit it. It's fair to push back a little here too: building an extension point for a variation that may never show up is just complexity paid for in advance, with nothing to show for it yet. What justifies doing it for ShiftDesk's priority points specifically is the visible pattern in the codebase's own history — new shift kinds keep showing up — which means a brand-new "emergency callout" value arriving six months from now should cost exactly one new class, and zero re-testing of every rule that came before it.