Cut scope, not corners: an honest way to scope an MVP
Speed has to come out of somewhere. Take it out of scope and you ship something small that works. Take it out of engineering and you ship something that looks finished and cannot be built on.
There are two ways to make software arrive sooner. Cut what it does, or cut how well it is built. In a planning meeting they feel like the same lever. Six months later they are nothing alike.
The first is scope, and it is reversible. The feature you did not build is still written down, and you can build it later with better information than you have now. The second is corners: authentication, error handling, the data model, the path to production. Those are load-bearing, they touch everything else, and retrofitting them costs several times what building them would have.
So when we scope an MVP, most of the work is deciding what to leave out, and refusing to take the discount that is on offer everywhere else.
01. What an MVP is actually for
An MVP is not a small version of the product. It is an instrument for answering one question you cannot answer by talking about it.
That distinction decides everything downstream. A small version of everything has no natural boundary, so it grows until the money runs out. An instrument has a question, and the question tells you what to build and, more usefully, when to stop.
Write the question down as one sentence, and next to it what result would change your mind. Risky assumptions fall into three kinds: will anyone do this at all (demand), can it be built to a standard people accept (technical), will it survive the way people actually work (operational). Most first versions hedge all three and prove none.
Suppose a founder wants a tool that reads incoming supplier invoices and posts them into an accounting system. The tempting scope is a product: dashboards, multi-user accounts, a supplier directory, reporting. The risky assumption is narrower and harsher. It is whether extraction is accurate enough on the invoices those suppliers actually send that a bookkeeper stops checking every line. If that is false, the dashboards are decoration. If it is true, they are a straightforward build you can fund with evidence.
Name the assumption first. Everything else in this essay is downstream of that one sentence.
02. Finding the three MVP features
Three is not a magic number. It is a forcing function. A list of MVP features you can hold in your head is one you can also defend. A list of eleven is a wish.
The method is subtraction. Write down everything anyone has asked for, then take each item and ask one question: if this were missing, would the test still answer the question? If yes, it goes to the backlog. Keep going until removing anything else would break the answer. What remains is the scope.
Done honestly, the survivors have the same shape. Something that gets real data in. Something that does the one hard thing. Something that puts the result where a person can act on it. Input, judgement, output. In the invoice example: an inbox the supplier emails, the extraction with a confidence signal, and a review screen where a bookkeeper approves or corrects a line. No dashboard, no directory, no reporting.
Two things sneak through. The competitor feature, on the list because a rival has it rather than because anything depends on it. And the cheap feature, on the list because it is easy, and easy things accumulate faster than hard ones because nobody argues about them. Same test for both. Does it move the assumption?
What gets cut is written down, not deleted. People agree to cuts far more readily when the cut is a queue rather than a refusal, and a written backlog stops the same argument being had weekly.
one risky assumption
│
▼
┌──────────────────────────┐
│ does this feature prove │
│ it, or kill it, in one │
│ release? │
└────────────┬─────────────┘
yes │ no
┌───────────┴───────────┐
▼ ▼
┌──────────────┐ ┌────────────────────┐
│ v1: three │ │ backlog: written │
│ features │ │ down, not deleted │
└──────┬───────┘ └────────────────────┘
│
▼
───────────────────────────────────────────
real auth · real error states · a data
model that survives success · deployable
infrastructure · one evaluation loop
─────────────────────────────────────────── fig. 01: the top half is a negotiation and everything in it is reversible. The floor is not part of the negotiation.
03. The corners that never get cut
These five are the floor. They are cheap while the codebase is small and expensive once it is not, because each of them touches every part of the system that comes after it.
Real authentication. Not a shared password, not "we will add login later". Identity reaches into every route, every query and every row you store, so adding it afterwards is a migration plus a re-reading of the codebase to find everywhere that assumed one user. Use an established provider or a well-maintained library, never your own. Sessions, password reset, and one role boundary if there will ever be two kinds of user. Small at the start of a project. A project of its own later.
Real error states. Every call that crosses a network fails eventually. The MVP standard is not retries with backoff and a dead letter queue. It is three things: nothing fails silently, every failure produces a message a person can act on, and every failure is logged with enough context to find it again. Products with a model in the loop need one more, because the characteristic failure there is not an exception but a confident, well-formed, wrong answer. Validate in ordinary code before the output reaches a screen, and show the user when you are unsure.
A data model that survives success. This is the corner with the sharpest retrofit cost, because data has inertia. A screen can be rewritten in an afternoon. A year of rows written under the wrong assumption cannot.
-- Not more tables. Better keys, and columns you cannot add later for free.
create table account (
id uuid primary key,
created_at timestamptz not null default now()
);
create table document (
id uuid primary key,
account_id uuid not null references account(id), -- owner is the account,
created_by uuid not null references app_user(id), -- not the person
status text not null, -- a value, not a boolean
created_at timestamptz not null default now(),
updated_at timestamptz not null default now()
);
create index on document (account_id, created_at desc); Three decisions in that sketch pay for themselves. Records are owned by an account rather than a person, so the day a customer says "my colleague needs access" is a feature and not a migration. Status is a value rather than a boolean, because there is always a third state. Timestamps exist from the first row, because nobody has ever regretted knowing when something happened. None of that is over-engineering: the same number of tables, with columns chosen by someone who has been asked these questions before.
Deployable infrastructure. If it only runs on a laptop it is not a product, it is a demo with a good disguise. The standard is modest: one merge puts it live, configuration lives in environment variables, secrets are not in the repository, there is somewhere to try things that is not production, backups are on, and it sits behind a real domain with TLS. Doing this on day one is small because there is nothing to move. Doing it later means moving live data and live users, which is a different job with a worse failure mode.
At least one evaluation or test loop. Not full coverage. One automated way to know the critical path still works: an end to end test that walks the main journey, and for anything with a model in it, a scored set of real examples with agreed answers. Without it, every later change is a guess, and the product gets harder to change as it grows, which is backwards for something whose purpose is to be changed.
Added up, the floor is a modest share of the build. It gets cut anyway, and the reason is not cost. It is that none of it is visible in a demo. Nobody has ever been applauded for a foreign key.
04. What always gets cut first
The list of things you can safely drop is longer than anyone expects, and almost none of it hurts.
- Settings and preferences. Pick sensible defaults and hard-code them. If an early user wants a different value, change it for them. Two lines and a deploy beats a settings page, and you learn which preferences people really have.
- Admin polish. An internal admin panel is usually a database client, a couple of scripts and a message in a shared channel. Build the screens your customers see, not the ones you see.
- The second platform. Web or one mobile platform. Not both, and not a native app and a web app that have to stay in step. Every platform you add multiplies the surface for a test that has not run yet.
- Edge-case automation. Automate the common path and handle the unusual ones by hand, deliberately, while counting how often they turn up. Manual handling is not a failure. It is measurement, and it tells you which edge case is worth automating rather than guessing.
- Everything that decorates. Onboarding tours, notification systems, granular permissions, billing before anyone has agreed to pay, dark mode, translations, integrations beyond the one your test needs, and any design system larger than the screens you are shipping.
One rule underneath all of it: anything a person can do for the first users, a person should do. Software written to serve ten users is mostly wasted, and doing the work by hand is how you find out what the software should have been.
05. What week one should look like
A first week that produces a plan, a backlog and some designs has produced opinions. A first week that produces something running has produced information.
What we aim for is a working slice: narrow, vertical, on real data, deployed. Not three half-built layers. One path that goes all the way through. In the invoice example that is a real invoice arriving, being read, and a result appearing on a screen, with everything either side stubbed out and obviously stubbed out.
Real data is the part that cannot be skipped. Sample data is written by the person writing the code, which makes it a mirror. Real invoices are scanned at an angle, run to three pages, quote in two currencies, and include the one supplier who sends a photograph. Assumptions die on contact with the real set, and the earlier they die the cheaper they are. It is why the first week is shaped around getting to that slice rather than around documents.
Then demo it live. Not screenshots, not a recording. A live demo cannot be faked, and it changes the meeting: instead of a status report you get the first honest reactions to the thing itself, usually including at least one "that is not how we do it here" that would otherwise have surfaced much later.
06. Sizing it honestly
This is where most proposals stop being truthful, so it is worth being plain: we do not give a duration for a build before we have seen what it has to work with.
The reason is not caution. It is that the variance sits almost entirely in things a feature list does not show. Data quality is the largest by some distance: the same feature over clean structured records and over scanned PDFs from a dozen suppliers are not the same project and never were. Then what it has to integrate with, and whether that system has an API or only a login page. How many approvals sit in the path, and how quickly someone can answer a question when we are blocked.
So the order runs: a scoping conversation, then a working slice on real data, then a size. Anything quoted before that is a number chosen to win the work, and the honest version of it returns later as a change request.
A size you can trust names the risky assumption it is sized against, states in writing what is out of scope, and says what would make it longer. That last part tells you whether the person writing it has done this before. It starts with a scoping call, and the work beyond it sits under product development.
07. When not to build the MVP at all
Sometimes the honest answer is that there is nothing to build yet. Five cases come up often enough to check for.
- The question can be answered without software. If the risky assumption is demand, a landing page, a spreadsheet and twenty conversations answer it faster than any build. If it is whether a model can do the task at all, a notebook over fifty real examples answers it before a product exists.
- It already exists. Some problems are a subscription and a couple of days of configuration. Building your own is defensible when the thing you are building is the difference, and hard to defend when it is not.
- There is no route to the users. If nobody can put this in front of the people who would use it, the MVP cannot answer anything. It is a demo with a longer build time.
- The constraint is organisational. If a process is ignored because nobody trusts it or nobody is accountable for it, a nicer interface will be ignored too, in colour. Software makes a working process faster. It does not make a broken one work.
- Nobody can say what success looks like. "See if it takes off" is not a criterion. If no one can state the result that would count as proof, the project has no ending.
We give some version of that answer regularly, and it is almost always the cheaper one to receive.
When it is a yes, the method is the whole discipline. Cut scope until what is left is three features that would genuinely settle the question. Refuse to cut the floor underneath them. Get a slice running on real data and look at it together. Then size the rest, with evidence, once there is something to size.