Interview guides · Canopy
Canopy Software Engineer Interview Guide
Canopy Software Engineer interview guide: five reported rounds, schema, SQL, REST API and pairing questions, plus behavioral stories to rehearse.
The 60-second brief
Candidates describe Canopy as a company that builds software tools. The reports name no specific product, customer or team, so this guide does not guess at one. For the Software Engineer role, candidates describe work across backend architecture, database performance and user-facing features. They also describe design reviews, pair programming, and regular contact with product managers and engineering leaders. The requirements candidates list include one major programming language, SQL and database design, and building and consuming REST APIs. Experience with AI and RAG systems and with microservices is listed as a plus.
This guide is for engineers preparing for the Canopy Software Engineer loop. It covers the five reported rounds, the technical questions candidates report (a library database schema, SQL for overdue books, a REST API over that schema, JavaScript scope versus context, troubleshooting, a parking structure program, a gift exchange program, a Fibonacci lookup, and an AI and RAG motivation question) and the four behavioral prompts reported alongside them. It also gives a seven-day plan that sequences all of it.
Candidates report five rounds over roughly 4-6 weeks, running from an initial screening through technical and behavioral assessments and collaborative panels to a virtual onsite that can include pair programming.
Focus areas
- Behavioral Interviewing
- Conflict Resolution with Management
- Database Design (Relational)
Overview
The work candidates describe is full-lifecycle product engineering: taking a feature from requirements through design, implementation and peer review. That includes backend structure, database performance and user-facing changes, with a good deal of time spent pairing or debugging existing systems. The preparation that follows from this is practical. You need to produce correct, readable code and a sensible data model while talking through your choices.
The reported technical questions cluster around a few things. Three of them read as one scenario: design a schema for a library (users, books, loans), write SQL against it such as finding overdue books with date functions, then design a REST API that sits on top of that schema. Practise them as a chain, because the API you outline should match the tables you drew. The rest of the technical set is smaller: JavaScript scope versus context, a troubleshooting approach, a parking structure with large, medium and small spaces, a gift exchange with a no-mutual-gifts rule, and finding a Fibonacci number from an index. Candidates describe the emphasis as database design, API structure and language fundamentals rather than competitive-programming algorithms, so spend your time on clean modelling, edge cases and tests.
Four behavioral prompts are reported: a conflict with a manager, a missed project estimate, difficulty respecting a colleague, and handling code review feedback. Candidates also report that the process leans on pairing and design discussion, so your explanation while you work matters as much as the final code. Rehearse by speaking, with a partner if you can, and keep your stories ready in a structured form.
One reported question asks why you are interested in AI and RAG systems. Candidates list that experience as a plus rather than a requirement, so prepare an honest, specific answer based on what you have built, read or tried. Do not invent a project you have not done.
The Canopy interview process
Candidates report five rounds over roughly 4-6 weeks. The reports name the rounds but not which questions come up in each, so the sections below pair each round's format with the preparation that fits it.
Initial Screening
Candidates report the opening stage as an initial screening that checks qualifications. The reports give no further detail on its format or on who runs it. Treat it as the point where your background gets matched against the listed requirements: proficiency in one major language, SQL and database design, and REST API experience. Expect to be asked about your own work, so have a short, concrete account ready for each.
What to demonstrate
- Your qualifications measured against the listed requirements for the role
- How clearly you summarise your background and recent work
- Whether your language, SQL and API experience is concrete rather than a list of keywords
How to prepare
- Write a two-minute summary of your career built around three headings: your main language, SQL and database design, and REST APIs. Attach one real project to each heading.
- Prepare a short, honest reason for choosing Canopy based on the work the role describes (backend structure, database performance, user-facing features), not on guesses about the product.
- Ask in this stage which language you may use in later coding sessions, since the reports do not say.
Technical Assessment
Candidates describe a series of technical evaluations. The emphasis they report is on practical engineering: database design and normalization, RESTful API design and language-specific features such as JavaScript scope, rather than puzzle-style algorithms. The reports do not say which round each technical question belongs to, so prepare the whole technical set. A technical stage is where written code, a query or a schema gets judged on whether it runs and handles edge cases.
What to demonstrate
- Working code or queries, including syntax and edge-case handling
- Relational schema design: keys, relationships, normalization
- API design that follows from the data model
- Language fundamentals such as scope and context in JavaScript
How to prepare
- Do the library chain end to end in one sitting: schema for users, books and loans, then the overdue-books query, then the REST endpoints. Check that each step matches the one before.
- Write the overdue query against real sample data and test the cases where a loan has been returned, is due today, or has no due date set.
- Write three small JavaScript examples that separate scope (which variables a function can see) from context (what this refers to), including a callback that loses its context.
- Build a repeatable troubleshooting sequence and rehearse it aloud on a real incident from your own work.
Behavioral Assessment
Candidates report that this stage covers behavioral interviews on communication and team fit. The topics they list are conflict with leadership, managing expectations when a project goes off plan, and giving and receiving technical feedback. The four reported prompts map directly to these topics. This is a stage where prepared stories do most of the work, so decide your stories before the loop begins and practise them aloud.
What to demonstrate
- How you describe and resolve disagreement with a manager or colleague
- How you communicate when a plan or estimate slips
- How you give and receive technical feedback, for example in code review
How to prepare
- Write three or four stories in Situation, Task, Action, Result form. Between them they should cover a conflict with a manager, a missed estimate, a colleague you struggled to respect, and a code review disagreement.
- For each story, write the single decision you personally made and the outcome, including any part that did not go well.
- Say each story aloud and trim it until the situation takes two or three sentences and most of the time goes to your actions and reasoning.
Collaborative Panels
Candidates describe collaborative panels as sessions that simulate real work scenarios, and report that the wider process leans on pairing exercises and design discussion. The reports do not list the questions asked here. The reported design and small-program questions (the parking structure, the gift exchange rules, the library API) are good material to rehearse as a conversation with a colleague rather than a monologue.
What to demonstrate
- Collaboration: working a problem through with several people
- Structuring data and services cleanly, including how entities relate
- Handling stated constraints in a simulated work problem
How to prepare
- Talk through the parking structure problem aloud: list the vehicle and space types, decide what the objects are, and say what happens when the preferred space size is full.
- Work the gift exchange rules out loud: state your assumptions about who gives to whom, how you rule out mutual pairs and self-assignment, and what you do when no valid assignment exists.
- Practise stopping to ask a clarifying question before you start, and ask for the other person's view at a design fork.
Virtual Onsite Experience
Candidates report that, depending on the role, the virtual onsite can include pair programming, and the process overview also mentions design reviews. This may not apply to every role, so confirm the format with your recruiter. Prepare to write and run code in a shared editor while explaining your reasoning, and to stay engaged across a longer session.
What to demonstrate
- Producing working code while collaborating live over video
- Explaining your reasoning as you go
- Staying consistent across a longer, more intensive session
How to prepare
- Hold at least one mock pairing session with a friend over video and a shared editor, solving a small problem such as the Fibonacci lookup or the parking structure while narrating.
- Have your answer to why you are interested in AI and RAG systems ready, built from work you have really done or studied.
- Prepare your setup in advance: editor, language runtime, tests and a quiet connection, so that the session time goes to the problem.
Where candidates lose points
Drawing the library schema and the REST API as unrelated answers, for example a book row with a borrower column that cannot hold loan history
Model users, books and loans as separate tables with a loan carrying its checkout date, due date and return date, and keys between them. Then derive the endpoints from those entities and say which tables each one reads or writes.
Writing the overdue-books query so that it also lists books that were already returned, or that breaks on loans due today
Decide the rule first: a loan is overdue when it has no return date and its due date is before today. Write the query from that sentence, then test it on loans that are returned, due today and not yet due.
Starting the parking structure or the gift exchange with code before the rules are pinned down
Spend the first minutes asking questions: what happens when the preferred size is full, whether everyone gives and receives exactly one gift, whether self-assignment is allowed, and what to do if no valid assignment exists. Write your assumptions down, then code.
Going quiet while typing in a pairing or panel session
Narrate what you are about to do and why, say aloud where you are stuck and what you will try next, and invite the other person's opinion at each design choice. Practise this in a mock session before the loop.
Telling a conflict or missed-estimate story where someone else is the cause and you have no part in it
Choose stories in which you made a decision and can name what you got wrong. Cover the situation briefly, spend most of the time on your actions and reasoning, and end with the specific change you made afterwards.
Questions & practice
Archive a resource graph without breaking live references or recursing
Medium · graph traversal · topological order · tenant isolation
Resources reference other resources within a tenant; for the largest tenant the reference table holds up to 2,000,000 nodes and 8,000,000 edges. Archiving a resource must archive everything reachable from it that nothing outside the set still references, refuse when a live external referrer exists, and terminate when references form cycles, which they legitimately do. Produce the archive order and the refusal list, targeting O(V+E). Say what stops the traversal crossing a tenant boundary, and why recursion is the wrong control structure at this size.
Approach
- Load the subgraph with the tenant predicate on both endpoints of the edge, not only on the side you started from. Scoping the left table alone is the classic cross-tenant leak: one mis-entered edge then pulls another tenant's resources into the traversal and, worse, into the archive.
- Traverse iteratively with an explicit stack. A 2,000,000-node graph can hold a chain deep enough to exhaust a native stack in the low tens of thousands of frames, and that failure is a process crash rather than an error you can return.
- Treat cycles as data rather than corruption: compute strongly connected components with Tarjan in O(V+E) using its own explicit stack, then condense. The condensation is a DAG, so a topological order over it gives the archive order, and every member of a component archives in one transaction because no order within a cycle is valid.
- Decide refusals with reverse edges. A candidate is archivable only if every in-edge originates inside the candidate set, so build the transpose or count in-degrees restricted to the visited set, and emit each blocked resource with the id of the external referrer, which is the only part of the answer an operator can act on.
Follow-up
- The graph is read in one query and the archive writes a minute later. What can change in between, and how do you make the write safe?
- The candidate set is 400,000 resources. Is that one transaction, and if not, what does a half-finished archive look like to a reader?
Identify the heaviest tenants in a five-minute window under memory pressure
Medium · top-k · heavy hitters · streaming
The edge service handles about 3,000 requests per second across roughly 50,000 tenants, peaking near 9,000. Expose the 50 heaviest tenants by request count over the trailing five minutes so limits can be tightened before one tenant's backfill starves the fleet. You may not retain five minutes of raw records. Give the exact solution and its memory, then the bounded-memory approximation with its error stated as a formula, and say which you would ship and at what tenant cardinality that choice changes.
Approach
- Do the exact version first, because it is affordable at this cardinality: a ring of 300 one-second counters per tenant, advanced lazily, is 1,200 bytes of counters per tenant and roughly 60 to 90 MB for 50,000 tenants with overhead. Carry a running total and subtract the bucket you overwrite so a window read is O(1) rather than 300 adds.
- Extract the top 50 with a size-k min-heap over the tenant sums: O(d log k) for d tenants, against O(d log d) to sort them all. Maintaining the heap continuously instead of on query requires a tenant-to-heap-index map, because incrementing a count already inside the heap means sifting from a known position, and without that map you rebuild the heap on every request.
- State the approximation precisely rather than gesturing at sketches. Misra-Gries with m counters retains every item whose true count exceeds N/(m+1), and each retained count underestimates the truth by at most N/(m+1). With m = 1,000 and N = 900,000 requests in the window the error is roughly 900 requests, which is fine for spotting a tenant sending 50,000 and useless for ranking two tenants 200 apart.
- Say what breaks when the window slides: Misra-Gries and Space-Saving are insert-only and cannot be decremented as records age out. The workable construction is one summary per sub-window, say ten seconds, with 30 summaries merged at query time, and the merged error is the sum of the per-summary errors, so the bound degrades linearly in the number of sub-windows.
Follow-up
- The heaviest tenant is heavy because of one export job rather than user traffic. Should the limiter treat those as the same tenant?
- Two tenants sit tied at the boundary of the top 50. Does your answer flap, and does the flapping matter?
Diff a projection against the primary without per-row point reads
Hard · reconciliation · range hashing · throttling
The listing projection has drifted and some rows show a stale version. The primary holds 40,000,000 resource rows across 12,000 tenants while serving 1,200 writes and 14,000 reads per second. The obvious repair, reading each resource row and comparing its version against the projection, is correct and would eventually finish. Explain precisely why it is unacceptable here, then give a diff that finds the differing rows, state its complexity, and make it safe to run against a live primary. Replication lag is usually under 100 ms and is not bounded.
Approach
- Quantify the naive cost rather than calling it slow: 40,000,000 point reads at even 0.5 ms each is over five hours serialised, and the only lever is concurrency, which is exactly what you cannot spend. The primary's pool is sized for the write path, and 40,000,000 random reads evict the buffer cache that sustains the 85 percent cache hit rate, so the audit degrades the system it is auditing.
- Replace random access with one ordered pass per side. Both sides can be read in (tenant_id, resource_id) order, which is a sequential scan on each and a merge join in O(n) time and O(1) memory. For a dense diff that is the whole answer, and it reads the primary once instead of 40,000,000 times.
- For the expected sparse case, compare range hashes instead of rows: partition the key space, compute per range an order-independent aggregate over hash(resource_id, version), compare aggregates, and descend only into ranges that differ. With d differing rows and branching factor B, at most d ranges mismatch per level, so the drill-down examines O(d log_B(n/d)) ranges and reads full rows only in mismatching leaves.
- Aggregate with a sum modulo 2^64 or a multiset hash, never XOR. XOR is order-independent but self-cancelling, so two rows wrong in the same way, or a row duplicated on one side, leave the range aggregate matching and the range is declared clean.
Follow-up
- The diff reports 900 stale rows. How do you decide between patching those rows and rebuilding the projection from resource_revision?
- Same job, but the projection lives in a search index that cannot be scanned in key order. What changes?
Write SQL queries to retrieve specific data, such as finding overdue books using date functions.
Medium · Technical & Domain Knowledge
Approach
- Query shape: start from loans, filter to open and late rows, then join outward.
SELECT u.name, b.title, l.due_at, CURRENT_DATE - l.due_at AS days_overdue FROM loans l JOIN users u ON u.id = l.user_id JOIN copies c ON c.id = l.copy_id JOIN books b ON b.id = c.book_id WHERE l.returned_at IS NULL AND l.due_at < CURRENT_DATE. - Know the date function per dialect. In Postgres, date minus date returns an integer number of days, and timestamp minus timestamp returns an interval (use
::dateor EXTRACT). In MySQL, useDATEDIFF(CURDATE(), due_date). UseCURRENT_DATE - INTERVAL '30 days'for rolling windows. - Keep the filter sargable. Compare the raw column (
due_at < CURRENT_DATE) instead of wrapping it in a function, so a partial index on due_at WHERE returned_at IS NULL can serve it. - State the edge cases explicitly. A book due today is not overdue. Loans returned late are a different question (
returned_at > due_at). With timestamps, time zones matter. For per-member counts, use GROUP BY with HAVING, and a LEFT JOIN when members with zero overdue loans must still appear.
Follow-up
- List members with more than two overdue books, including how many days the oldest one is late.
- Find books that have never been borrowed: would you use LEFT JOIN ... IS NULL or NOT EXISTS, and why?
- Compute a fine of a fixed amount per day overdue, capped at a maximum, in a single query.
Find version gaps and relay lag with window functions
Medium · window functions · event tables · frame semantics
outbox_event holds event_id, aggregate_type, aggregate_id, aggregate_version, event_type, payload, status ('pending','published','dead'), attempts, created_at, published_at. A projection is missing rows and you must decide whether the relay skipped events or the consumer dropped them. Write three queries over the last seven days: one listing every aggregate_id whose published aggregate_version sequence has a hole, one giving per-day counts with a running total, and one returning the newest published event per aggregate. For each, say where the window function is evaluated relative to WHERE and LIMIT. PostgreSQL 16.
Approach
- Gaps: compute lead(aggregate_version) OVER (PARTITION BY aggregate_id ORDER BY aggregate_version) in a subquery, then filter next_version <> aggregate_version + 1 in the outer query. Window functions are evaluated after WHERE, GROUP BY and HAVING and before the outer ORDER BY and LIMIT, so the predicate cannot sit in the same WHERE clause and PostgreSQL 16 has no QUALIFY.
- Say what the seven-day filter does to the answer: it truncates every partition, so the first row per aggregate has no predecessor inside the window and a hole spanning the boundary is invisible. Widen the window, or join to resource.version as the authority for the true maximum.
- Running total: SELECT date_trunc('day', created_at) AS d, count() AS n, sum(count()) OVER (ORDER BY date_trunc('day', created_at) ROWS UNBOUNDED PRECEDING). An aggregate inside a window call is legal because grouping runs before windowing. The grouping key is unique per row here so ROWS and RANGE agree, but write the frame anyway — over ungrouped rows with tied timestamps the default RANGE frame pulls in every peer row and the total jumps.
- Newest per aggregate: DISTINCT ON (aggregate_id) ... ORDER BY aggregate_id, aggregate_version DESC is the cheap PostgreSQL-only form when an index matches that order; row_number() OVER (PARTITION BY aggregate_id ORDER BY aggregate_version DESC) = 1 is the portable form and needs a subquery for the same evaluation-order reason as the gap query.
Follow-up
- Relay failover redelivers events. Does a duplicate break the gap query, and how would you detect one from this table alone?
- Turn the gap check into a continuous monitor rather than a query someone runs after an incident. What does it watch?
What is the difference between scope and context in JavaScript?
Medium · Technical & Domain Knowledge
Approach
- Separate the two terms up front: scope is lexical and fixed by where the code is written, and it decides which variables an identifier resolves to. Context is the value of
this, and it is decided by how the function is called. - Scope details:
varis function-scoped and hoisted (initialised to undefined), whilelet/constare block-scoped and sit in the temporal dead zone until declared. Inner functions close over outer variables, which is what a closure is. - Context rules in order:
newbindsthisto the new object;call/apply/bindset it explicitly;obj.method()binds it to obj; a plain call gives undefined in strict mode (and in class bodies) or globalThis in sloppy mode. - Arrow functions have no
thisof their own. They take it lexically from the enclosing scope, which is the one point where the two concepts meet. That is why arrows fix callbacks but are a poor choice for object methods that needthis. - Edge case to show:
setTimeout(obj.method)orconst f = obj.method; f()loses the receiver. I fix it withobj.method.bind(obj)or a wrapping arrow. I also mention that the spec's "execution context" is a separate, broader term.
Follow-up
- What does
thisrefer to inside a method passed directly as an event handler or to setTimeout, and how would you fix it? - If a function is bound with
bindand then called withnew, whichthiswins? - Why does a loop that schedules callbacks with
var iprint the same value every time, and why doeslet ifix it?
Design a database schema for a library system (users, books, loans).
Medium · Technical & Domain Knowledge
Approach
- Start with entities and cardinality: users, books at title level (isbn, title), physical copies (copy_id, book_id FK, barcode), and loans. Authors go in their own table with a book_authors join table, because the book-author relationship is many-to-many.
- Loans: id, copy_id FK, user_id FK, borrowed_at, due_at, returned_at NULL. An open loan is
returned_at IS NULL. Keeping one row per loan preserves history, so I would not overwrite a status column on the copy. - Enforce the invariants in the database: in Postgres,
CREATE UNIQUE INDEX ON loans(copy_id) WHERE returned_at IS NULLallows only one open loan per copy.UNIQUE(email)on users,CHECK (due_at > borrowed_at), and ON DELETE RESTRICT on loan foreign keys so history cannot be orphaned. - Indexes follow the queries: loans(user_id) for a member's loans, and a partial index on loans(due_at) WHERE returned_at IS NULL for overdue lookups. I normalise to 3NF and only denormalise (an available-copies count, say) if a measured read path needs it.
- Edge cases to raise: one title with many copies, lost or damaged copies (a copy status column), deleting a member who has loan history (soft delete), and per-member loan limits. A CHECK constraint cannot count rows, so the limit belongs in the checkout transaction.
Follow-up
- How would you add holds or reservations, with a queue per title when every copy is out?
- Where would you store fines, and would you compute them on the fly or persist them?
- How do you enforce a maximum number of open loans per member without a race between two checkouts?
Design a REST API to support your database schema.
Medium · Technical & Domain Knowledge
Approach
- Map resources to the schema: /users, /books, /books/{id}/copies and /loans, with nested reads such as GET /users/{id}/loans?status=overdue. Nouns in paths and verbs in HTTP methods.
- Checkout is POST /loans with {copy_id, user_id}, returning 201 and a Location header. Return is PATCH /loans/{id} setting returned_at, or a POST /loans/{id}/return action if I want the server to own the timestamp. I would say which one I picked and why.
- Status codes: 400 for malformed input, 404 for an unknown copy or user, and 409 when the copy already has an open loan. The 409 is backed by the partial unique index, so two simultaneous checkouts cannot both succeed.
- Idempotency: GET, PUT and DELETE are idempotent by definition and POST is not. To make a retried checkout safe after a timeout, I accept an Idempotency-Key header and store it with the result.
- Lists need pagination (cursor-based for stable paging under inserts, or limit/offset for simplicity), filtering and sorting parameters. Version the API (/v1 or a header), and add authorisation so members can only read their own loans.
Follow-up
- Two clients try to check out the last copy at the same moment: walk through what each one receives.
- Would you choose offset or cursor pagination for a member's loan history, and what breaks with offset?
- How would you add an endpoint for renewing a loan, and what rules would it validate?
Design a program to manage a parking structure with varying space sizes (large, medium, small) for different v
Medium · System Design & Problem Solving
Design a program to manage a parking structure with varying space sizes (large, medium, small) for different vehicle types.
Approach
- Clarify the rules first: vehicle types (motorcycle, car, bus or truck), the size each needs, whether a smaller vehicle may take a larger spot, multiple levels, entry and exit with tickets, and whether pricing is in scope.
- Core classes: ParkingLot (levels, ticket map), Level (spots), Spot (id, size, current vehicle), Vehicle (plate, required size), and Ticket (spot, vehicle, entry time). An ordered size enum (SMALL < MEDIUM < LARGE) lets the fit check be a single comparison.
- Allocation: for a vehicle, try the smallest size that fits first, then larger sizes, so large spots stay free for large vehicles. Keep a free-spot set or queue per size per level for O(1) park and leave instead of scanning every spot in O(n).
- Leaving: look up the ticket in a hash map, free the spot, and push it back to its size's free set. Return a clear result for a full lot, an unknown ticket, or a plate that is already parked.
- Extensions: a vehicle needing several contiguous spots, which needs a range search instead of a free set. Concurrent gates, which need park to be atomic (a lock per size pool, or a conditional update in the database). Per-size availability counts for a display board.
Follow-up
- How would pricing work by duration and vehicle type, and where does that logic live?
- Two entry gates assign the last medium spot at the same time: how do you prevent a double assignment?
- What changes if a bus must occupy five adjacent large spots?
Implement a gift exchange program with specific constraints (e.g., ensuring no two people give gifts to each o
Medium · System Design & Problem Solving
Implement a gift exchange program with specific constraints (e.g., ensuring no two people give gifts to each other).
Approach
- Restate the constraints: everyone gives exactly one gift and receives exactly one, nobody gives to themselves, and no two people give to each other. That is a permutation with no cycles of length 1 or 2.
- Simple correct construction: shuffle the participants with Fisher-Yates, then have each person give to the next one in the shuffled order, with the last giving to the first. That is one cycle of length n, so for n >= 3 there are no self-gifts or reciprocal pairs. It runs in O(n).
- Handle impossible inputs explicitly. With n = 1 or n = 2 there is no valid assignment (for two people the only option is a swap, which is reciprocal), so raise an error or return an empty result instead of looping.
- Trade-off: the single cycle never produces assignments made of several smaller cycles, so it is not uniform over all valid assignments. If uniformity matters, use rejection sampling on random permutations. The share with no cycles shorter than 3 tends to e^-1.5, about 22%, so it takes about 4.5 tries on average.
- Extra rules (household members cannot draw each other) call for backtracking with pruning, or for retrying the shuffle. Inject a seeded RNG so tests are reproducible, and assert the invariants on every output.
Follow-up
- Add exclusion lists, such as partners not drawing each other: how does your algorithm change, and how do you detect that no valid assignment exists?
- How would you test a function whose output is random?
- How do you guarantee the same result when last year's pairs must also be avoided?
Given an index, find the number in the Fibonacci sequence.
Medium · System Design & Problem Solving
Approach
- Clarify the indexing (F(0) = 0, F(1) = 1, or 1-based), what negative input should do, and how large n can get. The size of n decides the number type.
- Naive recursion is exponential, O(phi^n), because it recomputes subproblems. Memoisation brings it to O(n) time and O(n) space, but deep recursion can overflow the stack.
- The default answer is iterative: keep two variables (a, b = b, a + b) for O(n) time and O(1) space. Test it at n = 0, 1 and 2 and on one larger value.
- For very large n, use fast doubling (F(2k) = F(k)(2F(k+1) - F(k)) and F(2k+1) = F(k)^2 + F(k+1)^2) or 2x2 matrix exponentiation, both O(log n) arithmetic steps. Binet's closed form becomes inexact for larger n because of floating-point rounding.
- Overflow: in JavaScript, Number is exact only up to 2^53 - 1, and F(78) is the last Fibonacci value below that, so use BigInt beyond it. A signed 64-bit integer holds up to F(92). Otherwise, return the result modulo a given m.
Follow-up
- Return F(n) modulo 1,000,000,007 for n up to 10^18.
- How would you serve many repeated queries efficiently, and what would you cache?
- Write the recursive version with memoisation, then explain when it would hit the recursion limit.
Why are you interested in working with AI and RAG systems?
Medium · System Design & Problem Solving
Approach
- Answer with a concrete reason from your own work, such as a search or support feature you built or a prototype you shipped, rather than general enthusiasm. The requirements candidates describe list AI/RAG experience as a nice-to-have, so tie your answer to what you have actually done.
- Show you understand the pipeline. Documents are split into chunks and embedded into a vector index. At query time, the top-k chunks are retrieved, optionally reranked, and placed in the prompt so the model answers from that context and can cite sources.
- Name the trade-offs you have run into or would watch for: chunk size against retrieval precision, dense retrieval against keyword (BM25) or hybrid search, latency and cost per query, and index freshness when source documents change.
- Talk about evaluation and failure modes: retrieval recall@k on a labelled question set, answer groundedness checks, hallucination when retrieval misses, and access control so a user only retrieves documents they are allowed to see.
- Close with what you want to learn or build next. Keep it honest: if your experience is small, say exactly what you built and what you would do differently.
Follow-up
- How would you measure whether a RAG feature is answering correctly before and after a change?
- When would you choose fine-tuning over retrieval, or use both?
- The answers are wrong because the right chunk is never retrieved: how do you debug that?
Explain your approach to troubleshooting complex technical issues.
Medium · Technical & Domain Knowledge
Approach
- Define the symptom precisely: who is affected, since when, how often, and what the expected behaviour is. Then reproduce it, ideally as a minimal case or a failing test.
- Ask what changed: deploys, config or feature flags, data volume or shape, dependency versions, infrastructure. Line the change timeline up against when the symptom started.
- Gather evidence before theorising: logs with a request or correlation id, metrics around the start time, traces across services, and the database query plan if it is a slowness issue. Check that the monitoring itself is correct.
- Narrow the search space with bisection:
git bisectacross commits, toggling a flag, or removing components until the failure disappears. Form one hypothesis at a time and pick the test that rules out the most. - Close the loop: fix the root cause rather than the trigger, add a regression test, and write up what happened and what would have caught it earlier. Anchor all of this in one real incident from your own work.
Follow-up
- The bug happens only in production and you cannot reproduce it locally: what do you do next?
- How do you debug an intermittent failure that shows up once in a few hundred runs?
- Tell me about the hardest bug you have tracked down, and what told you the cause.
Suggested practice checklist
The plan follows the reported loop: it starts with the library schema, SQL and API chain, moves to JavaScript, the small programs and troubleshooting, then builds behavioral stories and ends with a full mock session.
Day 1 — Map the loop and audit your three must-haves
- Write out the five reported rounds in order: Initial Screening, Technical Assessment, Behavioral Assessment, Collaborative Panels, Virtual Onsite Experience. Beside each, note one thing you will practise for it.
- Rate yourself from one to five on the three listed must-haves (one major language, SQL and database design, REST APIs) and pick the language you will use in coding sessions.
- Write your two-minute background summary organised around those three must-haves.
Deliverable: A one-page loop map, a three-line self-rating with your chosen language, and a written two-minute background summary.
Day 2 — The library chain: schema, SQL, REST API
- Write the schema for users, books and loans as SQL table definitions with primary keys, foreign keys and the return and due dates on the loan.
- Load a few rows of sample data and write the overdue-books query with date functions. Test returned, due-today and not-yet-due loans.
- Outline the REST endpoints for the same schema: resources, methods, status codes, error cases and how you would page a long list.
Deliverable: A schema file, a tested overdue-books query with its sample data, and an endpoint table that maps each route to the tables it touches.
Day 3 — JavaScript fundamentals and window-function SQL
- Write short code examples that show scope versus context in JavaScript: closures, hoisting, and a callback that loses its this binding and how to fix it.
- Say your explanation of scope versus context aloud in under two minutes.
- Do one SQL rep from the practice library on window functions to widen your query range beyond the overdue case.
Deliverable: A file of annotated JavaScript scope and context examples, a recorded spoken explanation, and one solved window-function exercise.
Day 4 — Small programs: parking, gift exchange, Fibonacci
- Write the parking structure program with large, medium and small spaces and the vehicle types, plus tests that cover a full structure and a vehicle that has to take a larger space.
- Write the gift exchange program for the no-mutual-gifts rule, listing your assumptions first and adding tests for two people, three people and an impossible case.
- Write the Fibonacci lookup by index in more than one way and state each one's time and memory cost.
- Optionally do one coding rep from the practice library as a warm-up.
Deliverable: Three programs with tests (parking, gift exchange, Fibonacci) and a list of the assumptions you stated for each.
Day 5 — Troubleshooting and the AI and RAG answer
- Write your troubleshooting sequence as steps (reproduce, narrow the change, check logs and metrics, form and test a hypothesis, fix, prevent) and apply it to a real incident you handled.
- Write a specific answer to why you are interested in AI and RAG systems, using only work, reading or experiments you have actually done.
- Say both answers aloud twice and cut anything vague.
Deliverable: A written troubleshooting walkthrough of one real incident and a written, spoken-ready AI and RAG answer.
Day 6 — Behavioral story bank
- Write four stories in Situation, Task, Action, Result form, one for each reported prompt: conflict with a manager, a missed estimate, difficulty respecting a colleague and code review feedback.
- Mark in each story the decision you personally made and what changed afterwards.
- Say each story aloud and trim it so that the situation takes two or three sentences.
Deliverable: Four written stories with the key decision and the lesson highlighted in each, plus a spoken run-through of all four.
Day 7 — Full mock pairing session
- Run a mock session with a friend over video and a shared editor: they pick the parking or gift exchange problem and you code it while narrating.
- In the same session, answer one behavioral prompt and the library schema question aloud.
- Afterwards, list the three places where you went silent, skipped an assumption or ran long, and fix them.
Deliverable: A session recording or notes, and a short list of three specific fixes.
Conflict, estimates and feedback stories
Candidates report a behavioral stage and name its topics: conflict with leadership, managing expectations when a project does not go to plan, and giving and receiving technical feedback. For an engineer, that means stories about disagreeing with a manager, a missed estimate, a hard working relationship and code review. Prepare each as a real episode where you made a choice and can name what it cost.
- Tell me about a time you disagreed with a technical decision and how it ended.
Describe a situation where you had a conflict with your manager and how you resolved it.
Medium · Behavioral & Leadership
Approach
- Choose a disagreement with real stakes (scope, a deadline, a technical approach or priorities) where you owned part of the outcome. A story where you only complained or watched will not carry.
- Open with the situation in two sentences. Then state both positions fairly, including your manager's reasoning and any constraints you could see from their side.
- Describe your actions concretely: you raised it early and privately, brought evidence or options (a prototype, numbers, a risk list) rather than opinion, and asked what would change their mind.
- Report the result honestly. If you persuaded them, say what moved them. If you lost, say that you committed, delivered anyway and what happened later.
- Close with what you now do differently, such as agreeing success criteria up front or raising concerns sooner. The sinking mistake is casting the manager as the villain.
Follow-up
- What would you do differently if you ran that situation again?
- How did the working relationship look afterwards?
- What if your manager had still said no and you believed the plan would fail?
Tell me about a time you missed a project estimate.
Medium · Behavioral & Leadership
Approach
- Pick a real miss with consequences, not a trivial slip. State what you estimated, what the estimate was based on and what the actual outcome was.
- Diagnose the cause specifically: an unknown dependency, scope growth, underestimated testing or integration work, or optimism about a familiar task. Own your part rather than blaming other teams.
- Say when you noticed the slip and how you communicated it: who you told, how early, and what options you offered (cut scope, move the date, add help).
- Show the change you made afterwards: smaller tasks, an explicit allowance for unknowns, a short spike before committing, or comparing past estimates with actual time.
- Avoid the answer where the project slipped but you claim you were never wrong, and the answer where you only describe a problem without any change in your habits.
Follow-up
- When did you tell your stakeholders, and what did you say?
- How do you estimate differently today?
- What if the slip came from requirements that changed mid-project?
Describe a situation where you found it difficult to respect someone you were working with.
Medium · Behavioral & Leadership
Approach
- Choose a situation involving a specific, observable behaviour (dismissing others' ideas, missing commitments, careless reviews), not a personality judgement. Describe the behaviour and its effect on the work.
- Be honest that you found it hard, then show you examined your own reaction: what you assumed about them and what you might have missed about their constraints or context.
- Describe what you did: a direct, private conversation about the behaviour, agreed working practices (for example review expectations or handoffs), and escalation only after trying that.
- Give the outcome, including partial progress if that is what happened, and what you took away about working with people whose style or standards differ from yours.
- The mistake that sinks this answer is venting about the person, or saying you have never met such a colleague. Keep the tone professional throughout.
Follow-up
- Did you ever raise it with them directly, and how did that conversation go?
- What if their behaviour had not changed?
- Would you be comfortable working with them again, and why?
How do you handle feedback during a code review?
Medium · Behavioral & Leadership
Approach
- Answer with a concrete example rather than a statement of temperament. Pick a review where a comment challenged your approach and you had to decide how to respond.
- Describe your process: read the comment for its intent, ask a clarifying question if it is vague, and check the claim with a test, a benchmark or the code itself before replying.
- Show both outcomes: a time you accepted the feedback and improved the change, and a time you disagreed, explained your reasoning with evidence and reached a compromise or deferred to team conventions.
- Mention the practical habits: small, well-described pull requests, replying to each comment, and thanking the reviewer for catches. Add how you give feedback yourself: specific, about the code, with a suggested alternative.
- Avoid the extremes: saying you accept everything without question, or presenting every review as a fight you won.
Follow-up
- Tell me about a time you pushed back on review feedback. What happened?
- How do you give review feedback to a colleague who is more senior than you?
- How do you settle a disagreement about style versus correctness?