cswork / libraryOpen practice workspace

Interview guides · B.B. Energy

B.B. Energy Software Engineer Interview Guide

B.B. Energy Software Engineer interview guide: the reported panel and technical-behavioral rounds, reported questions, STAR answers and a 7-day plan.

The 60-second brief

B.B. Energy is described in candidate-facing role descriptions as a global energy business, with software that supports its trading, risk management and day-to-day operations. The Software Engineer role is reported to cover the full lifecycle of that software: gathering requirements from business users, designing, building, deploying and keeping systems healthy in production. Candidates describe the users as traders and operations staff, which means the systems you discuss are ones where data flows between technical teams and business teams.

This guide is for candidates interviewing for the Software Engineer role at B.B. Energy. It covers the two reported stages (a Panel Interview, then a Technical and Behavioral Assessment), the five reported questions on problem solving, production debugging, code quality, quick fix versus long-term design and trade-offs, and the topics candidates say to expect: system architecture, design patterns, database management and data integrity, and the languages and frameworks of the team you are joining.

Candidates report two stages, a Panel Interview and a Technical and Behavioral Assessment, over roughly 2-4 weeks. Some describe the process as one combined panel conversation that mixes technical depth and behavioral fit.

Focus areas

  • Technical problem solving
  • Interview question answering under pressure
  • Role-focused technical assessment

Overview

The reported questions are conversational rather than puzzle-shaped: a complex problem you solved recently, how you debug a failing production system, how you protect code quality when time is short, how you choose between a quick fix and a lasting design, and the trade-offs in your latest project. Every one of them is answered from your own work, so the main preparation is choosing two or three real projects and knowing them well enough to defend each decision.

Candidates also report that technologies listed on your CV can be discussed in detail, including why you chose them. For each technology on your CV, be ready to explain what problem it solved, what you considered instead, and where it hurt. Two example scenarios are reported for the technical side: designing a system that handles high-frequency data updates, and a time you had to learn a new technology quickly to finish a project. Prepare a structured answer for each.

The topics candidates mention for technical depth are system architecture and design patterns, database management and data integrity, and the specific languages and frameworks the team uses. The listed requirements are core programming languages, data structures and algorithms, and database design, with cloud infrastructure, CI/CD pipelines and energy-sector data models as nice-to-haves. Review these as fundamentals you can reason about aloud, not as trivia.

Because the role serves traders and operations staff, and candidates report that explaining technical ideas to non-technical people matters, practise giving each answer twice: once with the engineering detail, and once in plain terms a business user would follow. Candidates also report little warm-up before technical detail, so have your project walkthroughs ready to start immediately.

The B.B. Energy interview process

Candidates report two stages over roughly 2-4 weeks, and some say the whole process is a single panel session. The descriptions below separate the stages so you can prepare for each part.

Panel Interview

Candidates report meeting several people at once: the hiring manager, an HR representative and senior engineering staff, with some mentioning a panel of four. Reports say there is very little warm-up before technical detail. Approach it as a project walkthrough in front of a mixed audience: have one or two projects ready with the problem, your part in it, the design choices and the result, and aim your explanation so both the engineers and the HR representative can follow it.

What to demonstrate

  • How clearly you walk through your own projects and technical decisions
  • Communication across a panel that mixes engineering and non-engineering members
  • Depth on the technologies listed on your CV

How to prepare

  • Write a two-minute walkthrough of your most complex recent project and a longer version that includes the decisions, the alternatives you rejected and the outcome
  • For every technology on your CV, write one sentence on why you chose it and one on where it caused you trouble
  • Practise looking at every panel member while you answer, not only the person who asked, and rehearse the version of each answer a non-engineer can follow
  • Prepare two questions about the team's current technical challenges to ask at the end

Technical and Behavioral Assessment

Candidates describe a conversation that covers technical depth and behavioral fit together, with some reporting that it happens in the same sitting as the panel. This is where the technical and behavioral questions are practised: production debugging, code quality, quick fix versus long-term design, trade-offs, and example scenarios such as designing for high-frequency data updates and learning a new technology fast. Approach it by giving each answer a clear structure and moving between technical detail and the reasoning behind it.

What to demonstrate

  • Technical depth across architecture, design patterns, databases and data integrity
  • How you reason through ambiguous or difficult scenarios aloud
  • Behavioral fit, shown through specific past decisions and outcomes

How to prepare

  • Outline a design for a system that ingests high-frequency data updates: ingestion path, ordering and duplicate handling, storage choice, how readers see consistent data, and what you would monitor
  • Revise database design and integrity basics: keys and constraints, transactions and isolation, indexing trade-offs, and how you would backfill or migrate a table safely
  • Write STAR stories for a production incident, a quick-fix-versus-redesign decision and a time you learned a technology quickly, each with a concrete result
  • Rehearse the production debugging sequence aloud: assess impact, find what changed, narrow with evidence, mitigate, then fix the cause

Where candidates lose points

Telling the complex-problem story in the team's voice, so nobody can tell what you personally decided or built

Write each story with explicit lines for what you decided, what you wrote or changed, and what a teammate did. Say 'I' for your decisions and name teammates for theirs.

Answering the production debugging question with a list of fixes or guesses before establishing impact

Open with a sequence: how many users or processes are affected, what changed recently, how you narrow it with logs and metrics, how you mitigate or roll back, and only then the root-cause fix and a follow-up to stop a repeat.

Naming only the option you picked when asked about trade-offs in your latest project

For each major decision, name at least one alternative you rejected, the criterion that decided it (latency, consistency, team skill, deadline) and what you gave up by choosing as you did.

Listing technologies on your CV that you cannot explain beyond the surface when asked why you chose them

Cut or rehearse every item. For each technology, know the problem it solved, the alternative, one limitation you hit, and one thing you would change if you built the project again.

Explaining technical choices in engineer-only jargon to a panel that includes an HR representative and a hiring manager

Give a one-sentence plain-language version of each answer first, covering what the system does for its users and why the choice mattered, then go into the technical detail for the engineers.

Questions & practice

Can you walk us through a complex technical problem you solved recently?

Medium · Technical Competency and Problem Solving

Approach

  1. Pick a problem with a hard, measurable constraint (latency, data volume, correctness or a deadline), and open with it in one line: "A nightly reconciliation job took 3 hours and had to finish in under 1." A problem with no number in it sounds routine however hard it was.
  2. Show the diagnosis before the fix: how you found the real bottleneck (profiler, query plan from EXPLAIN ANALYZE, timing logs) rather than guessing. For example, a nested-loop comparison that was O(n*m), replaced by a hash map keyed on the join field for O(n+m).
  3. Name at least one alternative you rejected and why: "I considered more workers, but the bottleneck was lock contention on one table, so parallelism would have made it worse." This shows the choice was reasoned, not the first idea that worked.
  4. Cover the edge cases that nearly broke it: duplicate or late-arriving records, nulls in the key, partial failure halfway through a run, and how you made a rerun safe (idempotent writes, upserts, a checkpoint).
  5. Close with the verified result and your own share: before-and-after numbers, how you confirmed them in production, and which part you personally owned versus the team.

Follow-up

  • Which alternative did you reject, and what would have had to be true for it to win?
  • How did you verify the fix in production, not just on your machine?
  • What breaks first if the data grows tenfold?

What is your process for ensuring code quality and maintainability in a fast-paced environment?

Medium · Technical Competency and Problem Solving

Approach

  1. Automate what a reviewer should not have to catch: formatter and linter in pre-commit, static type checking (mypy or TypeScript), and unit tests required to pass in CI before merge. When those gates are cheap and fast, speed and quality stop competing.
  2. Shape the test suite by risk: many fast unit tests for pure business logic (pricing, quantity or unit conversions), integration tests at the boundaries (database, queues, external APIs) against a real database in a container, and a few end-to-end checks for the paths that would cost the most if they broke.
  3. Keep pull requests small and reviewable: one concern per change, a description that says why, and a review checklist covering error handling, input validation and SQL injection, query performance (N+1 queries, missing indexes) and logging.
  4. Ship in small increments behind feature flags so unfinished work can merge without reaching users. Keep schema changes backward compatible (expand, migrate, contract) so a deploy can be rolled back safely.
  5. Treat shortcuts as debt you track: log each one as a ticket with its cost and a trigger for paying it down, and back the process with numbers such as change failure rate, escaped defects or time to restore.

Follow-up

  • Under a hard deadline, which check would you skip and which would you never skip?
  • How do you keep the CI suite fast as the codebase grows?
  • How do you settle a review where you and the author disagree on the design?

Explain the technical trade-offs you considered in your most recent project.

Medium · Technical Competency and Problem Solving

Approach

  1. Choose two or three real decisions from the project and give each the same shape: the options, the constraint that decided it, the cost you accepted, and the signal that would make you revisit it. A list of technologies with no rejected option is a description, not a trade-off.
  2. Data storage: a relational database with transactions, foreign keys and unique constraints protects integrity at the price of rigid schemas and harder horizontal scaling. A document or key-value store scales writes easily, but the application has to enforce invariants itself.
  3. Synchronous calls versus a message queue: a queue decouples services, absorbs bursts and allows retries, but brings eventual consistency, at-least-once delivery (so consumers must be idempotent, for example with a dedup key or upserts) and a harder debugging trail.
  4. Caching and denormalisation: a read cache or precomputed table cuts latency and database load, but you pay in staleness and invalidation. State the TTL or invalidation rule you picked and which readers could tolerate stale data.
  5. Quantify what the choice bought and cost (latency before and after, infrastructure spend, delivery time), and say honestly which trade-off you would make differently now.

Follow-up

  • What would have to change for you to reverse that decision?
  • Which cost of the trade-off did you underestimate, and when did it show up?
  • How would the design hold up if write volume grew tenfold, for example with high-frequency data updates?

Find version gaps and relay lag with window functions

Medium · window functions · event tables · frame semantics

outbox_event holds event_id, aggregate_type, aggregate_id, aggregate_version, event_type, payload, status ('pending','published','dead'), attempts, created_at, published_at. A projection is missing rows and you must decide whether the relay skipped events or the consumer dropped them. Write three queries over the last seven days: one listing every aggregate_id whose published aggregate_version sequence has a hole, one giving per-day counts with a running total, and one returning the newest published event per aggregate. For each, say where the window function is evaluated relative to WHERE and LIMIT. PostgreSQL 16.

Approach

  1. Gaps: compute lead(aggregate_version) OVER (PARTITION BY aggregate_id ORDER BY aggregate_version) in a subquery, then filter next_version <> aggregate_version + 1 in the outer query. Window functions are evaluated after WHERE, GROUP BY and HAVING and before the outer ORDER BY and LIMIT, so the predicate cannot sit in the same WHERE clause and PostgreSQL 16 has no QUALIFY.
  2. Say what the seven-day filter does to the answer: it truncates every partition, so the first row per aggregate has no predecessor inside the window and a hole spanning the boundary is invisible. Widen the window, or join to resource.version as the authority for the true maximum.
  3. Running total: SELECT date_trunc('day', created_at) AS d, count() AS n, sum(count()) OVER (ORDER BY date_trunc('day', created_at) ROWS UNBOUNDED PRECEDING). An aggregate inside a window call is legal because grouping runs before windowing. The grouping key is unique per row here so ROWS and RANGE agree, but write the frame anyway — over ungrouped rows with tied timestamps the default RANGE frame pulls in every peer row and the total jumps.
  4. Newest per aggregate: DISTINCT ON (aggregate_id) ... ORDER BY aggregate_id, aggregate_version DESC is the cheap PostgreSQL-only form when an index matches that order; row_number() OVER (PARTITION BY aggregate_id ORDER BY aggregate_version DESC) = 1 is the portable form and needs a subquery for the same evaluation-order reason as the gap query.

Follow-up

  • Relay failover redelivers events. Does a duplicate break the gap query, and how would you detect one from this table alone?
  • Turn the gap check into a continuous monitor rather than a query someone runs after an incident. What does it watch?

Denormalise tenant onto revisions and backfill it live

Hard · denormalisation · online migration · backfill

resource_revision (revision_id, resource_id, version, actor_user_id, change_kind, patch, request_id, created_at) has 400M rows and no tenant column; tenant_id lives only on resource. Two reads need it: a tenant-scoped audit feed ordered by created_at DESC, and an offboarding purge. Both join back to resource today. Justify adding tenant_id to resource_revision against those two reads, name the anomaly the copy introduces and the constraint that prevents it, then give the ordered migration for a live table taking 1.2k writes/second — the lock each step takes, how the backfill is batched, and where each step stops being reversible. PostgreSQL 16.

Approach

  1. Justify from the access path rather than from taste. Without the column, the audit feed either scans resource_revision by created_at and discards other tenants' rows, or resolves the tenant's resource_ids first and probes with them — both proportional to the tenant's whole history rather than to one page. With (tenant_id, created_at DESC, revision_id DESC) it is a seek that stops at 50 rows, and the purge becomes a ranged delete instead of a join.
  2. Name the cost exactly: a second copy of a fact can disagree with the first. Make the disagreement unwritable rather than documented — add UNIQUE (resource_id, tenant_id) on resource so it can serve as a foreign-key target, then FOREIGN KEY (resource_id, tenant_id) REFERENCES resource (resource_id, tenant_id) on the revision table. A revision can then only ever carry its parent's tenant.
  3. Step one, expand: ALTER TABLE resource_revision ADD COLUMN tenant_id BIGINT NULL, with no default, so it is a catalogue change and no rewrite. It still needs ACCESS EXCLUSIVE for an instant, and that instant queues behind the longest open transaction on the table while every later query queues behind it — set lock_timeout to 2s and retry rather than wait.
  4. Step two, dual-write: deploy the writer that populates tenant_id on every new revision while reads still use the join. Reversible by redeploying the previous build, because nothing reads the column yet.

Follow-up

  • The backfill is half finished and a rollback is required. What state is the table in, and what does the previous build do with a half-populated column?
  • How do you verify the backfill actually finished, given rows are still being inserted while it runs?

Evolve the resource contract without breaking integrations you cannot upgrade

Hard · versioning · backward compatibility · deprecation

GET /v1/resources/{id} returns status from a four-value enum ('draft','active','archived','deleted'), a numeric version, and the body inline. Consumers are a browser app you deploy and roughly 300 server-side integrations, some untouched for two years, that switch exhaustively on status and parse ids as JSON numbers. You must add a 'pending_review' status, move bodies over 256 KB to a body_ref pointer, and expose per-field change history from resource_revision. Specify the compatibility policy, the wire changes, how both generations are served, and the evidence that lets you remove the old shape.

Approach

  1. Write the policy first and date it: fields are added, never retyped or repurposed; consumers ignore unknown fields; an unknown enum value maps to a documented fallback; nothing is removed until telemetry shows no caller reads it. Then say the uncomfortable part out loud - v1 shipped without the unknown-value rule, so 300 running integrations have no fallback, and no server change can install one into code that is already deployed.
  2. That single fact forces per-request negotiation rather than a server-side default. Keep one internal model and select a serialiser from an explicit version in the request, and default a caller that sends nothing to the oldest supported version. Defaulting to the newest is the change that breaks every integration that never asked for anything, on the day you ship.
  3. Downgrade 'pending_review' for old callers to the nearest state they already handle, 'draft', and state the loss explicitly: those integrations cannot see review state and will treat the resource as editable. If that is unacceptable for one integration, the remedy is moving it to the new version, not a cleverer projection - there is no mapping that invents a state the client has no code for.
  4. Make the body change additive. Old callers keep body inline; the new shape adds body_ref and a size field, and resources over the limit are served to old callers by resolving the pointer server-side or by refusing with a documented code, chosen once and published. Never repurpose body to carry the pointer: a client that renders it shows a storage key to a user, and that failure is silent, where a missing field would have been loud. While you are here, serialise BIGINT ids as strings in the new shape - a browser parsing JSON numbers gets IEEE-754 doubles, exact only to 2^53 - and treat that as its own breaking change requiring the same negotiation, not a quiet fix.

Follow-up

  • An old integration submits a status transition while the resource is really in 'pending_review'. What does the write path accept, and what does it reject?
  • Two years on you want to delete the v1 serialiser. What evidence makes that safe, and who must be contacted before it happens?

Keep one tenant's bulk export from starving projection updates

Medium · backpressure · fair scheduling · head-of-line blocking

The worker fleet runs about 600 jobs/second out of job_run, claimed under a lease and heartbeated while running. Most handlers finish under 200 ms; exports run for minutes. One tenant enqueues 50,000 exports. Design the scheduling so that tenant's exports slow down and nothing else does: the queue split, the concurrency caps and where they are enforced, the claim query, and the backpressure signal that stops accepting new work. State the in-flight worker count each class needs at its arrival rate, and what the cap costs the tenant that hits it.

Approach

  1. Do the concurrency arithmetic first, because it determines the pool shapes. Required in-flight work is arrival rate times service time: 600/second of 200 ms handlers needs about 120 workers, while one export per second at 180 seconds needs 180 on its own. The long tail dominates any pool it shares, so a single pool sized from the mean is consumed by exports while 50 ms projections queue behind them. That is head-of-line blocking, and adding capacity does not fix it because the ratio is what is wrong.
  2. Split by job class rather than by priority. Priority inside one pool still lets a running export hold its worker for the next four minutes - there is no preemption for a handler already executing. Separate queues and separate worker processes give each class a floor the other cannot take.
  3. Enforce the per-tenant cap inside the claim, not at enqueue. Claim with SELECT ... WHERE status='queued' AND run_after <= now() AND job_type=$1 ORDER BY run_after, job_run_id FOR UPDATE SKIP LOCKED LIMIT 1, restricted to tenants currently under their cap. Derive the running count from rows in status 'running' with a live lease rather than from a counter incremented at claim and decremented at completion: the derived count self-heals when a worker dies, and the counter leaks a slot every time one does.
  4. Make the ordering fair over tenants instead of over jobs. Strict FIFO with a cap still forces the claim to scan past 50,000 rows belonging to a capped tenant before it finds anyone else's work, so cost grows with backlog depth. Pick the tenant first from a small per-tenant queue-depth summary, then claim within that tenant, which makes the scan proportional to the number of active tenants instead.

Follow-up

  • An export outruns its lease, so two copies run. What must the handler do to make the second copy harmless, and what does it write to guarantee that?
  • With a cap of 4, the tenant's 50,000 exports now take hours. What do you tell them, and does the answer change if they are the largest tenant on the platform?

How do you approach debugging a system that is failing in production?

Medium · Technical Competency and Problem Solving

Approach

  1. Mitigate first, then diagnose: establish the blast radius (which users, endpoints or jobs fail, and since when), and if a recent deploy or config change lines up with the start, roll it back or turn off the feature flag before chasing the root cause.
  2. Build a timeline of what changed: deploys, config, schema migrations, dependency versions, traffic and data volume. Then read the request-level signals (rate, error rate and latency per endpoint) to find which component is failing rather than which one is loudest.
  3. Narrow the failure with logs correlated by request ID and with traces. Ask what the failing requests have in common (one host, one tenant, one input shape, one downstream call), since a fault on a fraction of requests usually lives in that shared factor.
  4. Check the usual causes of intermittent failure: exhausted connection pools or file descriptors, memory leaks and long GC pauses, timeouts that set off retry storms, lock contention, and a full disk. Confirm one hypothesis with a reproduction or a targeted query before changing code.
  5. Fix the cause, then prevent a repeat: a regression test that reproduces the failure, an alert on the symptom that fired late, and a blameless write-up of the trigger, the mechanism and the detection gap.

Follow-up

  • A schema migration already ran, so rolling back is not possible. What do you do?
  • Only 2% of requests fail and you cannot reproduce it locally. How do you narrow it down?
  • How do you tell the actual cause from something that merely changed at the same time?

Suggested practice checklist

The plan moves from your own project stories to production debugging, code quality, trade-offs and the database and high-frequency-data design topics candidates report. It ends with a mixed-audience mock.

Day 1 — Map the loop and your CV

  • Write the two reported stages (Panel Interview, then Technical and Behavioral Assessment) and note that some candidates face one combined session
  • List every technology on your CV and write why you chose it, the alternative, and one limitation you hit
  • Pick the two projects you will lead with and write a two-minute walkthrough of each

Deliverable: A CV technology table with a why, an alternative and a limitation for each entry, plus two written two-minute project walkthroughs.

Day 2 — Complex problem and trade-offs

  • Write and speak aloud the story of a complex technical problem you solved, separating your decisions from the team's
  • List the three biggest trade-offs in your latest project, each with the rejected alternative and the deciding criterion
  • Record yourself answering both and cut anything that does not carry a decision

Deliverable: One spoken and one written answer for the complex-problem question and one for the project trade-offs question, each with named alternatives.

Day 3 — Debugging a failing production system

  • Write your debugging sequence: impact assessment, what changed, evidence gathering, mitigation, root cause, prevention
  • Attach a real incident of yours to each step so the sequence is not abstract

Deliverable: A one-page debugging playbook with a real incident mapped to each step, and a spoken incident narration.

Day 4 — Code quality and quick fix versus long-term design

  • Write your process for code quality under time pressure: review habits, tests you refuse to skip, CI checks, how you record shortcuts
  • Build a STAR story for a quick-fix-versus-long-term decision, with criteria and follow-through

Deliverable: A written code-quality process with concrete habits, a STAR story on the quick-fix decision, and a spoken answer on a reversed decision.

Day 5 — Databases, data integrity and high-frequency updates

  • Outline a design for a system that receives high-frequency data updates, covering ingestion, ordering, duplicates, storage, consistent reads and monitoring
  • Review database design and integrity: constraints, transactions, isolation levels and indexing trade-offs

Deliverable: A design outline for high-frequency updates, a one-page integrity checklist, and solved SQL practice questions.

Day 6 — Learning fast and speaking to non-technical listeners

  • Write a STAR story for a time you learned a new technology quickly to finish a project, including how you checked your understanding
  • Rewrite two technical answers in plain language for a trader or operations user, then in full engineering detail
  • Write two questions about the team's technical challenges to ask at the end

Deliverable: A learning-fast STAR story, two answers each written in plain and technical versions, and two questions to ask.

Day 7 — Panel dry run

  • Ask three friends to act as a panel and run all five reported questions plus the high-frequency-data design scenario back to back, with no warm-up
  • Practise giving each answer to the whole group, not only the questioner
  • Write down the two answers that wobbled and tighten them

Deliverable: A completed panel mock and a list of two answers revised afterwards.

Behavioral preparation for the panel

Candidates report that the second stage mixes technical depth with behavioral fit, and that STAR-structured answers about your own decisions, communication with non-technical people and responsiveness to feedback matter. Build stories where you made a call, show the alternatives, and give a result you can measure.

  1. Describe a time you had to learn a new technology quickly to complete a project.
  2. Describe a production failure you helped resolve, from the first symptom to the follow-up that prevented a repeat.
  3. Tell me about a time you explained a technical constraint to a non-technical stakeholder and changed what they asked for.
  4. Describe feedback you received on your code or design, what you changed and what you learned from it.

How do you handle situations where you have to choose between a quick fix and a long-term architectural soluti

Medium · Technical Competency and Problem Solving

How do you handle situations where you have to choose between a quick fix and a long-term architectural solution?

Approach

  1. Pick a story where both options were genuinely available and you owned the call. Name the quick fix concretely (a patch, a feature flag, a manual workaround) and the long-term change concretely (a refactor, a schema change, a new component), plus what forced the timing, such as an incident or a release date.
  2. Spend most of your time on the decision criteria: how bad the failure was and who it affected, how often that code path changes, whether the quick fix was reversible, and how long the proper fix would take. A strong answer often ships the narrow fix with a test, then schedules the real fix with an owner and a trigger.
  3. Show the follow-through. Say how you recorded the shortcut (a ticket, a code comment, a design note), whether the long-term work happened, and what changed afterwards, with a number if you have one such as fewer repeat incidents, shorter deploys or fewer manual steps.
  4. Avoid the answer that always picks one side. Saying you always choose the long-term design sounds disconnected from deadlines, and always choosing the quick fix sounds careless about debt. Explain the conditions under which you would have chosen the other option.
  5. If people depended on the system, such as business users on a trading or operations tool, say how you told them about the interim limitation and what you asked them to watch for until the full fix landed.

Follow-up

  • What did the quick fix cost you later, and how did you keep track of it?
  • How did you handle a stakeholder who wanted the opposite choice?
  • Under what circumstances would you have made the other decision?

Reverse your own decision and price the reversal

Medium · reversibility · measurement · migrations

Describe a technical decision you made and later reversed. Pick one that cost something: a service you split and merged back, a cache you added and removed, an index you created that pushed the planner onto a worse plan, a projection you rebuilt from scratch. State what you believed when you decided, the measurement that changed your mind, how long the wrong version ran in production, and what the reversal cost in migrations, dual writes, and a deprecation window for callers you did not own.

Approach

  1. State the original rationale without irony, in the version you would still defend given what was known then. If it is not defensible, the story is about carelessness rather than judgement, and a different example serves you better.
  2. Give the measurement that moved with a before and after: the p99 that did not improve, the cache hit rate that sat at 40%, the plan that flipped to a sequential scan once the table passed a size you can name.
  3. Cost the reversal in steps, not adjectives: expand-and-contract deploys, the dual-write window, the callers who had to be notified, the rows already written in the wrong shape that had to be backfilled or abandoned.
  4. Distinguish reversal from rewrite by naming what you kept. Most good reversals preserve the schema or the interface and undo one decision inside it, which is also why they were affordable.

Follow-up

  • What in that decision was irreversible, and did you know it was irreversible when you made it?
  • How did you tell the people who had already built on top of the original decision?

Narrate an outage you owned from page to postmortem

Hard · incident response · blast radius · postmortems

Pick an incident you personally drove, ideally one where writes were affected rather than reads. In six to eight minutes: state the symptom as it first appeared on a dashboard, the blast radius you established before you knew the cause, the mitigation you applied and when, the mechanism you eventually proved, and the follow-up that would prevent a repeat. Bring numbers: error rate, tenants affected, minutes to mitigate, minutes to resolve. If you cannot name what you measured, choose a different incident.

Approach

  1. Open on the signal rather than the cause: which metric at which percentile moved, on which service, at what time, so the listener follows the same evidence you had rather than a conclusion you already reached.
  2. Separate mitigation from diagnosis out loud. State what you did to stop the bleeding (flag off, shed traffic, drain a lease, roll back a deploy) and say plainly that you did it before the mechanism was known, because those are two jobs with different deadlines.
  3. Establish blast radius in countable terms: how many tenants, how many writes, and crucially whether the effect was loss or only delay. An append-only revision table or a pending outbox row means the change survived and the projection was merely behind, which is a repair rather than a data-loss incident.
  4. Prove the mechanism instead of asserting it. Name the trace span that grew, the plan that flipped to a sequential scan, the lease that expired, plus one alternative you ruled out and the signal that stayed flat while you ruled it out.

Follow-up

  • What would you do differently in the first five minutes, given the same dashboard and no more information?
  • Which follow-up action did you deliberately not take, and why was dropping it the right call?