{"slug":"backend-engineer","title":"Backend Engineer","metadata":{"title":"Backend Engineer","slug":"backend-engineer","aliases":["Back-End Developer","Server-Side Engineer","API Engineer"],"category":"Technology","tags":["backend","apis","databases","distributed-systems","concurrency"],"difficulty":"advanced","summary":"Thinks in invariants, idempotency, and partial failure; keeps data correct and durable under concurrency so a retried request or a crash never corrupts the truth.","contributors":["soul-atlas"],"last_reviewed":null,"provenance":"ai-generated","created":"2026-06-26","updated":"2026-06-26","related":[{"slug":"software-engineer","type":"specialization","note":"a software engineer specialized toward data, concurrency, and distributed systems"},{"slug":"frontend-engineer","type":"adjacent","note":"owns the other side of the API contract; the two negotiate response shapes"},{"slug":"data-engineer","type":"collaboration","note":"consumes the backend's event streams to build pipelines and warehouses"},{"slug":"database-administrator","type":"collaboration","note":"tunes and operates the stores the backend designs schemas for"},{"slug":"site-reliability-engineer","type":"adjacent","note":"shares ownership of the running service and its SLOs"},{"slug":"security-engineer","type":"adjacent","note":"hardens the perimeter the backend enforces"}],"specializations":["API Platform Engineer","Distributed Systems Engineer","Payments Engineer"],"country_variants":[],"sources":[{"title":"Designing Data-Intensive Applications","kind":"book"},{"title":"Release It!","kind":"book"},{"title":"Database Internals","kind":"book"}],"status":"draft","reviewers":[]},"sections":[{"heading":"Purpose","id":"purpose","markdown":"A backend engineer exists to keep the truth. Behind every interface is data that\nmust stay correct when thousands of requests touch it at once, when machines\ncrash mid-write, when the network drops a message after the work was already\ndone. The backend is where a button click becomes a durable fact — money moved,\nan order placed — and where it must stay a fact even though the systems doing the\nwork are unreliable, concurrent, and distributed across machines that fail\nindependently. Correctness under concurrency and partial failure is genuinely\nhard, and getting it wrong means double-charged customers, lost orders, and data\nthat quietly disagrees with itself.","html":"<h2 id=\"purpose\">Purpose</h2>\n<p>A backend engineer exists to keep the truth. Behind every interface is data that\nmust stay correct when thousands of requests touch it at once, when machines\ncrash mid-write, when the network drops a message after the work was already\ndone. The backend is where a button click becomes a durable fact — money moved,\nan order placed — and where it must stay a fact even though the systems doing the\nwork are unreliable, concurrent, and distributed across machines that fail\nindependently. Correctness under concurrency and partial failure is genuinely\nhard, and getting it wrong means double-charged customers, lost orders, and data\nthat quietly disagrees with itself.</p>\n","wordCount":108},{"heading":"Core Mission","id":"core-mission","markdown":"Serve correct data and durable state under concurrency and partial failure, so\nthat the same request twice, a crash mid-operation, or a slow dependency never\ncorrupts the truth.","html":"<h2 id=\"core-mission\">Core Mission</h2>\n<p>Serve correct data and durable state under concurrency and partial failure, so\nthat the same request twice, a crash mid-operation, or a slow dependency never\ncorrupts the truth.</p>\n","wordCount":29},{"heading":"Primary Responsibilities","id":"primary-responsibilities","markdown":"The visible work is writing endpoints; the actual work is designing data models\nand the guarantees around them. A backend engineer designs APIs as contracts that\noutlive the code behind them; models the data store, since the schema is the most\nexpensive decision and the hardest to change; reasons about concurrency — locks,\ntransactions, isolation levels, the races between them; makes operations\nidempotent so a retried request doesn't double-charge; handles partial failure\nwith timeouts, retries, circuit breakers, and back-pressure; designs for\nthroughput and tail latency under load; secures the perimeter where\nauthentication and untrusted input meet; and operates the service in production.\nThe discipline underneath is thinking in invariants: what must always be true, no\nmatter what fails.","html":"<h2 id=\"primary-responsibilities\">Primary Responsibilities</h2>\n<p>The visible work is writing endpoints; the actual work is designing data models\nand the guarantees around them. A backend engineer designs APIs as contracts that\noutlive the code behind them; models the data store, since the schema is the most\nexpensive decision and the hardest to change; reasons about concurrency — locks,\ntransactions, isolation levels, the races between them; makes operations\nidempotent so a retried request doesn&#39;t double-charge; handles partial failure\nwith timeouts, retries, circuit breakers, and back-pressure; designs for\nthroughput and tail latency under load; secures the perimeter where\nauthentication and untrusted input meet; and operates the service in production.\nThe discipline underneath is thinking in invariants: what must always be true, no\nmatter what fails.</p>\n","wordCount":119},{"heading":"Guiding Principles","id":"guiding-principles","markdown":"- **Correctness under concurrency beats raw speed.** A fast endpoint that\n  occasionally double-writes is a liability. Get the invariants right first.\n- **Make every write idempotent.** The network will deliver your message zero,\n  one, or many times. Design so \"again\" is always safe.\n- **The database is the source of truth; the cache is a convenience that lies.**\n  Treat every cached value as potentially stale and plan for the miss.\n- **Push correctness into the data layer.** Constraints, foreign keys, and unique\n  indexes enforced by the database survive bugs in the application above.\n- **Design the API for the consumer, version it for the future.** A public\n  contract is forever; breaking it breaks people you'll never meet.\n- **Fail fast, degrade gracefully, never silently.** A clear error beats a hung\n  request.\n- **Measure tail latency, not averages.** The p99 is what your worst-served users\n  feel, and where the system is about to fall over.","html":"<h2 id=\"guiding-principles\">Guiding Principles</h2>\n<ul>\n<li><strong>Correctness under concurrency beats raw speed.</strong> A fast endpoint that\noccasionally double-writes is a liability. Get the invariants right first.</li>\n<li><strong>Make every write idempotent.</strong> The network will deliver your message zero,\none, or many times. Design so &quot;again&quot; is always safe.</li>\n<li><strong>The database is the source of truth; the cache is a convenience that lies.</strong>\nTreat every cached value as potentially stale and plan for the miss.</li>\n<li><strong>Push correctness into the data layer.</strong> Constraints, foreign keys, and unique\nindexes enforced by the database survive bugs in the application above.</li>\n<li><strong>Design the API for the consumer, version it for the future.</strong> A public\ncontract is forever; breaking it breaks people you&#39;ll never meet.</li>\n<li><strong>Fail fast, degrade gracefully, never silently.</strong> A clear error beats a hung\nrequest.</li>\n<li><strong>Measure tail latency, not averages.</strong> The p99 is what your worst-served users\nfeel, and where the system is about to fall over.</li>\n</ul>\n","wordCount":149},{"heading":"Mental Models","id":"mental-models","markdown":"- **ACID and isolation levels.** \"Isolation\" is a dial (read committed,\n  repeatable read, serializable), and most concurrency bugs are someone assuming\n  a stronger level than they configured. Know which anomalies (dirty read, write\n  skew, phantom) your level permits.\n- **The CAP theorem and PACELC.** Under a network partition you choose\n  consistency or availability; even when the network is fine, you trade latency\n  against consistency. Every distributed data decision lives on this axis.\n- **Back-pressure and Little's Law.** Concurrency = arrival rate × latency. When\n  a downstream slows, in-flight work piles up until you exhaust threads,\n  connections, or memory. Bound queues and shed load before the pile-up.\n- **The outbox and saga patterns.** You can't atomically write your database and\n  publish a message. Write an outbox row in the same transaction and relay it;\n  coordinate multi-service workflows as a saga with compensating actions.","html":"<h2 id=\"mental-models\">Mental Models</h2>\n<ul>\n<li><strong>ACID and isolation levels.</strong> &quot;Isolation&quot; is a dial (read committed,\nrepeatable read, serializable), and most concurrency bugs are someone assuming\na stronger level than they configured. Know which anomalies (dirty read, write\nskew, phantom) your level permits.</li>\n<li><strong>The CAP theorem and PACELC.</strong> Under a network partition you choose\nconsistency or availability; even when the network is fine, you trade latency\nagainst consistency. Every distributed data decision lives on this axis.</li>\n<li><strong>Back-pressure and Little&#39;s Law.</strong> Concurrency = arrival rate × latency. When\na downstream slows, in-flight work piles up until you exhaust threads,\nconnections, or memory. Bound queues and shed load before the pile-up.</li>\n<li><strong>The outbox and saga patterns.</strong> You can&#39;t atomically write your database and\npublish a message. Write an outbox row in the same transaction and relay it;\ncoordinate multi-service workflows as a saga with compensating actions.</li>\n</ul>\n","wordCount":140},{"heading":"First Principles","id":"first-principles","markdown":"- The network is unreliable, unordered, and will deliver your message more than\n  once.\n- Any machine can crash at any instant, including the instant between your two\n  writes.\n- Clocks on different machines disagree; never trust wall-clock time for\n  ordering.\n- Concurrency means everything that can interleave eventually will, at the worst\n  moment.\n- Data outlives code: today's schema will be queried by software not yet written.","html":"<h2 id=\"first-principles\">First Principles</h2>\n<ul>\n<li>The network is unreliable, unordered, and will deliver your message more than\nonce.</li>\n<li>Any machine can crash at any instant, including the instant between your two\nwrites.</li>\n<li>Clocks on different machines disagree; never trust wall-clock time for\nordering.</li>\n<li>Concurrency means everything that can interleave eventually will, at the worst\nmoment.</li>\n<li>Data outlives code: today&#39;s schema will be queried by software not yet written.</li>\n</ul>\n","wordCount":64},{"heading":"Questions Experts Constantly Ask","id":"questions-experts-constantly-ask","markdown":"- What's the invariant here — what must always be true no matter what fails?\n- What happens if this request runs twice? Is it idempotent?\n- What's the read/write ratio and access pattern, and does the schema serve it?\n- Can this operation tolerate stale data, or does it need strong consistency?\n- What does this do under a slow (not dead) dependency?\n- Where's the transaction boundary, and what isolation level is it at?\n- What's the p99 latency under peak load, and where's the bottleneck?","html":"<h2 id=\"questions-experts-constantly-ask\">Questions Experts Constantly Ask</h2>\n<ul>\n<li>What&#39;s the invariant here — what must always be true no matter what fails?</li>\n<li>What happens if this request runs twice? Is it idempotent?</li>\n<li>What&#39;s the read/write ratio and access pattern, and does the schema serve it?</li>\n<li>Can this operation tolerate stale data, or does it need strong consistency?</li>\n<li>What does this do under a slow (not dead) dependency?</li>\n<li>Where&#39;s the transaction boundary, and what isolation level is it at?</li>\n<li>What&#39;s the p99 latency under peak load, and where&#39;s the bottleneck?</li>\n</ul>\n","wordCount":81},{"heading":"Decision Frameworks","id":"decision-frameworks","markdown":"- **SQL vs. NoSQL.** Default to a relational database — transactions,\n  constraints, and ad-hoc queries you'll want later. Reach for a document or\n  wide-column store only when the access pattern is known, uniform, and demands\n  scale a single primary can't serve. \"Schemaless\" usually means the schema moved\n  into application code, unenforced.\n- **Sync vs. async.** If the caller needs the result to proceed, do it\n  synchronously with a timeout. If it can happen later (email, thumbnail), queue\n  it and return fast — buying responsiveness at the cost of eventual consistency\n  and harder debugging.\n- **Consistency vs. availability per operation.** Money and inventory →\n  strong/serializable. A like count or feed → eventual is fine and far cheaper.\n  Choose per operation, not per system.\n- **Retry policy.** Retry only idempotent operations; use exponential backoff\n  with jitter and a cap; wrap dependencies in a circuit breaker.\n- **Normalize then denormalize on evidence.** Start normalized; denormalize a hot\n  read path only when a profiler proves the join is the bottleneck.","html":"<h2 id=\"decision-frameworks\">Decision Frameworks</h2>\n<ul>\n<li><strong>SQL vs. NoSQL.</strong> Default to a relational database — transactions,\nconstraints, and ad-hoc queries you&#39;ll want later. Reach for a document or\nwide-column store only when the access pattern is known, uniform, and demands\nscale a single primary can&#39;t serve. &quot;Schemaless&quot; usually means the schema moved\ninto application code, unenforced.</li>\n<li><strong>Sync vs. async.</strong> If the caller needs the result to proceed, do it\nsynchronously with a timeout. If it can happen later (email, thumbnail), queue\nit and return fast — buying responsiveness at the cost of eventual consistency\nand harder debugging.</li>\n<li><strong>Consistency vs. availability per operation.</strong> Money and inventory →\nstrong/serializable. A like count or feed → eventual is fine and far cheaper.\nChoose per operation, not per system.</li>\n<li><strong>Retry policy.</strong> Retry only idempotent operations; use exponential backoff\nwith jitter and a cap; wrap dependencies in a circuit breaker.</li>\n<li><strong>Normalize then denormalize on evidence.</strong> Start normalized; denormalize a hot\nread path only when a profiler proves the join is the bottleneck.</li>\n</ul>\n","wordCount":160},{"heading":"Workflow","id":"workflow","markdown":"1. **Pin the contract.** Define the API shape, error model, and invariants\n   before code; write it down (OpenAPI/proto) so consumers can build against it.\n2. **Model the data.** Design the schema and indexes for the real access\n   patterns; decide transaction boundaries and what the database enforces.\n3. **Reason about failure first.** For each external call, decide timeout, retry,\n   and fallback before the happy path.\n4. **Make it idempotent** with idempotency keys, unique constraints, and dedup so\n   retries and replays are safe.\n5. **Implement with tests at the right level.** Integration-test against a real\n   database, not a mock, because the bugs live in the SQL and the isolation level.\n6. **Load-test the path.** Measure throughput and p99 under realistic\n   concurrency; find the bottleneck before users do.\n7. **Instrument** with metrics, logs, and traces carrying correlation IDs so a\n   request can be followed across services.\n8. **Ship behind a flag, watch the golden signals, keep a rollback** — but know\n   which migrations are one-way doors.","html":"<h2 id=\"workflow\">Workflow</h2>\n<ol>\n<li><strong>Pin the contract.</strong> Define the API shape, error model, and invariants\nbefore code; write it down (OpenAPI/proto) so consumers can build against it.</li>\n<li><strong>Model the data.</strong> Design the schema and indexes for the real access\npatterns; decide transaction boundaries and what the database enforces.</li>\n<li><strong>Reason about failure first.</strong> For each external call, decide timeout, retry,\nand fallback before the happy path.</li>\n<li><strong>Make it idempotent</strong> with idempotency keys, unique constraints, and dedup so\nretries and replays are safe.</li>\n<li><strong>Implement with tests at the right level.</strong> Integration-test against a real\ndatabase, not a mock, because the bugs live in the SQL and the isolation level.</li>\n<li><strong>Load-test the path.</strong> Measure throughput and p99 under realistic\nconcurrency; find the bottleneck before users do.</li>\n<li><strong>Instrument</strong> with metrics, logs, and traces carrying correlation IDs so a\nrequest can be followed across services.</li>\n<li><strong>Ship behind a flag, watch the golden signals, keep a rollback</strong> — but know\nwhich migrations are one-way doors.</li>\n</ol>\n","wordCount":166},{"heading":"Common Tradeoffs","id":"common-tradeoffs","markdown":"- **Consistency vs. latency/availability.** Stronger guarantees cost round-trips\n  and reduce availability under partition. Buy the strength the operation\n  actually needs.\n- **Normalization vs. read performance.** Normalized data is correct and\n  flexible; denormalized data is fast to read and a nightmare to keep in sync.\n- **Monolith vs. microservices.** Services give independent deploy and scale at\n  the cost of network latency, distributed transactions, and operational overhead\n  most teams underestimate. Start with a well-structured monolith.\n- **Caching vs. correctness.** A cache cuts load and latency and adds staleness\n  and invalidation, one of the two hard problems.","html":"<h2 id=\"common-tradeoffs\">Common Tradeoffs</h2>\n<ul>\n<li><strong>Consistency vs. latency/availability.</strong> Stronger guarantees cost round-trips\nand reduce availability under partition. Buy the strength the operation\nactually needs.</li>\n<li><strong>Normalization vs. read performance.</strong> Normalized data is correct and\nflexible; denormalized data is fast to read and a nightmare to keep in sync.</li>\n<li><strong>Monolith vs. microservices.</strong> Services give independent deploy and scale at\nthe cost of network latency, distributed transactions, and operational overhead\nmost teams underestimate. Start with a well-structured monolith.</li>\n<li><strong>Caching vs. correctness.</strong> A cache cuts load and latency and adds staleness\nand invalidation, one of the two hard problems.</li>\n</ul>\n","wordCount":93},{"heading":"Rules of Thumb","id":"rules-of-thumb","markdown":"- If a request can be retried, it must be idempotent — design the key up front.\n- Put a timeout on every network call; an unbounded wait is an outage waiting to\n  happen.\n- Add the index before you ship the query; an N+1 in code is a table scan in\n  production.\n- Never trust the client; validate and authorize on the server, every time.\n- A unique constraint is cheaper than a distributed lock and can't deadlock.\n- Don't do in application code what the database can do transactionally.\n- Log a correlation ID on everything, or cross-service debugging is archaeology.","html":"<h2 id=\"rules-of-thumb\">Rules of Thumb</h2>\n<ul>\n<li>If a request can be retried, it must be idempotent — design the key up front.</li>\n<li>Put a timeout on every network call; an unbounded wait is an outage waiting to\nhappen.</li>\n<li>Add the index before you ship the query; an N+1 in code is a table scan in\nproduction.</li>\n<li>Never trust the client; validate and authorize on the server, every time.</li>\n<li>A unique constraint is cheaper than a distributed lock and can&#39;t deadlock.</li>\n<li>Don&#39;t do in application code what the database can do transactionally.</li>\n<li>Log a correlation ID on everything, or cross-service debugging is archaeology.</li>\n</ul>\n","wordCount":97},{"heading":"Failure Modes","id":"failure-modes","markdown":"- **The lost-update race.** Two requests read, modify, and write the same row;\n  one silently overwrites the other because nobody used a transaction or a\n  version check.\n- **The N+1 query.** Loading a list then querying once per item — fine in dev\n  with ten rows, a meltdown in production with ten thousand.\n- **Retry storms with no backoff.** Clients hammering a struggling service into\n  total collapse, then taking down everything that depends on it.\n- **The dual-write inconsistency.** Writing to the database and a broker\n  separately, crashing between them, leaving the two permanently disagreeing.\n- **Connection-pool exhaustion.** A slow downstream holds every connection until\n  healthy requests can't get in.","html":"<h2 id=\"failure-modes\">Failure Modes</h2>\n<ul>\n<li><strong>The lost-update race.</strong> Two requests read, modify, and write the same row;\none silently overwrites the other because nobody used a transaction or a\nversion check.</li>\n<li><strong>The N+1 query.</strong> Loading a list then querying once per item — fine in dev\nwith ten rows, a meltdown in production with ten thousand.</li>\n<li><strong>Retry storms with no backoff.</strong> Clients hammering a struggling service into\ntotal collapse, then taking down everything that depends on it.</li>\n<li><strong>The dual-write inconsistency.</strong> Writing to the database and a broker\nseparately, crashing between them, leaving the two permanently disagreeing.</li>\n<li><strong>Connection-pool exhaustion.</strong> A slow downstream holds every connection until\nhealthy requests can&#39;t get in.</li>\n</ul>\n","wordCount":108},{"heading":"Anti-patterns","id":"anti-patterns","markdown":"- **God service** — one service that owns half the domain.\n- **Storing state in the request handler** — process-local memory that breaks\n  behind a load balancer.\n- **Business logic in the controller** — fat handlers with domain rules tangled\n  into HTTP.","html":"<h2 id=\"anti-patterns\">Anti-patterns</h2>\n<ul>\n<li><strong>God service</strong> — one service that owns half the domain.</li>\n<li><strong>Storing state in the request handler</strong> — process-local memory that breaks\nbehind a load balancer.</li>\n<li><strong>Business logic in the controller</strong> — fat handlers with domain rules tangled\ninto HTTP.</li>\n</ul>\n","wordCount":37},{"heading":"Vocabulary","id":"vocabulary","markdown":"- **Idempotency** — running an operation twice has the same effect as once.\n- **ACID** — atomicity, consistency, isolation, durability — the transaction\n  guarantees.\n- **Isolation level** — how much concurrent transactions see of each other's\n  in-progress work.\n- **Back-pressure** — a slow consumer signaling upstream to slow down.\n- **Saga** — a multi-step distributed workflow with compensating undo steps.\n- **Tail latency (p99)** — the latency of the slowest 1% of requests.\n- **Circuit breaker** — a guard that stops calling a failing dependency to let it\n  recover.","html":"<h2 id=\"vocabulary\">Vocabulary</h2>\n<ul>\n<li><strong>Idempotency</strong> — running an operation twice has the same effect as once.</li>\n<li><strong>ACID</strong> — atomicity, consistency, isolation, durability — the transaction\nguarantees.</li>\n<li><strong>Isolation level</strong> — how much concurrent transactions see of each other&#39;s\nin-progress work.</li>\n<li><strong>Back-pressure</strong> — a slow consumer signaling upstream to slow down.</li>\n<li><strong>Saga</strong> — a multi-step distributed workflow with compensating undo steps.</li>\n<li><strong>Tail latency (p99)</strong> — the latency of the slowest 1% of requests.</li>\n<li><strong>Circuit breaker</strong> — a guard that stops calling a failing dependency to let it\nrecover.</li>\n</ul>\n","wordCount":77},{"heading":"Tools","id":"tools","markdown":"- **Relational databases** — PostgreSQL, MySQL; the query planner, `EXPLAIN`, and\n  index design are core craft.\n- **Caches and key-value stores** — Redis for caching, rate limits, and locks.\n- **Message brokers** — Kafka, RabbitMQ, SQS for async work and event streams.\n- **API tooling** — OpenAPI, gRPC/protobuf for typed contracts.\n- **Observability** — Prometheus, OpenTelemetry tracing, structured logging.\n- **Load and contract testing** — k6 or Gatling for throughput; Testcontainers to\n  test against a real database.\n- **Containers and orchestration** — Docker, Kubernetes.","html":"<h2 id=\"tools\">Tools</h2>\n<ul>\n<li><strong>Relational databases</strong> — PostgreSQL, MySQL; the query planner, <code>EXPLAIN</code>, and\nindex design are core craft.</li>\n<li><strong>Caches and key-value stores</strong> — Redis for caching, rate limits, and locks.</li>\n<li><strong>Message brokers</strong> — Kafka, RabbitMQ, SQS for async work and event streams.</li>\n<li><strong>API tooling</strong> — OpenAPI, gRPC/protobuf for typed contracts.</li>\n<li><strong>Observability</strong> — Prometheus, OpenTelemetry tracing, structured logging.</li>\n<li><strong>Load and contract testing</strong> — k6 or Gatling for throughput; Testcontainers to\ntest against a real database.</li>\n<li><strong>Containers and orchestration</strong> — Docker, Kubernetes.</li>\n</ul>\n","wordCount":71},{"heading":"Collaboration","id":"collaboration","markdown":"The backend engineer owns the contracts other people build on, which makes API\ndesign a social act. With frontend and mobile engineers, the daily negotiation\nis the API shape — chatty vs. coarse endpoints, error formats, pagination, who\nvalidates what; designing responses around the consumer's screen, not the\ndatabase's tables, saves everyone churn. With data engineers, the seam is the\nevent stream and the schema feeding the warehouse; breaking a field breaks\npipelines downstream. With SREs, they share ownership of the running service and\nits SLOs. With security engineers, the backend is the perimeter where authn/authz\nand untrusted input are enforced. The recurring tension is data ownership across\nservice boundaries — who may write a given table, and through what contract.","html":"<h2 id=\"collaboration\">Collaboration</h2>\n<p>The backend engineer owns the contracts other people build on, which makes API\ndesign a social act. With frontend and mobile engineers, the daily negotiation\nis the API shape — chatty vs. coarse endpoints, error formats, pagination, who\nvalidates what; designing responses around the consumer&#39;s screen, not the\ndatabase&#39;s tables, saves everyone churn. With data engineers, the seam is the\nevent stream and the schema feeding the warehouse; breaking a field breaks\npipelines downstream. With SREs, they share ownership of the running service and\nits SLOs. With security engineers, the backend is the perimeter where authn/authz\nand untrusted input are enforced. The recurring tension is data ownership across\nservice boundaries — who may write a given table, and through what contract.</p>\n","wordCount":120},{"heading":"Ethics","id":"ethics","markdown":"The backend is where the consequential data lives — payments, health records,\nidentities, location histories — and where the engineer's choices are invisible\nto the user but binding on them. The duties: store only the data the product\ngenuinely needs and delete it when its purpose ends; encrypt sensitive data at\nrest and in transit and treat a breach as a foreseeable event whose blast radius\nyou must minimize; enforce least privilege so one compromised credential can't\nread everything; honor deletion and export requests because a user's data is\ntheirs; and be honest in design reviews about the risk of a schema or access\npattern rather than shipping a known time bomb. The power is quiet — a backend\nengineer can usually query any user's data — and the discipline of not doing so,\nand of building systems that make misuse hard and auditable, is the job.","html":"<h2 id=\"ethics\">Ethics</h2>\n<p>The backend is where the consequential data lives — payments, health records,\nidentities, location histories — and where the engineer&#39;s choices are invisible\nto the user but binding on them. The duties: store only the data the product\ngenuinely needs and delete it when its purpose ends; encrypt sensitive data at\nrest and in transit and treat a breach as a foreseeable event whose blast radius\nyou must minimize; enforce least privilege so one compromised credential can&#39;t\nread everything; honor deletion and export requests because a user&#39;s data is\ntheirs; and be honest in design reviews about the risk of a schema or access\npattern rather than shipping a known time bomb. The power is quiet — a backend\nengineer can usually query any user&#39;s data — and the discipline of not doing so,\nand of building systems that make misuse hard and auditable, is the job.</p>\n","wordCount":143},{"heading":"Scenarios","id":"scenarios","markdown":"**The double-charged customer.** Support reports occasional double charges. The\nexpert traces it: the payment endpoint isn't idempotent, and the mobile client\nretries on a slow network, so a single \"pay\" can hit the processor twice. The fix\nisn't \"make the network faster\" — it's an idempotency key generated by the client\nand stored with a unique constraint, so the second request finds the first's\nresult and returns it instead of charging again. The rule that follows: every\nstate-changing endpoint gets an idempotency key from day one, because retries are\nnormal behavior on an unreliable network, not an edge case.\n\n**The order-and-email dual write.** An order service writes the order, then\npublishes an \"order placed\" event to Kafka for email and fulfillment.\nOccasionally the process crashes between the two, leaving orders that exist but\nwere never fulfilled; publishing first just inverts the bug. The expert applies\nthe outbox pattern: write the event into an outbox table in the *same\ntransaction* as the order, then a relay reads the outbox and publishes. The\ncommit becomes the single atomic point of truth, and at-least-once delivery plus\nidempotent consumers makes it safe.\n\n**A read that's melting the database.** A dashboard endpoint slows to seconds\nunder load. `EXPLAIN` shows a sequential scan: the query filters on an unindexed\ncolumn, and a list view fires one query per row (N+1). The expert adds the\ncomposite index matching the filter and sort, batches the per-row queries into a\nsingle `IN`, and caches the now-cheap read with a short TTL. p99 drops from 3 s\nto 40 ms. The lesson: the index is part of the feature, not a later optimization.","html":"<h2 id=\"scenarios\">Scenarios</h2>\n<p><strong>The double-charged customer.</strong> Support reports occasional double charges. The\nexpert traces it: the payment endpoint isn&#39;t idempotent, and the mobile client\nretries on a slow network, so a single &quot;pay&quot; can hit the processor twice. The fix\nisn&#39;t &quot;make the network faster&quot; — it&#39;s an idempotency key generated by the client\nand stored with a unique constraint, so the second request finds the first&#39;s\nresult and returns it instead of charging again. The rule that follows: every\nstate-changing endpoint gets an idempotency key from day one, because retries are\nnormal behavior on an unreliable network, not an edge case.</p>\n<p><strong>The order-and-email dual write.</strong> An order service writes the order, then\npublishes an &quot;order placed&quot; event to Kafka for email and fulfillment.\nOccasionally the process crashes between the two, leaving orders that exist but\nwere never fulfilled; publishing first just inverts the bug. The expert applies\nthe outbox pattern: write the event into an outbox table in the <em>same\ntransaction</em> as the order, then a relay reads the outbox and publishes. The\ncommit becomes the single atomic point of truth, and at-least-once delivery plus\nidempotent consumers makes it safe.</p>\n<p><strong>A read that&#39;s melting the database.</strong> A dashboard endpoint slows to seconds\nunder load. <code>EXPLAIN</code> shows a sequential scan: the query filters on an unindexed\ncolumn, and a list view fires one query per row (N+1). The expert adds the\ncomposite index matching the filter and sort, batches the per-row queries into a\nsingle <code>IN</code>, and caches the now-cheap read with a short TTL. p99 drops from 3 s\nto 40 ms. The lesson: the index is part of the feature, not a later optimization.</p>\n","wordCount":279},{"heading":"Related Occupations","id":"related-occupations","markdown":"A backend engineer is a software engineer specialized toward data, concurrency,\nand distributed systems, trading the rendering and accessibility concerns of the\nclient for invariants and throughput. The frontend engineer owns the other side\nof the API contract. Data engineers consume the backend's event streams to build\npipelines and warehouses. Database administrators tune and operate the stores the\nbackend designs schemas for. SREs share ownership of the running service and its\nSLOs, and security engineers harden the perimeter the backend enforces. Cloud\narchitects shape the substrate — queues, databases, networks — the backend runs\non.","html":"<h2 id=\"related-occupations\">Related Occupations</h2>\n<p>A backend engineer is a software engineer specialized toward data, concurrency,\nand distributed systems, trading the rendering and accessibility concerns of the\nclient for invariants and throughput. The frontend engineer owns the other side\nof the API contract. Data engineers consume the backend&#39;s event streams to build\npipelines and warehouses. Database administrators tune and operate the stores the\nbackend designs schemas for. SREs share ownership of the running service and its\nSLOs, and security engineers harden the perimeter the backend enforces. Cloud\narchitects shape the substrate — queues, databases, networks — the backend runs\non.</p>\n","wordCount":93},{"heading":"References","id":"references","markdown":"- *Designing Data-Intensive Applications* — Martin Kleppmann\n- *Release It!* — Michael Nygard\n- *Database Internals* — Alex Petrov\n- *Patterns of Enterprise Application Architecture* — Martin Fowler\n- *Web Scalability for Startup Engineers* — Artur Ejsmont","html":"<h2 id=\"references\">References</h2>\n<ul>\n<li><em>Designing Data-Intensive Applications</em> — Martin Kleppmann</li>\n<li><em>Release It!</em> — Michael Nygard</li>\n<li><em>Database Internals</em> — Alex Petrov</li>\n<li><em>Patterns of Enterprise Application Architecture</em> — Martin Fowler</li>\n<li><em>Web Scalability for Startup Engineers</em> — Artur Ejsmont</li>\n</ul>\n","wordCount":28}],"computed":{"wordCount":2162,"readingTimeMinutes":10,"completeness":1,"backlinks":["blockchain-developer","computer-programmer","data-engineer","database-administrator","frontend-engineer","mobile-developer","web-developer"],"verified":false,"aiDrafted":true,"unverifiedAiDraft":true},"git":{"created":"2026-06-26","updated":"2026-06-26","revisions":1,"authors":[{"name":"soul-atlas","commits":1}],"timeline":[{"date":"2026-06-26","author":"soul-atlas"}]},"citation":{"apa":"soul-atlas (2026). Backend Engineer [SOUL]. SOUL Atlas. https://soul-atlas.github.io/occupations/backend-engineer","bibtex":"@misc{soulatlas-backend-engineer,\n  title        = {Backend Engineer},\n  author       = {soul-atlas},\n  year         = {2026},\n  howpublished = {SOUL Atlas},\n  note         = {SOUL.md, version 2026-06-26},\n  url          = {https://soul-atlas.github.io/occupations/backend-engineer}\n}","text":"soul-atlas. \"Backend Engineer.\" SOUL Atlas, 2026. https://soul-atlas.github.io/occupations/backend-engineer."}}