Prediction versus evidence
It is easy to look at a first implementation and imagine the reusable library it might become.
That is usually the wrong time to generalize. You do not yet know which parts are stable, which requirements are imaginary, or whether a second consumer would want the same boundary.
Duplication is evidence. Premature generalization is prediction.
The useful sequence is:
The promotion sequence
Shared infrastructure should be the result of repeated evidence, not a guess made before the second consumer exists.
-
source
Specific solution
Solve the first real problem directly.
-
input
Repeated consumers
The same shape appears in more than one place.
-
boundary
Stable semantic contract
Separate the meaning that callers share from implementation details.
-
component
Shared implementation
Move the proven mechanism behind the contract.
-
result
Narrower callers
Consumers depend on the useful boundary, not the machinery.
How the pieces relate
- Specific solution Repeated consumers
- Repeated consumers Stable semantic contract
- Stable semantic contract Shared implementation
- Shared implementation Narrower callers
The shared module is the end of the investigation, not the beginning of it.
SSS to H3
Static Switching System had local copies of utilities that were no longer local in any meaningful sense. Commit 7cb5a731 moved szudzik, tableHash, and randomGen into H3 because repeated instances already existed and another project was using the same ideas.
The migration removed SSS-local duplicate files and changed consumers to stable H3 module paths. The current SSS module format and H3 API reference show the resulting package boundary.
The same promotion appears in smaller stories:
- S3maphore's
isOpenMWmodule became H3 ina9afe80a, then S3maphore deleted its copy ind6a45c62; - a dedicated
clearoperation moved from a S3maphore-specific need into an H3 module that can use Rubic0n's fast implementation or a Lua fallback in30ca0dbeandbf0b6505; randomGengained a non-allocating range path and uniform integer selection in0595f2b1and4e8235f5.
The library was not guessed into existence. Consumers earned it.
Keep the contract small
Promotion is not a reward for having a clever implementation. It is a response to a stable question that multiple consumers need answered.
The reusable module should own the parts that are genuinely shared:
- the semantic name;
- the input and output contract;
- the relevant failure behavior;
- the package and context boundary.
It should not inherit every detail from its first consumer. A shared helper that exposes one project's storage layout, lifecycle assumptions, or private cache is not shared infrastructure yet. It is a copy with a nicer address.
See API and Interface Design for the broader contract rules. S3lf and CamHelper show the same promotion pressure at larger semantic boundaries.
What to steal
When you see duplication, do not immediately extract it. First ask whether the copies share meaning, lifetime, ownership, and failure behavior.
If repeated consumers prove that they do, extract the smallest stable contract and move the implementation behind it. Let the callers become simpler because they no longer need to know how the answer is produced.
When not to use this
If there is only one consumer or the repeated code only looks similar, keep it local. Do not extract a library because two files happen to have matching shapes; that is a prediction, not evidence.