The first thing we built to be reused
Starting a second product from an empty directory made the case for shared infrastructure obvious. Building it revealed that reusable and working are different disciplines.
Algodyne
After the study platform, the next thing began the way the last one had: an empty directory, a framework, and a week of assembling the parts every application needs before it can do anything specific. Authentication. Data access. A component layer. Deployment. Documentation nobody would read.
Doing that once is the cost of entry. Doing it a second time, deliberately, while remembering doing it the first time, is where the argument for shared infrastructure stops being a slide and becomes something you can feel. So the second build was structured from the start as a core that a third build could consume.
Reusable is a different discipline from working
Code that works has one consumer and one set of assumptions, and it can encode them freely. Code that is reusable has an unknown number of consumers whose assumptions it has not met yet, and every convenience it takes becomes a constraint someone else inherits.
The practical difference showed up as import paths. Early on, examples reached into the internals of the thing they were demonstrating, because it was the same repository and the file was right there. That works perfectly and it is not reuse — it is proximity. Restructuring so that every consumer, including our own examples, went through the package boundary was tedious and it was the entire point. A boundary that only outsiders respect is not a boundary.
The same applies to documentation. A guide that hardcodes a value nobody else will have is a guide that only works in the room it was written in.
The first consumer pays
Generalising costs more than solving the case in front of you, and the cost falls entirely on the project doing the generalising. It gets a slower build and a more awkward API in exchange for a benefit that accrues to something that does not exist yet.
That asymmetry is why teams measured on their own delivery never choose it, and why the decision cannot sit with the team doing the work. It has to be made above the project, by whoever is accountable for the second one being cheaper.
It is also why the payoff is invisible for a long time. There is no moment where the shared core announces that it has paid for itself. There is only a series of later builds that were less painful than they would have been, which is precisely the kind of counterfactual nobody gets credit for.
What we got wrong
Too much was built before a second consumer existed. An interface designed against one caller is a guess dressed as a design, and several of ours were wrong in ways that only became visible when something else finally tried to use them.
The rule that came out of it is narrow and has held: generalise at the second call site, not the first. Solve the immediate case completely, and when a second consumer appears, extract what they genuinely share rather than what you predicted they would.
The other thing that started here, almost incidentally, was publishing. A page went up for research and write-ups at the same time as the shared core. The instinct was right even though it stayed mostly empty — the work of explaining a system to someone outside it is the fastest way to find the parts that only make sense from the inside.