Clean Code

"Change is Local": Strategies for Flexible and Adaptable Programming

I changed a date format in a utility function. It broke checkout, invoice generation, and two reporting dashboards. A one-line change. Four teams involved...

16 Apr 2024

"Change is Local": Strategies for Flexible and Adaptable Programming

I changed a date format in a utility function. It broke checkout, invoice generation, and two reporting dashboards. A one-line change. Four teams involved in the fix.

That's what happens when change isn't local. A modification in one place ripples across the entire system.

What "change is local" means

It's a design mindset. When you change something, the blast radius should be small. The change stays in one module, one class, one function. It doesn't leak into unrelated parts of the codebase.

Think of bulkheads on a ship. If one compartment floods, the rest stay dry. Your code should work the same way.

Why it matters

Reduced risk. Small blast radius means fewer unintended consequences. You can deploy a change with confidence instead of holding your breath.

Faster iteration. When changes are contained, you move faster. No need to coordinate across teams or run every test suite in the system.

Easier debugging. When a bug appears, you know where to look — in the module that changed. Not in 30 files across 5 services.

Better collaboration. Teams can work on their own areas without stepping on each other. The boundaries are clear.

How to make change local

Modular design. Break the system into modules with clear boundaries. Each module owns its data and behavior. Communication happens through defined interfaces.

Single Responsibility Principle. If a class has one job, changing that job only affects that class. If it has five jobs, a change to any one can break the other four.

Dependency injection. When a module depends on an abstraction instead of a concrete implementation, you can swap the implementation without touching the dependent code.

Encapsulation. Hide internal details behind a public API. If other modules only interact with the surface, changing the internals is safe.

Continuous refactoring. Code that resists local change is telling you something. Refactor it. Extract the tangled parts. Draw better boundaries.

The trade-off

Designing for local change takes more upfront effort. You need to think about boundaries, interfaces, and encapsulation before you start coding. That's slower than just writing the quickest solution.

But the first time a "simple change" takes 30 minutes instead of two weeks, the investment pays for itself. Design for local change and your future self will thank you.