Note from production
The backend is where product decisions become real
Why unclear product behavior eventually shows up as queues, retries, state, and edge cases.
Backend architecture is not separate from product work. It is where product decisions become durable behavior.
If the product is unclear about state, permissions, retries, ownership, or user intent, the backend will eventually encode that confusion. The symptoms often look technical: strange data, duplicate jobs, brittle integrations, missing audit trails. The cause is usually a product decision that was made implicitly.
Good architecture makes these decisions visible. It gives the team a map, not just more code.
Every durable behavior contains a product decision
Consider a workflow that lets a customer upload something, ask the system to process it, and receive a result. The interface may show one button and one progress indicator. The backend still has to answer questions the interface can avoid:
- Is the request accepted, running, partially complete, failed, or cancelled?
- Can the customer submit the same request twice?
- What happens if processing succeeds but the notification fails?
- Who can view, retry, correct, or delete the result?
- Which state is authoritative when two services disagree?
- How long must the system retain evidence of what happened?
Those are product rules. A queue, database schema, or API can implement them, but none of those tools can decide what the rules should be.
When the rules remain implicit, each component makes a local guess. The API returns one status, a worker records another, the interface invents a timeout, and support learns a manual recovery path. The system becomes difficult to explain because it contains several conflicting versions of the product.
State should describe the user’s reality
Teams often model state around implementation details: a row was inserted, a job was claimed, or a provider returned a response. Those facts matter operationally, but they are not always the state the user needs.
A useful state model connects three views:
- Customer state: what the person can reasonably believe has happened.
- Business state: what the company has committed to deliver or record.
- System state: what each component has completed and what can safely happen next.
The model does not need to expose every technical step. It does need to prevent contradictory outcomes. If payment is captured but fulfilment fails, for example, the system needs an explicit recoverable state rather than a generic error that hides the commercial obligation.
This is why I start consequential architecture work with a workflow and state map. The purpose is not documentation for its own sake. It is to find the points where a technical transition changes what the product promises.
Retries need a business meaning
“Retry on failure” sounds like an infrastructure decision. It becomes a product decision as soon as the operation can charge money, send a message, create a record, or trigger an external action twice.
A safe retry design asks:
- Which operation is idempotent, and what key proves it is the same request?
- Which failures are temporary and which require a person or a different input?
- How many attempts are useful before the workflow should change state?
- What evidence should an operator see before retrying manually?
- Does the customer need to know that the workflow is delayed rather than complete?
Without those answers, retries can hide a broken dependency, create duplicates, or keep work in a permanent “processing” state. With them, the queue becomes part of a deliberate recovery model.
Ownership is an architectural boundary
Many distributed-system problems are ownership problems wearing technical names.
If several services can change the same business state, the team needs to know which one decides, which ones observe, and how disagreement is repaired. If several teams operate one workflow, they need a shared contract for support, schema changes, and incident response. If no component owns the final outcome, every component can be healthy while the customer journey is broken.
The ownership boundary should be visible in code, data contracts, telemetry, and team responsibility. That does not mean putting everything into one service. It means having one clear decision point for each important state transition.
The shared API delivery case study shows the same principle at team scale. Templates and automation helped, but the durable improvement came from making contracts, delivery paths, and responsibility explicit across several streams.
Observability should answer product questions
Infrastructure metrics can tell you that a process is alive or a queue is growing. They do not automatically tell you whether customers are receiving the promised outcome.
For a critical workflow, I want an operator to answer:
- How many requests entered each meaningful state?
- Where are requests waiting, failing, or being retried?
- Can one customer or tenant be affected while aggregate health looks normal?
- What changed before the behavior changed?
- Can the team reconstruct one request without reading several unrelated systems by hand?
This is product observability: technical evidence organized around the user journey and business commitment. It makes incidents easier to diagnose and also exposes ambiguous behavior before it becomes an incident.
A practical decision sequence
Before choosing a framework, queue, or database pattern, I work through the decision in this order:
- Name the user outcome and the business commitment.
- Draw the states and the events that move between them.
- Assign one owner to each consequential transition.
- Define duplicate, timeout, cancellation, and partial-failure behavior.
- Decide what evidence a user, support person, and engineer each need.
- Only then choose the storage, messaging, and service boundaries that enforce the model.
The result is not necessarily a larger architecture. It is usually a smaller set of rules with fewer places allowed to improvise.
For a future product, an Architecture Decision Sprint can make these rules explicit before implementation hardens around them. For a live product, a Production Systems Review traces where the current behavior has already diverged and sequences the smallest useful repairs.