BDO · Software Engineer
Updated · 2026-09-24

BDO Software Engineer
Interview Questions & Guide 2026

THE 60-SECOND BRIEF

A Software Engineer at BDO plays a pivotal role in bridging the gap between complex business challenges and scalable technological solutions. Unlike product-focused tech firms, BDO operates within a professional services environment where your code directly impacts the efficiency, security, and strategic output of high-stakes advisory and infrastructure projects. Beyond writing software, the role builds the digital backbone that BDO's consultants and clients use to make data-driven decisions.

Ask how many rounds there are and what each one is before you plan your weeks, because the composition is what your hours should follow. A loop with three coding rounds and one short design conversation deserves a different split from the reverse, and whoever schedules it will usually say plainly which it is.

PracHub has no confirmed round sequence for BDO. Treat the sections below as preparation areas and confirm the format with your recruiter.

Version an API you cannot force clients to upgradeScope every query by tenant below application codeMake integration retries idempotent without target-side idempotency keys

33 min read

Browse Software Engineer questions

See the practice prompts

13Practice promptsAcross five skill areas
3With worked solutionsIncluded in the practice prompts

A Software Engineer at BDO plays a pivotal role in bridging the gap between complex business challenges and scalable technological solutions. Unlike product-focused tech firms, BDO operates within a professional services environment where your code directly impacts the efficiency, security, and strategic output of high-stakes advisory and infrastructure projects. Beyond writing software, the role builds the digital backbone that BDO's consultants and clients use to make data-driven decisions.

The work is characterized by its diversity and intellectual rigor. You will collaborate with cross-functional teams, including project managers and infrastructure advisors, to translate nuanced requirements into robust, maintainable systems. This role is ideal for engineers who thrive on variety, enjoy solving unstructured problems, and want their technical expertise to serve as a catalyst for real-world business outcomes.

01

Preparation focus

editorial

No round sequence has been reported for this company, so work the categories below and confirm the format with your recruiter.

What to demonstrate

  • Breadth across SQL, experimentation and product reasoning
  • Ability to state assumptions before choosing a method

How to prepare

  • Drill the practice exercises below and time yourself
  • Prepare three quantified stories about decisions you drove
PracHub interview preparation framework ↗

PracHub editorial advice for the preparation topics above.

01

Long-lived shared credentials for client systems

One static key used by the connector runtime, a debugging script and three engineers cannot be attributed to a person in an audit, cannot be expired at engagement close, and cannot be rotated without breaking an unknown number of consumers at once. The expensive part of the eventual incident is not the leak; it is that rotation requires finding every holder under time pressure, and nothing recorded who they were. Issue per-principal, per-target, short-lived grants from a broker so rotation is a no-op, attribution is automatic, and closure is a TTL rather than a search.

02

Forking the product per client instead of building a configuration or extension point

A fork is the cheapest possible answer for one client and the most expensive possible answer for the estate. Maintenance cost grows as O(clients x changes): a single security patch now needs one port per fork, each with its own conflicts, its own test run and its own release window, and the forks drift further apart with every port. The honest rule is that a required fork is a product gap, so it should either become a supported extension point with a stable interface, or be an explicit, time-boxed and separately priced artefact that is never expected to receive upstream fixes.

03

Starting work without saying what you are about to spend time on

State the plan before executing it: the approach, roughly how long it will take, and what you intend to leave hand-waved. That gives the interviewer a chance to redirect you in ten seconds rather than watching you spend fifteen minutes on the wrong sub-problem.

04

Designing for a scale nobody asked for

Ask for request rate, data size, read-to-write ratio and expected growth, then size the simplest option first; one relational instance on current hardware covers a large share of real workloads. Reaching for shards, queues and a cache tier before any number has been quoted reads as pattern-matching rather than judgement.

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

10 technical prompts3 include a worked solution

Top-k longest connector runs from a stream too large to sort

mediumWorked solution
heaptop-kstreaming

A day of connector_run rows sits in object storage: 200,000,000 rows, unsorted, far larger than memory, and streamable once. Each row has run_id, connector_id, started_at and finished_at, where finished_at is NULL for runs that never reached a terminal state. Return the 200 longest terminated runs by (finished_at - started_at), ties broken in favour of the lower run_id, plus the count of rows with a NULL finished_at. You may not sort the input or hold it in memory. State the time and space complexity you achieve.

Approach
  1. Keep a bounded min-heap of capacity k=200 ordered on (duration, -run_id). The root is then the weakest retained entry: smallest duration, and on a duration tie the largest run_id, which is exactly the one the stated tie-break should evict.
  2. Per row: if finished_at is NULL, increment a counter and skip; otherwise compute the duration and push when the heap holds fewer than k, else compare against the root and replace only if strictly better. O(n log k) worst case, O(k) space, and after the heap warms nearly every row costs a single comparison against the root.
  3. Reject the alternatives explicitly. A full sort is O(n log n) and at 2e8 rows means an external merge sort over hundreds of gigabytes to produce 200 rows. Quickselect is O(n) average but needs the whole array resident, which the constraint forbids.
  4. Handle the NULL as data, not as an edge case: depending on the language, subtracting from NULL either throws or yields a sentinel that lands at the top of the list. Count those rows and report them, because a spike of unterminated runs is its own signal.
  5. To parallelise, give each of p shard readers its own size-k heap and merge the p results. The union of per-shard top-k sets contains the global top-k, because an element beaten by fewer than k rows globally is beaten by fewer than k rows in its own shard, so the merge is exact at O(pk log k).
Worked solution 20 min
  1. Stream eleven rows as (run_id, duration_seconds): (1,12) (2,405) (3,7) (4,88) (5,405) (6,3) (7,1200) (8,61) (9,NULL) (10,99) (11,405). Use k=3.
  2. Fill the heap with the first three terminated rows, then maintain it: after (2,405) and (5,405) and (7,1200) have been seen, the heap holds those three and the root is (405, -5), which is run 5.
  3. Row 9 has no finished_at, so it increments the unterminated counter and never reaches the heap.
  4. Row 11 has duration 405, equal to the root's duration, but run_id 11 > 5, so under (duration, -run_id) it is not strictly better than the root and is discarded on the tie-break rather than on duration.
  5. Drain the heap in descending order to produce the final list.
EXPECTED RESULTTop 3 = run 7 (1200s), run 2 (405s), run 5 (405s). Unterminated count = 1 (run 9). Run 11, also at 405s, is excluded by the lower-run_id tie-break.
Follow-up
  • Now return the top 20 bindings by total run time instead of the top runs. What changes, and how many distinct keys must you hold to make it exact?
  • The key space is too large to hold an exact aggregate. What does a Misra-Gries summary with m counters actually guarantee about the counts it returns?
  • Rows now arrive continuously and you want a rolling one-hour top-k. Does the bounded heap still work, and if not, what breaks?

Find peak window utilisation and the first rejected request

medium
sliding windowtwo pointersrate limiting

One connector binding's requests against a client endpoint arrive as timestamps t[0..n-1] in milliseconds, sorted non-decreasing, n up to 1,000,000. The endpoint's budget is R requests per rolling window of W milliseconds, and a request at time t is admitted only if strictly fewer than R already-admitted requests fall in the half-open window (t-W, t]. Return (a) the maximum number of requests falling in any W-millisecond window, counting every request regardless of admission, and (b) the index of the first request the limiter would reject. Both parts in O(n) time.

Approach
  1. Part (a) is a two-pointer scan: for each right index, advance left while t[right] - t[left] >= W, which leaves the window exactly (t[right]-W, t[right]], and track max(right-left+1). Left is monotone non-decreasing, so total work is O(n) amortised with O(1) extra space. The maximum over all windows of width W is attained at a window whose right edge is a request timestamp, so scanning right edges is sufficient.
  2. Part (b) is not the same scan. A rejected request consumes no budget, so the window must count admitted requests only. Keep a FIFO deque of admitted timestamps: pop from the front while front <= t - W, admit if the deque holds fewer than R, and return the first index where it does not. O(n) total pushes and pops, O(R) memory.
  3. Pin the boundary convention before writing either loop. With a half-open (t-W, t] window a request exactly W milliseconds after an earlier one does not see it; switching to a closed window changes the answer at every boundary and is where most disagreements with the client's own limiter come from.
  4. Note what fixed buckets of width W buy and cost: O(1) memory, but they admit up to 2R inside a span shorter than W, R at the end of one bucket and R at the start of the next. If buckets are unavoidable, halve the bucket width or use a weighted estimate across two adjacent buckets.
  5. If part (a) already exceeds R, the binding cannot run at this concurrency under any limiter shape. That is a scheduling problem, not a retry-policy problem, and no backoff tuning fixes it.
Follow-up
  • Three bindings and four workers share this one endpoint's quota. Where does the counter live, and what is the correct behaviour when that store is unreachable?
  • Add full-jitter backoff to the retry path and state precisely what it prevents that plain exponential backoff does not.
  • The client documents the limit as 'about 100 per minute'. How would you measure the real one without tripping it in their production?

Assign connector bindings to rollout waves and name the cycle

medium
topological sortcycle detectiondependency graph

Connector bindings declare ordering dependencies: an edge u -> v means v must not run in a wave earlier than one after u has succeeded. You have up to 50,000 bindings and 200,000 edges, and a misconfigured dependency may have created a cycle. Assign each binding the earliest wave number such that every predecessor sits in a strictly earlier wave, return the total wave count, and if a cycle exists return the bindings on one concrete cycle rather than a boolean. The implementation must be iterative: a dependency chain can be 50,000 deep.

Approach
  1. Build an adjacency list and an indegree array, then run Kahn's algorithm from every indegree-zero node. Bindings with no predecessors get wave 0. O(V+E) time, O(V+E) space.
  2. Relax waves as you decrement: when popping u, set wave[v] = max(wave[v], wave[u]+1) for each successor before enqueueing v at indegree zero. Because v is only enqueued after its last predecessor is popped, wave[v] is 1 + max over predecessors, which is the earliest legal wave. Total wave count is max(wave)+1, the longest path in nodes.
  3. If Kahn emits fewer than V nodes, the residual subgraph is exactly the nodes lying on or downstream of a cycle. Every residual node still has an in-edge inside the residual, otherwise it would have been popped, so walking backwards along in-edges cannot dead-end and must revisit a node within |residual| steps; the segment between the two visits is a concrete cycle. O(V) with a visited-position map.
  4. Use an explicit stack or a queue rather than recursion. Recursive DFS on a 50,000-node chain exceeds the default stack in most runtimes, and the failure looks like a crash rather than a cycle.
  5. At this size, recompute the whole plan whenever an edge changes. Incremental topological order maintenance costs far more code than the O(V+E) rebuild it saves.
Follow-up
  • Two bindings land in the same wave but hit the same client endpoint, whose rate budget is shared. How does the wave plan have to change, and what problem class does that turn into?
  • One dependency holds only for overlapping watermark ranges rather than globally. Is the dependency graph still a DAG over bindings, and what is the right vertex if not?
  • Report the critical path so an operator can see which chain sets the wave count, not just that it is five.

Day one measures instead of guessing, under a fixed rubric, and the remaining hours are allocated in proportion to the gaps before any studying begins. The allocation is deliberately not renegotiated midweek, because the area that feels worst on day three is usually the one that is moving.

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
01Diagnostic, scored before you study anything
  • Sit a 110-minute diagnostic in four blocks: forty-five minutes on two coding problems, twenty-five on one design prompt taken to interface and data model, twenty of short-answer fundamentals, and twenty delivering two behavioural answers aloud.
  • Score each block from 0 to 3 on a fixed rubric where 3 is correct and fluent, 2 is correct but slow or prompted, 1 is partially correct and 0 is stuck, grading the artifact rather than how the attempt felt.
  • Allocate days two to five in proportion to 3 minus each block's score, write the allocation down, and commit to leaving it alone.

Deliverable: A scored rubric and a fixed hour allocation for the rest of the week.

Practice prompt ↗Practice prompt ↗Worked solution ↗
02Largest gap: find the boundary rather than the subject
  • Split the weakest area into named sub-skills and rate each separately. For coding those are restating the problem, choosing the structure, stating the invariant, turning the invariant into loop bounds, handling empty and single-element input, and accounting for complexity out loud.
  • Attempt three items positioned just above where the rating drops off, and for each write the first move you failed to make.
  • Re-attempt one of them from blank four hours later with nothing open.

Deliverable: A sub-skill map with the two blocking sub-skills circled.

Practice prompt ↗Practice prompt ↗
03Drill the blocking sub-skill by repeating the shape
  • Do eight short repetitions of the same shape rather than eight different problems, so what gets practised is the pattern and not the puzzle.
  • State the rule you now hold in one sentence, then test it against a case built to break it, a sliding window over an array containing negative values, or a cache-aside read path whose invalidation message is dropped.
  • Have someone else read your one-sentence rule and find the precondition you left out.

Deliverable: One rule statement with its preconditions attached and one counterexample that would have caught the incomplete version.

Practice prompt ↗Practice prompt ↗
04Second gap, plus maintenance on the strongest area
  • Run the same sub-skill decomposition on the second-largest gap in half the time.
  • Spend twenty-five timed minutes on the block you scored highest, choosing the hardest item you can still finish rather than a warm-up.
  • Write whether each area fails you on recall, on setup, or on execution, and set the fix accordingly: repetition for recall, a written checklist for setup, timed work for execution.

Deliverable: A second sub-skill map plus a one-line failure diagnosis for each area.

Practice prompt ↗Practice prompt ↗Worked solution ↗
05The gap that is not a skill
  • Record one technical and one behavioural answer, then count two things in the playback: seconds before your first clarifying question, and sentences you began without knowing where they would end.
  • Practise saying that you do not know, followed by how you would find out, without letting it soften into a guess, and practise stating a complexity or an estimate before being asked for it.
  • Redeliver one answer under a hard ninety-second cap, which forces structure ahead of detail.

Deliverable: Two recordings with a counted reduction in time-to-first-question.

Practice prompt ↗Practice prompt ↗
06Retest under day-one conditions
  • Sit the same 110-minute structure with new prompts of comparable difficulty and score it on the identical rubric.
  • For any block that did not move, change the method rather than adding hours: a block stuck at 1 usually means the practice was too varied, not too short.
  • Write down which single block you would still lose the offer on.

Deliverable: A second scored rubric placed beside the first, with one named remaining risk.

Practice prompt ↗Practice prompt ↗
07Full loop under interview conditions
  • Run a sixty-minute mock over the two blocks that moved least, with an interviewer briefed to interrupt and change direction mid-answer.
  • Write the recovery script for going blank: restate the question, state your assumption, name the first thing you would check.
  • Say every rule from the week aloud without reading it, and cut any you cannot state in a single sentence, since a rule you have to reconstruct mid-answer will not survive an interruption.

Deliverable: A one-page card holding the recovery script and only the rules you could state from memory.

Practice prompt ↗Worked solution ↗

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

Every story you tell gets read for blast radius and judgement: what could have broken, who else it touched, what you knew at the moment you decided. Nobody can audit your code in an hour, so they audit your reasoning instead. Pick work where the call was genuinely yours and the consequences were real enough to remember.

What are your top three strengths and your top three weaknesses?

medium
behavioural and engineering judgement

What are your top three strengths and your top three weaknesses?

Approach
  1. State the situation in two sentences and spend the rest on the reasoning.
  2. Pick a story where you made the decision, not one where you watched it.
  3. Close with what you would do differently, concretely.
Follow-up
  • What would you do differently if you ran that again?
  • What did you decide not to do, and why?

Own a cross-tenant read that reached a client

hard
tenant isolationincident responseblast radius

Prepare a five-minute account of an isolation or data-exposure incident you owned: a query that returned another tenant's rows, a cache keyed without a tenant, or a report that crossed a boundary. State the mechanism precisely, how you established blast radius (which tenants read which tenants' rows, over what window), the containment step, and the fix that made the class impossible rather than the instance. Finish with the notification decision and who made it. If you have never owned one, use the closest near-miss and say so.

Approach
  1. Open with the mechanism in one sentence rather than the symptom. The canonical version here: a session-scoped SET app.tenant_id on a connection returned to a transaction-mode pool with that value still attached, so the next checkout inherited it and row-level security then enforced the previous tenant's policy flawlessly.
  2. Separate containment from fix. Containment is what you did in the first twenty minutes (drain the pool, switch the pool to session mode, disable the endpoint); the fix is structural (SET LOCAL, which dies with the transaction, plus an assertion that the setting equals the request's tenant immediately before the first statement).
  3. Give the blast-radius method, not an adjective: reconstruct from the query log joined to request context on a correlation id, count distinct (reading tenant, row tenant) pairs and rows, and state what you could not reconstruct and why.
  4. Name the class-level fix and its cost. FORCE ROW LEVEL SECURITY so the table owner is not exempt, separate migration and application roles because a role with BYPASSRLS defeats every policy, and a test that drives two tenants' requests concurrently over one pooled connection, which is the load profile a serial integration suite never produces.
  5. Close with the notification call: it is a contractual question, not only an engineering one, so say who decided, how long the decision took, and what you would not repeat.
Follow-up
  • Your suite ran one request at a time and passed. What test would have caught this, and what does it cost to run on every change?
  • The same defect inside a dedicated deployment touches one client. Does that change your severity, your containment, or only your disclosure?
  • How do you know today that no other endpoint in the estate has the same defect?

Reverse a decision on token validation after measuring

medium
credential lifetimereversibilitymeasurement

Recount a decision you made and then reversed on evidence. A worked example from this domain: choosing offline validation of self-contained credentials for latency, then reversing once you measured that a revoked grant stayed usable until its own expiry, with an engagement already closed. State what you originally optimised for, the measurement that changed your mind, what the reversal cost in work already done, and how you concluded that reversing was cheaper than compensating around the original choice.

Approach
  1. State the original decision with the objective it optimised and the property you did not measure. Revocation lag is the usual one, because it is invisible until somebody is offboarded mid-engagement.
  2. Give the measurement as a number with a method: time from revocation to first rejected call, observed across real grants, not a value read out of a configuration file.
  3. Compare the mechanisms on all three axes honestly. Offline validation adds no round trip and keeps working while the issuer is down, but cannot recall a token before its own expiry because offline validation never asks anyone. Introspection bounds revocation lag by its cache TTL and pays for it with a per-call dependency on the issuer's availability and latency.
  4. Say what you actually chose, which is often neither extreme: a short TTL with offline validation is frequently correct, because capping every grant at min(requested_ttl, engagement_end + grace - now) bounds worst-case access by a number you picked rather than by whether a revocation call succeeded.
  5. Account for the sunk work and the migration: what shipped, what was discarded, and how you avoided a flag day for callers already holding credentials.
Follow-up
  • What TTL do you pick, and what requirement are you trading against as you shorten it?
  • An engagement terminates early on a Friday evening. Trace the worst case under your final design and say precisely what is still valid on Saturday morning.
  • 01

    What are your top three strengths and your top three weaknesses?

  • 02

    Prepare a five-minute account of an isolation or data-exposure incident you owned: a query that returned another tenant's rows, a cache keyed without a tenant, or a report that crossed a boundary. State the mechanism precisely, how you established blast radius (which tenants read which tenants' rows, over what window), the containment step, and the fix that made the class impossible rather than the instance. Finish with the notification decision and who made it. If you have never owned one, use the closest near-miss and say so.

  • 03

    Recount a decision you made and then reversed on evidence. A worked example from this domain: choosing offline validation of self-contained credentials for latency, then reversing once you measured that a revoked grant stayed usable until its own expiry, with an engagement already closed. State what you originally optimised for, the measurement that changed your mind, what the reversal cost in work already done, and how you concluded that reversing was cheaper than compensating around the original choice.

PracHub interview preparation framework ↗
Is this an official BDO interview guide?

No. It is PracHub's own research and practice material for the Software Engineer role at BDO. Rounds and questions reflect what candidates have reported, not a process BDO has published, and they change over time. Confirm the current format and scope with your recruiter.

PracHub interview research ↗
How long should I expect the interview process to take?

The timeline can vary, but generally, the process is efficient. Expect to move through the stages over a few weeks, though communication can occasionally vary by region.

PracHub interview research ↗
Is there a heavy emphasis on whiteboard coding?

While technical skills are tested, the interview is often more focused on your practical experience and how you solve problems in a real-world context rather than abstract algorithmic puzzles.

PracHub interview research ↗
What is the best way to prepare for the behavioral questions?

Use the STAR method (Situation, Task, Action, Result) to structure your answers. This ensures your responses are concise, focused, and highlight your contributions effectively.

PracHub interview research ↗
How does BDO view remote work?

Expectations around location vary by specific role and office. It is best to clarify current policies during your initial screening call.

PracHub interview research ↗
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.