Candidate-facing descriptions of the Software Engineer role at The Trade Desk describe designing, building and operating ad-bidding platforms, real-time data streaming engines and data pipelines. The areas named are real-time bidding (RTB) engines, distributed caching systems, audience targeting databases and user-facing reporting analytics. The languages listed are C#, Java, C++ and Python. The same descriptions emphasize concurrency, thread safety, low-latency networking and efficient memory management.
The reported questions follow the same themes. On the object-oriented side there is an N-way set-associative cache with pluggable LRU and MRU eviction that must be thread-safe, an in-memory rate limiter with per-client limits, a refactor of buggy legacy code, and a class design for an event logging system with thread pools and storage sinks. The reported distributed design questions include a real-time ad bidding engine under a sub-10ms latency SLA, a streaming reporting pipeline, cache invalidation and replication across regions, and an asynchronous queue with delivery guarantees. On the coding side, candidates describe progressive problems that start simple and add constraints in later parts.
Use this guide to prepare in that order: get the coding fundamentals solid, then build caches and concurrency-safe classes until you can do them from a blank file, then practice system design with an explicit latency budget. The rounds and questions are what candidates report, not a published process. The drills are original practice, and the SQL, coding and design drills with worked solutions show the level of detail to aim for when you explain an answer.
Automated Technical Assessment
reportedCandidates describe this as an initial online assessment of technical skills. The sources do not give its format, platform or number of problems. The reported coding questions are the best material to prepare with: contiguous subarrays matching a condition, reordering string patterns or log lines, 2D array problems solved in O(1) auxiliary space, a sliding-window maximum or minimum over a stream, and a progressive three-part problem that moves from string manipulation to matrix traversal to dynamic programming. Nobody here ties a particular question to this round. If no one is available to answer questions, the prompt's constraints and examples are all you have, so read them twice. Get a correct version working before you optimize, and test the edge cases yourself before you submit.
What to demonstrate
- Whether the solution is correct on edge cases like empty input, a single element, duplicates and all-equal values, without anyone prompting you
- Whether the complexity you choose fits the stated input bounds rather than whichever pattern you recognized first
- Whether a working baseline exists before any optimization, so a partial optimization never leaves you with nothing that runs
How to prepare
- Implement a sliding-window maximum with a monotonic deque from a blank file, then change it to a minimum and to a stream that arrives one value at a time
- Drill in-place 2D array problems such as rotating a matrix and zeroing rows and columns, and state the auxiliary space of each version
- Before each practice submission, write four edge-case inputs and their expected outputs, and run them
- Practice in the language you will actually use, with a timer running, so the pressure of an automated assessment is familiar
Recruiter Discussion
reportedCandidates report that this conversation covers your background, team fit and compensation expectations. It is not a coding round. Assume a non-engineer may need to retell your projects, so make them survive a paraphrase. Map your experience to the areas the role descriptions name: backend services, concurrency, caching, streaming data and high-throughput systems. Say plainly where you have no experience. This is also the cheapest place to learn the format of the next rounds, so bring questions about it.
What to demonstrate
- Whether your background can be summarized accurately in a few sentences, with what you owned separated from what the team did
- Whether your experience lines up honestly with the areas the role describes, including gaps you name yourself
- Whether you have a considered answer on compensation expectations and team preferences instead of improvising one
How to prepare
- Write each headline project as two sentences with no internal codenames: what was breaking or needed, what you changed, and the measured result
- Decide your compensation range from your own research before the call, and have one sentence ready on what drives it
- Prepare questions about the screening call (live coding or low-level design, which languages are allowed, which editor) and about how the Superday sessions are split
- Name the one concurrency or performance problem you have handled in production. It is your strongest link to the reported questions
Technical Screening Call
reportedCandidates describe this as a phone assessment built around live coding or low-level design. The reported object-oriented questions are the natural material to prepare with, though the sources do not say which one shows up in which round: an N-way set-associative cache with custom eviction strategies (LRU, MRU) that stays correct under concurrent access, an in-memory thread-safe rate limiter with configurable windows and per-client limits, and a refactor of buggy legacy code without breaking behavior. Start by stating the interface and the concurrency contract, then build the core, then add eviction policies and locking. Talk through your reasoning as you go, since the interviewer may be on the phone and can only follow what you say.
What to demonstrate
- Whether the class boundaries allow extension, for example eviction behind an interface so MRU is a new class and not an edited branch
- Whether get and put run in O(1) and you can say why, using a hash map plus a doubly linked list per set
- Whether thread safety is designed and not bolted on: what the lock protects, its granularity, and why get needs exclusive access under LRU
- Whether you clarify requirements before writing code: capacity, set count, key hashing, and behavior on a miss
How to prepare
- Build LRU and MRU caches from a blank file in O(1) per operation. Note that both share one linked list and evict from opposite ends
- Extend that to an N-way set-associative cache with one lock per set, and explain why a single global lock serializes every caller
- Implement a per-client rate limiter twice, once as a sliding window log and once as a token bucket, and compare their memory and precision
- Rehearse by explaining aloud while you type in a plain editor, so your reasoning is clear without anyone watching your screen
Panel Round (Superday)
reportedCandidates report a final panel called the Superday: 4 to 5 back-to-back sessions covering algorithms, object-oriented design, distributed system architecture, and leadership or cultural fit. The sources do not give the order of the sessions or which reported question lands in which one. Two things to prepare for are the depth of each category and staying sharp across consecutive sessions. The reported system design questions include a real-time ad bidding engine with a sub-10ms latency SLA, a streaming reporting pipeline with fast queries, cache invalidation and replication across regions, and a queueing system with delivery guarantees. For the latency-bound designs, build around an explicit budget: what sits in memory, what is precomputed, and what the system does when a dependency is slow.
What to demonstrate
- Whether a design states its latency budget and keeps database lookups off the synchronous bid path
- Whether single points of failure and bottlenecks are named, with a concrete remedy for each
- Whether the object-oriented design and algorithms sessions reach the same standard of correctness and thread safety as a fresh first session
- Whether behavioral answers show ownership of a trade-off, a disagreement or a production bottleneck, with a measured outcome
How to prepare
- Run a back-to-back mock of at least three sessions (coding, object-oriented design, system design) with no break, then note where quality dropped
- Design the ad bidding engine with a per-hop deadline and a no-bid fallback, then work through the debugging drill on late bids and the bidder snapshot drill
- Practice a multi-region cache invalidation answer that names the consistency you give up and where stale reads are acceptable
- Prepare four behavioral stories covering a speed-versus-quality trade-off, an architecture disagreement, ambiguous requirements and a production bottleneck you fixed
2 candidate reports. Individual accounts describe a particular role and hiring cycle.
The Trade Desk Software Engineer Interview Experience — A Take-Home Stock-Price API Task
I am not sure whether this take-home assessment is the same as an online assessment. Implement a single function that returns a list containing every date between first_date and last_date, together with the stock's opening and closing prices for each date. The rough interface was: The output looked roughly like this: All of this information had to be obtained through real HTTP requests. The promp…
Read full experienceThe Trade Desk Senior Software Engineer Interview Experience — Two Read-Heavy Design Rounds and a Bowling-Score Coding Question
View report detailsPracHub editorial advice for the preparation topics above.
Handing in a single-threaded cache or rate limiter when the reported prompt says thread-safe
Decide the concurrency contract before writing the core. In an N-way set-associative cache, one lock per set lets unrelated keys proceed in parallel, while one global lock serializes every caller. Under LRU, get updates recency, so it mutates the list. A read-write lock where get takes the read side is a bug, not an optimization. Say this out loud, then show which fields each lock protects.
Hard-coding LRU inside the cache class when the reported question asks for custom eviction strategies
Put eviction behind a small interface (record access, choose a victim) and inject it. MRU then becomes a second implementation. It uses the same doubly linked list and evicts from the other end, so one extra class shows the design is extensible. Mention how a new policy would be added without touching the cache's lookup path.
Writing part one of a progressive problem so tightly that part two forces a rewrite
Progressive multi-part coding problems are reported for this role. Keep parsing, the core traversal and the output as separate functions with clear inputs, and state the complexity of each part before moving on. When a later part adds scale or asks for dynamic programming, you can then replace one function instead of starting from a blank file with less time left.
Designing the ad bidding engine with synchronous database or service lookups on the request path
The reported bidding question sets a sub-10ms latency SLA, so start with a budget, not boxes. Keep campaign and targeting state in an in-memory snapshot rebuilt off the request path, and give each downstream call the remaining deadline rather than a fixed timeout. Treat a no-bid as the safe failure when the budget runs out. Also say how you would detect a stale snapshot.
Rewriting the reported legacy codebase from scratch instead of refactoring it
The reported prompt asks you to improve structure without breaking existing functionality. First name the smells and any race conditions you see, then pin the current behavior with a few tests, then change one thing at a time and say why each step is safe. A plan explained step by step before you touch the code is part of the answer.
Choose a category, try a prompt, then open its approach, worked solution or follow-up when you need it.
Solve a progressive 3-part problem starting with a basic string manipu…
Solve a progressive 3-part problem starting with a basic string manipulation, building to a matrix traversal, and concluding with a dynamic programming optimization.
Approach
- Name the brute-force solution and its complexity before improving on it.
- Choose the data structure from the access pattern, not from familiarity.
- State the target complexity and say which constraint rules the naive version out.
Follow-up
- Which test case would catch an off-by-one here?
- How does this change if the input no longer fits in memory?
Compute eligible serving time per flight minus overlapping pauses
Each line item has flight_start_ts and a nullable flight_end_ts, and its change history yields pause intervals [pause_start, pause_end) - up to 10^7 pauses across 10^6 line items, unsorted, frequently overlapping or nested, some with a null end meaning still paused. For each line item return the number of seconds it was eligible to bid inside its flight, clipped to a reporting horizon where the flight is open-ended. Give the complexity, and state your interval convention explicitly before you write any code.
Approach
- Fix the convention first: half-open [start, end), integer epoch seconds in UTC, a null pause_end resolved to the horizon and a null flight_end_ts likewise. Mixing closed and half-open ends is what produces the off-by-one-second sums nobody notices until a full-day flight reports 86401 seconds.
- Group by line_item_id, sort each group by pause_start, then merge: hold a running [cur_start, cur_end), extend cur_end when the next start is at most cur_end, otherwise emit and restart. Sorting dominates at O(m log m) over m pauses.
- Clip merged pauses to the flight interval before subtracting, not after. A pause can begin before the flight opens and end after it closes, and an unclipped subtraction removes time the line item never had in the first place.
- Eligible time is flight length minus the summed clipped merged pause length. With merging done first this cannot go negative, so assert it and treat a firing assertion as a bug in the merge rather than as unusual data.
- For the batch shape given, sort the entire array once by (line_item_id, pause_start) and sweep it. Grouping then costs nothing and memory stays at one pass, instead of building a map of 10^6 vectors.
Follow-up
- The same figure now has to be maintained incrementally as pause events stream in rather than recomputed as a batch. What changes?
- How would you answer 'how many line items were eligible at instant T' over the same input, and what does that cost?
- A pause row arrives whose end precedes its start. Do you reject it, clamp it, or drop the line item from the report, and who finds out?
Select the top eight candidates under a shrinking deadline budget
Candidate selection hands the scorer between 1 and 20,000 eligible line items per impression slot. The expensive second-stage model can score only 8 of them inside the request's remaining budget, and every candidate carries a cheap precomputed score readable in O(1). Return the 8 highest by cheap score, deterministically, and describe what you do when the remaining budget is smaller than the cost of scoring 8. Beat O(C log C), and state the time and space complexity you are targeting.
Approach
- Use a bounded min-heap of size k = 8: push the first 8, then for each remaining candidate compare against the root and replace only when larger. That is O(C log k) time and O(k) space, and it consumes candidates as posting-list intersection emits them rather than requiring the full array up front.
- Compare against quickselect honestly rather than reciting its average case: it is expected O(C) but needs the whole candidate array materialised and mutable, its worst case is quadratic without an introselect fallback, and at C = 20,000 with k = 8 the log k factor is 3, so the constant decides this, not the asymptotics.
- Make ties deterministic by ordering on (cheap_score, line_item_id). Without it, two replicas handed the same candidate set can return different eights, which turns bid replay and any experiment comparison into noise you cannot attribute.
- Derive k from the deadline rather than configuring a timeout for the second stage: divide the time remaining on the request by the measured per-candidate scoring cost at a high percentile, floor at zero, and when it reaches zero either bid from the cheap score alone or no-bid.
- Measure that per-candidate cost at a tail percentile rather than at the mean, because a mean-derived k overruns the deadline on exactly the requests where the fleet is already slow.
- Account for the fan-out: one bid request carries several impression slots, so this selection runs per slot against a budget that is per request. The affordable k shrinks as slots are processed.
Worked solution 25 min
- Write the bounded min-heap loop and state the steady-state work per candidate: one comparison against the root, and a sift only when it replaces.
- Do the arithmetic for C = 20,000 and k = 8 - roughly C root comparisons plus at most C sifts of depth 3 - against a full sort at C log2 C, about 20,000 x 14.
- Write the formula for the affordable k from remaining_micros and the p99 per-candidate cost, and evaluate it at 2 ms and at 200 microseconds remaining.
- Add the (cheap_score, line_item_id) tie-break and state the determinism property it buys.
Follow-up
- C becomes 2 million because one advertiser created a line item per postcode. What in your design changes and what does not?
- The cheap score is a replica of a model refreshed every ten minutes. How does that staleness change which candidates you are willing to drop?
- You need the top 8 per slot, but the union across 6 slots must not exceed 20 second-stage calls. How do you allocate them?
Explain why this billing-notice query ignores the primary key
delivery_event is RANGE partitioned by received_ts date, has PRIMARY KEY (impression_id, event_type), and carries line_item_id, creative_id, exchange_id, clearing_price_micros, clearing_currency, event_ts, received_ts and ivt_status. A PostgreSQL reporting query filters line_item_id = $1 AND event_type = 'billing_notice' AND received_ts::date BETWEEN $2 AND $3 and sums clearing_price_micros. EXPLAIN shows a sequential scan on every partition. Give three separate reasons the existing index cannot serve it, rewrite the predicate so partition pruning applies, and specify the index you would add including column order.
Approach
- Reason one is coverage: the primary key contains neither line_item_id nor received_ts, and its leading column is a UUID with no predicate supplied, so there is no start point to seek to and nothing in the index that answers the filter. A btree scan begins from a prefix of its own column order or it begins from the start.
- Reason two is the cast on the partition key. received_ts::date applies a function to the column, so the planner cannot map the predicate onto partition boundaries and prunes nothing. Rewrite as a half-open range on the raw column, received_ts >= $2 AND received_ts < $3 + interval '1 day', and note that timestamptz to date conversion depends on the session TimeZone, so the rewrite must pin the zone or the day boundaries move.
- Reason three is parameter typing. If $1 arrives as numeric rather than bigint, the comparison casts the column rather than the constant, and a btree on line_item_id becomes unusable. Read the EXPLAIN for which side of the operator the cast landed on, because a cast on the constant is free and a cast on the column is fatal.
- Specify the index as (line_item_id, received_ts) with a partial predicate WHERE event_type = 'billing_notice', created on each partition. Equality column first so the scan starts at one point, range column second so the matching rows are contiguous, and the partial predicate shrinks the index to the minority event type that carries a price.
- Consider INCLUDE (clearing_price_micros) for an index-only scan, and state the precondition rather than asserting the win: an index-only scan requires the partition's visibility map to be largely all-visible, which holds for a sealed older partition and does not hold for the one currently receiving writes.
Worked solution 25 min
- Count the partitions named in the EXPLAIN output; if it is all of them, pruning failed and the predicate is the reason.
- Rewrite the date filter as a half-open timestamptz range and re-run EXPLAIN to confirm pruning to only the overlapping partitions.
- Create (line_item_id, received_ts) WHERE event_type = 'billing_notice' on one partition and compare the plan and the buffers read with EXPLAIN (ANALYZE, BUFFERS).
- Inspect the EXPLAIN filter text for a cast applied to the column side of the comparison rather than the parameter side.
Follow-up
- The partial predicate is a literal event type. What do you do when the same report also needs click counts, and is a second partial index better than one wider index?
- line_item_id = $1 matches 40% of the rows in a partition. Does the planner still choose the index, and what statistic decides?
- How do you create this index on a live partitioned table without blocking inserts?
Design the serving snapshot a bidder reads instead of line_item
line_item(line_item_id, status, bid_strategy, bid_value_micros, daily_budget_micros, pacing_mode, frequency_cap_per_day, flight_start_ts, flight_end_ts, targeting_hash, version) is authoritative; creative_approval(creative_id, exchange_id, status, expires_ts) carries per-exchange approval. A stateless bid service answers within tens of milliseconds and cannot query either table, so it loads a denormalised snapshot rebuilt every few minutes and held in memory. Specify the snapshot's record shape, which fields you copy and which you precompute, and the mechanism by which a bidder decides its snapshot is too stale to serve from, plus what it does at that point.
Approach
- Derive the shape from the read pattern before listing fields. One bid request carries several impression slots and each slot evaluates many candidates inside a tens-of-milliseconds budget, so every value the candidacy test reads has to be resident and flat. A per-candidate lookup into a second structure is the thing the snapshot exists to remove.
- Copy status, flight_start_ts, flight_end_ts, pacing_mode, frequency_cap_per_day, bid_strategy and bid_value_micros as scalars. Precompute what a join would otherwise cost: the compiled posting lists keyed on targeting predicate values, and, per creative, a bitmask over exchange_id of the exchanges where approval is currently present and unexpired.
- expires_ts makes approval time-dependent, so decide where that predicate is evaluated. Baking eligibility at build time makes the bid path a bitmask test and inherits up to one build period of error; carrying expires_ts into the record moves the comparison onto the bid path and costs one timestamp compare per candidate. Pick one and say which error you accepted.
- Handle freshness at the snapshot level rather than the row level. The per-line-item version column only advances when that line item changes, so a bidder whose build pipeline stopped sees identical versions indefinitely. Put generation_id and built_at in a snapshot header, and have the index service emit a heartbeat so absence of new builds is itself observable.
- Fail closed past the bound: drop candidates rather than bid from a snapshot older than the limit, and state the limit as build period plus fan-out time plus the interval at which a bidder checks. That sum, not the build period alone, is the number an advertiser hears when they ask how fast a pause takes effect.
Follow-up
- A build ships with a corrupt posting list and every bidder has already loaded it. What is the rollback path, and how long is the fleet wrong for?
- One advertiser holds 10^5 line items and the index build is now the bottleneck. What do you change: build frequency, partitioning of the index, or the staleness bound?
- The bidder is told its snapshot is stale. Is dropping candidates always right, or is there a case where serving from a slightly old snapshot is the safer failure?
Design an N-Way Set-Associative Cache featuring custom eviction strate…
Design an N-Way Set-Associative Cache featuring custom eviction strategies (e.g., LRU, MRU) and ensure thread safety in a multi-threaded environment.
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.
- Name the read and write paths separately; they rarely have the same bottleneck.
Follow-up
- How does this behave when that dependency is down for an hour?
- What breaks first when traffic grows ten times?
Explain how to handle cache invalidation, data consistency, and replic…
Explain how to handle cache invalidation, data consistency, and replication across multiple geographic regions in a high-traffic web application.
Approach
- Fix the scope first: who calls this, how often, and what they do when it fails.
- Choose a partition key and say what query it makes expensive.
- Name the read and write paths separately; they rarely have the same bottleneck.
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?
Implement an in-memory thread-safe rate limiter class with configurabl…
Implement an in-memory thread-safe rate limiter class with configurable time windows and request limits per client.
Approach
- Fix the scope first: who calls this, how often, and what they do when it fails.
- Choose a partition key and say what query it makes expensive.
- Name the failure you are designing for, then the recovery path.
Follow-up
- How does this behave when that dependency is down for an hour?
- What breaks first when traffic grows ten times?
Design the billing notice callback an exchange fires later
At bid time your bidder mints impression_id and returns notice URLs the exchange calls afterwards: a win notice, and a separate billing notice carrying the clearing price substituted into a macro, sometimes encrypted under a per-exchange key. The callback is a public endpoint reached by a caller whose retry behaviour you do not control, and its result becomes a budget_ledger charge row. Design the URL and handler contract: what the URL carries, how you authenticate it, what must be durable before you respond, and which status codes you return.
Approach
- Put identity in the URL and sign it: impression_id, line_item_id, exchange_id, an expiry, and an HMAC over that tuple keyed per exchange. These URLs travel through intermediaries and appear in markup on some integrations, so an unsigned endpoint lets anyone who can read one charge an advertiser's budget or flood the ledger. Verify with a constant-time comparison and reject anything past its expiry.
- Treat the price as untrusted input from a known counterparty. Decrypt and verify it with the per-exchange key, and treat a MAC or decryption failure as an authentication failure to reject and alert on, never as a parse failure to default to zero or to your bid price. The clearing price is not knowable at bid time and is not generally equal to the bid, so there is nothing safe to fall back to.
- Charge on the billing notice only, and keep win and billing as separate event_type rows on the same impression_id. A win is an auction outcome; a billing notice is the exchange asserting the impression was served. Charging on the win inflates spend in proportion to render failure, which varies by supply source and surfaces later as an unexplained reconciliation gap rather than as an obvious bug.
- Make the handler's synchronous work a keyed durable append and nothing more: insert delivery_event (impression_id, 'billing_notice') and the budget_ledger charge under the partial unique index on impression_id where entry_type = 'charge', commit, then respond. A duplicate must return 2xx — returning an error on a replay invites further retries and can get your endpoint marked unhealthy by the caller.
- Set the status codes from what you want the caller to do. 4xx for failed verification or expiry, because retrying will not help and you want it to stop; 5xx only when the write is genuinely not durable, because that is the one case where a retry is the correct outcome; 2xx for success and for duplicates alike. Defer enrichment, invalid-traffic review and currency conversion to downstream consumers of the log.
Worked solution 30 min
- Write the notice URL template the bidder emits, listing every parameter, the price macro placeholder, the expiry, and the exact HMAC input string in field order.
- Write the handler's step order and mark the commit point: verify signature and expiry, verify and decrypt the price, insert the delivery_event row, insert the ledger charge, commit, respond.
- Enumerate six cases — first valid notice, duplicate, bad signature, expired, undecryptable price, database unavailable — and give each a status code with a one-line justification in terms of what the caller should do next.
- Estimate the synchronous work per notice and list what you deliberately deferred to the downstream consumer, with the reason.
Follow-up
- The same billing notice arrives again a week later from a replay — does it charge, and which specific part of your design decides that?
- Your charge count and the exchange's reported count differ by 0.4% at daily close — where do you look first, and what row do you write to the ledger?
Exchange reports late bids while internal dashboards look healthy
Your bidder answers an exchange that enforces a 100 ms deadline measured from its own send to its own receive. Internal dashboards show mean handler time at 9 ms with no regression at any deploy, but the exchange now discards 6% of your responses as late and has warned about throttling your access to its supply. The bid path makes three sequential dependency calls, each given a 40 ms timeout, added by three different changes. Give the ordered list of what you inspect and in what order, and the change you make to the timeout scheme.
Approach
- Fix the measurement boundary before trusting any number. The exchange times from its socket write to its socket read, so its figure includes network round trip, your accept-queue wait, TLS handshake on cold connections and response flush. Instrument accept-to-flush and compare it against the handler-only timer; a divergence puts the regression in queueing rather than in code.
- Replace the mean with p99 and p99.9, cut per exchange and per region. At 10^5 requests per second a 6% late rate is thousands of requests a second, and a mean over that population cannot move enough to be visible. An average is the wrong statistic for a deadline because the deadline is a threshold, not a central tendency.
- Do the deadline arithmetic explicitly. Take 100 ms, subtract measured round trip and the exchange's own slack, and you have roughly 70 ms of internal budget. Three sequential calls with 40 ms timeouts admit 120 ms, so any two slow hops blow the budget while every per-dependency dashboard still reports healthy, because each hop stayed inside its own constant.
- Attribute the tail rather than the mean: per-hop span timings at p99, garbage collection and pause logs, connection pool checkout wait, and DNS or TLS cost on new connections. Look for the hop whose p99 moved, not whose average moved.
- Change the scheme to a deadline carried on the request and decremented at every hop, granting each call the remaining time minus a reserve rather than a constant. Write the degraded behaviour next to each dependency before writing code: which ones can be skipped into a lower-confidence bid and which force a no-bid. A late response is worse than a no-bid, because it consumes capacity, buys nothing, and counts against the supply relationship.
- Alert on your own internal budget overrun rate rather than waiting for the exchange to complain, since the exchange's signal arrives only after it has already decided to throttle you.
Follow-up
- The identity lookup has a p50 of 2 ms and a p99 of 36 ms. Do you keep it on the path, and what does the bid look like when you skip it?
- How do you tell a no-bid caused by a squeezed deadline apart from a no-bid caused by no eligible line item, in metrics you would actually keep?
- The exchange's deadline and your measured round trip both vary by region. Where does the per-region budget live, and who owns changing it?
Roughly ninety minutes on weeknights with one longer weekend block. The plan cuts scope rather than compressing everything, on the assumption that one thing finished per night beats four half-started.
Prepare, practise & reflect
One practical outcome each day. Spend longer where you need it.
0 / 7 done01Coding baseline for the automated assessment
- Attempt the reported progressive problem (reported-algorithms-1) cold: string manipulation, then matrix traversal, then a dynamic programming optimization, keeping each part in its own function.
- Implement a sliding-window maximum over a stream with a monotonic deque, then adapt it to the minimum.
- Solve one in-place 2D array problem in O(1) auxiliary space and write down the auxiliary space of your first attempt as well.
- For every problem, write edge-case inputs before running, and log what you missed.
Deliverable: Three working solutions with stated complexity, and a list of the edge cases you missed on the first try.
Practice prompt ↗Practice prompt ↗Worked solution ↗02Caches from a blank file
- Implement LRU and MRU caches in O(1) per operation with a hash map and a doubly linked list, from an empty file both times.
- Build the reported N-way set-associative cache (reported-systemdesign-2) single-threaded, with eviction behind an interface so LRU and MRU are separate classes.
- List the clarifying questions you would ask first: capacity, number of sets, key-to-set mapping, and behavior on a miss.
Deliverable: A single-threaded N-way set-associative cache with pluggable LRU and MRU eviction, plus your clarifying-question list.
Practice prompt ↗Practice prompt ↗03Thread safety and refactoring for the screening call
- Add per-set locking to yesterday's cache and write two sentences on why get needs exclusive access under LRU.
- Implement the reported per-client rate limiter (reported-systemdesign-4) with configurable windows, then make it thread-safe and state what each lock protects.
- Take a messy class you have written or found, list its smells and race conditions, pin its behavior with tests, and refactor it one step at a time.
- Explain one of the three designs aloud end to end as if on a phone call.
Deliverable: A thread-safe cache, a thread-safe rate limiter, and a refactoring log with behavior-pinning tests.
Practice prompt ↗Practice prompt ↗04Algorithms with production constraints
- Solve the interval drill (drill-coding-3): state the half-open convention, merge the pauses, clip them to the flight, and give the O(m log m) bound.
- Work through the top-k under a deadline drill (drill-coding-4) and compare your answer with its worked exercise, especially the tie-break and how k is derived.
- Do the partitioned-table indexing drill (drill-sql-1) and check your three reasons against its worked exercise.
Deliverable: Two coding solutions and one SQL analysis, each compared line by line with the worked exercise where one exists.
Practice prompt ↗Practice prompt ↗Worked solution ↗05Distributed system design for the panel
- Design the reported ad bidding engine under a sub-10ms SLA: in-memory state, a per-hop deadline, and no-bid as the fallback. Then work the late-bids debugging drill (drill-debugging-6).
- Specify the bidder's serving snapshot (drill-sql-2), including how a bidder detects that its snapshot is too stale.
- Answer the reported multi-region cache invalidation question (reported-systemdesign-3), naming the consistency you give up and where stale reads are acceptable.
- Design the billing notice callback (drill-design-5) and check it against its worked exercise for idempotency and status codes.
Deliverable: Four one-page designs, each with a latency or consistency budget, the failure it is built to handle, and its single points of failure named.
Practice prompt ↗Practice prompt ↗06Recruiter call and behavioral stories
- Write two-sentence summaries of your headline projects with no internal codenames, each with a measured result, for the recruiter discussion.
- Prepare stories for the reported behavioral prompts: a challenging project and its architecture choices (reported-behavioral-5), and a production flaw or bottleneck you fixed (reported-behavioral-6).
- Add stories for a speed-versus-quality trade-off, an architecture disagreement, and ambiguous requirements. Rehearse the code review disagreement drill (drill-behavioral-7).
- Write your questions for the recruiter about the screening format, allowed languages and how the Superday is split.
Deliverable: Project summaries, five behavioral stories each with a decision and an outcome, and a list of questions for the recruiter.
Practice prompt ↗Practice prompt ↗07Superday rehearsal
- Run back-to-back mocks covering algorithms, object-oriented design, system design and one behavioral story, with no break between them.
- Afterwards, write down where quality dropped: missed edge cases, a forgotten lock, a design without a latency budget, a vague story.
- Fix only those points. Then rebuild the cache and rate limiter once more from a blank file as a final check.
Deliverable: Notes from the mock sequence naming each point where quality dropped and the fix, plus one clean rebuild of the cache and the rate limiter.
Practice prompt ↗Worked solution ↗Expand any day for tasks and deliverables. Your progress is saved on this device.
The behavioral questions reported for this role focus on trade-offs, ownership of production problems, ambiguous requirements and technical disagreement. Build each story around one decision you made: what you chose, what you gave up, what you measured, and what happened next. For the architecture and performance prompts, expect follow-ups about the technical detail, so choose stories you can defend at code level.
Walk me through a challenging project on your resume, focusing on the …
Walk me through a challenging project on your resume, focusing on the specific architectural choices you made and the outcome.
Approach
- Name the disagreement and how you resolved it with evidence.
- Give the blast radius: what could have broken, and what you measured.
- Pick a story where you made the decision, not one where you watched it.
Follow-up
- How did you know your change caused the improvement?
- What would you do differently if you ran that again?
Tell me about a time you identified a critical flaw or performance bot…
Tell me about a time you identified a critical flaw or performance bottleneck in a production system and drove the fix.
Approach
- Close with what you would do differently, concretely.
- Give the blast radius: what could have broken, and what you measured.
- Name the disagreement and how you resolved it with evidence.
Follow-up
- What did you decide not to do, and why?
- How did you know your change caused the improvement?
Take a code review disagreement about duplicate impression charges
A colleague's change charges a won impression by selecting from budget_ledger on impression_id, inserting a charge row if nothing is found, and wrapping the pair in a transaction. They note the tests pass, that a 30-second in-memory dedup cache sits in front of the worker, and that you are the only objector. The billing notice arrives from the exchange over the public internet and is retried on any non-2xx. Reconstruct the review: the comment you wrote, how you showed the defect without a reproduction, and what you would have accepted instead.
Approach
- Name the interleaving instead of saying race condition. Worker A selects and finds nothing, worker B selects and finds nothing, both insert, both commit. Under READ COMMITTED and under REPEATABLE READ in PostgreSQL this pair of transactions both succeed, because a read that returns no rows takes no lock on rows that do not exist yet.
- Explain why the defect is invisible where they looked: the window is the gap between the SELECT and the INSERT, so it never appears in a single-threaded test and appears constantly under a backlog drain, which is exactly when the team scales workers up to catch up.
- Propose the mechanism that removes the race rather than narrowing it. The partial unique index on budget_ledger (impression_id) WHERE entry_type = 'charge' means the second write is rejected by the database. The application inserts first, catches the unique violation (SQLSTATE 23505), treats it as success, increments a duplicate counter, and returns 2xx so the exchange stops retrying.
- Address the cache argument on its own terms rather than dismissing it. A 30-second cache absorbs a retry seconds apart and does nothing for the same notice replayed a week later during a reprocess, and its hit rate is a function of worker restarts, so it is a cost optimisation and not a correctness mechanism.
- Concede the alternative that also works and say why you did not choose it: SERIALIZABLE isolation would abort one of the two transactions, at the cost of serialization failures and retries on the hottest table in the system.
- Finish on the review dynamics, not just the technical point: what you wrote, whether you blocked the merge, who decided, and how you would have behaved if the author had still disagreed.
Follow-up
- The same notice arrives twice a week apart during a reprocess. Walk both designs through that case.
- Where does impression_id come from, and what breaks if you derive the key by hashing the notice body instead?
- The insert succeeds but the process crashes before acknowledging the notice to the exchange. What happens next, and is that acceptable?
- 01
Describe a time when you made a complex technical trade-off between delivery speed and system performance or code quality.
- 02
Walk me through a challenging project on your resume, focusing on the specific architectural choices you made and the outcome.
- 03
How do you handle a situation where requirements for a project are ambiguous or continuously changing?
- 04
Describe a situation where you had a disagreement with a team member or technical lead on software architecture, and how you resolved it.
- 05
Tell me about a time you identified a critical flaw or performance bottleneck in a production system and drove the fix.
- 06
Explain how you prioritize work across multiple simultaneous projects with shared people, conflicting stakeholder pressure, and uneven urgency.
Is this an official The Trade Desk interview guide?
No. It is PracHub's own research and practice material for the Software Engineer role at The Trade Desk. Rounds and questions reflect what candidates have reported, not a process The Trade Desk has published, and they change over time. Confirm the current format and scope with your recruiter.
PracHub interview research ↗What rounds do candidates report for this role?
Four rounds over roughly 3 to 5 weeks. First an automated technical assessment, then a recruiter discussion about background, team fit and compensation expectations. Next is a technical screening call built around live coding or low-level design. Last is a panel called the Superday, with 4 to 5 back-to-back sessions covering algorithms, object-oriented design, distributed system architecture, and leadership or cultural fit. Treat this as reported, not guaranteed, and confirm it with your recruiter.
PracHub Software Engineer practice ↗How hard are the technical rounds?
This guide gives no difficulty rating. What candidates report is the content: thread safety, object-oriented design of caches and rate limiters, refactoring existing code, practical algorithms and high-throughput system design. The most useful preparation is to build the reported cache and rate limiter from a blank file until you can explain the locking and the O(1) operations without notes.
PracHub interview research ↗What kinds of questions are reported?
Four categories. Coding: subarrays, string and log reordering, in-place 2D arrays, sliding windows over a stream, and progressive multi-part problems. Object-oriented and low-level design: an N-way set-associative cache with LRU and MRU eviction, a thread-safe rate limiter, a legacy refactor, and an event logging system. Distributed design: an ad bidding engine under a sub-10ms SLA, a streaming reporting pipeline, multi-region cache invalidation, and a reliable queue. Behavioral: trade-offs, disagreements, ambiguity and production bottlenecks.
PracHub interview research ↗Which programming language should I use?
The role descriptions list C#, Java, C++ and Python. Ask your recruiter which languages each round allows. Because thread-safety questions are reported, choose a language in which you can write locks, atomic operations and thread-safe collections fluently, and practice the cache and rate limiter in that language specifically.
PracHub interview research ↗Are SQL questions part of this loop?
The reported Software Engineer questions do not include a SQL category. The SQL drills in this guide are original practice on indexing, partition pruning and denormalized serving snapshots. They are useful for the storage and reporting parts of a system design answer. If your recruiter confirms there is no database-focused session, spend that time on the cache and concurrency material instead.
PracHub Software Engineer practice ↗How should I split limited preparation time?
Start with coding fundamentals for the automated assessment. Then spend two days building the cache and rate limiter with thread safety, and practicing a legacy refactor, since those questions recur in candidate reports. After that, return to algorithms and SQL with production constraints, give distributed design with an explicit latency budget a full day, and keep one session for behavioral stories before a back-to-back rehearsal. The 7-day plan in this guide uses that sequence and points at the worked exercises for the SQL, top-k and billing callback drills.
PracHub interview research ↗Sources & methodology 3 sources ↗
Official role evidence, timestamped platform data and clearly labeled preparation advice.
- 01PracHub interview research ↗
PracHub editorial research into this company and role, maintained with this guide. Candidate-reported, not an employer publication.
platform · Accessed 2026-09-24 - 02PracHub Software Engineer practice ↗
Cross-company practice questions for this role.
platform · Accessed 2026-09-24 - 03PracHub interview preparation framework ↗
The framework the preparation plan follows.
platform · Accessed 2026-09-24