cswork / libraryOpen practice workspace

Interview guides · Algowire Trading Technologies pvt.ltd

Algowire Trading Technologies pvt.ltd Software Engineer Interview Guide

Algowire Trading Technologies pvt.ltd Software Engineer interview guide: reported rounds, questions and how candidates describe the process.

The 60-second brief

Candidate reports place Algowire Trading Technologies in the trading industry. The Software Engineer role is described as building and maintaining the software behind the firm's trading platforms, including code that processes data in real time and implements financial logic. The reported work covers C++ development, mobile services and web-based data parsing over HTTP and JSON. Candidates also describe owning features or components from requirement to delivery, plugging modules into a larger trading framework, improving existing code and building services that retrieve data. Android development, system-level services, low-latency design and unit testing are listed as useful extras rather than requirements.

This guide is for candidates interviewing for a Software Engineer position at Algowire Trading Technologies. It covers the three reported rounds (Aptitude Screening, Technical Coding Assessment and Face-to-Face Discussion), the reported questions on OOP, C++ memory and pointers, 2D matrix search, grid shortest path, complexity analysis, an Android service, an HTTP and JSON function and asynchronous data loading, plus a seven-day plan and project-discussion prompts.

Candidates report three rounds over roughly 3-5 weeks: an Aptitude Screening, a Technical Coding Assessment and a Face-to-Face Discussion. A machine test, meaning code written in a restricted environment, is also mentioned as part of the process.

Focus areas

  • C++
  • Data Structures
  • Algorithms

Overview

The reported questions fall into three groups. The first is C++ and object-oriented fundamentals: the principles of OOP, how you manage memory for performance, and how you handle pointers and references inside complex data structures. The second is algorithms on grids: optimising search over a large 2D matrix, finding a shortest path in a grid, and justifying the time and space complexity of whatever you wrote. The third is practical implementation: an Android service that updates a TextView with a random number, a function that makes an HTTP request and parses JSON, and a question on loading data asynchronously in production.

That mix tells you how to spend your time. Candidates describe the C++ requirement as strong, and the stack they list is C++ with some JavaScript, so be ready to write real C++ rather than pseudocode, and to explain why you chose a raw pointer, a reference or a smart pointer. For the grid questions, know the standard toolkit cold: breadth-first search for unweighted shortest paths, binary search or a staircase walk for sorted matrices, and the cost of the visited structure you choose.

Because candidates mention a machine test, rehearse in a restricted setting: a plain editor, a command-line compiler, no search engine and no autocomplete. Tips from candidates stress commenting and clean structure, so practise naming things clearly and leaving short comments on the non-obvious lines. The nice-to-have list (Android, system-level services, low-latency design, unit tests) is a good reason to write a few tests for every solution you practise and to be able to describe how you would measure and cut latency in a data path.

The aptitude stage comes first and candidates describe it as a filter for the later stages, so do not leave quantitative practice for the end. Put a timed set at the start of the week, and keep the habit of skipping a stuck problem and returning to it.

The Algowire Trading Technologies pvt.ltd interview process

Candidates describe three stages, in this order: Aptitude Screening, Technical Coding Assessment and Face-to-Face Discussion, with the whole process taking roughly 3-5 weeks.

Aptitude Screening

Candidates describe the Aptitude Screening as the first stage, an assessment of quantitative skills that sets a baseline, and say it decides whether you reach the technical stages. It is the round people are most tempted to under-prepare because it has nothing to do with C++. Treat it as a timed written test: practise a mixed set of quantitative problems against a clock, decide in advance how long you will give any single problem, and move on when you hit that limit. Come back to skipped items at the end.

What to demonstrate

  • Quantitative reasoning, which candidates describe as the baseline for the rest of the process
  • Accuracy and pacing across a set of problems under a clock
  • Whether you can recover from a problem you cannot solve and keep scoring elsewhere

How to prepare

  • Do a timed set of quantitative problems on paper and mark which kinds cost you the most time
  • Practise a skip-and-return routine: mark a stuck problem, move on, and revisit it only after finishing the rest
  • Rehearse mental arithmetic, percentages and ratios so routine steps do not eat your time

Technical Coding Assessment

The Technical Coding Assessment is the stage candidates describe as an in-depth check of coding ability. They also mention a machine test, where you write working code in a restricted environment without outside help, and tips from candidates say comments and readable structure matter even when the logic is right. The reported coding questions cover grid and matrix problems, complexity analysis, C++ memory and pointers, an HTTP request with JSON parsing, and an Android service. Practise writing complete programs that compile and run on the first or second attempt, in a plain editor.

What to demonstrate

  • Working, bug-free code written without an IDE or internet access
  • Algorithmic skill on grid and matrix problems, with complexity stated and edge cases handled
  • C++ fluency: standard library use, memory management and pointer handling
  • Readable code with comments on the non-obvious lines

How to prepare

  • Write a breadth-first shortest path on a grid and a search over a sorted 2D matrix in C++ with only a plain editor and a command-line compiler
  • Write a function that issues an HTTP GET and parses the JSON body, including the failure branches, then add a few unit tests
  • After each solution, write its time and space complexity and a list of edge cases (empty grid, single cell, blocked start or end, no path)
  • Re-read your code once for off-by-one errors, uninitialised variables and missed returns before calling it finished

Face-to-Face Discussion

Candidates describe the Face-to-Face Discussion as an in-person conversation that looks at problem-solving style and communication. Tips from candidates say to talk through your reasoning while you work, to be ready to discuss the technical challenges in your previous projects, and to keep OOP and data structure basics sharp. Expect to explain why you made a choice, not only what the choice was. Prepare two projects you can describe in terms of constraints, alternatives you rejected and what you would change.

What to demonstrate

  • Problem-solving style, shown by how you break a problem into steps out loud
  • Communication: explaining design and complexity choices clearly to another engineer
  • Depth on your own projects and on core topics such as OOP, memory management and data structures

How to prepare

  • Pick two projects and write down the hardest technical problem in each, the options you considered and the measurement or test that settled it
  • Practise explaining the principles of OOP using a C++ class hierarchy from your own work, not a textbook example
  • Solve one grid problem aloud with a friend, narrating assumptions, brute force, the improvement and the complexity
  • Prepare a short account of a time you handled data loading, a bug or a review comment, with the outcome you can state

Where candidates lose points

Describing C++ memory management as 'I just use smart pointers' without saying who owns what

Be able to explain stack versus heap, RAII, unique_ptr for single ownership, shared_ptr with its reference-count cost, weak_ptr to break cycles, and when a plain reference or raw non-owning pointer is the right choice. Tie each to a structure such as a linked list or tree.

Giving the nested-loop answer to the large 2D matrix search and stopping there

Ask whether rows and columns are sorted. If they are, show the staircase walk from a corner in O(m + n) or a per-row binary search in O(m log n); if not, say a full scan is O(mn) and explain what indexing or preprocessing would change that.

A grid shortest-path solution that misses blocked cells, repeated visits or the no-path case

Use breadth-first search with a queue, mark cells visited when you enqueue them, bound-check neighbours, and return a clear value when the start is blocked, the target is unreachable or the grid is a single cell. State O(rows x cols) time and space.

Treating the machine test like an IDE session, then losing minutes to syntax and missing includes

Practise in a plain editor with a command-line compiler, with no search engine. Keep a short template for headers, main and input handling, and leave brief comments, since candidates say readability counts.

Skipping the aptitude stage preparation because it is not coding

Candidates describe it as a filter for later rounds. Run timed quantitative sets early in your week, track which problem types cost time, and practise moving on from a stuck item.

Questions & practice

Describe how you manage memory in C++ to ensure performance.

Medium · Technical Foundations and C++

Approach

  1. Start with RAII: every resource is owned by an object whose destructor releases it. Use std::unique_ptr for single ownership (no overhead over a raw pointer with the default deleter), and use std::shared_ptr only when ownership really is shared.
  2. Explain what shared_ptr costs: a control block and atomic reference-count updates on every copy. std::make_shared puts the object and the control block in one allocation, and std::weak_ptr breaks reference cycles that would otherwise leak.
  3. Keep allocation off the hot path: call reserve() on vectors whose size you know, reuse buffers instead of reallocating them, and use object pools or arena/monotonic allocators (std::pmr) for many short-lived objects of the same size.
  4. Lay data out for the cache: contiguous std::vector storage beats node-based containers for iteration, struct-of-arrays layout helps when a loop reads one field, and move semantics avoids deep copies when objects are returned or inserted.
  5. Measure before and after a change: profile allocations, and run AddressSanitizer or Valgrind to find leaks, use-after-free and double frees.

Follow-up

  • What does std::vector do when push_back exceeds its capacity, and what happens to existing pointers and iterators into it?
  • How would you find a memory leak in a long-running process that only shows up after several hours?
  • When would you write a custom allocator, and what would you measure to justify it?

How do you handle pointers and references in complex data structures?

Medium · Technical Foundations and C++

Approach

  1. Decide ownership first: owning links are std::unique_ptr (tree children, the next pointer in a singly linked list), and non-owning links are raw pointers or references (a parent back-pointer, an observer). That way each node has exactly one owner.
  2. Use references for parameters and return values that can never be null. Do not use them as members that must change later: a reference cannot be reseated or be null, which makes a class with reference members non-assignable.
  3. Watch for invalidation: a pointer or iterator into a std::vector dangles after reallocation. Store indices instead, or use a container with stable element addresses (std::list, or std::deque when adding only at the ends).
  4. For graphs with cycles, store nodes in one container and represent edges as indices, or use shared_ptr for owning edges and weak_ptr for back edges. Cycles of shared_ptr never free.
  5. Cover the edge cases: a long unique_ptr chain is destroyed recursively and can overflow the stack, so write an iterative destructor. Never return a reference or pointer to a local variable. Null-check every non-owning pointer before you dereference it.

Follow-up

  • How would you deep-copy a linked list where each node also has a random pointer to any node in the list?
  • Reverse a singly linked list in place: which pointers do you need to save before relinking each node?
  • What is the difference between passing a std::unique_ptr by value, by reference, and as a raw pointer from get()?

How would you optimize a search algorithm for a large 2D matrix?

Medium · Data Structures and Algorithms

Approach

  1. Ask what is guaranteed about the matrix, because that decides the algorithm. With no ordering, a single lookup needs an O(mn) scan. If there are many lookups, build a hash map from value to positions once in O(mn), and each lookup is then O(1) on average.
  2. If every row is sorted and each row starts above the previous row's last value, treat the matrix as one sorted array of mn items. Binary search index mid maps to row mid / n and column mid % n, which gives O(log(mn)).
  3. If rows and columns are each sorted but rows overlap, use the staircase search. Start at the top-right cell: move left if the value is greater than the target and down if it is smaller. That is O(m + n). Running a binary search on each row costs O(m log n) instead, which is better when there are far fewer rows than columns.
  4. For large inputs, store the matrix as one contiguous row-major array and traverse it in row order for cache locality. Compute mid as lo + (hi - lo) / 2, and use 64-bit indices when m*n can exceed the int range.
  5. Edge cases: an empty matrix or empty rows, a target smaller than the first cell or larger than the last, duplicates (say whether you return any match or the first), and a 1 x n or m x 1 shape.

Follow-up

  • In a matrix with sorted rows and columns, how would you count the elements less than or equal to a value, and then find the k-th smallest?
  • How does your approach change if the matrix is too large for memory and is stored in row blocks on disk?
  • What changes if the matrix is updated between queries?

Solve a problem involving finding the shortest path in a grid.

Medium · Data Structures and Algorithms

Approach

  1. Clarify the model: 4- or 8-directional moves, which cells are blocked, and whether every move costs the same. For unit costs, BFS from the start finds the shortest path. Mark a cell visited when you enqueue it, not when you dequeue it, so no cell enters the queue twice.
  2. Complexity is O(RC) time and O(RC) space for the visited/distance array and the queue. Return -1 when the target is never reached, and keep a parent array if the path itself is required, not just its length.
  3. For non-negative cell weights, switch to Dijkstra with a min-heap, O(RC log(RC)). When weights are only 0 or 1, 0-1 BFS with a deque (0-cost edges pushed to the front) gives O(RC). With a single target, A with a Manhattan-distance heuristic is admissible for 4-directional unit moves.
  4. For variants, add state to the search: 'may remove up to k obstacles' becomes BFS over (row, col, removals left), O(RCk). 'Distance from every cell to the nearest exit' becomes a multi-source BFS that starts from all exits at once.
  5. Edge cases: start or target blocked, start equal to target (distance 0), a 1x1 grid, bounds checks before indexing, and grids large enough that recursion-based DFS would overflow the stack (DFS does not give shortest paths anyway).

Follow-up

  • How would you change the search if you may break through at most k walls?
  • How would you return the actual path, and how much extra memory does that need?
  • If many start/target queries hit the same static grid, what would you precompute?

How do you determine the time and space complexity of your algorithmic solution?

Medium · Data Structures and Algorithms

Approach

  1. Name the input-size variables first (n, or m and n for a grid) and count how often the dominant operation runs as a function of them. Nested loops multiply, sequential blocks add, and constants and lower-order terms are dropped.
  2. For recursion, write the recurrence and solve it. T(n) = 2T(n/2) + O(n) is O(n log n) by the master theorem, binary search's T(n) = T(n/2) + O(1) is O(log n), and naive Fibonacci recursion is exponential until memoisation makes it O(n).
  3. Count hidden costs inside library calls: std::map operations are O(log n), unordered_map is O(1) on average but O(n) in the worst case, substr and string concatenation copy O(k) characters, and std::sort is O(n log n).
  4. Use amortised analysis where it applies: vector push_back with geometric growth is amortised O(1) even though a single push can copy every element.
  5. Separate auxiliary space from input space, and count the recursion stack. A recursive DFS over an R x C grid can go O(R*C) frames deep. Keep both variables in the answer, for example O(m + n) rather than O(n).

Follow-up

  • What is the difference between amortised, average-case and worst-case complexity? Give an example of each.
  • Why can no comparison-based sort beat O(n log n) in the worst case?
  • Your solution is O(n log n) but slower than an O(n^2) one on small inputs: why can that happen?

Stop tag and share joins from fanning out a page

Medium · join fan-out · semi-joins · many-to-many

resource_tag is (resource_id, tag_id) with PK (resource_id, tag_id); resource_share is (resource_id, shared_with_user_id, permission). The tagged-and-shared listing inner-joins resource to both, filters tenant_id, tag_id = ANY($2) and shared_with_user_id = $3, orders by updated_at DESC and takes 50. Pages come back with fewer than 50 distinct resources and the total in the header is far too high. Explain the row multiplication, rewrite both the page query and the count query so each is correct, and name the index each one needs. PostgreSQL 16.

Approach

  1. Do the arithmetic against the predicates that are actually there. An inner join emits one row per matching child row, and both joins are filtered: tag_id = ANY($2) admits only the requested tags, shared_with_user_id = $3 admits one user's share rows. So a resource holding three of the requested tags and shared with $3 once yields three rows, not one — the multiplier is its count of matching tags times its share rows for that single user, and that second factor is 1 unless the table admits duplicate (resource_id, shared_with_user_id) pairs. LIMIT 50 then limits rows rather than resources, and COUNT(*) counts pairs — the header is the product, not the population.
  2. Reject DISTINCT as the fix. It deduplicates after the product has been built, so the planner must materialise and sort the fanned-out set before the LIMIT can apply, and it leaves any SUM or AVG in the same select list wrong.
  3. Rewrite both filters as semi-joins, keeping resource as the only row source: AND EXISTS (SELECT 1 FROM resource_tag rt WHERE rt.resource_id = r.resource_id AND rt.tag_id = ANY($2)) and the same shape against resource_share. A semi-join stops at the first match per resource and preserves the driving index order, so ORDER BY updated_at DESC, resource_id DESC LIMIT 50 still stops after 50 rows.
  4. Count with the same predicates and no join at all: SELECT count(*) FROM resource r WHERE r.tenant_id = $1 AND r.status = 'active' AND EXISTS (...) AND EXISTS (...). Nothing multiplies a resource, so the number is the population.

Follow-up

  • The filter changes from 'any of these tags' to 'all of these tags'. Rewrite it and state what it costs relative to the ANY form.
  • A resource can be shared with the same user twice under different permissions. Does your count change, and should it?

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

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

Explain the core principles of OOPs and how you implement them in your projects.

Medium · Technical Foundations and C++

Approach

  1. Name the four principles and give each a C++ mechanism: encapsulation (private data plus member functions that keep an invariant true), abstraction (an abstract base class with pure virtual functions as the interface), inheritance (public derivation for is-a relationships), polymorphism (virtual dispatch at runtime, templates and overloading at compile time).
  2. Anchor each one in a project: for example, an OrderBook class whose fields are private, so prices can only change through methods that keep bids sorted, and an abstract FeedParser interface with one subclass per message format.
  3. Explain what runtime polymorphism costs: each polymorphic object carries a vtable pointer, and a virtual call is an indirect call the compiler usually cannot inline. On a hot path, I would consider CRTP or templates for static dispatch instead.
  4. State the rules that prevent real bugs: give a polymorphic base class a virtual destructor, pass polymorphic objects by reference or pointer to avoid slicing, and use override so a signature mismatch fails at compile time.
  5. Say when you would skip inheritance: prefer composition when the relationship is has-a, or when a subclass would have to break the base class contract (the Liskov substitution principle).

Follow-up

  • What happens when you delete a derived object through a base pointer whose destructor is not virtual?
  • How does the diamond problem arise with multiple inheritance in C++, and what does virtual inheritance change?
  • When would you choose templates over virtual functions for polymorphism, and what does that cost you?

Create an Android service that updates a TextView with a random number.

Medium · Practical Implementation and Web/Mobile

Approach

  1. Point out the threading rule first: a Service's callbacks run on the main thread by default, and only the main thread may touch a TextView. Updating it from another thread throws CalledFromWrongThreadException.
  2. Use a bound service for UI updates: the Activity binds in onStart and unbinds in onStop, and the service exposes a LocalBinder plus a LiveData/StateFlow (or a callback interface) that emits each new number. The Activity observes it and calls setText on the main thread.
  3. Generate the numbers on a schedule with Handler(Looper.getMainLooper()).postDelayed or a coroutine loop with delay(), using kotlin.random.Random or java.util.Random. Cancel the loop in onDestroy so it does not keep running after the service stops.
  4. Avoid leaks: the service must not hold a strong reference to the Activity after unbind, so clear the callback. Survive rotation by keeping the latest value in a ViewModel, or by rebinding and reading the current value.
  5. Know the platform limits: declare the service in the manifest. If it must keep running while the app is in the background, Android 8+ requires a foreground service with a notification, and Android 14 also requires a declared foreground service type.

Follow-up

  • What changes if the service runs in a separate process (Messenger or AIDL)?
  • How would you keep the number updating while the app is in the background, and what does the user see?
  • How would you unit-test the number-generation logic separately from the Android framework?

Write a function to perform an HTTP request and parse the resulting JSON data.

Medium · Practical Implementation and Web/Mobile

Approach

  1. Pick a language and say so. In JavaScript, write an async function that awaits fetch(url) and checks response.ok before parsing, because fetch rejects only on network failure, not on 4xx or 5xx status codes. Then call await response.json(), which throws a SyntaxError on invalid JSON.
  2. In C++, use libcurl with a write callback that appends chunks to a std::string, check the CURLcode and the HTTP status, then parse with nlohmann::json::parse. Either catch its parse_error, or pass allow_exceptions=false and test is_discarded().
  3. Add a timeout (AbortController or AbortSignal.timeout in JavaScript, CURLOPT_TIMEOUT in libcurl). Retry only idempotent requests, and only on network errors, 5xx or 429, with exponential backoff that honours Retry-After. Never retry on other 4xx errors.
  4. Validate the shape before using the data: required fields present, types as expected, and empty bodies (204) or a non-JSON content type handled explicitly. Return a typed result or a clear error rather than a half-filled object.
  5. Mention the edge cases: integers above 2^53 lose precision in JavaScript numbers (read them as strings or BigInt), very large payloads need a streaming parser, and character encoding should be handled as UTF-8.

Follow-up

  • The API is paginated with a cursor: how would you fetch every page without loading everything into memory?
  • How would you test this function without calling the real endpoint?
  • The server starts returning 429 responses: what does your client do?

Exports duplicate a row range about once a week

Hard · leases · clock skew · idempotency

Roughly once a week an export writes a file containing a duplicated range of rows. The affected job_run rows show attempt = 1, status = succeeded, one started_at, and a lease_owner naming a different host from the one whose logs show the job starting. Leases last 30 seconds and are heartbeated every 10 from inside the handler; lease_expires_at is computed on the worker and compared against the database's now(). Find the mechanism, and give a fix that holds even if you cannot fix the clocks.

Approach

  1. Start from the fact that eliminates the obvious answer. attempt = 1 means no retry was recorded, so this is not a re-run after failure; two workers ran the same row concurrently and the takeover path never touched the counter. lease_owner naming a host other than the one that started the job is the same statement from the other side.
  2. Enumerate the mechanisms that cause a premature takeover, then find the signal that separates them. Either the lease genuinely expired because the heartbeat did not fire, which is what happens when the heartbeat runs on the handler's own thread and the handler makes a long blocking call, or it only appeared expired because two clocks disagree, since lease_expires_at is written from the worker's clock and evaluated against the database's. The discriminator is the distribution: incidents clustered on the longest exports indict the heartbeat, incidents clustered on one host indict skew. Measure both, and measure each host's offset against the database directly.
  3. Read the reclaim query precisely. In PostgreSQL now() is transaction start time, not statement time, so a reclaimer holding a long transaction compares against an older timestamp than expected; clock_timestamp() is the statement-time function. This is worth ruling in or out before you redesign anything, because it changes which rows look expired.
  4. Remove the second clock rather than trying to synchronise it. Issue and extend the lease in the database, with lease_expires_at = now() + interval '30 seconds' in both the claim and the heartbeat, so exactly one clock is ever compared and worker skew stops mattering to this predicate.

Follow-up

  • The displaced worker has already streamed half the file to object storage. What makes that side effect safe to repeat?
  • You now count takeovers. What alert fires on that counter, and at what threshold?

Suggested practice checklist

The plan follows the reported loop: a timed aptitude baseline first, then C++ foundations, grid algorithms, complexity and the practical HTTP, JSON and Android tasks, ending with a project and production-story rehearsal. Each day produces something you can check.

Day 1 — Aptitude baseline and loop map

  • Write the three reported rounds in order and one line on what each covers
  • Do a timed set of mixed quantitative problems and record which ones you skipped or got wrong
  • List your weakest topics across the whole loop and rank them

Deliverable: A one-page loop map plus a scored aptitude attempt with a ranked weak-topic list.

Day 2 — C++ memory, pointers and references

  • Write a small singly linked list or binary tree in C++ twice: once with raw owning pointers and once with unique_ptr, and note what changed
  • Write short notes on stack versus heap, RAII, shared_ptr cost, weak_ptr cycles and iterator invalidation
  • Say aloud how you would reduce allocations in code that handles a stream of market-style records

Deliverable: Two working C++ implementations and a one-page ownership cheat sheet, plus a spoken answer for each of the memory and pointer questions.

Day 3 — OOP principles with C++ examples

  • Write one example each for encapsulation, abstraction, inheritance and polymorphism, including a virtual destructor and an override
  • Explain composition versus inheritance and when you would pick each
  • Map each principle to a piece of code from one of your own projects

Deliverable: A small C++ program showing the four principles and a rehearsed spoken answer that cites your own project.

Day 4 — Grid and matrix algorithms

  • Implement a search over a row-sorted and column-sorted matrix using the staircase walk, then a variant using binary search per row
  • Implement breadth-first shortest path on a grid with obstacles, returning the length or a clear no-path result
  • Test both with empty, single-cell, blocked and no-path inputs

Deliverable: Two compiled C++ solutions with a test list of edge cases that you ran.

Day 5 — Complexity analysis and edge cases

  • Write the time and space complexity for each day-4 solution and justify each term
  • Practise explaining how to derive complexity for loops, recursion and a queue-based traversal aloud
  • Compare the brute-force and improved version of the matrix search with operation counts on a large input

Deliverable: A complexity table for your solutions and a recorded spoken explanation of how you determine it.

Day 6 — HTTP, JSON and the Android service

  • In a plain editor, write a function that performs an HTTP GET, checks the status, parses the JSON and handles timeouts and malformed bodies
  • Outline an Android Service that generates a random number on a schedule and passes it to an Activity that sets a TextView on the main thread
  • Write three unit tests for the parsing function

Deliverable: A working HTTP and JSON function with tests and a written outline of the Android service and its UI update path.

Day 7 — Production story and full rehearsal

  • Write and rehearse your asynchronous data loading story: problem, mechanism, safeguards, measured result
  • Do a final run: one timed grid problem solved aloud in a plain editor, then two project questions

Deliverable: A written story outline, a recorded run of the practice incident narration and one timed full solution with spoken reasoning.

Project discussion and production stories

Candidates describe the Face-to-Face Discussion as a look at problem-solving style and communication, and tips from candidates say to be ready to discuss the technical challenges of your past projects. Prepare stories where you made the call and can state what you measured, and be ready to explain your reasoning in plain terms.

  1. Walk me through the hardest technical problem in one of your projects and how you solved it.
  2. Tell me about a memory, pointer or lifetime bug you traced to its cause, and how you confirmed the fix.
  3. Describe a time you were stuck on a problem and how you made progress.
  4. Tell me about a code review comment you disagreed with and how it ended.

How do you handle asynchronous data loading in a production environment?

Medium · Practical Implementation and Web/Mobile

Approach

  1. Choose one concrete production case you personally handled, such as a screen or service that fetched data from a slow API, and state the problem in two sentences: what was blocking, who was affected and what you were asked to change. Spend the rest of the answer on your decisions.
  2. Name the mechanism you used: non-blocking I/O with callbacks, promises or async/await, or worker threads with futures. The point is that the thread serving the user or the hot path never waits on the network. Say how results reach the caller, for example posting back to the main thread in a mobile app.
  3. Cover correctness under concurrency: cancel requests that are no longer needed (AbortController in JavaScript, lifecycle-aware cancellation on Android), ignore stale responses with a request token so an old reply cannot overwrite a newer one, and show loading, empty and error states instead of a frozen screen.
  4. Cover reliability: timeouts on every call, bounded retries with exponential backoff and jitter only for idempotent requests, pagination or batching for large payloads, and a bounded queue so a slow source cannot grow memory without limit.
  5. Close with evidence: the metric you watched (latency percentiles, error rate, queue depth), the before and after numbers, and one thing you would change next time. Avoid a tour of library APIs with no incident behind it, and avoid claiming an improvement you did not measure.

Follow-up

  • How do you stop an old response from overwriting a newer one when two requests are in flight?
  • What do you retry, and what must never be retried automatically?
  • How would you find out the loading change caused the improvement and not something else?

Tell callers you do not own that their integration breaks

Medium · deprecation · compatibility · stakeholders

A field in a write endpoint's response must change shape. You own the endpoint; you do not own the four internal callers or the outbound webhook consumers who read it. Describe a deprecation you were responsible for: what you shipped first, how you established who was actually reading the field, the window you gave and what set its length, what you did about the consumer who never moved, and how you decided removal was safe. Name the signal you used, not the announcement you sent.

Approach

  1. Establish the reader set empirically rather than from a wiki of owners: per-field usage counters keyed by principal, or access logs attributed to a consumer. State the blind spot of whichever you pick, since a consumer that reads the field only on a monthly job will not appear in a week of logs.
  2. Ship additive first. Populate the new field alongside the old one so no reader is forced to move, which is also what keeps a rolling deploy safe, because old and new instances answer the same requests at the same time and a rollback must still find the old shape present.
  3. Set the window from the slowest legitimate consumer's release cadence, not from your calendar, and decide separately what to do for a consumer with no release process at all, such as an external webhook endpoint you can only email.
  4. Convert silence into evidence before you rely on it: a short, low-traffic removal window that makes a still-dependent consumer fail visibly and loudly while you are watching, rather than at three in the morning after you have moved on.

Follow-up

  • How would you detect a consumer that reads the field only during a monthly export?
  • One caller refuses to move and has a commercial relationship behind it. What changes in your plan and what does not?

Narrate an outage you owned from page to postmortem

Hard · incident response · blast radius · postmortems

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?