Interview guides · Tesla
Tesla Software Engineer Interview Guide
Tesla Software Engineer interview guide: five reported rounds, coding, embedded, system design and physics questions, plus a 7-day prep plan.
The 60-second brief
Software Engineers at Tesla work in areas such as Autopilot, battery management for Tesla Energy, high-throughput pipelines for vehicle telemetry, and factory automation. Code in these seats often controls physical hardware like high-voltage systems and robots on the factory floor, and teams work with mechanical, electrical and manufacturing engineers. The reported questions reflect that: they go past algorithms into memory management, embedded C, and basic physics and circuits.
This guide covers the five rounds candidates report: recruiter screening, a technical screen or take-home exam, a panel interview loop, a technical project presentation, and 1:1 technical sessions. It also covers the five reported question categories: algorithms and data structures, low-level and systems programming, system design, first-principles physical engineering, and behavioral and mission questions. Which categories you face most depends on the team, so find out early which area the seat is in.
Focus areas
- Reconcile a movement ledger against derived positions
- Keep a site operating during a network partition
- Model units, lots and state machines precisely
Overview
The Software Engineer role at Tesla covers software that runs close to physical machines: Autopilot, battery management for Tesla Energy, data pipelines that monitor vehicles across the fleet, and automation on the factory floor. Software engineers work alongside mechanical, electrical and manufacturing engineers, so a bug can have physical consequences, not just a failed request.
For interview preparation, that shapes what gets asked. Reported questions include standard coding problems (a peak element, the maximum depth of a binary tree, a graph traversal, and a function that computes collision states or time-to-collision from a vehicle event log). They also include language and systems internals (Java garbage collection, stack versus heap, debugging embedded C with race conditions or leaks), design prompts about fleet telemetry, supercharger charging sessions and battery-line monitoring, and physical engineering questions such as stress-strain curves, pre-charge circuits and OEE.
The reported loop has five stages and includes a project presentation where you present a system you personally drove and answer questions on it. Plan your preparation so the presentation is finished before the onsite, and treat every language or tool on your resume as something you may need to explain from the inside.
The Tesla interview process
Tesla candidates report 5 rounds · ≈ 4-6 weeks. The stages below are what candidates describe, not a published process.
Recruiter Screening
Candidates describe an initial recruiter screen that assesses fit, with no further detail. Use it to find out which team the seat is on. The reported questions range from tree and graph coding to embedded C, fleet telemetry design and battery or circuit fundamentals, and the team decides which of these you will see. Ask whether the next stage is a live screen or a take-home, whether a project presentation is expected, and what domain the 1:1 sessions cover. One reported behavioral question asks why you want to work at Tesla specifically, so have a short, concrete answer ready.
What to demonstrate
- Whether your background maps clearly onto one area, such as vehicle software, energy, manufacturing, data infrastructure or embedded work
- Whether your reason for wanting this company and team is specific, not a generic statement about the mission
How to prepare
- Write three sentences on why this team: the product area, the kind of problem it involves, and a project of yours that is closest to it
- Prepare questions that settle the format: screen or take-home, whether a presentation is expected, and what the 1:1 sessions focus on
- Optionally, pick your presentation project now and write a two- or three-sentence summary, so you can mention it if the recruiter asks about your work
Technical Screen/Take-Home Exam
Candidates report either a live technical screen or a take-home exam. Some candidates also report quick-turnaround assessments sent by email that had to be returned within 60 to 90 minutes, so keep your schedule flexible once you reach this stage. No specific coding question is tied to this stage, so prepare the coding category as a whole: peak element, maximum depth of a binary tree with its edge cases, a medium-to-hard graph problem where you justify the traversal, a deque-based card game with memory optimisation, and a vehicle event-log metrics function. Under a short return window, a correct, readable solution with its edge cases written down is safer than an unfinished optimal one.
What to demonstrate
- Whether your code is correct on edge cases such as an empty tree, a single element, or equal neighbours in a peak search
- Whether you can explain your choice of traversal or data structure and state its time and space complexity
- Whether a take-home submission runs cleanly and states the assumptions you made
How to prepare
- Solve peak element in O(log n) with binary search under the standard precondition that adjacent elements differ (nums[i] != nums[i+1]) and positions past both ends count as -infinity; explain why moving toward the larger of mid and mid+1 then always reaches a peak, and why equal neighbours (plateaus) break the O(log n) guarantee
- Write maximum depth of a binary tree both recursively and with a BFS queue, and state when recursion depth becomes a problem
- Rehearse a timed solo task end to end, including a short README with the run command and your assumptions
Panel Interview Loop
Candidates describe a series of interviews with a panel of engineers and managers, without listing the individual sessions. No question category is tied to the panel, so prepare all five to a working level: algorithms, low-level and systems programming, system design, first-principles physical engineering, and behavioral. Reported design prompts include a real-time pipeline for telemetry from millions of vehicles, an API that coordinates charging sessions between vehicles and superchargers with high availability and low latency, a system for monitoring throughput and yield on a battery assembly line, and speeding up a slow ingestion pipeline without losing data at peak.
What to demonstrate
- Whether a design names its failure modes, such as a reconnecting vehicle, a peak burst or a downstream outage, and how data survives them
- Whether you can move between coding, design and fundamentals questions without losing structure
- Whether you explain your reasoning out loud while working, not just state a final answer
How to prepare
- For the telemetry pipeline, sketch ingestion, buffering, partitioning, storage and backpressure, and say where data could be lost and how you prevent it
- For the charging-session API, define the session state machine and say what happens when a request is retried or the vehicle disconnects mid-session
- Practise starting a technical answer cold, with no warm-up, then moving straight to a coding problem
Technical Project Presentation
Candidates report presenting a complex project they personally drove to a panel. Prepare it as a technical defense: be ready to explain why you chose each technology, architecture or algorithm, what you personally built and decided, the metrics and outcomes behind your claims, and how the system failed and how your software handled it. Two questions worth rehearsing: why a specific database over a relational model for a high-throughput pipeline, and what the physical or logical failure mode of your system was. Choose a project where you can answer every 'why' yourself, not one where the key decisions belonged to someone else. Confirm the expected length and format with your recruiter.
What to demonstrate
- Whether you can defend each major design decision from its constraints, not from convention
- Whether your personal contribution is clearly separated from the team's
- Whether you back claims of impact with measured numbers and can explain how you measured them
- Whether you can describe a real failure of the system and what changed afterwards
How to prepare
- List every major decision in the project, with the alternative you rejected and the constraint that ruled it out
- Mark each slide 'I' or 'the team' and rewrite any slide where your part is unclear
- Have a colleague interrupt with 'why not X?' on every slide, and write down the questions you could not answer cleanly
- Prepare one failure story from the project: what broke, how you found it, and what the software does now
1:1 Technical Sessions
Candidates describe several back-to-back technical sessions on your domain expertise. Prepare the internals of every language and protocol you list: memory allocation, the concurrency model and runtime behaviour of your main language, and, if the team is close to hardware, interrupts, RTOS scheduling, CAN, SPI and I2C, and registers. Reported low-level questions include how Java garbage collection works and when to use static, stack versus heap memory, debugging an embedded C program with race conditions or leaks, bit-swizzling for register manipulation, and FIFO buffer handshakes in RTL. These questions are not tied to a specific round, but they show the depth worth preparing for. Because the sessions run back to back, practise answering fundamentals when you are already tired.
What to demonstrate
- Whether you can explain what your main language's runtime actually does with memory and threads
- Whether you can find a race condition or leak by reasoning about shared state and ownership
- Whether your depth matches what is on your resume, item by item
How to prepare
- Explain Java GC roots, reachability and generations aloud, then explain the stack-versus-heap difference in a language without a garbage collector
- Take a small C program with a shared counter updated from an interrupt and a main loop, find the race, and fix it two ways
- For each language, protocol and tool on your resume, write the one internal detail you would be asked about and check that you can explain it
Where candidates lose points
Presenting a project as a tour of features and then being unable to say why each design choice was made
Prepare the project presentation as a technical defense: why this database, why this architecture, what the failure mode was and how your software handled it. For every major decision, prepare the alternative you rejected and the constraint that ruled it out. Keep 'I' and 'the team' separate on every slide, and have numbers ready for any outcome you claim, along with how you measured them.
Listing a language or tool on your resume that you cannot explain from the inside
Prepare the memory, concurrency and performance internals of every language and tool on your resume. Reported questions include Java garbage collection and the static keyword, and stack versus heap. Go through your resume line by line, write the internal detail most likely to be asked for each item, and remove any item you cannot explain in a few clear sentences.
Treating physics, circuits or manufacturing questions as outside a software engineer's scope
Reported questions include a stress-strain curve and Young's modulus, how pre-charge circuits work in high-voltage systems and their software safety implications, calculating OEE on a manufacturing line, and basic circuit analysis. Review the basics, especially if the team is close to vehicles or the factory. When you are unsure, reason out loud from the underlying physics and connect it back to what the software has to guarantee.
Designing the telemetry or ingestion pipeline for the steady state and ignoring peak load and reconnects
Reported design prompts include ingesting telemetry from millions of vehicles and fixing a slow ingestion pipeline so it does not lose data at peak. Name the failure you are designing for first: a burst, a downstream outage, or a vehicle replaying buffered data after reconnecting. Then show the buffering, backpressure and idempotent writes that stop data from being lost or double-counted. The worked design exercise on replaying buffered records works through that last case.
Answering 'why Tesla' with a generic line about the mission
One reported behavioral question asks why you want to work at Tesla specifically and how your experience fits its mission. Tie your answer to the team's product area and a concrete thing you have built that is close to it, such as hardware-adjacent code, telemetry pipelines or factory tooling. A specific answer is easier to believe than enthusiasm alone.
Questions & practice
Solve a medium-to-hard graph problem under tight time constraints, explaining your choice of traversal method.
Medium · data structures and algorithms
Approach
- Choose the data structure from the access pattern, not from familiarity.
- Restate the input: its shape, its size, and what is guaranteed about it.
- Name the brute-force solution and its complexity before improving on it.
Follow-up
- Which test case would catch an off-by-one here?
- How does this change if the input no longer fits in memory?
Implement a function to find the peak element in an array.
Medium · data structures and algorithms
Approach
- Walk one small example through your approach before writing the whole thing.
- Name the brute-force solution and its complexity before improving on it.
- Choose the data structure from the access pattern, not from familiarity.
Follow-up
- Which test case would catch an off-by-one here?
- How does this change if the input no longer fits in memory?
Describe the design of a FIFO buffer and how you would handle handshakes in RTL design.
Medium · languages, concurrency and fundamentals
Approach
- Identify the window where an invariant is briefly untrue.
- Distinguish a value from a reference to it, and say which one you handed out.
- Say what the runtime actually does before reasoning about the code.
Follow-up
- How would you prove the race exists rather than suspect it?
- Where could this allocate more than you expect?
Debug an embedded C program containing race conditions or memory leaks live on a scratchpad.
Medium · languages, concurrency and fundamentals
Approach
- Distinguish a value from a reference to it, and say which one you handed out.
- Identify the window where an invariant is briefly untrue.
- Name what is shared across threads and what owns each piece of state.
Follow-up
- How would you prove the race exists rather than suspect it?
- What happens if two callers reach this at the same time?
Parse partner quantity and date segments without floating point
Easy · parsing · unit-of-measure · time zones
A partner sends a delimited flat file whose segments look like QTY+17:4.500:CS and DTM+232:20260317. Quantities carry up to three decimal places in a named unit; each item has an integer pack factor to eaches that is versioned by effective date. Produce observation_event rows with an integer quantity in eaches, the unit recorded, and occurred_at resolved, rejecting any line whose conversion is not exact. Files reach 4 GB. Single pass, no floating point. State your bounds and what you do with the zoneless date.
Approach
- Scan with indices, not a regex. Find the segment terminator, then split the payload on
:by scanning forward and slicing — O(bytes) with no backtracking and no per-line allocation beyond the output row. A regex with nested quantifiers over 4 GB is where this job silently becomes CPU-bound. - Parse the decimal as an integer mantissa plus a scale.
4.500becomes(mantissa = 4500, scale = 3): accumulate digits into an int64, count digits after the point, and never call the runtime's float parser. Reject a mantissa that would overflow int64 when multiplied by the pack factor, checking before the multiply rather than after. - Convert by integer arithmetic and demand exactness:
numerator = mantissa * factor; emitnumerator / 10^scaleonly whennumerator % 10^scale == 0, otherwise reject the line with a reason code. Worked:4.500 CSat 12 eaches per case gives 54000/1000 = 54, exact.0.125 PLat 36 eaches per pallet gives 4500/1000 = 4.5, which is half a sealed unit and must fail at the boundary, not round three services away. - Select the pack factor by the file's effective date, not by the current item master. Factors are properties of a point in time — a supplier moving a case from 12 to 10 must not reinterpret last quarter's file — so the lookup is a range query on the factor's validity interval.
20260317carries no zone and no time. Attach the IANA zone of the node the segment refers to, captured at ingestion, because it cannot be recovered downstream; then pick and document one convention for a date-only field (start of local day is the usual choice) and store the raw local string beside the resolved instant so the assumption stays visible. Complexity: O(total bytes) time, O(longest line) working space, one pass.
Worked solution (20 min)
- Write the integer conversion as a pure function
(mantissa, scale, factor) -> Result<int64>and unit-test it before touching the file reader. - Table-drive the cases: exact conversion, non-dividing conversion, a mantissa near int64 overflow, a zero quantity, and a unit not in the ladder.
- Wire the scanner, emitting one rejection row per bad line with the raw segment attached so the partner can be shown what was sent.
- Feed a fixture file containing a date on a day the destination zone changes offset, and assert the resolved instant against a hand-computed value.
- Re-run the whole file and confirm identical output, including identical rejections.
Expected result: 4.500 CS at factor 12 yields 54 eaches; 0.125 PL at factor 36 is rejected as non-exact rather than stored as 4 or 5; every emitted row carries both the eaches integer and the source unit; the date-only field resolves through the node's zone, not the server's.
Verify it yourself
- No float type appears anywhere between the file bytes and the stored quantity — grep the parser for it.
- Summing the emitted eaches and converting back to the source unit reproduces the source decimal exactly for every accepted line.
- Changing the process time zone leaves every resolved
occurred_atunchanged.
Follow-up
- The same file is re-sent in full tomorrow with three lines changed. What makes the second ingest a no-op for the unchanged lines?
- A line names a unit that is not in the ladder for that item. Reject the line, reject the file, or quarantine it — and who finds out?
- The partner starts sending an offset like
+0100on some dates. Does that change your storage decision for a future appointment as well as a past event?
Decide whether available-to-promise is derived or stored
Hard · denormalisation · read path · cache staleness
Available to promise at one node equals inventory_position.qty in state on_hand minus the sum of allocation.qty in status held or committed for that key. The read sits inside checkout: 4,000 reads per second at peak, p99 budget 20 ms. inventory_position holds 40 million rows; during a promotion a single hot item-node pair carries about 2,000 open allocations. Decide whether to compute this per read or to maintain available_qty on the position row. Give both paths, the failure mode of each, and what the browse read may do that the allocate read may not.
Approach
- Cost the derived read in tuples, not in plans. One index probe into the position is trivial; the aggregate over allocation touches one tuple per open claim on that key. Even if only a tenth of peak lands on the hot pair, 400 reads per second times 2,000 rows is 800,000 index tuples per second for one item at one node, and it gets worse exactly as the key gets hotter. A partial index on status IN ('held','committed') does not help, because the row count is the cost, not the selectivity.
- Maintaining available_qty on the position row is nearly free on the contention axis, which is the point most candidates miss. The allocator already takes a row lock or a compare-and-set on that same position row, so the extra column costs no lock that was not already held, and the read collapses to a single primary-key probe well inside 20 ms.
- It is not free on the correctness axis. available_qty becomes a second derived value that can drift, so it joins qty under the same reconciliation job with its own re-sum against the allocation table, and a drift alert on that comparison is the operational price of the read speed.
- Split the two reads rather than arguing about one. The browse read may serve from a replica or a short-TTL cache and must err low, showing less than is there. The allocate read must be on the primary and inside the same transaction as the conditional update, because replication lag peaks during the write burst that made the key hot. Conflating them is what makes a replica read look safe in a benchmark.
- Pick the TTL against the drain rate, with a number. If a promotion burns 2,000 units in a minute, a 30-second cache is a thousand units stale, so the displayed figure should be a banded signal such as in stock or low stock rather than an exact count that the allocate step will then contradict.
- Do not denormalise availability across nodes into a single network number. A yes-somewhere answer cannot be allocated against, so sourcing will disagree with the page, and the customer sees a promise retracted after checkout rather than an honest out-of-stock before it.
Follow-up
- Roll this out on a live system. How do both paths run side by side, what do you compare, and what result gates the cut-over?
- The reconciliation job finds available_qty drifted by 3 on one key. What do you do, and what must you not do?
- Lot-tracked items multiply the position rows per item-node. Does your answer change, and where does the read now spend its time?
Attribute multi-stop freight cost without fanning it out
Medium · many-to-many joins · window functions · integer money
shipment_leg(leg_id, shipment_id, sequence_no, linehaul_cost_cents, accessorial_cost_cents, actual_arrive_at) joins to fulfilment_order_line through leg_order_line(leg_id, order_line_id, allocated_weight_g). One multi-stop truckload leg carries 40 order lines. The current report SUMs linehaul_cost_cents after joining all three tables and returns roughly forty times the real freight spend. Write the query that returns cost per order for one month, explain the fan-out in terms of the join's row count, and make the per-order amounts sum exactly to the leg totals in integer cents.
Approach
- Name the cardinality: joining shipment_leg to leg_order_line produces one row per (leg, line) pair, so the result has SUM over legs of lines-per-leg rows rather than one row per leg. SUM(linehaul_cost_cents) over that result counts each leg's cost once per line it carries, which is why 40 lines gives 40 times the spend. The bug is not the SUM, it is aggregating a parent measure across a child-expanded row set.
- Compute a share before aggregating anything. In one pass: leg.linehaul_cost_cents * b.allocated_weight_g / SUM(b.allocated_weight_g) OVER (PARTITION BY b.leg_id), which keeps the denominator local to the leg and needs no self-join.
- Do the division in integer cents and settle the remainder deliberately. Floor each share, then distribute the leftover cents one each by descending remainder, ordered by a stable tiebreak such as order_line_id. Floating-point shares leave a residue that makes the freight accrual miss by a cent per leg, which costs more to investigate than the freight.
- Aggregate to the order only after the share exists: GROUP BY order_id over the per-line allocated cents. Restrict the month on shipment_leg.actual_arrive_at, not on the order date, so a leg is attributed in the period it actually ran.
- Index for the shape of the query: leg_order_line needs (leg_id) for the window partition and (order_line_id) for the reverse lookup, and shipment_leg needs an index on actual_arrive_at to bound the month without a full scan.
- Apply the same treatment to accessorial_cost_cents separately. Accessorials such as a detention charge often belong to one stop rather than to the whole leg, so weight-sharing them across every line on the load misattributes cost even though the total ties out.
Worked solution (30 min)
- Build a fixture with one leg at 100,003 cents carrying three lines weighted 1000 g, 1000 g and 1 g.
- Write the naive join and observe the total reported as three times the leg cost.
- Rewrite using the SUM(...) OVER (PARTITION BY leg_id) share, floor to integer cents, and add a largest-remainder pass ordered by remainder then order_line_id.
- Aggregate to order level and compare the grand total against SELECT SUM(linehaul_cost_cents + accessorial_cost_cents) FROM shipment_leg for the same window.
Expected result: Per-order allocated cents whose total equals the sum of leg costs for the month exactly, with no leg double-counted and the 2-cent remainder on the fixture distributed deterministically rather than lost or duplicated.
Verify it yourself
- The reconciliation total matches to the cent, not to within rounding.
- COUNT(DISTINCT leg_id) in the result equals the leg count for the month, proving no leg was expanded.
- Re-run with the line order shuffled and confirm the same order receives the same remainder cent.
- Add a fourth line to the leg and confirm the leg total is unchanged while the shares redistribute.
Follow-up
- A line is cancelled after the leg ran. Does its share of the freight disappear, move to the remaining lines, or stay as a cost with no revenue?
- Weight is the wrong basis for a light bulky pallet. What would you use instead, and does the reconciliation check still hold?
- The carrier invoice arrives three weeks later and differs from the rated cost. Where does the correction land, and does it re-run this allocation?
Design a real-time data pipeline capable of ingesting and processing telemetry data from a fleet of millions of vehicles.
Medium · system design and architecture
Approach
- Name the read and write paths separately; they rarely have the same bottleneck.
- Name the failure you are designing for, then the recovery path.
- Fix the scope first: who calls this, how often, and what they do when it fails.
Follow-up
- What would you drop to keep the system up under load?
- How does this behave when that dependency is down for an hour?
Architect an API designed to coordinate charging sessions between vehicles and superchargers, considering high availability and latency.
Medium · system design and architecture
Approach
- Name the read and write paths separately; they rarely have the same bottleneck.
- Name the failure you are designing for, then the recovery path.
- State the consistency you need, and where you are willing to be stale.
Follow-up
- What breaks first when traffic grows ten times?
- How does this behave when that dependency is down for an hour?
Design a full-stack system that allows manufacturing engineers to monitor real-time throughput and yield on a battery assembly line.
Medium · system design and architecture
Approach
- Name the failure you are designing for, then the recovery path.
- State the consistency you need, and where you are willing to be stale.
- Choose a partition key and say what query it makes expensive.
Follow-up
- How does this behave when that dependency is down for an hour?
- What would you drop to keep the system up under load?
Walk through a stress-strain curve and explain how you would calculate Young's modulus for a given material.
Medium
Approach
- Clarify what is being asked and what a complete answer contains.
- State your assumptions explicitly before working the problem.
- Say what you would check first and why it is the highest-information step.
Follow-up
- What assumption would you test first?
- How would you know your answer was wrong?
Accept a reconnecting site's six hours of buffered movements
Medium · partial failure · batch api · at-least-once
A Warehouse Execution Service buffered movements locally through a six-hour network partition and now has 40,000 records to replay. Design POST /movements:batch. Cover the per-record shape (caller idempotency_key, client_sequence, item, node, state, delta_qty, uom_code, occurred_at), the size limits, the response when record 8,113 fails validation while the rest apply, and the acknowledgement the site uses to truncate its buffer. The site must lose nothing and apply nothing twice. State what it does on 429, on 413 and on a timeout.
Approach
- Put the idempotency at the record, not the batch. The unit of work is one movement, because a partially applied batch has to be resumable; echo the site's client_sequence back so the acknowledgement is positional and the buffer can be truncated precisely rather than approximately.
- Apply with one statement: INSERT ... ON CONFLICT (idempotency_key) DO NOTHING RETURNING idempotency_key, then derive per-record outcomes of applied, duplicate or rejected from what came back. That is O(n) in one round trip instead of n round trips, and it makes duplicate a success rather than an error - which it must be, since at-least-once delivery is the premise.
- Return 200 with a per-record array and keep business outcomes out of the transport status. One bad record must not make the response non-2xx, or the site re-sends 40,000 records whose individual fate it cannot determine. Avoid 207, which is defined for WebDAV in RFC 4918 and reaches general clients as an unrecognised 2xx.
- Bound the request: cap records and bytes, answer 413 with the limit in the body so the client can split deterministically, and use 429 with Retry-After for backpressure. Write the rule that the site retains every record until that record is individually acknowledged - a timeout is indistinguishable from success, so it re-sends and the keys absorb it.
- Decide ordering deliberately. Signed deltas commute for conservation, so movements need no global order, but state transitions and allocation consumption do not commute; either apply within an (item, node) group in client_sequence order or reject a record whose prerequisite is absent with a retryable code, and say which you chose and why.
- Finish with reconciliation rather than trust: after the replay, re-sum inventory_movement into inventory_position for the affected keys, compare against the running totals and raise variance instead of assuming the incremental path got it right.
Worked solution (35 min)
- Write the request and response JSON for a three-record batch where one is a duplicate and one is invalid.
- Write the insert statement and show how the RETURNING set plus the submitted set yields the three outcome classes.
- Pick concrete limits - records per batch, bytes per batch, expected wall time for 40,000 records - and derive the number of requests the replay takes.
- Write the client's state machine: send, await per-record ack, truncate acked prefix, retry the rest, honour Retry-After, never drop unacked records.
- Run the reconciliation query for the touched (item, node, lot, state) keys and decide what happens to a variance.
Expected result: Per-record keys and sequences, a single-statement apply, a 2xx carrying a per-record outcome array, explicit 413 and 429 semantics with the buffer retained until individual acknowledgement, and a reconciliation pass after the replay.
Verify it yourself
- Re-sending the identical batch produces the same outcome array with every record marked duplicate and no position change.
- A batch containing one invalid record still applies the other 999 and identifies the failure by client_sequence.
- After the replay, re-summing the ledger for the affected keys matches inventory_position exactly, or reports a variance rather than silently correcting one.
Follow-up
- Two sites reconnect at once and saturate the write path. What sheds first, and what must never shed?
- A buffered pick conflicts with a cycle count taken during the partition. Which one wins, and what evidence survives?
- How does the site learn that a record it sent three hours ago was rejected, and who owns it after that?
Two committed allocations against a position holding one unit
Hard · concurrency · compare-and-set · isolation levels
Six oversells in a week, all on the twenty hottest item-node pairs, all inside promotion minutes. In one case inventory_position.qty was 1 and two allocation rows exist with qty 1 and status 'committed', created 4 ms apart; both transactions committed cleanly. The code reads availability, then issues UPDATE inventory_position SET qty = qty - :n, version = version + 1 WHERE item_id = :i AND node_id = :d AND lot_id = :l AND state = 'on_hand' AND version = :v, then inserts the allocation. A 200-thread load test across 50,000 SKUs never reproduces it. Find the defect and prove it.
Approach
- Reconstruct from the data before reading the code. Pull inventory_movement and allocation for that key ordered by identifier with the version values involved. Two commits that both proceeded from version v prove the compare-and-set did not gate anything; a single row correctly stepping v then v+1 with an oversell anyway would instead send you to the read path.
- Name the defect: the affected-row count of the conditional UPDATE is never tested. When version has moved the UPDATE matches nothing and affects zero rows, but control flow continues into the INSERT and the transaction commits, so the WHERE version = :v clause is decoration. A compare-and-set only protects you if the zero-row outcome changes what happens next.
- Explain why the load test is silent. With 200 threads spread over 50,000 SKUs, the chance that two allocators land on one row inside the UPDATE's execution window is negligible, while production traffic concentrates on twenty rows. Pin the same test to a single SKU with a position of 1 and N threads, assert that exactly one allocation survives, and it fails on the first run. That test is the proof, and it belongs in the suite.
- Rule out the decoy rather than ignoring it. If availability is read from a replica, lag peaks exactly when write volume does, so the read is often stale. But a stale read only mis-sizes the attempt: with a working compare-and-set the write still fails and retries, so the replica is a latency and retry-rate problem, not the oversell. Say that explicitly instead of fixing two things and learning nothing.
- Fix and then choose the mechanism deliberately. Test the rowcount; on zero rows re-read the position from the primary and retry with bounded attempts and jittered backoff, and never reuse the version captured before the failed attempt. Compare-and-set is lock-free but burns retries under contention on a single hot row; SELECT ... FOR UPDATE inside a short transaction queues writers predictably and is usually calmer for twenty hot keys; above that, funnel allocations for one item-node key through a single writer and accept the added latency.
- State what the isolation level does and does not do, since identical code is not equally safe everywhere. On PostgreSQL READ COMMITTED, which is the default and what this deployment runs, the second UPDATE blocks on the row lock, re-evaluates its predicate against the newly committed row, matches nothing and affects zero rows; control flow falls into the INSERT and the transaction commits, and that is the oversell. InnoDB's REPEATABLE READ ends the same way for this statement, because an UPDATE takes a current read rather than the snapshot read: it blocks, applies against the latest row, affects zero rows and does not abort. PostgreSQL REPEATABLE READ is the one that does not oversell, and not because the code is right: it raises SQLSTATE 40001 on a row a concurrent transaction updated after the snapshot, which aborts the whole transaction, so the unchecked INSERT can never commit. That is failing closed on an exception no handler anticipated, on one of the three configurations, at the cost of an error the caller has to catch and retry. Two of three commit the oversell, so the rowcount check is not optional, and the invariant belongs in a continuous monitor as well as in a test: assert per key that the sum of allocation.qty in status 'held' or 'committed' does not exceed the position quantity, and let the reconciliation job re-sum movements into positions and raise a variance when they disagree.
Follow-up
- An allocation must span two positions atomically. What changes in your mechanism, and what if the two live in different shards?
- Under the retry design, what stops a hot key from livelocking when fifty allocators all retry together?
- The six oversells are already promised to customers. What is the compensating path, and what does it write to inventory_movement?
Suggested practice checklist
Four days sample coding, design, fundamentals and the practical rounds at deliberately shallow depth, which is enough to surface the topics you did not know were in scope. That map, rather than a guess made on day one, decides where the last three days go.
Day 1 — Coding: the reported algorithm questions
- Solve peak element with binary search (stating the distinct-neighbour precondition), and maximum depth of a binary tree both recursively and iteratively, writing down the edge cases for each before running anything
- Solve one medium-to-hard graph problem and write one sentence on why you chose BFS or DFS for it
- Write a function that sorts a vehicle event log by time and computes collision episodes and minimum time-to-collision in one pass
- If time remains, do a bank problem from the same category, such as trapping rain water or shortest bridge between two islands
Deliverable: Four solved problems, each with stated complexity and a written list of edge cases checked.
Day 2 — Low-level and language internals
- Explain aloud how Java garbage collection works (roots, reachability, generations) and when you would use static
- Contrast stack and heap memory in a language without a garbage collector, including what a leak looks like there
- Work the debugging drill 'Two committed allocations against a position holding one unit' to practise proving a race condition, not just suspecting it
- Sketch a FIFO ring buffer with full and empty detection, then explain bit-swizzling for register manipulation
Deliverable: One-page notes on GC, memory and one race you found and fixed, written in your own words.
Day 3 — System design: fleet and factory prompts
- Design the real-time telemetry pipeline for millions of vehicles: ingestion, partitioning, storage, and what happens at peak
- Design the charging-session API between vehicles and superchargers, including the session state machine, retries and disconnects
- Work through the worked design exercise 'Accept a reconnecting site's six hours of buffered movements' and apply its idempotency and acknowledgement ideas to vehicles replaying buffered telemetry
Deliverable: Two design sketches, each with a named failure mode and a recovery path.
Day 4 — First-principles and physical engineering
- Walk through a stress-strain curve and explain how to calculate Young's modulus from the linear region
- Explain how a pre-charge circuit works in a high-voltage system and list what software must check before the main contactor closes
- Calculate OEE from availability, performance and quality on a made-up line, and say which data you would collect to improve throughput
- Solve one basic circuit analysis problem and explain it aloud as if to a software interviewer
Deliverable: Four short written explanations you could give aloud without notes.
Day 5 — Technical screen and take-home rehearsal
- Take a coding problem you have not seen and complete it inside a 60-to-90-minute window, the return window some candidates report for emailed assessments
- Write a README with the run command, your assumptions, and the known limits of the solution
- Work the worked coding exercise 'Parse partner quantity and date segments without floating point' and the worked SQL exercise on freight cost fan-out as extra timed practice
Deliverable: One timed submission with a README, and notes on where the time went.
Day 6 — Project presentation
- Build the presentation for one project you personally drove: problem, architecture, your decisions, metrics, and one failure
- For every decision, write the rejected alternative and the constraint that ruled it out
- Deliver it to a colleague who interrupts with 'why not X?' and 'what did you personally do?', then fix the weakest slides
Deliverable: A finished presentation plus a list of the defense questions you had trouble with, each now with an answer.
Day 7 — Behavioral answers and a back-to-back mock
- Prepare answers to the reported behavioral prompts: why Tesla, your most complex technical issue, a severe setback or team conflict, and handling pressure and tight deadlines
- Run two technical mocks back to back, one coding and one low-level or design, to rehearse the 1:1 sessions
- Review days 1-6 and rework the single weakest area once more
Deliverable: Four behavioral answers with a concrete outcome in each, and notes from the back-to-back mock.
'We rewrote it in a better framework' is not a story
The reported behavioral questions cover motivation for Tesla specifically, the most complex technical problem you have solved, setbacks and conflict, and working under pressure. For each answer, make your personal contribution clear, include a concrete technical detail or number, and say what you would do differently. For 'why Tesla', tie your answer to the team's product area and something you have actually built.
- Why do you want to work at Tesla specifically, and how does your past experience align with the company's mission?
- Tell me about a time you faced a severe project setback or team conflict. How did you overcome it to deliver results?
- How do you handle extreme pressure, tight deadlines, and environments with minimal work-life balance?
- Walk through a project you personally drove: why you made its key design decisions, and what failed and how your software handled it.
Describe the most complex technical issue you have solved. What was your personal impact, and how did you approach the problem?
Medium · behavioural and engineering judgement
Approach
- Close with what you would do differently, concretely.
- Pick a story where you made the decision, not one where you watched it.
- Give the blast radius: what could have broken, and what you measured.
Follow-up
- How did you know your change caused the improvement?
- What would you do differently if you ran that again?
Reverse an allocation design after peak contention
Medium · concurrency control · lock contention · reversibility · measurement
You chose optimistic concurrency for allocation: read the position, then UPDATE inventory_position SET qty = qty - :n, version = version + 1 WHERE version = :v, retrying on an affected-row count of zero. It was correct and fast in load tests with spread keys. At peak, a few hundred hot item-node pairs absorbed most write traffic, retries amplified, and allocation p99 went past the checkout budget. Describe a decision you reversed under production evidence: what you originally reasoned, the measurement that forced the change, what you replaced it with, and what you would have measured before committing.
Approach
- Say why the original choice was reasonable, because a reversal story is only useful if the first decision was defensible. Compare-and-set avoids holding a lock across the read, has no deadlock surface, and is uncontended on the long tail of keys, which is most keys most of the time.
- Name the mechanism of the failure rather than calling it contention. On PostgreSQL under READ COMMITTED, a conflicting UPDATE does not fail fast: it blocks on the row lock until the other transaction commits, then re-evaluates its predicate against the new row version and reports zero rows affected. Each loser therefore pays a full lock wait before learning it must retry, so with k writers queued on one pair the work is quadratic in k across the burst, and the retry loop adds round trips rather than avoiding waits.
- Bring the measurement that settled it, not the anecdote: attempts per successful allocation on the hottest pairs, the distribution of write traffic across item-node keys, and the p99 contribution of lock wait time separated from query time. Load tests with spread keys cannot show any of this, which is the real lesson and the thing you would run differently.
- State the replacement and its cost. Serialising each hot key behind a single writer with a bounded queue converts an unbounded retry storm into a bounded wait plus explicit shedding, at the cost of a new component, a routing decision and a failure mode when the writer for a key is unavailable. SELECT ... FOR UPDATE is the smaller change and trades the retry loop for an in-database queue that still consumes a connection per waiter.
- Describe the migration, since reversing a write path in production is where these stories become concrete: route only the measured hot keys first, keep both paths live behind a per-key decision, and verify with the same attempts-per-success metric before widening.
- Close on what you would have measured before committing, and be specific: key skew from production traffic, not from a synthetic generator, is the input the original decision was missing.
Follow-up
- Under REPEATABLE READ on PostgreSQL that same conflict raises a serialization failure instead. What changes in your retry code and your error budget?
- One key becomes so hot that even the single writer saturates. How do you shed load without overselling?
- An allocation must span two positions atomically. What breaks in your replacement design if those rows live on different shards?
Own an outage that double-tendered loads to a carrier
Medium · incident response · idempotency · blast radius · carrier integration
A retry wrapper in the carrier gateway re-issued tenders whose responses had timed out, minting a fresh idempotency key on each attempt. Over 70 minutes, 212 of 1,340 legs were tendered twice and 19 became second physical pickups before dispatchers noticed. Take the on-call role and describe an outage you owned with a comparable blast radius: how it was detected, how you bounded the affected legs, what you stopped first, and how the duplicate physical work was unwound. Give a wall-clock timeline, the query that sized the damage, and the guard that would have caught it in minutes rather than an hour.
Approach
- Open with the invariant that broke rather than the symptom: at most one booking exists per shipment_leg, keyed by booking_idempotency_key. Stating the invariant tells the listener what is countable, which is what makes the rest of the story checkable.
- Size the population with a named query, not an adjective. Duplicates are visible two ways and a strong answer says which one it trusted: legs carrying more than one distinct carrier_booking_ref, and the carrier's own booking export left-joined to shipment_leg on the reference, where the unmatched rows are bookings the system does not know it owns. The second is authoritative because the partner, not you, holds the truth about what was accepted.
- Separate mitigation from fix and say which came first. Mitigation is blunt and cheap: disable the retry path, drop gateway concurrency, hold tendering behind a flag so the floor keeps picking while dispatch stops booking. The fix, minting and persisting the key before the call with an explicit unknown status, is not an incident-window change.
- Split the blast radius into tiers, because the recovery cost is not uniform: a duplicate record is a delete, a duplicate booking not yet dispatched is a cancellation call, and a duplicate that became a pickup is a physical reversal with a trailer, a driver and an invoice behind it. The 19 that moved dominate the cost and belong at the front of the account.
- Close with one detector and its price. A counter on bookings-per-leg with an alert above one, or a nightly reconciliation of the partner export against shipment_leg, are both defensible; naming one and saying how many false pages per week it costs beats listing five that nobody staffed.
- Name what you got wrong inside the response window, not only in the writeup. Interviewers weight that heavily because it is the part candidates rehearse away.
Follow-up
- The partner has no idempotency concept on their tender endpoint. What do you do differently, and what is the residual exposure you accept?
- How would you have detected this in five minutes instead of 70, and what would that detector have cost in noise?
- Dispatch disputes your count of duplicate pickups. What artefact do you show them?