concept

Expensive-to-Change Core

The small part of a system whose shape is copied into stored data and into other people's code, where a shortcut cannot be repaid locally - so deliberate debt belongs everywhere else.

technical-debtidentifiersdata-modelreversibilitydelivery

Two teams take a shortcut under the same deadline. One skips pagination on an internal admin screen. The other exposes sequential integer order ids in a public API. Both save about 3 days. Eighteen months later the first is repaid in an afternoon; the second needs a versioned endpoint, a permanent translation table and a customer migration measured in quarters.

The difference is not code quality. It is that one choice was copied into other people's systems and into stored rows, and the other was not. Delivery-versus-maintainability arguments become tractable when the question changes from how much debt to take to where to take it.

Why it matters

The distinction is between shortcuts whose reversal touches one module and shortcuts whose reversal touches data you cannot reconstruct or contracts you do not control. The second set is small and nameable in advance: identifiers, stored money, the tenancy and partition key, time representation, public contracts, audit records.

Everything outside that list is where deliberate debt belongs. Screens, internal reports, job schedules and anything behind a feature flag can be done badly and fixed later near the original estimate. That is what makes a cost-of-delay argument sound: shipping 8 weeks earlier is worth real money, and the bet holds only while rework stays bounded.

Implementation patterns

  • Write the list down once: 5 to 8 items, agreed in a review, referenced in every later argument about shipping fast.
  • Gate the core, not the codebase. A change to an identifier format, a tenancy key or a public contract needs a decision record; everything else does not. Universal gates produce empty templates.
  • Contain the shortcut behind one interface. A rule table read through a single module is 6 engineer-weeks to replace; the same rules read from four call sites are 25. Add the tenancy column before you have tenants, because retrofitting ownership into 40 million rows is not a refactor.
  • Store money in minor units as integers, and time as an instant plus a zone. Both are unrecoverable later: the original values are gone once the wrong representation is persisted.

Industry example

Sharding decisions show the boundary. Figma's colocation groups collect tables sharing one sharding key, which is what keeps joins and transactions working within that key; choosing the key is the near-permanent decision and it is made before any data moves. Their 2024 write-up separates it from the routing layer, which rolled out by percentage and could be rolled back.

The same split appears in any partitioned system: the partition key is core and the host count is not. Treat both as equally serious and the team slows down; treat both as casual and you pay for the key for years.

Failure scenarios

  • Floating-point money. Totals drift by fractions of a unit, reconciliation against the payment provider fails at a growing rate, and the fix is a backfill of rows whose true values are gone.
  • Sequential public ids. Customers script against them, competitors infer volume from two timed orders, and the format cannot change without a migration programme.
  • Missing tenancy key. Ownership is inferred from joins, one bug leaks another customer's data, and a residency question cannot be answered.
  • Shortcut that escaped containment. The rule table is read from four services by the time anyone looks, so the bounded rework estimate no longer applies.

Trade-offs

Choose Gains Pays
Shortcut outside the core Weeks of delivery at a bounded repayment cost Ugly internal code and a repayment trigger to honour
Care inside the core Reversal stays possible for years Days to weeks of design before the first line ships
Uniform care everywhere A tidy codebase Cost of delay on every feature

When not to use it

The framing assumes the product will survive to pay the bill. For a two-week validation prototype with no customers and no retained data nothing is core, and applying this list is ceremony that can kill the experiment: say the artifact is disposable and delete it rather than promote it. The list also goes stale, since a private beta with four design partners can still change an id format cheaply. Re-agree it when the customer base or compliance surface changes.

Interview question

Q: A product manager wants a feature in three weeks that you estimate at eight done properly. You agree to cut one corner. How do you choose which one?

What a strong answer covers: pick the corner whose reversal touches one module and is not copied into stored data or an external contract, and name the candidates excluded for that reason - identifiers, money representation, tenancy key, public contracts. Then bound the repayment: contain the shortcut behind one interface, estimate the rework in engineer-weeks, compare it against the measured cost of delay, and record the trigger that calls it in. A strong answer also names what voids the deal, such as the shortcut spreading to several call sites.

Quick check

Quiz: Which four things belong in almost every expensive-to-change core? Identifier format, stored money representation, the tenancy or partition key, and public contracts.

Flashcard: What decides whether a shortcut is cheap to repay? — Whether reversing it touches one module only, and whether the choice was persisted into data or published in a contract.