Build vs BuyGENERALSCALE-SPECIFICILLUSTRATIVE

Integration and Operating Cost

"Build" is estimated for the week it takes; "buy" is estimated for the SDK call. Both are wrong the same way: the cost of a capability is what it takes to connect it and what it takes to live with it, and neither appears in the first estimate.

The moveWorked exampleNext questions

The situation, the reflex, and why it stalls

Every lesson starts where being stuck starts: someone has a problem, and the first move that comes to mind feels like progress.

The question

Two options meet the requirement: build it, or integrate a provider. What are the costs that the obvious estimates leave out, and how do you find them before they find you?

The situation

Sending order emails. Building: "a template and an SMTP call, a day". Buying: "their SDK, an afternoon". Both estimates are honest and both are about the first day. Nobody has said what either option costs in month six, and the decision is about to be made on the difference between a day and an afternoon.

The reflex

Compare the build estimate to the integration estimate and pick the smaller. It is a fair comparison of the two numbers that exist, it produces a decision quickly, and it feels rigorous because there are numbers.

Why it stalls

The build estimate covers construction and not operation. The SMTP call takes a day; deliverability, bounce handling, a blocked sending IP the week of the launch, the unsubscribe requirement — those are the email system, and they were not in the day.

What the reflex produces — and fails to produce
  • The build estimate covers construction and not operation. The SMTP call takes a day; deliverability, bounce handling, a blocked sending IP the week of the launch, the unsubscribe requirement — those are the email system, and they were not in the day.
  • The buy estimate covers the SDK call and not the integration it forces. For payment, the "afternoon" turned out to be a pending state, a webhook handler, a duplicate check, a return page and a public URL. The provider did the hard part; the integration is still a design.
  • Neither estimate includes the fee, and neither includes the alternative to the fee: the operational load of the built version, which is paid in attention rather than money and therefore does not appear on any invoice.
  • The decision is made on numbers that measure the wrong thing, and it feels rigorous, which is worse than feeling arbitrary — it will not be revisited.
ProblemUnderstandRequirementsConstraintsUnknownsDecompositionSmallest StepModelExperimentObserveDebugLearnIterate

The move

Precisely enough to apply it to a problem you have never seen — not a slogan.

  • Split each option's cost into three parts and estimate all three: *construction* (the build, or the first integration), *integration surface* (the states, handlers and failure paths the option forces into your design — for a bought thing this is most of the work; for a built thing it is where it touches the rest of the system), and *operation* (what it costs to keep working at month six — fees for the bought thing; on-call, edge cases and maintenance for the built one).
  • Estimate operation by asking what the capability needs when it *fails*, because operation is mostly failure handling that never ends. Email at month six is bounces, reputation and a blocked IP; payment at month six is disputes and reconciliation. Whoever owns the failure pays the operating cost (External Systems Fail).
  • Then compare the three-part costs, not the construction numbers, and write down which part dominated. For email the operation dominates and buying wins; for "search by name" the construction is a query and nothing dominates, so neither is needed yet (The Trade-Off Matrix, Without Fake Precision).
  • Put a boundary between the capability and the rest of the system regardless of the decision, so that the operating cost of being wrong — swapping providers, or replacing a built thing with a bought one — is a change in one place (Interfaces Emerge From Boundaries).

Three costs, two options, one capability

The reflex has one number per option. The matrix has three, and for email the third row is where the decision was actually made. The construction row — the one the reflex compares — is the least important line in the table.

CostBuild emailBuy email
ConstructionA template and an SMTP call: about a daySDK and a template: an afternoon
Integration surfaceOne call per order event; retries on failure; the order must not wait on itThe same call and constraint; plus a webhook for bounces
Operation at month sixDeliverability, bounce processing, domain reputation, a blocked IP once a quarter, list hygiene — paid in the one engineer's attentionA monthly fee, small at this volume; bounces reported, not chased
LeavingReplace with a provider behind the same call — cheap if the call is in one placeTemplates and suppression list move; addresses are ours anyway — cheap
Dominant costOperationFee, and it is small

The bought thing's real integration

For payment, the integration surface dominated — and it is entirely the store's to design. The ladder below is the reflex claim "just use the SDK" taken down to what was actually needed, with the case where the claim was right after all, because sometimes it is.

"The payment integration is an afternoon with the SDK"

Payment is an afternoon — install the SDK and call it.

  1. Why an afternoon? Because the SDK page shows a charge in ten lines.
  2. Why is that not the integration? Because the provider confirms later by webhook, so the ten lines are the request and none of the response handling.
  3. Why does the response need handling? Because an order must exist before the redirect, become paid on a verified, deduplicated confirmation, show a truthful state when the customer returns, and be reconciled if the confirmation never arrives.
  4. Why is that ours and not the provider's? Because those are states of *our* order, and only our system knows what an order is.
real requirement An order lifecycle that stays correct across a delayed, possibly repeated, possibly missing confirmation from an external system — the provider handles the card; the lifecycle is the integration.
simpler One pending state, one idempotent confirmation handler keyed on the provider's reference, one return page that reports pending honestly, and a scheduled reconciliation query — a few days, most of it the spike already did.

the claim was right when The provider offers a fully hosted checkout that creates and confirms the order on its side and merely tells you afterwards — then the integration really is close to an afternoon, and the cost moves to living with their order model instead of yours.

Scoring it without pretending

A trade-off matrix for the email decision, scored coarsely on purpose. The caveat is the important line: the numbers are a way to write down a judgment, and the judgment was made on the operation row of the previous section.

Order email: build, buy, or log it
OptionSimplicityReliabilityCostTimeMaintainabilityNote
Build: SMTP + templateCheap to start; reliability and maintainability decay as deliverability becomes the job.
Buy: email providerA fee, a small integration, and the failure modes are theirs to chase.
Neither yet: log the emailFine until a real customer places a real order; a boundary makes the upgrade one file.

caveat The scores are one to five and mean "worse" to "better" in this store, this year. They cannot express that the built option's reliability score is a two *because of month six*, not day one, nor that the "neither" option is a five on everything and unacceptable the day a real order is placed. Read the note column; the numbers are its summary.

The boundary that makes the decision cheap to change
1interface OrderMailer:
2 sendConfirmation(order) -> void // must not block order creation
3
4LogMailer implements OrderMailer // V1: writes a line
5ProviderMailer implements OrderMailer // later: one call + bounce webhook
6
7// checkout calls mailer.sendConfirmation(order) after commit,
8// never before, never awaited on the critical path

One interface, two implementations, one call site. Not a provider-agnostic email framework — that would be a built thing with its own operating cost.

How to do it

Most important first.

  • For the built option, write the month-six list before the day-one list: what breaks, who is paged, what the edge cases are. If you cannot write it, you do not know the capability well enough to estimate building it (Guarantees and Failure Modes).
  • For the bought option, sketch the integration as states and handlers — what your system must do before, during and after the call — and estimate that, not the SDK call (Treating External Systems as What They Are).
  • Find the fee structure and the rate limits in the provider's documentation, and ask what they look like at the traffic the store expects in a year, not today (Time, Users, Data).
  • Estimate leaving. For a bought thing: what data lives with them, and what it would take to move. For a built thing: what it would take to replace with a provider later. A boundary makes both cheap; its absence makes both a rewrite.
  • Record which cost dominated. The decision should be re-read when that cost changes — fees at scale, or the built thing's maintainer leaving.

Worked on a concrete problem

The move has to produce something. This is what it produced.

  • Email for the store, built: construction one day; integration surface small — one call per order event; operation: deliverability monitoring, bounce processing, reputation of a sending domain, list hygiene, a blocked IP once a quarter — a recurring cost in attention with no invoice. Bought: construction an afternoon; integration surface the same one call plus a webhook for bounces; operation: a monthly fee, small at the store's volume. Operation dominated; buy.
  • Payment, bought: construction "an afternoon" per the SDK page; integration surface a pending state, a redirect, a confirmation handler with verification and deduplication, a return page, a public URL and a reconciliation path — measured by the spike as the real cost, in days. Operation: a percentage fee per order, and disputes handled by the provider. The integration surface dominated and was still far cheaper than the built alternative, whose operation is a compliance regime.
  • Image storage, V1: build means a folder on the server — construction an hour, operation "what happens when the server is replaced". Buy means an object store — construction a morning, operation a small fee plus egress. Nothing dominates at V1; the folder wins *with a boundary* — an ImageStore interface — so that the day the server is replaced, the swap is one file.
  • Search: "filter by name" is a query; construction an hour, integration none, operation none. Both build-a-search-service and buy-a-search-provider lose to "neither yet". The three-part costing found the option the two-number comparison did not have a column for.

How you know it worked

What now exists that did not before, and what question you can now ask.

  • Each option has three costs written next to it, and you can say which one dominated the decision.
  • The month-six list for the built option exists and someone has been named as the person who would pay it.
  • The bought option's integration is a list of states and handlers with an estimate, not the word "SDK".
  • There is a boundary in the code, and swapping the decision is a change behind it.

The questions you can now ask

The field this whole domain exists for. After this lesson, these are the questions to put to an unfamiliar problem.

Next questions
  • ?What does this option cost to construct, to connect to the rest of the system, and to keep working at month six?
  • ?What does the built version need when it fails, and who is the person paying that?
  • ?What states, handlers and failure paths does the bought version force into my design?
  • ?What do the fees and rate limits look like at next year's volume?
  • ?What would it cost to leave — and is there a boundary that makes that a change in one place?

What can go wrong

How the move itself fails
  • Operating cost is estimated so pessimistically that nothing is ever built. Some built things — a query, a cron job, a template — have an operating cost of nearly nothing, and the move should say so as clearly as it says the opposite about email.
  • The three-part costing is done once and filed. Fees scale with volume and built things decay with neglect; the cost that dominated at V1 is not the cost that dominates at year two.
  • The boundary is drawn so abstractly that it costs more than the swap it protects against. An interface with one implementation and a config switch is enough; a provider-agnostic abstraction layer over email is a built thing with its own operating cost (Premature Abstraction).
  • Integration surface is counted for the bought option and not for the built one. A built email sender also has states and handlers — bounces, retries — and a comparison that only charges one side is the reflex in a spreadsheet.
What the move costs
  • Three-part costing takes longer than two numbers and asks for information — month-six failure modes — that a team without operating experience cannot produce well. It is still better than pretending the cost is zero.
  • A boundary drawn for every bought thing is an abstraction cost paid on every capability, including ones that will never be swapped. Draw it where the swap is plausible, thin elsewhere.
  • Estimating operation honestly makes "build" lose more often than engineers would like, and the lesson has to be careful that this is a finding rather than a rule.
Misreads
  • "Operating cost means fees." Fees are the *bought* option's operating cost. The built option's is on-call, edge cases and maintenance, and it is the one that does not appear on an invoice, which is why it is forgotten.
  • "So buying is always cheaper in the long run." Buying is cheaper when the provider's operation is cheaper than yours would be and the fee is small next to it — email, payment. A capability with a trivial operating cost — a query, a folder — is not worth a fee, and "always buy" is falsifiable there.
  • "Integration is just glue code." Glue is the part you can see. The pending state, the duplicate check and the reconciliation path are *design*, they are yours, and they are where bought-capability projects actually go wrong (Partial Failure).

Where this applies

Problem-solving advice is stated as universal far more often than it is. These labels say what each method is specific to — and where CONTESTED appears, the note gives the strongest form of the opposing view.

  • GENERALConstruction, integration surface and operation are the three costs of any capability with a provider alternative — email, payment, storage, search, models, authentication — regardless of what is being built around it.
  • SCALE-SPECIFICAt a store's early volume, provider fees are small and built-thing operation is paid by the one engineer who has no time; buying wins. At very high volume the fee can exceed the cost of a team, and the same three-part costing flips toward building — which is why the dominating cost is recorded, so the flip is noticed.
  • ILLUSTRATIVEThe day, the afternoon, the month-six list, the blocked IP once a quarter and every fee mentioned are invented to show the shape of the three costs; no real provider's pricing is described.

Where the depth lives

This domain asks the question and hands the answer off by name.