Engineering Practice
Scope Shared Code by Who's Allowed to See It
Deduplicating shared code is good, but "shared with everyone" is its own risk. The durable pattern is one canonical source, scoped by audience so nothing leaks where it shouldn't, deployed as a boring flat artifact.
- Engineering Practice
- Architecture
- Code Reuse
- Design
A handful of deployable bundles had drifted into copying the same helper files between each other by hand. Classic duplication: a fix in one copy didn’t reach the others, and the copies slowly diverged until “the shared helper” was a fiction. The obvious instinct is to yank the duplication out into one shared place. That instinct is right, but the naive version of it — one big pool of “common” code everyone pulls from — trades a duplication problem for a coupling problem. The pattern that actually held was more careful: one source of truth, scoped by who’s allowed to use each piece, deployed as plain flat files.
Duplication is the problem you can see
Hand-copied shared code is an obviously bad state, and it announces itself: you fix a bug in the logging helper, ship it, and three weeks later the same bug bites from a bundle that had its own stale copy. Every duplicate is a place drift accumulates, and drift is silent until it isn’t. So the motivation to consolidate is real and correct — byte-for-byte copies of “shared” logic are a maintenance tax you keep paying.
The trap is assuming the fix is simply “put it all in one shared folder everyone imports.” That removes the duplication, but it quietly creates a new problem that’s harder to see: now everything is visible to everyone, and the boundaries between different consumers have dissolved.
”Shared with everyone” is its own risk
Not all shared code has the same audience. Some helpers genuinely belong to every consumer. Others belong to a specific subset — the bundles serving one purpose, or one category of consumer — and have no business showing up in the others. Dump them all into a single flat “common” pool and you’ve made it trivial for a file meant for one audience to leak into a bundle where it doesn’t belong, or even shouldn’t be allowed.
One canonical copy is the goal. “One canonical copy everyone can grab anything from” is a different goal, and it’s the one that bites you later.
So the design question isn’t only “how do we stop copying this?” It’s “who is each piece for?” A single undifferentiated shared pool answers the first question and ignores the second, which is how shared code becomes a tangle where everything depends on everything.
Scope the shared module by audience
The pattern that worked: keep one canonical source for the shared code — a single module, consumed by each bundle as a pinned dependency, so there’s exactly one copy and no byte duplication anywhere — but organize that module by audience scope rather than as one flat heap. A section for things every consumer needs; separate sections for things that belong only to a particular family of consumers.
Each bundle then opts into exactly the scopes it belongs to, and nothing else. The shared logic for one category physically can’t end up in a bundle from a different category, because that bundle never pulls that scope. You get the dedup win — one source of truth — and you keep the boundaries that a flat pool would have erased. The blast radius of a shared file is limited to the audience that’s supposed to have it.
Deploy a boring artifact, not a clever mechanism
There’s a second lesson hiding in the deploy step. It’s tempting to lean on a clever filesystem mechanism — symlinks, mounts, something that makes the shared files appear in each bundle without copying. The trouble is that clever mechanisms make assumptions about the deploy environment, and the environment doesn’t always cooperate. If the thing that ultimately consumes your bundle doesn’t preserve symlinks, your clever sharing breaks exactly where you can least debug it.
So the shared files get flattened into plain, real files at build time. The mechanism for keeping one source of truth (a pinned module) is separate from what actually gets deployed (ordinary files with no special filesystem magic). The deploy artifact is boring on purpose, because boring survives contact with environments you don’t control. Cleverness can be an authoring convenience, but it shouldn’t be load-bearing in the thing that ships.
The rules I’d reuse
Pulling it together, when I consolidate shared code across several consumers now:
- One canonical source. A single module everyone depends on — no byte-for-byte copies living in each repo to drift apart.
- Scope by audience. Organize the shared code by who’s allowed to use it, and let each consumer opt into only its scopes, so nothing leaks across boundaries.
- Enforce uniqueness where it merges. When scoped files get assembled together, guard against name collisions so a drifted local copy can’t silently shadow the canonical one.
- Ship a flat, plain artifact. Keep the clever mechanism (a pinned module, maybe symlinks for authoring) out of the deploy. Deploy real files.
This sits alongside two other things I’ve written about sharing code: that submodules pin, they don’t sync (a dependency you control the version of, not a live mirror), and that the monorepo-vs-polyrepo question is often “pick both”. The throughline is that sharing code well is mostly about boundaries — and that files are not modules just because they sit in the same folder. If you’re untangling hand-copied shared code and want to talk through the scoping, I’m easy to reach.