MVPs and technical debt: shipping fast without going bankrupt
Monday, 9:30. The payout breakdown page is estimated at 9 weeks. We have 3. Karim wants to know what we're cutting. Omar wants to know what we'll owe for it later.
How to ship fast with shortcuts, and how to keep those shortcuts from quietly slowing everything down later.
- Problem
StayHub chose a payout breakdown page for hotel partners. The full version is estimated at 9 weeks; the budget is 3 weeks and 2 engineers, and nobody knows yet whether a breakdown actually answers partners' payout questions.
- Why the simple system fails
Option one: build the full version (live ledger, all currencies, PDF export, chargeback drill-down) and learn 9 weeks later whether it helped. Option two: hack it fast with no record, and months later a copied function silently disagrees with billing and nobody knows it exists.
- Engineering concept
Build the smallest thing that tests the riskiest assumption (an MVP), take shortcuts on purpose and write them down, then repay debt when its ongoing interest exceeds the cost of fixing it.
- Technology
Concierge and manual-backend MVPs, feature flags, debt registers, TODOs linked to tickets, ADRs, a fixed share of capacity for debt work.
- Trade-offs
Speed of learning now versus cost of change later. Debt is a tool when it's deliberate and tracked; it's a trap when it's accidental and invisible.
The problem
2 min- Karim · CTOFull page: 9 weeks. You have 3 weeks and 2 engineers. What are we cutting?
- Omar · On-call SREAnd whatever we cut, I'd like to know what we'll owe later.
- Lina · Senior engineer, your mentorWhat's the one thing we don't know that could make this page pointless?
The big idea
4 minBuild the smallest thing that tests the riskiest assumption. Cut scope, never trust, and write down every cut.
A mortgage is debt you chose: known rate, known amount, a payoff date. A forgotten credit card grows quietly. Tech debt works the same way.
How it works
5 minAn is the smallest thing that tests your riskiest assumption, not a small version of the final product. is a shortcut that saves time now and costs time later: interest is what it costs each week, principal what it costs to fix once.
- 1Name the riskiest assumption
"Seeing the breakdown answers partners' payout questions." Metric: payout tickets −50% in 8 weeks.
- 2Cut what doesn't test it
Nightly data instead of live, EUR only (81% of partners), chargebacks as one line, no PDF.
- 3Keep what can't be cut
Totals that match the real payout, each hotel sees only its own data, a way to measure tickets.
- 4Record every cut
A lists each shortcut with interest, principal, owner and the trigger that schedules repayment; the code carries its id.
- 5Ship to a slice, decide on a date
A feature flag for 1,200 eurozone hotels; after 8 weeks, build, change or remove.
Watch a decision being made
4 minYou cut the page to 3 weeks (Lina checks)
Learn whether a breakdown cuts payout tickets, with numbers partners can trust, and leave a clear record of what you owe.
- 1Say the metric first
Payout tickets per 1,000 bookings, flagged hotels vs the rest, −50% in 8 weeks.
Why: Lina: "Say the metric before you write the first line."
- 2Record each cut with its cost
One register entry per shortcut:
yaml- id: DEBT-033 title: Chargebacks shown as one "adjustments" line interest: ~200 tickets/month (~10 h/week) principal: ~2 engineer-weeks (~80 h) trigger: adjustments tickets > 150/month after launchWhy: Six months later nobody remembers why. The record turns a mystery into a scheduled task.
- 3Do the break-even maths
80 h ÷ 10 h a week = 8 weeks to pay back, and we're in this code all quarter: repay soon.
Why: "The code is ugly" gives product nothing to weigh; "pays back in 8 weeks" does.
- 4Keep interest-free debt listed
DEBT-032 (EUR only) costs nothing today but blocks the UK/CH rollout.
Why: A trigger puts repayment on the roadmap before it's urgent.
In real life
3 minZappos: a manual MVP
- Its founder described photographing shoes in stores and buying them at retail per order
- Tested demand with almost no system; obviously temporary
Fits when the riskiest question is demand.
Early Twitter: the shortcut became the platform
- Built quickly as one web app; famous for outages and the "fail whale"
- Rebuilt major parts over the following years
The interest due when shortcuts carry real scale.
What goes wrong
3 minWrong numbers or leaked data aren't debt; they're incidents.
Cut scope and automation, never trust.
Big-bang rewrites stall features and recreate old problems.
Repay where interest is highest, inside features touching that code.
Polishing a feature the data says to kill is waste.
Decide the feature's future first; deleting is the cheapest repayment.
Trade-offs
3 min| Approach | Fits when | Costs |
|---|---|---|
| Build properly from day one | Proven demand, stable needs, irreversible mistakes | Months before you learn anything |
| MVP with deliberate debt | The risky question is demand or behaviour | Interest; discipline to record and repay |
- Karim · CTOThree large groups want PDF export for their accountants. Two weeks. Build it next.
- Omar · On-call SREFirst repay DEBT-031 and DEBT-033. Three weeks.
- Omar · On-call SREA PDF built on a copied formula will be wrong too.
Your job as tech lead
4 minClaude Code can write the code for this. You still own the decisions, and you have to know what good looks like to accept or reject its work.
- The riskiest assumption and the written scope cut; everything else is out.
- Every shortcut and its register entry; what is never a shortcut (correct numbers, access control, personal data).
- When a debt gets repaid: when its trigger fires or interest passes principal, not "when we have time".
Build the MVP payout breakdown page; budget 3 weeks. Plan first and list every shortcut so I can approve each. A nightly job in `jobs/payout-breakdown/` writing one row per booking per month; a page in `src/extranet/payouts/`; EUR only; behind payout_breakdown for eurozone hotels. Call billing's commission function; never copy it, or stop and tell me. Each shortcut gets an entry in `docs/debt-register.md` and a DEBT id in code. Test that page totals equal billing's payouts.
- Each listed shortcut has a register entry; nothing unlisted appears in the diff.
- No duplicated business logic (rates, fees, rounding) in the diff.
- One test hotel can't open another hotel's payout URL.
- Billing's function copied "to avoid coupling", unrecorded.
- TODOs with no DEBT id.
- Scope creeping toward PDF export or multi-currency "because it was easy".
Check yourself
2 minNext episode: Maya's new one-page checkout went live last week. Her dashboard says it worked. Omar's says it didn't.
Mark it complete to update your skill map.
Go deeper (optional)You don't need this to understand the lesson. Open it when a project needs the details: Technical deep dive, Visual diagram, Analogy, Check your understanding, Practice ladder, Explain it yourself.
Technical deep dive
You cut the payout page to 3 weeks (Lina checks)
The full payout breakdown page is 9 weeks of work. You have 3 weeks and 2 engineers. Ship something that tells you whether a breakdown cuts payout tickets, with numbers partners can trust, and leave a clear record of what you owe.
- 1Name the riskiest assumption
"Seeing a breakdown answers partners' payout questions." Metric: payout tickets per 1,000 bookings, −50% in 8 weeks, for flagged hotels vs the rest.
Why: If this is false, currencies and PDFs don't matter. Lina: "Good. Say the metric before you write the first line."
- 2Cut what doesn't test it
Nightly data (not live), EUR only (81% of partners), chargebacks as one "adjustments" line, no PDF export, desktop only.
Why: Each cut removes weeks without weakening the test: partners can still see why their payout changed.
- 3Keep what can't be cut
Totals equal the real payout (a nightly check), each hotel sees only its own data (authorisation), and a ticket tag to measure the result.
Why: These are trust, not scope. Without them, the page creates incidents and the test gives a wrong answer.
- 4Record every cut
Add each shortcut to the register with interest, principal and trigger, and mark it in code with its id.
yaml- id: DEBT-032 title: Payout page in EUR only kind: deliberate interest: none until non-EUR partners get the page principal: ~1 engineer-week trigger: before UK/CH rollout # blocks rolloutWhy: Six months from now, nobody will remember why it's EUR only. The record turns a mystery into a scheduled task.
- 5Ship to a slice and decide on a date
Feature flag for 1,200 eurozone hotels. After 8 weeks, compare their payout tickets with the others, then decide: build the full page, change it, or remove it.
Why: A date and a metric turn the MVP into an experiment with an ending, not a forever-prototype.
| Signal | Usually means | Typical action |
|---|---|---|
| Interest × weeks you'll live with it > principal | Fixing now is cheaper | Schedule repayment |
| You're about to build on top of it | New work multiplies the interest | Repay first, as part of the feature |
| It blocks a planned launch or market | Hard deadline on repayment | Put it on the roadmap with a date |
| The feature may be removed | Repaying may be wasted | Wait; delete instead of fixing if it dies |
| Low interest, isolated code | Debt that costs almost nothing | Leave it, document it |
Visual diagram
A hypothetical StayHub MVP for group bookings: a concierge MVP with real users, a mostly manual backend, and deliberate debt written down.
Analogy
- Your personal moneyA mortgage, taken on purposeYour codebaseDeliberate technical debt
- Your personal moneyA forgotten credit cardYour codebaseAccidental technical debt
- Your personal moneyYour bank statementYour codebaseThe debt register
- Your personal moneyMonthly interest paymentsYour codebaseSlower work, incidents, manual chores
- Your personal moneyRenting before you buyYour codebaseAn MVP before the full build
Where the analogy breaks: a bank tells you your interest rate. Code doesn't. You have to estimate the interest yourself, and it often grows as more features are built on top.
Check your understanding
Practice ladder
Which debts are due?
Estimation Warm-upThe register this quarter (you'll work in all of this code for the next 12 weeks unless noted):
| id | interest | principal | notes |
|---|---|---|---|
| DEBT-033 | ~10 h/week | ~80 h | |
| DEBT-032 | 0 h/week | ~40 h | blocks UK/CH rollout in 6 weeks |
| DEBT-041 | ~1 h/week | ~120 h | isolated script, rarely touched |
| DEBT-044 | ~6 h/week | ~60 h | the feature it supports may be removed next month |
For each, trace the decision: repay now, schedule, leave, or wait. Show the break-even where it applies.
Write DEBT-031 properly
Design PracticeAfter the incident, Lina asks you to record the copied commission formula. Fill in the missing fields.
- id: DEBT-031 title: Nightly payout job uses its own copy of billing's commission formula kind: ___ owner: team-partner-finance interest: ___ principal: ___ trigger: ___ safety_net: ___
An MVP for group bookings
Design PracticeMaya: "Wedding and conference organisers want to book 10+ rooms at once. Nobody knows if they'll do it online." The full system (room blocks, contracts, deposit schedules) is estimated at 4 months.
Design an MVP: the riskiest assumption, what you build, what you do by hand, what you never cut, which debts you record, and how you decide after it runs.
Rewrite the booking-status logic?
Decision StretchDuring an incident, the team finds booking-status logic duplicated in 3 services (booking, payouts, notifications). It causes about 2 bugs a quarter, and every status change touches 3 codebases. A senior engineer proposes a 2-month rewrite into one shared status service, pausing feature work.
Next quarter, the roadmap includes a new status ("partially refunded") and two features in payouts.
Write a short decision: "We chose X over Y because…, accepting the risk of…".
Explain it yourself
Explain to a product manager how you'd ship a risky new feature fast without leaving the codebase in a mess.