A Software Engineer at Drw builds the systems trading runs on: exchange connectivity, real-time risk calculation, market data processing and the execution of quantitative strategies across equities, fixed income, commodities and cryptoassets. Engineers may sit on an algorithmic trading desk, the Unified Platform team, or front- and middle-office analytics groups, and they work alongside quantitative researchers, traders and infrastructure engineers.
The language spread is wide: C++ and Rust for exchange gateways and execution systems, and C#, Java, Python and Clojure for distributed analytics platforms and trading tools. That spread shows up in the reported questions. Some are language-neutral algorithms, and others ask how a vtable dispatches a call, how the JVM allocates and collects objects, or how a mutex and a condition variable are built.
For preparation, expect the reported questions to go below the level of "it works". Reported topics include virtual memory and process address spaces, thread synchronization primitives, CPU cache locality, the TCP handshake and socket buffers, and designs such as an order execution engine or a trade logging service that must not lose data in a crash. Pick one primary language and learn its runtime and standard library well enough to explain what your code does in memory, not only what it returns.
Online Assessment
reportedCandidates describe a proctored online assessment on Codility or HackerRank, with video and microphone enabled, that tests algorithmic problem solving, array manipulation and dynamic programming. PracHub's bank has two Drw entries framed as sets of algorithmic OA tasks, and other reported Drw coding problems in the bank include digit-string problems with even-count constraints, an odd-string task, a digit swap and a slot-assignment problem. Practise as if you cannot look anything up: standard-library calls, loop bounds and DP recurrences should come from memory, and the camera and platform setup should not be new to you on the day.
What to demonstrate
- Algorithmic problem solving and array manipulation, the areas candidates name for this stage
- Dynamic programming: whether you can define the state, write the recurrence and turn it into an iterative table without a reference
- Correctness on edge inputs such as empty arrays, a single element, repeated values and values at the edge of the input range
How to prepare
- Solve a few array problems and one of the bank's digit-string problems in a browser editor with the camera on and no other windows open, so the proctored setup is familiar before the real one
- Write three DP problems from a blank file, including a stock buy-and-sell variant, stating the state, the transition and the base case before writing any code
- For every failed submission, write down the smallest input that fails and its expected output before you edit anything
Technical Phone Screen
reportedCandidates describe a technical phone or video call with an engineer or a hiring manager covering core CS fundamentals, memory layout, language details and a review of past technical work. The reported low-level and fundamentals categories fit that description: virtual memory and address spaces, vtables and their overhead, how mutexes, condition variables and atomics work, JVM allocation and garbage collection, process scheduling and context switches, and cache locality. Prepare each answer as a mechanism, a cost and an example that ties the two together.
What to demonstrate
- Whether you can explain the mechanism under a language feature (dynamic dispatch, heap allocation, a lock) instead of naming the feature
- Grasp of memory layout: stack versus heap, virtual-to-physical translation, and why contiguous data is faster to scan than linked data
- Whether your account of a past project names your own decisions and the trade-offs behind them
How to prepare
- For each reported low-level question, write a spoken answer with three parts: what the runtime or OS does, what it costs, and one situation where that cost matters
- Pick the one language you will be questioned in and review its standard containers: layout, growth policy, iterator invalidation, and the complexity of each operation
- Prepare a walkthrough of your most technical project that names two decisions you made, the options you rejected and what each one would have cost
Take-Home Coding Project
reportedCandidates report that, depending on the team, some get a take-home project, with examples such as a game engine variant, an execution bot or a data processor, while others go straight to the Superday. Candidates also describe the Superday as including a code review of the take-home, so expect to discuss the submission and be ready to change it for a new requirement. Make naming, module boundaries, boundary tests and extensibility easy to see in what you submit, and treat it as code you will have to modify in front of someone, not just code that passes.
What to demonstrate
- Idiomatic style in the language you were asked to use: naming conventions, small functions and a clear module layout
- Test coverage that reaches boundary conditions, not only the example in the prompt
- Whether the design can take a new requirement, such as streaming input instead of a batch, without a rewrite
How to prepare
- Before submitting, list the two changes a reviewer is most likely to ask for and check that each one touches a single module
- Write tests for empty, single-element, duplicate and malformed inputs, then break the code on purpose and confirm at least one test fails
- Include a short README covering your assumptions, what you left out and why, and how to run the tests
Superday / Onsite Interview
reportedCandidates describe the Superday as several back-to-back technical sessions: live whiteboard or paired coding, a code review of your take-home if you had one, system design, and behavioral conversations with team members and leadership. Reported design questions include an object-oriented order execution engine handling thousands of quotes per second, a risk and P&L schema and API for historical and what-if scenarios, a low-latency trade logging service that must lose nothing in a crash, and a lock-free queue for dispatching orders across threads. Reported behavioral questions ask about your most complex project, debugging a production issue under time pressure, ambiguous requirements from traders or researchers, and why principal trading interests you.
What to demonstrate
- Object-oriented design with clear class responsibilities, interfaces and error handling for a trading-style component
- Thread safety and durability: who owns shared state, and what has to be written and flushed before a trade counts as recorded
- Whether you can extend or defend your take-home code live when the requirements change
- How clearly you explain trade-offs in past work and handle ambiguous requirements
How to prepare
- Design the order execution engine from the reported question on paper: the classes, the threading model, and where a lock or a queue sits on the hot path
- For the trade logging question, explain step by step what happens to a record between the API call and durable storage, and which crash each step survives
- Practise two design problems and a coding problem back to back, so the multi-session format is not new on the day
- Prepare the four reported behavioral stories with a concrete decision and an outcome in each
11 candidate reports. Individual accounts describe a particular role and hiring cycle.
DRW New Grad Quantitative Researcher Interview Experience — Auto-Rejected Before the OA Deadline Even Hit
I cold-applied online to DRW's US New Grad Quantitative Researcher role. Less than a week after applying, I got an online assessment invite. The email said the OA link would expire in seven days, and there was no other deadline notice anywhere. Then, five days later, I got an email saying I hadn't finished the OA in time, and I was flat-out rejected. But the OA link was still valid, so I went ahe…
Read full experienceDRW New Grad Software Engineer Interview Experience — A Greedy String-Parity Coding Problem
I ran into a greedy string problem. Given a string digits made up only of the characters '1' and '2', representing a positive integer, you can delete zero or more characters. After deleting, the requirements are: The remaining '1's must appear an even number of times. The remaining '2's must also appear an even number of times. Subject to those two conditions, the resulting integer should be as l…
Read full experienceDRW New Grad Software Engineer Interview Experience — A Greedy Deletion Problem on a String of 1s and 2s
I got a string greedy problem: Given a string digits made up only of '1' and '2', which represents a positive integer. You can delete 0 or more characters from it, and after the deletion: the number of remaining '1's must be even; the number of remaining '2's must also be even; and, while satisfying those first two conditions, the final integer should be as large as possible. Note that you can on…
Read full experienceDrw Customer Success Engineer interview: Three back-to-back interviews followed by a location rejection
I started with an internal recruiter reaching out about a very senior trade support type of role. My first call was with HR, and it felt like it went well. I then spoke with the hiring manager about my background, the team, and what the role involved. The conversation felt a little unfocused on their side, but it was still decent overall. The role I initially interviewed for didn't work out becau…
Read full experienceDrw Software Engineer interview with a one-hour coding assessment
The process began with an online coding assessment that took me about an hour, even though it was described as a roughly two-hour test. I felt confident after finishing it, but I didn’t hear anything afterward and received a rejection notification a couple of days later. I also interviewed with DRW for a technical role in Singapore, and that process took much longer than I expected. I completed e…
Read full experiencePracHub editorial advice for the preparation topics above.
Losing online-assessment time to the proctored platform instead of the problems
Candidates report Codility or HackerRank with video and microphone on. Beforehand, solve problems in a browser editor with the camera running and no other windows open, and make sure you can write sorting with a custom comparator, string splitting and your DP table setup without looking anything up. When a test fails, find the smallest failing input before you change code.
Answering a low-level question with the feature name instead of the mechanism
"Virtual functions give polymorphism" does not answer the reported vtable question. Explain where the vptr is stored, what the indirect call costs, and why it blocks inlining. Apply the same standard to virtual memory (page tables, address translation), JVM allocation (the allocation fast path, what a GC pause does to tail latency) and locks (what happens when a mutex is contended). Prepare each answer as mechanism, cost and example.
Submitting a take-home that passes but is not idiomatic, tested or extensible
Aim for idiomatic code, not only correct code. Follow the style conventions of the language you were given, separate parsing, core logic and output, test the boundaries, and keep the code modular enough that a live change for streaming input touches one place. Candidates describe a code review of the take-home during the Superday, so every shortcut is something you may have to explain.
Designing the order engine or trade logger without saying who owns shared state or when data is durable
For the reported execution engine and lock-free queue questions, state which thread owns each structure and how work moves between threads, whether through a single-writer queue, a lock or atomics. For the zero-data-loss logging question, say exactly when a record counts as written: appended, flushed to disk, and acknowledged. A design that skips these points does not answer the question as asked.
Describing your most complex project as team output with no decisions of your own
A reported behavioral question asks specifically about your own architectural choices and trade-offs. Choose two decisions you made, the alternatives you rejected, what each would have cost, and what you would change now. For the production-debugging question, give the symptom, the first thing you checked and why, and how you confirmed the fix.
Choose a category, try a prompt, then open its approach, worked solution or follow-up when you need it.
Implement a custom binary search tree traversal or serialization metho…
Implement a custom binary search tree traversal or serialization method from scratch without relying on external libraries.
Approach
- Name the brute-force solution and its complexity before improving on it.
- State the target complexity and say which constraint rules the naive version out.
- Walk one small example through your approach before writing the whole thing.
Follow-up
- How does this change if the input no longer fits in memory?
- Which test case would catch an off-by-one here?
1–2 sentences introducing the category and what it tests. This categor…
1–2 sentences introducing the category and what it tests. This category evaluates your ability to translate complex logic into clean, efficient code under time constraints, with a focus on data structures, time complexity, and edge case handling.
Approach
- Choose the data structure from the access pattern, not from familiarity.
- Walk one small example through your approach before writing the whole thing.
- Restate the input: its shape, its size, and what is guaranteed about it.
Follow-up
- Which test case would catch an off-by-one here?
- What is the worst case, and how likely is it on real data?
How does the Java Virtual Machine (JVM) manage object allocation in he…
How does the Java Virtual Machine (JVM) manage object allocation in heap memory, and how does garbage collection impact application latency?
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.
- 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?
Explain the difference between virtual memory, physical memory layout,…
Explain the difference between virtual memory, physical memory layout, and process address spaces in C++.
Approach
- Reach for the cheapest primitive that closes the race, not the broadest lock.
- Name what is shared across threads and what owns each piece of state.
- Identify the window where an invariant is briefly untrue.
Follow-up
- How would you prove the race exists rather than suspect it?
- What happens if two callers reach this at the same time?
Find overlapping job attempts and peak concurrency from lease records
A day of job_run history yields about 50,000,000 attempt records: (job_run_id, job_type, attempt, started_at, finished_at which is NULL when the worker died, lease_expires_at). Leases expire on a clock, so a job that outran its lease ran twice. Produce (a) every job_run_id whose attempts overlapped in wall-clock time and (b) the peak number of simultaneously running attempts per job_type with the minute it occurred. Target O(n log n). State how you treat a NULL finished_at and what clock skew does to your answer.
Approach
- Define the interval before sorting anything: an attempt occupies [started_at, COALESCE(finished_at, lease_expires_at)). finished_at is observed and lease_expires_at is only a promise, so every attempt without a finish contributes an estimate and the whole result is a lower bound on overlap rather than an exact count.
- For peak concurrency, sweep: emit 2n endpoints, sort by (timestamp, kind) with ends ordered before starts at equal timestamps, then walk the sequence maintaining a counter per job_type and record each type's maximum with its timestamp. O(n log n) dominated by the sort, O(n) space, or O(1) extra if the sort is external and the walk streams.
- For overlap detection, do not compare attempts pairwise. A single global sort by (job_run_id, started_at) gives both the grouping and the order; within a group, keep the maximum end seen so far and report an overlap exactly when the next start is less than that running maximum, which is one linear pass after the sort.
- Half-open intervals matter and are easy to get wrong: with closed intervals an attempt ending at the same millisecond another begins reads as concurrency two, and across 50,000,000 records that artefact swamps the real signal.
- State the clock caveat: started_at and finished_at are written by different workers, so under skew of a few hundred milliseconds an apparent overlap shorter than that bound is not evidence. Filter reported overlaps by a minimum duration, or prefer timestamps written by whichever component heartbeats the lease.
- Scale the sort rather than assuming it fits: the sweep emits two endpoints per attempt, so 50,000,000 records become 100,000,000 endpoints, and at roughly 24 bytes each, an 8-byte timestamp plus a 4-byte job_type plus a kind flag padded to alignment, that is about 2.4 GB of sort keys before any scratch space. Either push the ordering into the database behind an index on (job_type, started_at) or run an external merge sort in chunks; the overlap pass sorts n records rather than 2n, so it is the cheaper of the two.
Worked solution 30 min
- Write the interval derivation with the COALESCE and state in one line which of the two end sources is observed and which is assumed.
- Write the concurrency sweep: the endpoint tuples, the sort key including the end-before-start tie-break, and the per-job_type counter.
- Hand-trace four attempts of one job, two disjoint and two overlapping by three seconds, and confirm the overlap detector fires exactly once.
- Add the skew filter as a minimum overlap duration, state the value you chose, and justify it from how the timestamps are written.
Follow-up
- A handler is not idempotent and you have found 400 overlapping jobs. Which of them actually caused damage, and what would you query to find out?
- Peak concurrency for one job_type is 4 against a configured cap of 4. Is the cap working, or is the data hiding attempts that never started?
- How would you compute both answers incrementally as records arrive rather than in a daily batch?
Denormalise tenant onto revisions and backfill it live
resource_revision (revision_id, resource_id, version, actor_user_id, change_kind, patch, request_id, created_at) has 400M rows and no tenant column; tenant_id lives only on resource. Two reads need it: a tenant-scoped audit feed ordered by created_at DESC, and an offboarding purge. Both join back to resource today. Justify adding tenant_id to resource_revision against those two reads, name the anomaly the copy introduces and the constraint that prevents it, then give the ordered migration for a live table taking 1.2k writes/second — the lock each step takes, how the backfill is batched, and where each step stops being reversible. PostgreSQL 16.
Approach
- Justify from the access path rather than from taste. Without the column, the audit feed either scans resource_revision by created_at and discards other tenants' rows, or resolves the tenant's resource_ids first and probes with them — both proportional to the tenant's whole history rather than to one page. With (tenant_id, created_at DESC, revision_id DESC) it is a seek that stops at 50 rows, and the purge becomes a ranged delete instead of a join.
- Name the cost exactly: a second copy of a fact can disagree with the first. Make the disagreement unwritable rather than documented — add UNIQUE (resource_id, tenant_id) on resource so it can serve as a foreign-key target, then FOREIGN KEY (resource_id, tenant_id) REFERENCES resource (resource_id, tenant_id) on the revision table. A revision can then only ever carry its parent's tenant.
- Step one, expand: ALTER TABLE resource_revision ADD COLUMN tenant_id BIGINT NULL, with no default, so it is a catalogue change and no rewrite. It still needs ACCESS EXCLUSIVE for an instant, and that instant queues behind the longest open transaction on the table while every later query queues behind it — set lock_timeout to 2s and retry rather than wait.
- Step two, dual-write: deploy the writer that populates tenant_id on every new revision while reads still use the join. Reversible by redeploying the previous build, because nothing reads the column yet.
- Step three, backfill: batch by primary key rather than by created_at so the cursor is dense and resumable — UPDATE resource_revision rr SET tenant_id = r.tenant_id FROM resource r WHERE r.resource_id = rr.resource_id AND rr.revision_id > $1 AND rr.revision_id <= $1 + 5000 AND rr.tenant_id IS NULL — committing per batch and persisting the cursor. Throttle on replica replay lag and on dead-tuple count, since each batch writes 5,000 new row versions. Run the backfill before the index exists so those updates can stay HOT.
- Step four, index then enforce then contract: CREATE INDEX CONCURRENTLY (cannot run inside a transaction block, scans the table twice, waits on open transactions, and leaves an INVALID index to drop concurrently if it fails); ADD CONSTRAINT ... CHECK (tenant_id IS NOT NULL) NOT VALID, then VALIDATE CONSTRAINT, which takes only SHARE UPDATE EXCLUSIVE, after which SET NOT NULL uses the validated check instead of re-scanning on PostgreSQL 12 and later. Only then move the audit reads onto the column and, in a later deploy, delete the join path.
Follow-up
- The backfill is half finished and a rollback is required. What state is the table in, and what does the previous build do with a half-populated column?
- How do you verify the backfill actually finished, given rows are still being inserted while it runs?
- A resource must now be movable between tenants. What does that do to the composite foreign key and to the revisions already written?
Explain why the owner filter ignores the listing index
The only index on resource is (tenant_id, status, updated_at DESC, resource_id DESC). A new endpoint returns one user's resources across all statuses, newest created first: WHERE tenant_id = $1 AND owner_user_id = $2 ORDER BY created_at DESC LIMIT 20. On a tenant with 2M rows it takes 900 ms and EXPLAIN shows a sort above a large scan. Explain precisely why the existing index cannot serve it, give the index that can, and state which of these the new index still will not help: owner_user_id alone across tenants; the same query ordered by updated_at. PostgreSQL 16.
Approach
- Separate the two jobs an index does. For filtering, a composite btree is seekable only on a left prefix, so with no predicate on status the scan can at best range over tenant_id and test owner_user_id per row; PostgreSQL 16 has no btree skip scan to jump the unconstrained column.
- For ordering, the index is sorted by (status, updated_at) within a tenant and not by created_at, so the LIMIT cannot stop early: every matching row is read and then sorted. That is the 'Sort Method: top-N heapsort' line, and it is why the plan reads 2M rows to answer with 20.
- Derive the replacement from the access path — equality, equality, then the ordering column: CREATE INDEX CONCURRENTLY ON resource (tenant_id, owner_user_id, created_at DESC). The scan seeks to the (tenant, owner) range and walks 20 entries in order, so the Sort node disappears along with the row-read.
- Treat INCLUDE (title, status) as conditional, not free. An index-only scan still visits the heap for any row whose page is not marked all-visible, so on a table taking 1.2k writes/second the win depends on autovacuum keeping the visibility map current, and the wider index costs more on every insert.
- Answer the two negatives explicitly. owner_user_id alone is not a left prefix of the new index, so it degrades to a full scan of the index at best. Ordered by updated_at, the query still seeks on the (tenant, owner) pair but must sort, because only created_at is ordered within that pair.
- Measure both sides with EXPLAIN (ANALYZE, BUFFERS) and compare estimated against actual rows at the lowest node — a 2M-versus-200 misestimate there is usually what chose the plan, and adding an index will not fix a statistics problem.
Worked solution 25 min
- Load 2M resource rows across 5k owners in one tenant, run the query under EXPLAIN (ANALYZE, BUFFERS), and record the node reading the most rows plus the Sort Method line.
- Create (tenant_id, owner_user_id, created_at DESC) concurrently and re-run, confirming the Sort node is gone and actual rows fall to about 20.
- Run the two negative cases and capture the plan for each.
- Re-run the original tenant listing query to confirm the new index has not displaced the index that query depends on.
Follow-up
- 90% of rows are status='active'. Would a partial index WHERE status = 'active' change your answer, and for which of the three queries?
- A dashboard runs this for 40 owners in one page load. What changes about the design?
- How do you roll this index out on a table taking 1.2k writes/second, and what does it cost on every insert from then on?
How do you design a thread-safe, lock-free queue data structure for mu…
How do you design a thread-safe, lock-free queue data structure for multi-threaded trade order dispatching?
Approach
- Name the failure you are designing for, then the recovery path.
- Choose a partition key and say what query it makes expensive.
- State the consistency you need, and where you are willing to be stale.
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?
Design an object-oriented system for a real-time order execution engin…
Design an object-oriented system for a real-time order execution engine handling thousands of incoming quotes per second.
Approach
- Fix the scope first: who calls this, how often, and what they do when it fails.
- 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 the architecture of a low-latency trade logging and audit…
Walk through the architecture of a low-latency trade logging and auditing service that guarantees zero data loss during system crashes.
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?
Walk through the TCP/IP 3-way handshake and explain how socket buffers…
Walk through the TCP/IP 3-way handshake and explain how socket buffers and TCP window sizes affect network transmission delays.
Approach
- State your assumptions explicitly before working the problem.
- Say what you would check first and why it is the highest-information step.
- Work from the requirement backwards to the design.
Follow-up
- How would you know your answer was wrong?
- What assumption would you test first?
Relay committed events to the log without gaps or reordering
outbox_event rows are written in the same transaction as the state change and carry aggregate_type, aggregate_id, aggregate_version, payload and status, with a partial index on (created_at, event_id) WHERE status = 'pending'. The relay publishes about 4k events/second to a partitioned append-only log keyed by aggregate_id, with one leader per partition range holding a lease. Consumers must never miss an event; they may see one twice. Design the claim-publish-mark loop, and state exactly what consumers observe when a leader's lease expires while it is mid-batch.
Approach
- Claim with SELECT ... WHERE status='pending' ORDER BY created_at, event_id LIMIT $batch FOR UPDATE SKIP LOCKED inside a transaction. SKIP LOCKED lets several relay workers share a range without serialising on each other's rows, and the partial index keeps the claim proportional to the backlog rather than to a table that is overwhelmingly published rows. At 4k/second a batch of 500 is eight claims per second, each an index scan of 500 entries.
- Publish before marking, never the reverse, and say why it is a choice. Marking first loses the event outright if the process dies in the gap, and the loss is silent - nothing remains to retry, and it surfaces later as a projection missing a row. Publishing first can repeat the event, and repetition is what every consumer is already built to survive. That single ordering is the whole at-least-once guarantee.
- Preserve the only ordering on offer. Partition by aggregate_id and never publish two events for one aggregate concurrently: claim in (created_at, event_id) order and publish sequentially within an aggregate, or hash aggregate_id to a worker slot. Order across aggregates is not available at any price here, which is why the event carries aggregate_version and the full fact rather than a delta - a consumer can then discard what it has already applied without coordinating with anyone.
- State the failover behaviour precisely, because it is the consistency-versus-availability decision in this design. A lease expires because the holder is slow, and no mechanism distinguishes that from dead, so for the length of the lease window two leaders can publish the same claimed batch. The system accepts duplicates to avoid stalling publication for every aggregate in the range whenever one worker pauses. Consumers deduplicate on (aggregate_id, aggregate_version) and drop anything at or below what they have applied.
- Bound the failure paths and pick the right alarm. A row that fails to publish increments attempts, records last_error, and moves to 'dead' after a limit so one poison payload cannot block the backlog behind it. Alert on the age of the oldest pending row, not on the relay's error rate: the failure worth catching is a relay reporting itself healthy while nothing is being published.
Worked solution 25 min
- Write the claim statement and check it against the partial index: which columns it seeks on, how many entries it touches, and what two concurrent workers do to each other.
- Write both orderings of publish and mark, and for each state what exists after a crash at every point in the loop.
- Write the consumer's dedupe rule on (aggregate_id, aggregate_version) and test it against a replayed batch of 500.
- Compute the backlog after a 40-minute outage and the batch rate needed to drain it while 4k/second continues to arrive.
Follow-up
- The relay is down 40 minutes and 9.6 million rows are pending. What does catch-up do to the primary, and what changes in the claim loop to survive it?
- A consumer insists it never received an event. Which single query settles whether the relay lost it, and what does each answer look like?
- Delivery is at-least-once. What would exactly-once require end to end, and why is that a property of the consumer rather than of the relay?
One customer endpoint stalls deliveries to every other destination
The egress service delivers about 1.5k webhooks/second across 40,000 destinations, with a per-destination concurrency cap of 4 and a 10-second connect-plus-read timeout. Throughput falls to 300/second, queue depth climbs, and p99 delivery latency for unaffected destinations goes from 200 ms to minutes, while the error rate barely moves. One tenant holds 900 destination rows whose URLs share a hostname that now answers in 9.5 seconds. Explain the mechanism with the arithmetic, then give the containment in the order you would apply it.
Approach
- Look at saturation before errors. A flat error rate with collapsing throughput says nothing is failing, things are waiting, so the first signal to pull is in-flight request count or pool wait time rather than the error counter. This is the distinction that decides the whole investigation.
- Group in-flight work by resolved host, not by destination id. The cap is keyed per destination row, so 900 rows sharing one hostname buy 3,600 concurrent slots against a single host, each held for 9.5 seconds. The bulkhead was never a bulkhead for that host, and grouping by the wrong dimension is why the dashboard looked healthy.
- Do the arithmetic in both directions. Required concurrency is arrival rate times latency, so 1.5k/second at 200 ms needs about 300 in flight, which is entirely consumed by 3,600 slow slots; conversely whatever concurrency is left sustains rate equals concurrency divided by 9.5 seconds, which is the 300/second you are seeing. Matching both numbers is what promotes this from a plausible story to the mechanism.
- Explain why the circuit breaker never helped. It opens on consecutive failures, and a 9.5-second response inside a 10-second timeout is a success. Slow is not failing, so an error-rate breaker cannot see this; you need a slow-call ratio, a deadline propagated from the caller's remaining budget, or a concurrency limiter.
- Contain in order: park the offending host so the shared pool drains, add a per-resolved-host concurrency cap alongside the per-destination one, give slow hosts their own queue so they cannot occupy the general pool, derive the timeout from the delivery deadline rather than a round number, and check the retry policy is not tripling load on a host that is already slow. Use backoff with full jitter so retries do not resynchronise on recovery.
- State the invariant you are restoring: one tenant's endpoints degrade only that tenant's deliveries. That is a property to load-test for, not to assume from a config value.
Follow-up
- The host recovers to 80 ms. How long does the queue take to drain, and what does the drain do to the recovered host?
- Where should the 10-second timeout number actually come from?
- If that tenant had one destination row instead of 900, would the cap of 4 have saved you? What would you measure to be sure?
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.
Prepare, practise & reflect
One practical outcome each day. Spend longer where you need it.
0 / 7 done01Online assessment: arrays and dynamic programming
- Solve three array problems of the reported kind, such as finding non-overlapping sub-regions that meet a constraint, and a digit-string problem with even-count constraints like the Drw coding entries in PracHub's bank
- Write a stock buy-and-sell DP from a blank file, stating the state, transition and base case before coding
- Record every standard-library call you had to look up and drill each one until you can write it from memory
Deliverable: Four solved problems, a written DP state definition, and a list of library calls you can now write without a reference.
Practice prompt ↗Practice prompt ↗Practice prompt ↗Worked solution ↗02Online assessment: trees, grids and a proctored mock
- Implement BST serialization and deserialization from scratch, plus an iterative DFS over a grid that computes connected-component bounds
- Run a timed mock in a browser editor with the camera on and no other windows open, covering one array, one DP and one graph problem
- For each failure, write the smallest failing input, the expected output and the actual output before fixing it
Deliverable: Working serialization and grid DFS code, and mock notes listing each failing input you isolated.
Practice prompt ↗Practice prompt ↗Practice prompt ↗03Phone screen: memory, runtimes and the language you will be tested in
- Write spoken answers to the reported questions on virtual memory and address spaces, vtables and their overhead, and JVM allocation and garbage collection, each covering mechanism, cost and example
- Review your chosen language's main containers (for C++, vector and unordered_map; for Java, ArrayList and HashMap): layout, growth, and the complexity of each operation
- Compare arrays, linked lists and hash maps on memory layout and cache behavior, one paragraph each
Deliverable: A one-page answer sheet for the low-level category that you can say aloud without reading.
Practice prompt ↗Practice prompt ↗04Phone screen: concurrency, OS and networking
- Explain how a mutex, a condition variable and an atomic compare-and-swap work, and what a contended lock costs
- Answer the reported fundamentals questions: process scheduling and context-switch overhead, cache locality, the TCP three-way handshake, and how socket buffers and window sizes affect delay
- Rehearse a walkthrough of your most technical project that names two decisions you made and the trade-offs behind them
Deliverable: Written answers for the concurrency and networking questions, plus a rehearsed project walkthrough.
Practice prompt ↗Practice prompt ↗Worked solution ↗05Take-home: build it to be changed
- Build a small data processor or execution-bot core in your primary language, keeping parsing, logic and output in separate modules
- Test empty, single, duplicate and malformed inputs, then break the logic on purpose and confirm at least one test fails
- Change the design live to accept streaming input instead of a batch, and note which files you had to touch
Deliverable: A small tested project with a README of assumptions, and a note on what the streaming change required.
Practice prompt ↗Practice prompt ↗06Superday: system design
- Design the reported object-oriented order execution engine: classes, interfaces, threading model and error handling
- Explain the reported zero-data-loss trade logging service, stating exactly when a record counts as durable and which crash each step survives
- Sketch a thread-safe, lock-free queue for order dispatch and name the memory-ordering guarantees it relies on
- Work the guide's outbox relay design exercise for at-least-once delivery and deduplication
Deliverable: Three design sketches, each with a stated ownership model and durability point.
Practice prompt ↗Practice prompt ↗07Superday rehearsal: back-to-back sessions and behavioral
- Run a coding problem, a design problem and a behavioral block back to back with no break
- Prepare stories for the reported behavioral prompts: most complex project, a production issue debugged under time pressure, ambiguous requirements from traders or researchers, and why principal trading
- Read the debugging drill on a slow endpoint stalling a shared pool and explain the saturation mechanism aloud
Deliverable: Notes from the back-to-back mock and four behavioral stories, each with a decision and an outcome.
Practice prompt ↗Practice prompt ↗Worked solution ↗Expand any day for tasks and deliverables. Your progress is saved on this device.
The reported behavioral questions for this role ask about your own architectural choices, how you debugged a production problem under time pressure, how you handle vague requirements from traders or quantitative researchers, and why principal trading fits your goals. In each story, name a decision you made, the alternative you rejected, and what happened.
How do you handle ambiguous project requirements when building tools f…
How do you handle ambiguous project requirements when building tools for traders or quantitative researchers?
Approach
- State the situation in two sentences and spend the rest on the reasoning.
- 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?
Unblock an engineer without taking the keyboard
A teammate has spent two days on a job handler that occasionally writes duplicate rows. They are certain the queue is delivering twice by mistake. You suspect a lease expiring under a slow handler, so the job is running concurrently with itself. Describe how you have unblocked someone in this position: what you asked before offering a hypothesis, what you showed them rather than told them, and what you left them owning. Then say what you would do if their theory turned out to be the right one.
Approach
- Ask before diagnosing, and ask for things answerable from data they already have: the attempt count on the job rows that produced duplicates, the handler's observed duration against its lease expiry, and whether the duplicate rows share a natural key that a unique constraint could have caught.
- Teach the shape rather than the answer. A lease cannot distinguish a dead worker from a slow one, so a handler that outruns its lease is running twice by design, and deploys deliver the other half by killing handlers mid-run on every rollout. Both of their candidate theories produce identical duplicate rows, which is why the evidence has to come from timings rather than from argument.
- Hand over a checklist they execute: a natural key on every write the handler performs so the second copy collides rather than appends, the record of intent written before any external effect, a lease heartbeat while running, and the metric that shows it working.
- Keep ownership with them deliberately. Pair on the first write, then step back; if you finish it yourself you have closed one ticket and left the same person stuck on the next redelivery.
- Close on the systemic gap that let two days pass, which is usually a missing dashboard for attempt counts or an undocumented at-least-once contract, and fix that rather than only the bug.
Follow-up
- How would you distinguish a genuine double-delivery from a lease expiry using only the data already stored?
- Their handler calls an external endpoint before recording that it did. What do you tell them to change first?
- What do you do the third time the same person brings you the same class of bug?
Ship under a deadline and bound the debt you chose
You have four days to ship a tenant-facing listing endpoint. The version you would defend uses keyset pagination over (tenant_id, status, updated_at DESC, resource_id DESC); the version you can finish uses LIMIT/OFFSET with no matching index. Describe a deadline call you actually made of this shape: what you shipped, what you knowingly deferred, how you bounded the damage with a mechanism rather than an intention, and the specific numeric condition that would force the follow-up. Name who you told and where you wrote it down.
Approach
- Name the deferred failure precisely instead of calling it slow. OFFSET n makes the database produce and discard n rows, so cost grows with page depth; without an index matching the sort, every matching row is read and sorted before the limit applies; and rows inserted between two page fetches shift across the boundary so items are skipped or repeated with nothing in the response to signal it.
- Bound the blast radius with something mechanical rather than a promise: cap maximum page depth, cap page size, restrict the endpoint to one internal caller, or keep it behind a flag. State which failure each cap removes and which it leaves standing.
- Attach a number to the trigger and wire it to an alarm: the first tenant crossing N resources, or the endpoint's p99 crossing its share of the 400 ms budget, so the debt announces itself instead of waiting to be remembered.
- Write it where the next engineer looks, which is the code and the ticket, not a chat message: what was deferred, why, the cap, and the trigger.
- Report what actually happened in your real example, including the case where the trigger never fired and the debt was correctly never repaid.
Follow-up
- At what page depth does the offset version breach your latency budget, given your page size and row counts?
- What breaks first when you switch to keyset pagination later, and what does a client holding an old page token see?
- Who would have overruled you if you had asked for two more days, and did you ask?
- 01
Walk through the most technically complex project on your resume, focusing on your own architectural choices and trade-offs.
- 02
Describe a time you debugged a critical production issue under tight time constraints. What did you check first, and why?
- 03
How do you handle ambiguous project requirements when building tools for traders or quantitative researchers?
- 04
Why do you want to work at Drw, and how does principal trading fit your technical career goals?
- 05
Explain an architecture decision you made, the options you rejected, and what you would change now.
- 06
How would you handle a production incident in a live trading system: what you prioritize, who you tell, and when?
Is this an official Drw interview guide?
No. It is PracHub's own research and practice material for the Software Engineer role at Drw. Rounds and questions reflect what candidates have reported, not a process Drw has published, and they change over time. Confirm the current format and scope with your recruiter.
PracHub interview research ↗How much of the Drw interview is algorithms versus low-level knowledge?
Both appear in the reported questions. The coding category includes array sub-region problems, BST traversal or serialization, a stock buy-and-sell DP and grid DFS. Separate categories cover memory layout, vtables, synchronization primitives, JVM garbage collection, OS scheduling and networking. Prepare both instead of assuming the algorithm rounds are the whole bar.
PracHub interview research ↗Can I use any programming language?
Candidate reports suggest you can usually choose your language for online assessments and general algorithm rounds, while team-specific sessions and low-level infrastructure roles may use the team's main language, such as C++ for low-latency execution work. Ask your recruiter which language the team uses and learn its runtime and standard library in depth.
PracHub interview research ↗How should I approach the take-home coding project?
Treat it as production code: clean, idiomatic, sensibly structured, attentive to performance, and tested at the boundaries. Candidates describe the Superday as including a code review of the take-home, so be ready to defend your choices and change the code live for a new requirement. Keep it modular and write down your assumptions.
PracHub interview research ↗Does every candidate get a take-home?
Not according to candidate reports. Depending on the team, candidates either get a take-home project, with reported examples including a game engine variant, an execution bot and a data processor, or go straight to the Superday. Ask your recruiter which path applies to you.
PracHub Software Engineer practice ↗Do I need prior trading or finance experience?
Most reported questions cover CS fundamentals, language internals and design. A few, such as the risk and P&L sensitivities schema for historical and what-if scenarios, assume basic trading concepts. Put most of your preparation into the fundamentals, and learn enough about P&L and risk sensitivities to reason about that kind of design question. One reported behavioral question also asks why principal trading fits your goals, so have a specific answer ready.
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