Member-only story
Interfaces Everywhere vs Interfaces Where Needed: A Go Architecture Experiment
A hands-on Go experiment comparing interfaces-everywhere against interfaces-where-needed — the results might change how you code.
Somewhere along the way, a lot of us learned a rule that sounded wise: “program to an interface, not an implementation.” Fair enough advice — until it turns into a habit of slapping an interface on every single struct in your codebase, whether it needs one or not. Suddenly every service, every repository, every tiny helper has a matching interface definition sitting right above it, most of which are implemented by exactly one type, forever.
I wanted to know: does that actually help, or is it just ceremony we’ve all agreed to perform? So I ran a small experiment — building the same service two ways. One version wrapped everything in interfaces from day one. The other added interfaces only when a real need showed up. Let’s walk through what happened, and why the answer surprised me a little.
The Setup: Same Service, Two Philosophies
Both versions of the experiment implement a small order-processing service: fetch an order, validate it, apply a discount, and save it. Simple enough to reason about…



