BAH Partners · Software Engineer
Updated · 2026-10-02

BAH Partners Software Engineer
Interview Guide

THE 60-SECOND BRIEF

BAH Partners is a recruitment firm. Candidates describe it as placing engineers with financial and technology-driven organizations across Asia Pacific, so the roles you interview for sit with its client firms. The work behind those roles, as candidates report it, covers search, algorithmic trading platforms and large data-processing pipelines, including web crawling at a scale of hundreds of millions of pages per day. GPU orchestration, vector databases and low-latency backend platforms are the named technology areas. A Software Engineer on these teams works with researchers and traders to turn algorithms into fast production code, and is reported to own a project from design through deployment and maintenance.

This guide is for Software Engineer candidates going through BAH Partners. It covers the five questions candidates report (C++ memory management for low-latency trading, TCP vs UDP, scaling bottlenecks, concurrency in Golang or Java, vector database indexing), the performance and distributed-design areas candidates describe, and how to talk about your own past systems. It does not cover Research Engineering or DevRel loops, which candidates say some clients add as extra rounds.

No fixed round list is reported. Candidates describe a path from early technical screens to deep dives with senior engineers and stakeholders, then architecture-style design discussions, with extra rounds for some specialised roles.

Technical Fundamentals and Domain ExpertiseSoftware Engineer fundamentalsWorking through problems out loud

28 min read

Browse Software Engineer questions

See the practice prompts

12Practice promptsAcross five skill areas

The reported questions all sit at the boundary between software and hardware: how memory is laid out, how bytes cross a network, what limits a cluster, how threads share state, and how a vector index trades recall against speed. Candidates also describe example scenarios such as a search retrieval pipeline with a latency spike and the cost of data serialization in a high-throughput system. Prepare answers that start from a measurement and end in a trade-off, not a list of buzzwords.

The listed languages are C++, Python, Rust and TypeScript, and candidates report being pushed on language internals: memory models, garbage collection and standard-library behaviour. Pick the language you are strongest in and be able to say what it does with an allocation, a thread and a lock. The concurrency question names Golang or Java, so know at least one of them well enough to write a race and fix it.

Candidates report that a large share of the conversation is about your past projects and the architecture choices in them, plus how you would change those systems at a client's scale. Bring two or three systems you can explain down to the bottleneck, with before and after numbers. The same reports mention explaining technical risk to non-technical stakeholders, so rehearse a plain-language version of each trade-off you rely on.

Because BAH Partners is a placement firm, your resume travels to its client firms. Candidates are advised to agree in advance which firms receive it and to vet the consultant, so settle that before your first technical screen.

01

Preparation focus

editorial

Candidates describe a progression from initial technical screens, through deep dives with senior engineers and stakeholders, to architecture-style design discussions, and say some clients add rounds for specialised roles. No stage names, counts or durations are reported, so confirm them with your recruitment consultant, including whether you will write code and which language track (backend, infrastructure or research) applies. Prepare for the whole range: write correct code quickly in your primary language, explain how it behaves on the hardware, then design and defend a distributed system. The five reported questions (C++ memory for trading, TCP vs UDP, scaling bottlenecks, concurrency in Golang or Java, vector index strategies) are the core of that range.

What to demonstrate

  • Fluency in your primary language (Python, C++, Rust or TypeScript) including internals such as memory models and garbage collection
  • Breaking a large, ambiguous problem into modular components using load balancing, partitioning and fault tolerance
  • A systematic path from a performance symptom to an isolated bottleneck and a measured fix
  • Explaining past projects and the architectural choices inside them

How to prepare

  • Ask your consultant which client firm, language track and stages apply, and whether any stage is live coding
  • Write one-page answers to the C++ memory, TCP vs UDP and vector indexing questions, each ending in a stated trade-off
  • Reproduce a data race in Go or Java, then fix it three ways (lock, atomic, ownership by one thread or channel)
  • Prepare two past systems with a bottleneck, the measurement that exposed it and the number that changed
PracHub preparation framework ↗

PracHub editorial advice for the preparation topics above.

01

Answering the C++ memory question with 'use smart pointers' and stopping

Smart pointers address ownership, not latency. Talk about keeping allocation off the hot path: preallocated pools or arenas, contiguous layouts for cache locality, alignment and false sharing, and measuring with a profiler or allocation counters before and after.

02

Reducing TCP vs UDP to 'UDP is faster' without naming what you give up

Name what UDP drops (ordering, retransmission, congestion control) and what you must rebuild or tolerate, such as gap detection or sequence numbers. Name what TCP costs (head-of-line blocking, retransmit delay, Nagle and delayed ACK interplay) and tie the choice to the data: a stale market tick is worthless, an order is not.

03

Listing sharding, caching and load balancers for the scaling question without a bottleneck order

Walk the path: single hot partitions, coordination and metadata services, fan-out tail latency, network bandwidth, and slow or failed nodes. For each, say how you would detect it and the fix, and say what breaks first when traffic grows tenfold.

04

Claiming a performance win with no measurement or number

Practise the sequence from the reported scenarios: reproduce the symptom, measure to isolate the stage (for example a 50ms spike in retrieval), change one thing, re-measure. Give your own results with a before and after figure, not a general claim.

05

Listing a distributed system on your resume that you cannot unpack

Candidates report deep dives into listed projects. For each, write the scale, the partitioning, the failure you hit and what you would change at a larger scale, and rehearse it aloud until each bottleneck has a cause.

Choose a category, try a prompt, then open its approach, worked solution or follow-up when you need it.

9 technical prompts0 include a worked solution

How do you optimize memory management in C++ for low-latency trading applications?

medium
Technical Fundamentals and Domain Expert

How do you optimize memory management in C++ for low-latency trading applications?

Approach
  1. Start from the goal: keep allocation off the hot path. new/malloc can take a lock, touch fresh pages and page-fault, so its tail latency is unpredictable. I allocate everything at startup: reserve() containers, fixed-size object pools with an intrusive free list, or an arena such as std::pmr::monotonic_buffer_resource that I reset per batch.
  2. Optimise for cache locality: contiguous std::vector or flat arrays instead of node-based std::map or std::list, struct-of-arrays for the hot fields, and alignas(64) (or std::hardware_destructive_interference_size) on counters that different threads write, so they do not false-share a cache line.
  3. Remove hidden allocations and atomics: std::string beyond the small-string buffer, std::function with large captures, and shared_ptr copies, which do an atomic refcount increment. I use unique_ptr or plain references and string_view on the hot path, and move instead of copy.
  4. At the OS level: pre-fault and lock memory with mlock/mlockall, use huge pages to cut TLB misses, allocate NUMA-local to the pinned thread, and never free on the hot path. Freeing can be deferred to a non-critical thread.
  5. Prove it with measurements: p99/p99.9 latency rather than the mean, perf counters for cache and TLB misses, and a test that fails if the steady-state path allocates, for example by counting calls through a replaced global operator new.
Follow-up
  • How would you design a fixed-size object pool, and what should happen when it runs out?
  • Why can copying a shared_ptr between threads hurt latency even though it never allocates?
  • How would you show that your order-handling path performs zero heap allocations in steady state?

How do you handle concurrency and race conditions in Golang or Java?

medium
Technical Fundamentals and Domain Expert

How do you handle concurrency and race conditions in Golang or Java?

Approach
  1. Separate the two problems. A data race is concurrent unsynchronised access where at least one access writes. A race condition is wrong logic that depends on timing, such as check-then-act, and it can happen even when every single operation is synchronised. Then name the shared mutable state and who owns it; confinement and immutability come first.
  2. Java: synchronized or ReentrantLock for compound actions. volatile gives visibility and happens-before ordering, but count++ on a volatile field is still not atomic. AtomicLong works for counters, and LongAdder suits heavy contention. ConcurrentHashMap.compute/merge gives an atomic per-key check-then-act. Thread pools come from ExecutorService.
  3. Go: pass ownership through channels so only one goroutine touches the data, or guard it with sync.Mutex/RWMutex. Use sync/atomic for counters, sync.WaitGroup to join, and context for cancellation so goroutines do not leak.
  4. Avoid deadlock with a single global lock order, short critical sections, and no lock held across I/O or callbacks. In Java, tryLock with a timeout can break a cycle.
  5. Verify it: go test -race reports races that actually execute during the test, not every possible race, so the tests must exercise the concurrent paths. In Java, use stress tests or jcstress, and use thread dumps (jstack) to diagnose a hang.
Follow-up
  • Why is a counter declared volatile in Java still unsafe under concurrent increments?
  • When would you choose a channel over a mutex in Go, and when is a mutex the clearer choice?
  • A service hangs in production. How do you confirm it is a deadlock and find the two locks involved?

Identify the heaviest tenants in a five-minute window under memory pressure

medium
top-kheavy hittersstreaming

The edge service handles about 3,000 requests per second across roughly 50,000 tenants, peaking near 9,000. Expose the 50 heaviest tenants by request count over the trailing five minutes so limits can be tightened before one tenant's backfill starves the fleet. You may not retain five minutes of raw records. Give the exact solution and its memory, then the bounded-memory approximation with its error stated as a formula, and say which you would ship and at what tenant cardinality that choice changes.

Approach
  1. Do the exact version first, because it is affordable at this cardinality: a ring of 300 one-second counters per tenant, advanced lazily, is 1,200 bytes of counters per tenant and roughly 60 to 90 MB for 50,000 tenants with overhead. Carry a running total and subtract the bucket you overwrite so a window read is O(1) rather than 300 adds.
  2. Extract the top 50 with a size-k min-heap over the tenant sums: O(d log k) for d tenants, against O(d log d) to sort them all. Maintaining the heap continuously instead of on query requires a tenant-to-heap-index map, because incrementing a count already inside the heap means sifting from a known position, and without that map you rebuild the heap on every request.
  3. State the approximation precisely rather than gesturing at sketches. Misra-Gries with m counters retains every item whose true count exceeds N/(m+1), and each retained count underestimates the truth by at most N/(m+1). With m = 1,000 and N = 900,000 requests in the window the error is roughly 900 requests, which is fine for spotting a tenant sending 50,000 and useless for ranking two tenants 200 apart.
  4. Say what breaks when the window slides: Misra-Gries and Space-Saving are insert-only and cannot be decremented as records age out. The workable construction is one summary per sub-window, say ten seconds, with 30 summaries merged at query time, and the merged error is the sum of the per-summary errors, so the bound degrades linearly in the number of sub-windows.
Follow-up
  • The heaviest tenant is heavy because of one export job rather than user traffic. Should the limiter treat those as the same tenant?
  • Two tenants sit tied at the boundary of the top 50. Does your answer flap, and does the flapping matter?

Seven days built from the reported question types: first the format and scope, then one day each for memory, concurrency, networking and distributed design with vector indexes, then past-project stories and a mock. Practice-library drills are used where they match.

Small steps. Visible outcomes.0 / 7 completed
ONE WEEK · YOUR PACE

Prepare, practise & reflect

One practical outcome each day. Spend longer where you need it.

0 / 7 done
01Pin down the format and your track
  • Ask your consultant for the stages, whether code is written live, the language track (backend, infrastructure, research) and which client firms receive your resume
  • Choose your primary language from C++, Python, Rust and TypeScript and list five internals you can explain (allocation, GC or ownership, threads, standard-library containers, I/O)
  • List the five reported questions and rate your confidence in each from one to five

Deliverable: A written format and consent confirmation from your consultant, your chosen language, and a ranked list of the five questions by weakness.

02Memory and low latency in C++
  • Write a spoken answer to the C++ memory question covering preallocation and pools, arenas, avoiding allocation on the hot path, contiguous layouts, alignment and false sharing
  • Benchmark a vector of values against a vector of heap pointers for a scan, and note the difference
  • If your language is not C++, write the equivalent answer for it (allocation and GC pressure in Python, ownership and arenas in Rust)

Deliverable: A one-page memory answer, benchmark numbers for both layouts, and a list of the tools you would use to measure allocations.

Practice prompt ↗
03Concurrency and race conditions
  • Write a racy counter in Go or Java, reproduce the failure (Go's race detector, or a stress loop in Java) and fix it with a lock, an atomic and single-owner design
  • Write an answer for the concurrency question covering the memory model, happens-before, visibility, deadlock and thread pool sizing
  • Work the intermittent-failure debugging drill from the PracHub practice set

Deliverable: A working racy program with three fixes, a short written concurrency answer, and notes on the debugging drill.

Practice prompt ↗Practice prompt ↗
04Network I/O: TCP, UDP and serialization
  • Write a comparison of TCP and UDP for market-data style streams covering ordering, loss, congestion control, head-of-line blocking, multicast and Nagle with TCP_NODELAY
  • Describe how non-blocking I/O with an event loop and kernel bypass change the cost per packet
  • Answer the serialization example aloud: how you would measure the overhead and what you would change (binary formats, fewer copies, batching)

Deliverable: A comparison table, a spoken serialization answer, and one recommendation for a latency-sensitive feed with its reasons.

Practice prompt ↗
05Scaling bottlenecks and vector indexes
  • Write the scaling answer: bottlenecks in order, how to detect each, and the fix, covering hot partitions, coordination, fan-out tail latency and network limits
  • Write a comparison of vector index strategies (exhaustive scan, inverted-file, graph-based and quantised) on recall, latency, memory and update cost
  • Talk through the retrieval latency spike scenario from first measurement to a fix

Deliverable: A bottleneck checklist, an index comparison table with a recommendation per workload, and a recorded walkthrough of the spike scenario.

Practice prompt ↗Practice prompt ↗
06Past systems and stakeholder communication
  • Write deep-dive notes for two of your past systems: scale, partitioning, failures, what you would change, with measured before and after numbers
  • Rehearse a plain-language explanation of one technical risk for a non-technical stakeholder
  • Practise the outage-ownership and deadline-trade-off prompts from the PracHub practice set

Deliverable: Two project deep-dive sheets with numbers, one stakeholder-risk script, and rehearsed outage and deadline stories.

Practice prompt ↗Practice prompt ↗
07Full mock
  • Answer all five reported questions aloud back to back and note where you stalled or lacked a number
  • Warm up with the heaviest-tenants-under-memory-pressure drill from the PracHub practice set
  • Write three questions to ask about the client, the stack and the team's latency or scale targets

Deliverable: A recorded mock with a list of fixes, a solved warm-up drill, and three questions for the interviewers.

Practice prompt ↗Practice prompt ↗Practice prompt ↗Practice prompt ↗Practice prompt ↗Practice prompt ↗

Expand any day for tasks and deliverables. Your progress is saved on this device.

No behavioral questions are reported by name. Candidates report discussion of past projects, architectural choices and how you communicate technical risk to non-technical stakeholders, so prepare stories where you owned a performance or scale problem end to end.

Narrate an outage you owned from page to postmortem

hard
incident responseblast radiuspostmortems

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

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

Ship under a deadline and bound the debt you chose

medium
paginationtechnical debttradeoffs

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
  1. 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.
  2. 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.
  3. 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.
  4. 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.
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?

Estimate work you have never done and defend the range

hard
estimationbackfillsexpand-contract

You are asked to estimate a change you have never attempted: add a column to a 100-million-row table, populate it, move reads across, and drop the old shape. Give a range with the assumptions that generate it, including batch size, the signal your backfill throttles on, and wall-clock hours, and name the three unknowns that would move the number most. Then describe a real estimate you gave under comparable ignorance: how you expressed its uncertainty, what you committed to, and how wrong you turned out to be.

Approach
  1. Decompose into independently deployable steps before estimating anything: add the column nullable, write both shapes, backfill in batches, verify, move reads, stop writing the old shape, drop it. That is four deploys spread over days, and the calendar estimate is dominated by them rather than by the loop's runtime.
  2. Do the arithmetic aloud for the part that has arithmetic in it: batch size times number of batches times per-batch duration, at a write rate the primary can absorb alongside roughly 1.2k writes per second of production traffic. The loop is throttled by replication lag and lock waits, not by how fast it can issue statements.
  3. Price the schema step by its lock rather than its statement duration. In PostgreSQL an ALTER TABLE taking ACCESS EXCLUSIVE waits for every open transaction on that table while later queries queue behind it, so a millisecond change issued during a thirty-second analytics query stalls that table for thirty seconds. Adding a nullable column with a non-volatile default avoids a rewrite from version 11; a new index wants CREATE INDEX CONCURRENTLY, which cannot run inside a transaction block and leaves an invalid index behind if it fails.
  4. Express the answer as a range whose endpoints each trace to a stated assumption, then name the cheapest experiment that collapses it, which is almost always running one real batch against the real table and multiplying.
Follow-up
  • How do you verify the backfill genuinely finished, given rows written by production traffic while it ran?
  • Where does the backfill resume from after a worker is killed mid-batch, and what makes that resume point trustworthy?
  • 01

    Walk me through a system you built, the bottleneck you hit and the measurement that showed it.

  • 02

    Describe a performance problem you isolated: what you measured, what you changed and the number that moved.

  • 03

    Tell me about a time you explained a technical risk to a non-technical stakeholder and what they decided.

  • 04

    Describe a design decision where you chose consistency over availability, or latency over throughput, and what it cost.

  • 05

    Tell me about a project you owned from design through deployment and maintenance, and what you would change at ten times the scale.

PracHub preparation framework ↗
How long should I prepare for the BAH Partners loop?

Candidates report that many spend four to six weeks, concentrating on system design and language-specific optimization. If you have less, use the seven-day plan above as the core and spend the remaining time on your primary language's internals and on two past systems you can explain in depth.

BAH Partners Software Engineer candidate reports ↗
What helps a candidate stand out?

Candidates report that knowing the right answer is not enough: explain the trade-offs behind a choice and why a given stack fits a latency or throughput goal. For each reported question, practise stating the alternative you rejected and what it would have cost.

BAH Partners Software Engineer candidate reports ↗
Is the process purely technical?

Candidates describe a technical process that also covers working in a small, fast team and communicating technical risk to non-technical stakeholders. Prepare one story where you explained a risk in plain terms and one where you owned a project's full lifecycle.

BAH Partners Software Engineer candidate reports ↗
Are there remote or hybrid options?

Candidates report that arrangements vary by client, and that many firms in Singapore or Hong Kong ask for a hybrid model so engineers can work closely with trading and research desks. Ask your consultant about the client's location and working pattern early.

BAH Partners Software Engineer candidate reports ↗
What topics does BAH Partners test in interviews?

Candidates report distributed systems, web crawling, search and information retrieval, programming in Python and vector databases, with questions on C++ memory, TCP vs UDP, scaling bottlenecks, concurrency and vector indexes. Emphasis depends on the client and the track (backend, infrastructure or research).

BAH Partners Software Engineer candidate reports ↗
What should I agree with the consultant before interviewing?

Candidates are advised to confirm which firms will receive your resume, to share it only with your explicit consent and to vet the consultant. Ask for the stages, whether you will write code, and which language track applies.

PracHub Software Engineer practice ↗
Sources & methodology 3 sources ↗

No official company page is cited. Rounds and questions come from candidate reports and PracHub editorial material; each source shows the date it was read.