Interview guides · Arcesium
Arcesium Software Engineer Interview Guide
Arcesium Software Engineer interview guide: three reported rounds, DSA, core CS, SQL, LLD and ETL design questions, behavioral prompts and a 7-day plan.
The 60-second brief
Arcesium builds post-trade technology for financial institutions, hedge funds and institutional asset managers. Candidates describe the engineering work as data-processing platforms, accounting engines and financial management tools, with workloads such as reconciliation across asset classes, net asset value calculation and risk analytics. In the Software Engineer role, candidates describe writing Java or C++ for backend services, data pipelines and microservices, designing database schemas, tuning SQL, taking part in code reviews, and watching production services for bottlenecks and data-integrity problems. Cloud (AWS), Kafka, Spark, Spring Boot, Docker and Kubernetes appear as nice-to-have experience rather than requirements.
This guide is for candidates interviewing for the Software Engineer role at Arcesium. It covers the three reported rounds (Online Coding Test, Technical Interviews, Behavioral Evaluation) and the reported question types: arrays, trees, linked lists, dynamic programming and graphs; OOP, language internals, operating systems and SQL; low-level class design, schema design and pipeline design; and past-project and motivation questions. It does not cover other roles at the company, and it does not assume finance knowledge.
Candidates report three rounds over roughly three to five weeks: an online coding test, technical interviews that mix coding, core CS and design, and a behavioral evaluation. Some accounts give a shorter window of two to four weeks, depending on scheduling.
Focus areas
- Data Structures
- Algorithms (DSA)
- Problem Solving
Overview
The work candidates describe is backend engineering where wrong numbers are expensive: pipelines that ingest transactions, services that reconcile and account for them, and reporting on top. That shapes what the loop rewards you for preparing. Reports put core computer science (OOP, operating systems, DBMS) next to ordinary data structure and algorithm coding, and they name Java and C++ as the languages the role lists. Prepare the language you will code in down to its runtime behaviour, not only its syntax.
The reported coding questions are classic and checkable: search in a rotated sorted array, minimum depth of a binary tree, house-robber style dynamic programming and memoized grid paths, cycle detection and the median node of a linked list, and BFS or topological sort over dependency chains. The core CS questions cover the pillars of OOP and constructors, memory management and threads in your own language, B-tree indexing with multi-table JOINs, process scheduling and virtual memory, and exceptions, garbage collection and JVM memory. The design questions split into low-level machine coding (Snake and Ladder, Splitwise), schema design for an order or food-delivery system, an ETL pipeline for financial transactions, a rate limiter or alert-escalation engine, and the architecture of a low-latency platform.
Candidates report that finance knowledge is not required for software engineers and that domain concepts are learned on the job. You can still borrow the habits the domain implies when you answer: exact decimal arithmetic rather than floating point, idempotent writes so a replayed message cannot double-count, and reconciliation counts that prove a pipeline lost nothing. The final stage is reported to cover communication, ownership of past systems and motivation, so keep one project you can defend at the level of schema, concurrency and trade-offs.
The Arcesium interview process
Candidates report three rounds over roughly three to five weeks. These are candidate accounts of the sequence, not a published process, and details vary by office and team.
Online Coding Test
Candidates describe the first stage as an online assessment. Reports mention quantitative aptitude questions, multiple-choice questions on computer science fundamentals, and algorithmic coding problems of medium to hard difficulty, and candidates describe each stage as one you have to clear to move on. The array, tree, linked-list, dynamic programming and graph questions in this guide are the practice material for the coding part. Because the test is taken online, correctness on edge cases decides the result: settle on an approach, write it cleanly, and trace it on empty, single-element and duplicate inputs before you submit.
What to demonstrate
- Working code for array, tree, linked-list, graph and dynamic programming problems
- Edge-case handling and a correct complexity analysis of the submitted solution
- Quantitative aptitude and core CS multiple-choice, as candidates report
How to prepare
- Solve the rotated sorted array search and the minimum-depth question in your chosen language without an IDE, then write down the time and space complexity of each.
- In one sitting, on a timer you set, run a mixed set: shortest path in an unweighted grid with obstacles, house robber, and the median node of a linked list. Note which one cost the most time.
- Refresh aptitude basics (percentages, ratios, permutations, probability) and short OOP, OS and DBMS definitions for multiple-choice.
Technical Interviews
Candidates describe several technical interviews rather than one. Reports cover live coding, discussions of core computer science (OOP, operating systems, SQL and DBMS) and design at two levels: low-level machine coding, where you turn requirements into classes and interfaces, and high-level design of pipelines, queues and caches. Candidates also report being asked to explain and defend the architecture of past projects. Language questions come up in Java or C++ terms, so answer in the language you code in. For design prompts, start by pinning scope and entities, then API and schema, then failure behaviour.
What to demonstrate
- Live coding with clear spoken reasoning, edge-case checks and complexity analysis
- Core CS depth: OOP and constructors, threads and deadlocks, scheduling and memory, indexing and SQL
- Low-level class design and schema design, plus high-level pipeline and low-latency architecture
- Ability to explain and defend decisions made in past projects
How to prepare
- Write a short spoken answer, with one code snippet, for each internals topic: copy versus default constructors, memory management, thread safety, deadlock prevention, checked versus unchecked exceptions, garbage collection.
- Build Snake and Ladder and a Splitwise-style expense tracker as runnable code: entities, interfaces, and the design pattern you apply and why (Strategy for split types, for example).
- Draw an ETL pipeline for financial transactions with a queue, idempotent loads, a dead-letter path and reconciliation counts, then outline a rate limiter and an alert-escalation engine.
- Write a multi-table JOIN with GROUP BY on an order schema and explain which B-tree index it uses and what would stop it using one.
Behavioral Evaluation
Candidates describe the last stage as a behavioral evaluation of communication and cultural fit. Reports of the final stages mention a conversation with a hiring manager or engineering leadership and a discussion with HR; the managerial conversation is described as covering end-to-end ownership of systems, architecture decisions on previous projects, scenario-based problem solving and team fit. Reported prompts include a technical disagreement over system design, why you want to work at Arcesium on post-trade software, a technically challenging feature from your past work, and handling ambiguous requirements under tight delivery deadlines. Prepare stories that show a decision and its trade-off, not a list of duties.
What to demonstrate
- Clear communication of technical decisions and trade-offs
- Ownership of a system from design through production, as reported for the managerial conversation
- Handling of disagreement and ambiguous requirements
How to prepare
- Write four story outlines, one for each reported prompt: the disagreement, the challenging feature, the ambiguous-requirements deadline, and your reasons for this work. Each needs a decision, evidence and an outcome.
- Pick one past project and prepare to defend its database choice, concurrency handling and the bottleneck you removed, with numbers you can stand behind.
- Prepare two questions for the hiring manager about how the team handles reconciliation or data-quality problems in production.
Where candidates lose points
Coding rotated-array search by guessing which half to discard, then failing on tiny inputs
At each step decide which half is sorted by comparing the middle with the left end, then test whether the target lies inside that half. Trace a pivot at index 0, a two-element array and an absent target, and mention that duplicates can push the worst case to linear time.
Reciting the OOP pillars as definitions without saying what Java or C++ actually does
Tie each pillar to your language: shallow versus deep copy and the rule of three in C++, why Java has no compiler-supplied copy constructor, how virtual dispatch or overriding resolves at runtime. Give one short code example per answer.
Starting the Snake and Ladder or Splitwise design by writing classes before pinning requirements
List entities, operations and rules first: board size, number of dice and snake and ladder positions for one; equal, exact and percentage splits and balance settlement for the other. Then name the pattern (Strategy for split types, Factory for rule setup) and show how a new rule is added without editing existing classes.
Drawing an ETL pipeline as boxes and arrows with no failure semantics
Say what happens on a duplicate message, a poison record, a consumer restart and a partial load. Use an idempotency key or upsert on load, a dead-letter queue, replay from stored offsets, exact decimal types for money, and row-count and total reconciliation between source and target.
Answering the behavioral prompts with a team story and no personal decision, or reciting why the company sounds impressive
For each story, state the choice you made, the alternative you rejected, the evidence and the result. For the motivation question, connect a project you built to the post-trade work candidates describe, rather than repeating the employer's own description.
Questions & practice
Search for an element in a rotated sorted array and analyze its time complexity.
Medium · Data Structures & Algorithms
Approach
- Use a modified binary search: at each mid, one of the halves [lo..mid] or [mid..hi] is always sorted. Check nums[lo] <= nums[mid] to find the sorted half, test whether the target falls inside that half's range, and discard the other half. That is O(log n) time and O(1) space.
- An equivalent two-pass version: binary-search for the rotation point (the minimum) by comparing nums[mid] > nums[hi], then run an ordinary binary search on the segment that can contain the target. That is two O(log n) passes.
- State the distinct-values assumption out loud. With duplicates, nums[lo] == nums[mid] == nums[hi] gives no information about which half is sorted, so you shrink lo++ / hi--, and the worst case becomes O(n) (for example [1,1,1,1,0,1,1]).
- Edge cases to dry-run: empty array, a single element, rotation by 0 or n (array fully sorted), a target sitting at the rotation point, and a two-element array. Use lo <= hi as the loop condition and mid = lo + (hi - lo) / 2 to avoid int overflow in Java or C++.
Follow-up
- How does your solution change if the array can contain duplicates, and what is the new worst case?
- Return the number of times the array was rotated instead of the target's index.
- Find the first and last occurrence of a target in a rotated array that contains duplicates.
Implement a function to find the minimum depth of a binary tree and discuss iterative versus recursive approac
Medium · Data Structures & Algorithms
Implement a function to find the minimum depth of a binary tree and discuss iterative versus recursive approaches.
Approach
- Define it precisely: the minimum depth is the number of nodes on the shortest root-to-leaf path, and a leaf has no children. The classic bug is returning 1 + min(left, right) when one child is null. A root with only a right subtree is not a leaf, so recurse only into the child that exists.
- Recursive DFS: O(n) time and O(h) stack space, where h can reach n on a skewed tree. In Java a degenerate tree with many thousands of nodes can throw StackOverflowError, which is the main argument for an iterative version.
- Iterative BFS with a queue: process the tree level by level and return the current depth at the first leaf dequeued. It stops early, so with a shallow leaf it visits far fewer nodes than DFS. Worst case is O(n) time and O(w) space, where w is the widest level (about n/2 for a complete tree).
- An iterative DFS with an explicit stack of (node, depth) pairs avoids the recursion limit but cannot stop at the first leaf. Prune any branch whose depth already reaches the best leaf found so far.
- Edge cases: an empty tree returns 0, a single node returns 1, and a chain-shaped tree tests the one-child rule.
Follow-up
- Which approach would you pick for a very wide, balanced tree, and which for a deep, skewed one?
- Return the actual shallowest leaf, or the path to it, instead of the depth.
- How does the code differ for maximum depth, and why does the one-child trap not apply there?
Solve dynamic programming problems involving state transitions, such as variants of the house robber problem o
Medium · Data Structures & Algorithms
Solve dynamic programming problems involving state transitions, such as variants of the house robber problem or memoized grid paths.
Approach
- Frame each problem as state, transition, base cases and evaluation order. Start from the recursion with memoisation, then convert it to bottom-up tabulation and reduce the space where the transition only looks back a fixed distance.
- House robber: dp[i] = max(dp[i-1], dp[i-2] + nums[i]), with dp[0] = nums[0] and dp[1] = max(nums[0], nums[1]). Only the last two values are needed, so it runs in O(n) time and O(1) space with two rolling variables.
- Variants: in the circular version the first and last houses are adjacent, so run the linear solver on nums[0..n-2] and on nums[1..n-1] and take the max (n == 1 returns nums[0]). In the tree version, a post-order pass returns a pair (rob, skip): rob = val + skipL + skipR, and skip = max(robL, skipL) + max(robR, skipR).
- Grid paths: paths[r][c] = paths[r-1][c] + paths[r][c-1], and an obstacle cell is 0. The first row and first column are 1 up to the first obstacle and 0 after it. A single rolling row of width cols cuts space to O(cols). Without obstacles, the answer is C(m+n-2, m-1).
- Name the pitfalls: path counts overflow 32-bit integers quickly (use long, or the modulus the problem gives), top-down memoisation recurses up to rows + cols deep, and a start or end cell that is blocked must return 0.
Follow-up
- Reconstruct which houses were robbed, not just the maximum amount.
- Change the rule so robbed houses must be at least k apart. What is the new transition?
- Switch the grid question to minimum path sum with costs per cell. What changes in the recurrence?
Detect cycles and locate specific nodes in linked lists, including finding the median node in a single pass.
Medium · Data Structures & Algorithms
Approach
- Cycle detection with Floyd's algorithm: slow moves one step and fast moves two, and they meet if and only if there is a cycle. That is O(n) time and O(1) space, against O(n) extra space for a HashSet of visited nodes.
- To find the cycle's start: after the meeting, reset one pointer to the head and move both one step at a time. They meet at the cycle entry, because the distance from the head to the entry equals the distance from the meeting point to the entry, modulo the cycle length. For the cycle length, hold one pointer still and count the steps until the other returns.
- Middle node in one pass: advance slow by one and fast by two while fast != null && fast.next != null. For an even-length list, slow ends on the second middle. To get the first middle, loop while fast.next != null && fast.next.next != null.
- The k-th node from the end uses the same idea with a fixed gap: move a lead pointer k nodes ahead, then move both until the lead reaches the end. Handle k larger than the list length explicitly.
- Dry-run the empty list, one node, one node pointing to itself, and two nodes. Check fast and fast.next for null before every dereference.
Follow-up
- Remove the cycle once you have found it, without extra memory.
- Find the node where two singly linked lists intersect.
- If the list is sorted and even-length, how do you return the median value rather than a node?
Solve graph traversal challenges using Breadth-First Search (BFS) and Topological Sort to resolve system depen
Medium · Data Structures & Algorithms
Solve graph traversal challenges using Breadth-First Search (BFS) and Topological Sort to resolve system dependency chains.
Approach
- Model the dependencies as a directed graph where an edge u -> v means u must finish before v. Build an adjacency list and an in-degree map, and include isolated nodes so they still appear in the output.
- Kahn's algorithm: enqueue every node with in-degree 0, then pop a node, append it to the order, and decrement each neighbour's in-degree, enqueuing any neighbour that reaches 0. That is O(V + E) time and space. If the output has fewer than V nodes, there is a cycle, and the nodes with in-degree still above 0 are the ones on or behind it.
- DFS alternative: three-colour marking (unvisited, in progress, done). An edge into an in-progress node is a back edge and means a cycle, and reverse post-order gives a valid order. Note the recursion-depth risk on long dependency chains.
- Processing Kahn's queue one layer at a time gives batches that can run in parallel. The number of layers is the minimum number of sequential stages when every task takes one unit. With task durations, run a longest-path DP over the topological order to get the critical path.
- For the unweighted shortest-path variant (a grid with obstacles), use BFS from the source with four directions, and mark cells visited when you enqueue them rather than when you dequeue them. The first time you reach the target is the shortest distance, in O(rows * cols).
Follow-up
- Return the lexicographically smallest valid order. What replaces the queue, and what does it cost? (A min-heap, O((V + E) log V).)
- Print the actual cycle when the dependencies cannot be resolved.
- Dependencies arrive one at a time. How do you detect when a new edge creates a cycle without recomputing everything?
Explain the pillars of Object-Oriented Programming (OOP) and detail the differences between copy constructors
Medium · Core Computer Science & Language Interna
Explain the pillars of Object-Oriented Programming (OOP) and detail the differences between copy constructors and default constructors in C++ or Java.
Approach
- Name the four pillars with a concrete purpose for each. Encapsulation keeps state private behind methods that protect invariants. Abstraction separates an interface from its implementation. Inheritance models an is-a relationship (prefer composition for has-a). Polymorphism covers compile-time overloading and runtime overriding through dynamic dispatch.
- C++ default constructor: a no-argument constructor that the compiler declares implicitly only when the class has no user-declared constructor. The copy constructor T(const T&) is implicitly a member-wise copy, so raw-pointer members are copied shallowly, which leads to double deletes. Hence the rule of three/five: if you define a destructor, copy constructor or copy assignment, define all of them, plus the move operations.
- C++ details to state: the copy constructor's parameter must be a reference, or the call would recurse infinitely. It runs on pass-by-value and on T b = a, and on return-by-value unless elided (C++17 guarantees elision for prvalues).
- Java: the compiler adds a no-arg default constructor only if the class declares none. There is no implicit copy constructor, and b = a just copies the reference, so both names alias one object. You write a copy constructor yourself and decide deep versus shallow copying for each mutable field. Object.clone() is shallow by default and generally discouraged.
- Give a small example: a class holding a List of positions whose copy shares the list will see another holder's changes. Then say how a deep copy or an immutable class prevents that.
Follow-up
- How are overloading and overriding resolved in Java? (Overloads are chosen at compile time from static types; overrides are dispatched at runtime through invokevirtual or invokeinterface.)
- When would you choose composition over inheritance? Give an example from a design you know.
- What goes wrong if a C++ class owning a heap buffer defines a destructor but no copy constructor?
Compare dynamic memory management and thread execution models in your primary language, including thread safet
Medium · Core Computer Science & Language Interna
Compare dynamic memory management and thread execution models in your primary language, including thread safety and deadlock prevention.
Approach
- Memory: in Java, objects live on the heap and the GC reclaims whatever is unreachable from the roots. Leaks still happen through lingering references (static maps, unremoved listeners, caches). In C++, use RAII: unique_ptr for sole ownership, and shared_ptr for shared ownership with an atomic reference count. shared_ptr cycles leak, so break them with weak_ptr. Stack objects are destroyed deterministically at scope exit.
- Threading models: Java platform threads map 1:1 to OS threads, and Java 21 virtual threads are multiplexed onto a small pool of carrier threads. C++ std::thread is an OS thread. In standard CPython builds the GIL lets only one thread run bytecode at a time, so CPU-bound work goes to processes.
- Thread safety: races come from shared mutable state. Tools are synchronized or ReentrantLock, std::mutex with lock_guard, atomics (AtomicLong, std::atomic), immutability, thread confinement and concurrent collections such as ConcurrentHashMap. In Java, volatile gives visibility and ordering but does not make count++ atomic.
- Deadlock requires all four Coffman conditions: mutual exclusion, hold-and-wait, no preemption and circular wait. Break one of them: a global lock order (for example, lock two accounts by ascending id in a transfer), tryLock with a timeout and back-off, or acquiring all locks together (std::scoped_lock).
- Diagnosis: a jstack thread dump reports Java-level deadlocks, and ThreadMXBean.findDeadlockedThreads does the same programmatically. In C++, use a debugger to read each thread's stack and see which mutex it waits on.
Follow-up
- Write a thread-safe transfer between two accounts that cannot deadlock.
- How do deadlock, livelock and starvation differ? Give an example of each.
- Why does double-checked locking for a lazy singleton need volatile in Java?
Describe process scheduling, memory virtualization, and the differences between process contexts and thread ex
Medium · Core Computer Science & Language Interna
Describe process scheduling, memory virtualization, and the differences between process contexts and thread execution in modern Operating Systems.
Approach
- Process versus thread: a process has its own virtual address space, page tables and file descriptor table. Threads in a process share the address space, heap and open files, but each has its own stack, registers, program counter and thread-local storage.
- Context switches: switching between threads of the same process skips the address-space switch, so cached TLB translations stay valid and the switch is cheaper. Both kinds still pay for kernel entry, saving registers and cache disruption.
- Scheduling algorithms and their deciding properties: FCFS (convoy effect), SJF/SRTF (lowest average waiting time but needs burst estimates and can starve long jobs), round robin (a quantum too small wastes time on switches, too large degrades to FCFS), priority scheduling with aging against starvation, and multilevel feedback queues. Linux used CFS (lowest virtual runtime first) and moved to EEVDF in kernel 6.6.
- Virtual memory: per-process page tables map virtual pages to physical frames, the MMU translates, and the TLB caches translations. Touching a non-resident page causes a page fault and the kernel brings the page in. Replacement uses LRU approximations such as the clock algorithm, and thrashing starts when working sets exceed RAM. It gives isolation, copy-on-write fork and memory-mapped files.
- Know the process memory layout (text, data, BSS, heap, mmap region, stack) and how processes communicate (pipes, sockets, shared memory) compared with threads, which share the heap and therefore need synchronisation.
Follow-up
- What happens to memory when a process calls fork, and how does copy-on-write keep it cheap?
- How do user-level and kernel-level threads differ, and what happens when a user-level thread blocks on I/O?
- What does the kernel keep in a process control block?
Discuss language-specific features such as checked versus unchecked exceptions, garbage collection algorithms,
Medium · Core Computer Science & Language Interna
Discuss language-specific features such as checked versus unchecked exceptions, garbage collection algorithms, and JVM memory allocation.
Approach
- Checked exceptions (subclasses of Exception that are not RuntimeException, such as IOException and SQLException) must be caught or declared, and the compiler enforces it. Unchecked ones (RuntimeException subclasses such as IllegalArgumentException, plus Error) are not. Use checked exceptions for recoverable conditions the caller should handle and unchecked ones for programming errors. Lambdas force wrapping because standard functional interfaces declare no checked exceptions.
- Cover try-with-resources: it closes any AutoCloseable in reverse order, and an exception thrown by close() is attached as a suppressed exception instead of hiding the original. Contrast this with a finally block that throws and swallows the first exception.
- JVM memory areas: the shared heap (in generational collectors, a young generation of Eden plus two survivor spaces, and an old generation), per-thread stacks of frames, Metaspace for class metadata in native memory (it replaced PermGen in Java 8), and the code cache. Tie StackOverflowError to deep recursion and the OutOfMemoryError variants (Java heap space, Metaspace) to their areas.
- Garbage collection traces reachability from GC roots (thread stacks, static fields, JNI references), so reference cycles are collected. The generational hypothesis says most objects die young: minor GCs copy survivors out of Eden and promote them after a tenuring threshold. Collectors: Serial, Parallel (throughput), G1 (region-based with a pause-time goal, the default since JDK 9), and ZGC and Shenandoah (mostly concurrent, very short pauses).
- Allocation is cheap because of thread-local allocation buffers (bump-pointer allocation), and escape analysis can remove allocations of objects that never leave a method. Name the knobs you would actually touch: -Xms/-Xmx, -XX:MaxGCPauseMillis and -Xlog:gc for GC logs.
Follow-up
- A long-running service's heap keeps growing. How do you find the leak? (Heap dumps compared over time, the dominator tree in a heap analyser.)
- When would you choose ZGC over G1, and what do you give up?
- Should a data-access layer throw checked SQLException or wrap it? Defend your choice.
Give an example of how you handle ambiguous software requirements under tight production delivery deadlines.
Medium · Behavioral & Past Projects
Approach
- Choose a story with real ambiguity and a real deadline. The story must show how you turned the ambiguity into explicit decisions: you listed the open questions, got answers on the ones that changed the design, and wrote the rest down as stated assumptions that stakeholders could see.
- Show how you scoped it: the smallest correct slice that could ship by the deadline, deferred items named explicitly, and a design that kept the uncertain part easy to change (a configurable rule, an isolated module or a feature flag).
- Show risk control: tests built from the agreed acceptance examples, validation or reconciliation checks on the output, and a rollback plan for the release.
- Close with the measured result and what happened to your assumptions: which ones proved wrong and how cheaply you corrected them. The answers that sink this question are guessing and building alone, quiet late-night heroics with no communication, or blaming the product owner.
Follow-up
- What did you do when the person who could resolve a key question was unavailable?
- Tell me about an assumption that turned out to be wrong. What did it cost?
- How did you decide what to cut to meet the deadline?
Explain database indexing mechanisms (such as B-Trees) and write optimal SQL queries involving multi-table JOI
Medium · Core Computer Science & Language Interna
Explain database indexing mechanisms (such as B-Trees) and write optimal SQL queries involving multi-table JOINs and aggregations.
Approach
- Explain the B+tree: a balanced tree of sorted keys with linked leaves, so an equality lookup costs O(log n) page reads and a range query is a descent followed by a leaf scan. Distinguish a clustered index (InnoDB stores rows in primary-key order) from secondary indexes that point back to the row (by primary key in InnoDB, by heap tuple id in Postgres). Hash indexes support equality only.
- Usability rules: a composite index on (a, b) serves predicates on a, or on a and b (leftmost prefix), but generally not b alone. A covering index answers the query without a table lookup. Wrapping the column in a function (YEAR(created_at) = 2024) or using a leading-wildcard LIKE usually prevents index use, so rewrite it as a range.
- Trade-offs: every index slows inserts and updates and costs storage, and the planner may still choose a sequential scan when a large fraction of rows match. Check with EXPLAIN or EXPLAIN ANALYZE instead of guessing.
- Query shape for joins plus aggregation: aggregate each one-to-many child (order_items, payments) to the order grain in a CTE or subquery first, then join to orders and customers and GROUP BY. Joining two child tables directly multiplies rows and inflates sums. COUNT(DISTINCT) only hides that bug.
- Correctness details: use LEFT JOIN with COALESCE to keep customers who have no orders, put conditions on the right table in the ON clause so the left join survives, and filter aggregates with HAVING and raw rows with WHERE.
Follow-up
- Return the top three customers by spend in each region. (Use ROW_NUMBER() OVER (PARTITION BY region ORDER BY spend DESC).)
- Which index serves WHERE status = ? ORDER BY created_at DESC LIMIT 20, and why does column order matter?
- EXPLAIN shows a sequential scan even though an index exists. What are the possible reasons?
Write the update path that detects a concurrent edit
Medium · optimistic concurrency · transactional outbox · audit history
resource carries version INT NOT NULL DEFAULT 1. resource_revision holds revision_id, resource_id, version, actor_user_id, change_kind, patch JSONB, request_id, created_at with UNIQUE (resource_id, version). outbox_event holds aggregate_type, aggregate_id, aggregate_version, event_type, payload, status. A PUT carries the version the client read. Write the exact statements for the single transaction that applies the edit, records the revision and enqueues 'resource.updated', and give the handler's branch on zero affected rows. Then say what PostgreSQL 16 does under READ COMMITTED when two of these updates hit one row at once.
Approach
- One transaction, three writes, no network call inside it: UPDATE resource SET title = $3, version = version + 1, updated_at = now() WHERE resource_id = $1 AND tenant_id = $4 AND version = $2; then INSERT the resource_revision row at version $2 + 1; then INSERT the outbox_event row at the same aggregate_version. The event goes to a table rather than a broker because no transaction spans both.
- Branch on the affected-row count before doing anything else. Zero has three causes — stale version, wrong tenant, row gone — so re-read once and map to 409 carrying the current version, or 404 for an id outside the caller's tenant, which also stops the endpoint confirming that another tenant's id exists.
- State the engine behaviour instead of assuming it. Under READ COMMITTED the second UPDATE blocks on the row lock, and when the first commits PostgreSQL re-evaluates the WHERE clause against the newly committed row, so the version predicate now fails and the statement reports zero rows. Under REPEATABLE READ the identical collision raises SQLSTATE 40001 instead, so the handler must fold both shapes into one conflict response.
- Keep UNIQUE (resource_id, version) even though the predicate already serialises writers. It is what makes a lost update unwritable if any other path ever reaches the revision table, and it converts a logic bug into 23505 rather than into a silently missing history row.
Follow-up
- A client sends the version it read ten minutes ago and the resource has moved three versions. What is in your 409 so it can resolve the conflict without a full re-fetch?
- Two editors, two disjoint fields, no overlap. Does your answer still refuse the second write, and should it?
Design an Object-Oriented Low-Level Design (LLD) for a machine coding scenario like a Snake and Ladder game or
Medium · System Design & Low-Level Architecture
Design an Object-Oriented Low-Level Design (LLD) for a machine coding scenario like a Snake and Ladder game or Splitwise expense tracking application.
Approach
- Fix the requirements before drawing classes. For Snake and Ladder: number of players, board size, the snake and ladder positions, one or more dice, and the rule for overshooting the last cell. For Splitwise: users, groups, expenses, split types (equal, exact, percentage), balances and settle-up.
- Snake and Ladder classes: Game (board, a queue of players, dice, status), Board (size plus one Map<Integer, Integer> of jumps, since snakes and ladders are both start -> end), Player (id, name, position) and a Dice interface with a random implementation. The loop polls a player, rolls, moves, applies any jump, checks for a win and re-queues the player. Validate that jumps form no chains or cycles and that none starts on the final cell.
- Splitwise classes: User, Group, Expense (payer, amount, list of Split), an abstract Split with EqualSplit, ExactSplit and PercentSplit, validation per type (exact amounts sum to the total, percentages sum to 100), a factory that builds splits, and a balance sheet of net amounts per user pair. Keep money as BigDecimal or integer cents, and give the rounding remainder to one participant (100 split three ways is 33.34 + 33.33 + 33.33).
- Settling debts: compute each user's net balance, then greedily match the largest creditor with the largest debtor using two heaps. Finding the true minimum number of transfers is NP-hard in general, so call the greedy a heuristic.
- Name the patterns and why you used them: Strategy for split rules and dice so new variants plug in without editing existing classes (open/closed), Observer for expense notifications, and a Factory for object creation. Say how balance updates stay correct if expenses are added concurrently.
Follow-up
- Add a new split type, such as shares, without modifying existing classes. What do you touch?
- How would you run many Snake and Ladder games concurrently on one server?
- Map your Splitwise classes to relational tables. Which columns need indexes?
Walk through the database schema design and table relationships for an e-commerce order management or food del
Medium · System Design & Low-Level Architecture
Walk through the database schema design and table relationships for an e-commerce order management or food delivery system.
Approach
- List the entities and cardinalities. For e-commerce: customers 1-N addresses, customers 1-N orders, orders 1-N order_items, and products 1-N order_items (order_items resolves the many-to-many between orders and products), plus payments and shipments per order. For food delivery, add restaurants 1-N menu_items, deliveries and couriers.
- Normalise to roughly 3NF, but snapshot what changes over time onto the order: unit_price on order_items and the delivery address on orders, so a later price edit does not rewrite history. Store money as DECIMAL or integer minor units, never FLOAT.
- Model order status as a constrained enum with allowed transitions (placed -> paid -> shipped -> delivered, or cancelled), with an order_status_history table for audit and a version column for optimistic locking against concurrent updates.
- Integrity and concurrency: foreign keys with explicit ON DELETE behaviour, a unique (order_id, product_id) or a surrogate key, and an atomic stock decrement (UPDATE inventory SET qty = qty - ? WHERE product_id = ? AND qty >= ?, then check the affected row count). Use an idempotency key on payment creation so a retry cannot charge twice.
- Indexes follow the queries: orders(customer_id, created_at) for order history, order_items(order_id), payments(order_id), and deliveries(courier_id, status) for courier dashboards. Say which writes each index slows down.
Follow-up
- Write the query for the top ten products by revenue last month using this schema.
- How do you model partial refunds and returns without losing the original order record?
- The orders table outgrows one database. How would you shard it, and which queries become harder?
Design an end-to-end scalable Extract-Transform-Load (ETL) pipeline to process large streams of financial tran
Medium · System Design & Low-Level Architecture
Design an end-to-end scalable Extract-Transform-Load (ETL) pipeline to process large streams of financial transaction data reliably.
Approach
- Pin down requirements: sources (files, APIs, change-data-capture from databases), volume and arrival pattern, batch versus streaming latency, and correctness needs. For transactions that means no double counting, no silent drops and a full audit trail.
- Extract: land raw input immutably (object storage, or a Kafka topic as the raw zone) with source, checksum and ingestion time, so any day can be replayed. Partition Kafka by account or instrument key to keep per-key ordering.
- Transform: validate against a schema (a schema registry handles evolution), normalise timestamps to UTC and currency precision with decimal types, and deduplicate on a natural key such as source plus transaction id. Send invalid records to a quarantine or dead-letter table with a reason instead of dropping them. Spark suits large batch windows and consumer services suit streaming.
- Load: write with MERGE or upsert keyed on the transaction id, so a retry overwrites instead of duplicating. Commit consumer offsets only after the sink write succeeds: at-least-once delivery plus an idempotent sink gives an effectively-once result.
- Operate it: reconcile control totals (record counts and amount sums per batch) between source and target, checkpoint progress, reprocess by date partition after a bug fix, and handle late or amended transactions with event time and watermarks. Monitor consumer lag, quarantine rate and reconciliation breaks.
Follow-up
- A transform bug corrupted three days of output. Walk through the backfill without double-loading.
- How do you handle a correction to a transaction that was already loaded and reported?
- What exactly does Kafka's exactly-once support guarantee, and where does it stop?
Architect an enterprise rate-limiting service or alerting and escalation engine, detailing component interacti
Medium · System Design & Low-Level Architecture
Architect an enterprise rate-limiting service or alerting and escalation engine, detailing component interactions and message queues.
Approach
- Rate-limiting algorithms and their trade-offs. A fixed window counter is cheap but allows up to twice the limit across a window boundary. A sliding window log is exact but stores every request timestamp. A sliding window counter approximates by weighting the previous window. A token bucket (capacity b, refill rate r) allows bursts up to b. A leaky bucket smooths output to a constant rate.
- Distributed limiter: keep counters or buckets in Redis keyed by client and window, and make the check atomic with a Lua script (or INCR plus EXPIRE on the first hit). Return 429 with a Retry-After header. Decide fail-open versus fail-closed for when Redis is unavailable, and consider a local in-process pre-check to cut Redis round-trips.
- Alerting engine pipeline: ingest events or metrics, run a rule evaluator over windows, store alerts under a dedup key (rule plus entity) so repeated firings update one alert, run an escalation scheduler, then notification workers per channel (email, SMS, chat) that consume from a queue with retries, exponential back-off and a dead-letter queue.
- Escalation timing: put each pending step on a delayed queue (a Redis sorted set scored by due time, or a timer service feeding Kafka). Before sending a step, re-check the alert's state, because an acknowledgement can race with the scheduled notification. Key sends idempotently so a retried worker does not page someone twice.
- Protect the receivers: rate-limit notifications per recipient, group related alerts, and suppress flapping with hysteresis (separate fire and resolve thresholds).
Follow-up
- How do clock differences between nodes affect a window-based limiter, and how do you avoid them?
- Support different limits per tenant that can change without a deploy.
- An escalation worker crashes halfway through a step. How does the system make sure the next tier is still notified exactly once?
Explain high-level architecture decisions for low-latency trading or analytics platforms, focusing on fault to
Medium · System Design & Low-Level Architecture
Explain high-level architecture decisions for low-latency trading or analytics platforms, focusing on fault tolerance and concurrency.
Approach
- Start with the latency budget: trace the hot path (input -> processing -> output), keep it in memory with no blocking I/O or contended locks, and talk in tail percentiles (p99, p99.9), not averages.
- Concurrency: apply the single-writer principle by partitioning state by instrument or account so one thread owns each partition and needs no locks. Pass events between stages through bounded lock-free ring buffers (the Disruptor pattern), pad hot fields against false sharing, and preallocate or reuse objects in Java so GC pauses stay off the hot path.
- Fault tolerance through event sourcing: append every input to a durable, sequenced journal and treat processing as a deterministic state machine that can replay the journal. Snapshots bound replay time, and a hot standby consuming the same sequence can take over. Use leader election with fencing tokens (ZooKeeper, or a Raft-based store) so two primaries never act at once.
- Separate analytics from the hot path (CQRS): publish processed events to Kafka and build read models or materialised views for heavy queries. Apply backpressure or bounded buffers so a slow consumer cannot stall the writer.
- State the trade-offs: synchronous replication to a standby protects the last events but adds a network round-trip to every write; asynchronous replication is faster but can lose a tail on failover. Batching raises throughput at the cost of per-event latency.
Follow-up
- What must the state machine avoid to make replay deterministic? (Wall-clock reads, randomness, unordered iteration.)
- One downstream analytics consumer falls far behind. What happens to the hot path in your design?
- Some operations span two partitions, such as a transfer between accounts. How do you keep them consistent without a global lock?
Walk through a technically challenging feature from your past work, detailing the architecture, technical trad
Medium · Behavioral & Past Projects
Walk through a technically challenging feature from your past work, detailing the architecture, technical trade-offs, and scalability bottlenecks you overcame.
Approach
- Pick a project where you personally owned a design decision. Structure it as context and constraints (concrete scale: request rate, data volume, latency target), the architecture, the bottleneck, the options you weighed, what you chose and why, and the measured result.
- Prepare a diagram of five or six boxes you can redraw quickly, and be ready to go one level deeper on any box: schema and indexes, how concurrency was handled, what happens when a dependency fails.
- Quantify before and after (for example p95 latency, throughput, cost or error rate) and say how you measured it: profiler, load test, production dashboards. Have the raw numbers ready, because each one invites a follow-up.
- Name the trade-off you accepted (consistency for latency, a simpler design for less flexibility) and what you would change today. The mistakes that sink this answer are describing what the team did without separating your own part, and quoting numbers you cannot explain.
Follow-up
- Why did you not choose the most obvious alternative you mentioned?
- Which part of that design breaks first at ten times the load?
- If you rebuilt it today, what would you do differently?
Listing latency scales with page size, not with filters
Easy · n+1 · latency · query batching
The tenant listing endpoint reads resource filtered by tenant_id and status, ordered by updated_at DESC, and returns each row plus the owner's display name from app_user and the actor of that resource's latest resource_revision. p99 is 55 ms at 10 rows per page and 1.4 s at 200. Database telemetry shows 401 statements per request, each under 1 ms, and nothing in the slow-query log. Diagnose the cause and give the fix, stating the statement count per request and the p99 you expect afterwards.
Approach
- Read the counters before forming a theory. 401 statements for 200 rows is one driver query plus two per row, and sub-millisecond execution with an empty slow-query log rules out a bad plan. The time is round trips, which is why it is invisible in every per-query metric and scales with rows returned rather than with filter selectivity.
- Name the two per-row statements from their normalised text: a single-row app_user lookup by user_id, and a resource_revision lookup by resource_id ordered by version DESC LIMIT 1. Confirm by dropping those two response fields and watching the statement count fall to one. That locates the calls in the serialisation layer, not the repository.
- Check that the arithmetic accounts for the whole gap. Measure one round trip to the replica in isolation; 400 trips at roughly 3 ms of network plus 0.2 ms of execution is about 1.3 s on top of a 55 ms baseline, which matches. If the multiplication had fallen short, the N+1 would only be part of the story and you would keep looking.
- Batch both lookups. Collect owner_user_ids and resource_ids from the driver query, then issue WHERE tenant_id = $1 AND user_id = ANY($2) for the users, and PostgreSQL's SELECT DISTINCT ON (resource_id) ... WHERE resource_id = ANY($2) ORDER BY resource_id, version DESC for the latest revision, which the UNIQUE (resource_id, version) index serves directly. On an engine without DISTINCT ON, use a lateral join or a row_number window. Three statements per request at any page size.
Follow-up
- The page size is capped at 200 today. What breaks first if it is raised to 2,000, and is it still this bug?
- How do you stop the next N+1 from reaching production, given that no individual query is slow and the endpoint's tests pass?
Suggested practice checklist
Each day targets one cluster of reported questions: coding first, then core CS, SQL and schema, design, and finally the behavioral stories. Days end with something you can check, such as working code, a written answer or a story outline.
Day 1 — Map the loop and fix your language
- Write out the three reported rounds (Online Coding Test, Technical Interviews, Behavioral Evaluation) and, under each, the reported question types from this guide.
- Choose Java or C++ as your interview language and list five runtime behaviours you can currently explain without notes (for example garbage collection, constructors, thread creation, exceptions, memory layout).
- Mark your weakest area among coding, core CS, SQL, design and behavioral, and give it extra time on days 2 to 7.
Deliverable: A one-page map of the three rounds with question types listed and your weakest area marked, plus your language choice and the five runtime topics you can already explain.
Day 2 — Searching, trees and linked lists
- Code rotated-array search: pick the sorted half at each step, and test a pivot at index 0, two elements, an absent target, and duplicates (which makes the worst case linear).
- Write minimum tree depth two ways: recursive DFS (watch nodes with a single child) and iterative BFS that stops at the first leaf. Compare space on a skewed tree and a wide tree.
- Solve the linked-list pair: Floyd cycle detection including the node where the cycle starts, and the median node in one pass with slow and fast pointers, deciding which middle you return for even lengths.
Deliverable: Four working solutions in your language (rotated search, minimum depth recursive and iterative, cycle detection with start, median node), each with a complexity line and the edge cases you tested.
Day 3 — Dynamic programming and graphs
- Solve house robber with a rolling two-variable O(1) space version, then the circular variant; solve grid paths with obstacles once with memoized recursion and once with a table.
- Run BFS for the shortest path in an unweighted grid with obstacles, and explain why BFS and not DFS gives the shortest path.
- Implement topological sort with Kahn's algorithm for a dependency chain and detect a cycle by comparing the processed count with the node count.
- Write the staircase search for a 2D matrix sorted by rows and columns, starting from the top-right corner.
Deliverable: Working code for house robber (both variants), grid paths (two forms), grid BFS, topological sort with cycle detection and the 2D matrix search, each with its complexity written next to it.
Day 4 — OOP, language internals and operating systems
- Write spoken answers for OOP pillars and constructors: shallow versus deep copy, the rule of three in C++, and what happens when a class holds a pointer or a mutable reference.
- Write a small program that deadlocks two threads on two locks, then fix it with a fixed lock order; list the four conditions for deadlock and which one your fix breaks.
- Prepare short answers on processes versus threads, context switching, scheduling policies and how virtual memory maps pages.
- Prepare checked versus unchecked exceptions, how generational garbage collection works, and the heap versus stack split in the JVM (or the C++ equivalent for allocation and ownership).
Deliverable: Written outlines for the four topic groups, plus the deadlock program with its fix and a note saying which condition the fix removes.
Day 5 — SQL, indexing and schema design
- Design the schema for an order-management system: customers, products, orders and order items, with keys, constraints and one index per main query. Repeat the exercise briefly for a food-delivery system.
- Write a multi-table JOIN with GROUP BY and a subquery, then check each join for fan-out that inflates the sums.
- Explain how a B-tree index serves equality and range lookups, how column order in a composite index matters, and which predicates stop an index being used.
Deliverable: A schema with keys and indexes, a verified JOIN and aggregation query, a written explanation of B-tree behaviour, and a solved concurrent-edit exercise.
Day 6 — Low-level design and pipeline architecture
- Write Snake and Ladder or a Splitwise-style tracker as runnable code, with interfaces and a named pattern (Strategy for split types or dice rules), and add one new rule without editing existing classes.
- Draw an end-to-end ETL pipeline for financial transactions: queue ingest, validation, transform, idempotent load, dead-letter path, replay, reconciliation counts and exact decimal handling.
- Choose a rate-limiting service (token bucket per client, shared state, behaviour when the store is down) or an alerting and escalation engine (retry queue, escalation levels, deduplication) and outline its components and message flow.
- Write a one-page answer on a low-latency analytics or trading platform: where concurrency lives, how work is partitioned, what happens when a node fails.
Deliverable: One runnable low-level design, plus three architecture outlines (ETL pipeline, rate limiter or escalation engine, low-latency platform) each stating its failure behaviour.
Day 7 — Stories, motivation and a full rehearsal
- Write outlines for the technically challenging feature, the design disagreement, the ambiguous-requirements deadline and your reasons for choosing post-trade software, each with a decision, evidence and a result.
- Rehearse each outline aloud and cut anything that is background rather than reasoning.
- Finish with a mixed pass: one coding problem from days 2 and 3, one internals answer from day 4 and one design outline from day 6, spoken aloud.
Deliverable: Four story outlines you can tell aloud, plus a note listing what went wrong in the mixed rehearsal and the single fix for each.
Past projects, disagreements and motivation
Candidates describe the final stage as an assessment of communication and fit, with the managerial conversation covering ownership of whole systems, architecture decisions on past projects and team fit. For this role, the strongest stories involve backend decisions with a trade-off: a design you chose, a disagreement you handled, a vague requirement you pinned down. Quantify results where you honestly can, and say what you would change.
- Walk through a technically challenging feature from your past work, detailing the architecture, technical trade-offs, and scalability bottlenecks you overcame.
- Give an example of how you handle ambiguous software requirements under tight production delivery deadlines.
- Tell me about a time you diagnosed a production slowdown or data inconsistency: what you checked first, how you found the cause, and what you changed so it did not recur.
Describe a situation where you had a strong technical disagreement with a colleague or senior lead regarding s
Medium · Behavioral & Past Projects
Describe a situation where you had a strong technical disagreement with a colleague or senior lead regarding system design and how you resolved it.
Approach
- Choose a disagreement about a design choice you can name in one phrase: a synchronous call versus a queue between two services, a shared table versus separate stores, an in-memory cache versus reading the database. A story about vague differences of style gives the listener nothing to judge.
- Give the other person's position at full strength first, including what it got right. Then state your position and the specific failure you thought it carried, named as a mechanism: lost messages on a retry, lock contention on a hot row, stale reads after a failover.
- Say what evidence you brought: a load estimate, a small benchmark, a written failure scenario, or a prototype of the riskier part. The resolution should follow from that evidence, whether you won, lost or landed on a compromise.
- Finish with what happened afterwards: how you carried out the decision if it went against you, what you measured, and what you now do differently when you raise design objections. A story with no outcome is the usual way this answer fails.
Follow-up
- What evidence would have changed your mind?
- If the decision had gone against you, how would you have carried it out?
- How did the working relationship with that person change afterwards?
Explain why you are interested in working at Arcesium and how your technical career aspirations align with bui
Medium · Behavioral & Past Projects
Explain why you are interested in working at Arcesium and how your technical career aspirations align with building post-trade financial software.
Approach
- Build the answer from the work candidates report for this role: backend services and data pipelines for post-trade processing, such as reconciliation, accounting calculations and net asset value reporting, written in Java or C++ with SQL underneath. Pick the parts that connect to something you have actually built.
- Anchor it in your history: one project where correctness mattered more than speed (payments, inventory, bookings, audit data), what went wrong or nearly did, and what you took from it about idempotent writes, exact arithmetic or reconciliation.
- Be straightforward about finance. Candidates report that prior domain knowledge is not required for software engineers, so show that you have learned the basic flow and vocabulary well enough to ask a sensible question, without claiming experience you lack.
- Phrase the aspiration as skills you want to grow: concurrency and data-integrity design at volume, ownership of a service end to end, and a domain with strict accuracy requirements. Say why this kind of software builds those skills better than a generic backend would.
- Leave out pay, brand name and anything that would work unchanged for any backend employer. Reciting the careers page is the common failure.
Follow-up
- What do you know about what happens to a trade after it executes?
- Which of your projects is closest to this kind of work, and what would you change in it today?
- What would you want to have learned by the end of your first year in this role?
Argue against a design, lose, and commit anyway
Medium · disagreement · service boundaries · decision records
Describe a design you argued against and lost. State the failure you predicted as a named mechanism, not a feeling about complexity: two services that would need one transaction, a projection with no rebuild path, a write path with no idempotency key. Say what evidence you brought, what the decision maker weighed instead, and what you did after the decision was made: what you instrumented, what you wrote down, and whether the prediction came true. Five minutes.
Approach
- State the prediction in falsifiable form up front: the mechanism, the condition that triggers it, and the observable outcome. A prediction that cannot be checked also cannot be credited to you later.
- Show the evidence you had at the time and label each piece honestly as measured, analogous, or intuition. Keeping the intuition is fine; disguising it as data is the thing that erodes your standing in the next argument.
- Represent the opposing case at full strength, including the constraint you did not control: a fixed date, a team boundary, or the fact that the decision was cheap to reverse and yours was not.
- Make disagree-and-commit concrete. Name the artefact you left behind so the prediction could be settled without you: the alert and its threshold, the counter on the dashboard, the decision note that recorded the trade-off and the condition that would revisit it.
Follow-up
- What threshold on that alert would have proved you right, and did anyone ever look at it?
- If the same proposal arrived tomorrow with the same deadline, would you argue it the same way?