Guide chapters
Reversible and irreversible decisions
The problem#
Most decisions when building a marketplace are reversible and not worth more than a moment of thought. A dozen or so are not, and they decide whether in two years you extend the system or rewrite it.
This chapter is a list of those, gathered from the earlier chapters into one place.
Cheap to add later#
These are not worth planning ahead for. They cost the same today and in a year.
- Additional fields on the seller and product profiles.
- Filters, search and views in the panel.
- New notification templates and channels.
- Further shipping methods and free delivery thresholds.
- Further integration providers, if the first landed in a shared layer.
- Roles and permissions, as long as data isolation lives in the access layer.
Expensive to retrofit#
| Decision | Cost of changing it late | Chapter |
|---|---|---|
| An order has one seller | migrating every historical order | 1, 6, 7 |
| A product has one variant | migrating prices, stock and order lines | 3 |
| Stock without a location dimension | migrating stock and open reservations | 5 |
| No external identifier | re-matching every imported item | 3, 4 |
| Values computed on read | historical reports change their answers | 6, 9, 11 |
| Commission as a reference to a rule | a rate change rewrites the past | 11 |
| Cancellation only of whole orders | recalculating values and taxes across history | 7, 13 |
| Payouts not linked to orders | no way back for a refund | 10, 13 |
| Data isolation in the view | reviewing every access path | 15, 17 |
| No operation identifier | what already happened cannot be reconstructed | 16 |
Dangerous assumptions#
These are not decisions but beliefs that slip into the code unnoticed.
| Assumption | Simpler safe alternative |
|---|---|
| An order always has one seller | the seller on the line, not the order |
| There will only ever be one commission rate | record the amount charged on the line |
| A platform product and an external product are one thing | a separate identifier with its source |
| A successful payment means a successful order | two events and a way to spot discrepancies |
| A seller will never connect a shop | room for an external identifier |
| The current seller profile will always be enough | snapshot the details shown on the order |
| A live record can describe historical state | persist values at the time of the event |
How to use this#
Before any data model decision, ask three questions. If the answer to any is yes, the decision belongs in the second category and deserves an hour rather than a minute.
- Do historical records rest on this value?
- Would changing it force recalculating data that must not be recalculated?
- Is the reverse direction of the change free?
The third question is the most practical. Moving from a more general model to a narrower one is almost always free, and from narrower to more general almost never. So when in doubt you pick the general one, provided it costs no real work today.
What works in practice#
The corrections that cost me most concerned the shape of the data rather than missing features. A feature is written alongside the data that already exists. Changing how the data is arranged touches everything already recorded on it.
Checklist#
- You know which decisions in your project belong to the second category.
- For each you have chosen the general variant or rejected it deliberately.
- No value used in settlement is computed on read.
- No assumption from the last table is baked into the code by accident.
I design multi-vendor platforms with onboarding, payments, moderation, and operational workflows.
Explore marketplace development