cswork / libraryOpen practice workspace

Interview guides · Canva

Canva Software Engineer Interview Guide

Canva Software Engineer interview guide covering the reported rounds, JavaScript, coding, system design and behavioral questions, with a 7-day plan.

The 60-second brief

Canva makes a design product, and candidates describe the Software Engineer role as building and maintaining features on that platform. The work spans front-end features that users touch directly and back-end systems behind them, including performance work on busy features. The role is described as working alongside product managers and designers, taking part in code reviews, and debugging problems in applications that are already running. The requirements candidates list center on JavaScript and a modern framework such as React or Vue, plus data structures, algorithms and system design principles.

This guide is for candidates preparing for a Software Engineer interview at Canva. It covers the two reported rounds, the sixteen questions candidates report (JavaScript fundamentals, string and algorithm coding, system design, behavioral and production-debugging questions) and a seven-day plan. The behavioral questions have worked answer structures here, and the technical questions have their own guidance on the question cards.

Candidates report two stages over roughly 2-4 weeks: a Recruiter Screen, then Technical Interviews that combine coding challenges, system design discussions and behavioral assessments.

Focus areas

  • Coding Interviews (Live/Take-home/Screening)
  • System Design
  • Debugging

Overview

The requirements candidates describe for this role put JavaScript first, which means being able to explain the language as well as write it. Reported questions ask for the difference between let, const and var, how the event loop works, and how garbage collection works. Each has a precise answer you can rehearse: scoping and the temporal dead zone, the call stack with the task and microtask queues, and reachability-based collection. Add a modern framework (React or Vue are the examples listed) so you can talk about the front-end half of the role.

The coding questions candidates report are small and classic: reverse a string in JavaScript, implement binary search, check whether two strings are anagrams, and solve a dynamic programming problem. Because they are small, the preparation is about precision. Handle empty input, Unicode and off-by-one boundaries, say the complexity out loud, and be able to write working code in JavaScript without an editor's help. The dynamic programming question is open-ended, so practise naming the state and recurrence quickly on several problem shapes.

The system design questions are a chat application, an image upload path for a web application, and data consistency in a distributed system. The requirements also mention RESTful services and cloud platforms such as AWS and Google Cloud as nice-to-haves, so be ready to name real components: object storage, queues, WebSockets, caches and idempotent writes. Candidates also report two case-style questions, analysing an underperforming product feature and debugging a complex production issue, which reward a clear order of investigation.

Behavioral questions are reported as part of the technical interviews, and they are concrete: optimizing a piece of code, working with a difficult team member, taking the lead on a project, and prioritizing under tight deadlines. The role is described as collaborating with product managers and designers and joining code reviews, so choose stories that show you working across those lines. Prepare four real stories with numbers you can defend, and reuse them across questions.

The Canva interview process

Candidates report two rounds: a Recruiter Screen followed by Technical Interviews. Reports describe the second stage by its content (coding, system design, behavioral) rather than by a fixed order of sessions.

Recruiter Screen

Candidates report the first stage as a screen with a recruiter to decide whether you fit the role before any technical interview. Reports give no further detail on format or questions, so treat it as a conversation about your background, the Software Engineer role and logistics. Approach it with a short account of your experience that points at the JavaScript, framework and back-end work the role lists, and use the call to find out what the technical interviews will contain.

What to demonstrate

  • Fit between your background and the Software Engineer role
  • How clearly you summarise your experience and your reason for applying
  • Practical matters such as location, notice period and availability

How to prepare

  • Write a short walk-through of your career that names two projects involving JavaScript and React or Vue, or the back-end and REST work if that is your side.
  • Prepare a specific reason for wanting to work on a design product, based on something you have actually used.
  • Have notice period, location constraints and salary expectations ready, and ask the recruiter in what form the technical interviews will run and which topics they cover.

Technical Interviews

Candidates report that the technical interviews cover coding challenges, system design discussions and behavioral assessments. The reported questions group into JavaScript fundamentals, string and algorithm coding, system design (a chat application, image uploads, data consistency), a feature-analysis case, production debugging, and four behavioral prompts. Reports do not say how these are split across sessions, so prepare every type and practise speaking while you work: restate the problem, name the approach, then write or draw it.

What to demonstrate

  • Working JavaScript code for the reported coding problems, with complexity and edge cases stated
  • Design reasoning: components, data flow and trade-offs in cost, complexity and performance
  • Behavioral examples that show collaboration and impact, including with product and design colleagues
  • Order and clarity when analysing a failing feature or debugging a production issue

How to prepare

  • Explain let, const and var, the event loop and garbage collection out loud, with a small code sample for each.
  • Write reverse-a-string, binary search, anagram checking and a dynamic programming solution in JavaScript from a blank file, with test cases for empty and unusual input.
  • Sketch the chat application, image upload and distributed consistency designs on paper, ending each with the trade-offs you chose.
  • Prepare four stories (optimization, a difficult colleague, taking the lead, tight deadlines) and a fixed investigation order for production bugs.

Where candidates lose points

Explaining let, const and var as 'different scoping' and stopping there

Cover block versus function scope, hoisting and the temporal dead zone, redeclaration and reassignment, and the fact that const makes the binding constant, not the object. Add one snippet showing a var-in-a-loop closure bug.

Answering the event loop and garbage collection questions as definitions with no model behind them

Walk through the call stack, task queue and microtask queue with a short Promise-versus-setTimeout ordering example. For garbage collection, explain reachability from roots and name a leak you could cause, such as a listener or closure that keeps a large object alive.

Writing the small coding problems fast but ignoring boundaries, such as an off-by-one in binary search, Unicode characters in string reversal, or case and spacing in the anagram check

Before coding, ask about input range and character set. After coding, test an empty input, a single element, duplicates and a missing target. State time and space complexity every time.

Giving the chat, image upload or consistency design as a list of boxes with no data flow and no trade-offs

Draw the path of one message or one upload end to end, then name the failure points: dropped connections, retries causing duplicates, and large files through application servers. Say which consistency you pick and where you accept stale reads.

Telling behavioral stories with no measurement, no personal decision, or no result

Prepare the optimization, difficult-colleague, taking-the-lead and tight-deadline stories in advance. Give each a baseline or concrete outcome, say what you decided yourself, and say what you would change.

Questions & practice

How does garbage collection work in JavaScript?

Medium · Technical / Domain Questions

Approach

  1. Define the rule: engines free objects that are no longer reachable from the roots (the global object, the active call stack, live closures). It is mark-and-sweep tracing, not reference counting, so cycles of objects that reference each other are still collected.
  2. Describe V8's generational design. New objects go to a young generation collected by a fast copying scavenger, because most objects die young. Survivors are promoted to the old generation, which is collected by mark-sweep-compact. Incremental, concurrent and parallel marking keep main-thread pauses short.
  3. Explain that a JavaScript leak is unwanted reachability. Common causes are listeners that are never removed, intervals that are never cleared, closures holding large objects, detached DOM nodes still referenced from JS, and unbounded Map caches or globals.
  4. Name the tools. WeakMap and WeakSet hold keys weakly, so per-object metadata dies with the object. WeakRef and FinalizationRegistry exist, but their timing is not deterministic. For diagnosis, compare DevTools heap snapshots and read the retainer path. Page code cannot force a collection; gc() exists only behind the --expose-gc flag.

Follow-up

  • Memory grows each time a user navigates between views in a single-page app. How do you find what is retaining it?
  • When would you choose a WeakMap over a Map for caching data keyed by DOM nodes or objects?
  • Why can frequent allocation in an animation loop cause dropped frames, and how would you reduce it?

Write a function to reverse a string in JavaScript.

Medium · Coding / Algorithms

Approach

  1. Give the baseline first: str.split('').reverse().join(''). It is O(n) time and O(n) space, since JavaScript strings are immutable and any reversal builds a new string.
  2. Raise the Unicode problem: split('') splits UTF-16 code units, so emoji and other astral characters become broken surrogate pairs. [...str].reverse().join('') or Array.from(str) iterates by code point and fixes that case.
  3. Go one level deeper: code points still break grapheme clusters such as combining accents, flag emoji and ZWJ family emoji. Intl.Segmenter with granularity 'grapheme' gives user-perceived characters to reverse.
  4. If built-ins are not allowed, convert to an array and swap with two pointers from both ends until they meet: O(n) time, O(n) extra space for the array. Avoid a recursive version that slices substrings, which is O(n^2) and can overflow the stack on long input.
  5. Cover the edge cases: empty string, a single character, palindromes, and non-string input (decide whether to throw a TypeError or coerce).

Follow-up

  • Reverse the order of words in a sentence while keeping each word intact, and handle multiple spaces.
  • How would you test that your function handles emoji and accented characters correctly?
  • Check whether a string is a palindrome while ignoring case and punctuation, without building the reversed copy.

How would you implement a binary search algorithm?

Medium · Coding / Algorithms

Approach

  1. State the precondition: the array is sorted, or more generally the predicate is monotone (false...false, true...true). Without that, binary search is invalid.
  2. Write the iterative form: lo = 0, hi = n - 1, while (lo <= hi), mid = lo + Math.floor((hi - lo) / 2). Return mid on a match, otherwise set lo = mid + 1 or hi = mid - 1, and return -1 at the end. This is O(log n) time and O(1) space. Integer overflow in (lo + hi) is a concern in 32-bit-int languages, not for array indices held in JavaScript numbers.
  3. Show the lower-bound variant on a half-open range [lo, hi): while (lo < hi), if a[mid] < target then lo = mid + 1, else hi = mid. It returns the first index whose value is >= target, which handles duplicates and insertion points.
  4. Name the bugs: an infinite loop when lo = mid is combined with a floored mid, off-by-one between the inclusive and half-open styles, an empty array, and a target below the minimum or above the maximum.
  5. Mention binary search on the answer: minimum capacity, smallest feasible speed, integer square root. Any monotone yes/no check over a numeric range works the same way.

Follow-up

  • Find the first and last position of a target in a sorted array that contains duplicates.
  • Search for a target in a sorted array that has been rotated at an unknown pivot.
  • Compute the integer square root of n without Math.sqrt, and explain the loop invariant.

Solve a problem involving dynamic programming.

Medium · Coding / Algorithms

Approach

  1. Explain how to recognise DP: the problem asks for a count, a minimum or maximum, or feasibility; it has optimal substructure; and a naive recursion revisits the same subproblems.
  2. Define the state in words before writing code, for example dp[i] = fewest coins to make amount i. Then write the recurrence (dp[i] = 1 + min over coins c <= i of dp[i - c]), the base case (dp[0] = 0, others Infinity) and the iteration order.
  3. Start with recursion plus memoisation if it is easier to reason about, then convert to a bottom-up table. Complexity is states times transitions: coin change is O(amount x coins), and LCS or edit distance is O(m x n) time.
  4. Cut space where only the previous row is used: edit distance and LCS drop to O(min(m, n)) for the value alone. 0/1 knapsack uses one array iterated from high capacity down to low, so that each item is used once.
  5. Show why greedy fails when it does: with coins {1, 3, 4} and amount 6, greedy takes 4 + 1 + 1 (3 coins) while DP finds 3 + 3 (2 coins). Keep parent pointers if the actual solution, not only its value, is needed.

Follow-up

  • Reconstruct the actual choices (which coins, or which edit operations), not only the optimal value.
  • Reduce the memory of your 2D solution, and say what you lose by doing so.
  • Longest increasing subsequence: give the O(n^2) DP, then the O(n log n) method that uses binary search.

Denormalise tenant onto revisions and backfill it live

Hard · denormalisation · online migration · backfill

resource_revision (revision_id, resource_id, version, actor_user_id, change_kind, patch, request_id, created_at) has 400M rows and no tenant column; tenant_id lives only on resource. Two reads need it: a tenant-scoped audit feed ordered by created_at DESC, and an offboarding purge. Both join back to resource today. Justify adding tenant_id to resource_revision against those two reads, name the anomaly the copy introduces and the constraint that prevents it, then give the ordered migration for a live table taking 1.2k writes/second — the lock each step takes, how the backfill is batched, and where each step stops being reversible. PostgreSQL 16.

Approach

  1. Justify from the access path rather than from taste. Without the column, the audit feed either scans resource_revision by created_at and discards other tenants' rows, or resolves the tenant's resource_ids first and probes with them — both proportional to the tenant's whole history rather than to one page. With (tenant_id, created_at DESC, revision_id DESC) it is a seek that stops at 50 rows, and the purge becomes a ranged delete instead of a join.
  2. Name the cost exactly: a second copy of a fact can disagree with the first. Make the disagreement unwritable rather than documented — add UNIQUE (resource_id, tenant_id) on resource so it can serve as a foreign-key target, then FOREIGN KEY (resource_id, tenant_id) REFERENCES resource (resource_id, tenant_id) on the revision table. A revision can then only ever carry its parent's tenant.
  3. Step one, expand: ALTER TABLE resource_revision ADD COLUMN tenant_id BIGINT NULL, with no default, so it is a catalogue change and no rewrite. It still needs ACCESS EXCLUSIVE for an instant, and that instant queues behind the longest open transaction on the table while every later query queues behind it — set lock_timeout to 2s and retry rather than wait.
  4. Step two, dual-write: deploy the writer that populates tenant_id on every new revision while reads still use the join. Reversible by redeploying the previous build, because nothing reads the column yet.

Follow-up

  • The backfill is half finished and a rollback is required. What state is the table in, and what does the previous build do with a half-populated column?
  • How do you verify the backfill actually finished, given rows are still being inserted while it runs?

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?

What is the difference between let, const, and var in JavaScript?

Medium · Technical / Domain Questions

Approach

  1. Scope: var is function-scoped (or global at the top level of a script); let and const are block-scoped, so a variable declared inside an if or for body is not visible outside it.
  2. Hoisting: all three are hoisted, but var is initialised to undefined, while let and const sit in the temporal dead zone until their declaration runs. Reading them before that throws a ReferenceError.
  3. Rebinding: var can be redeclared in the same scope; let and const cannot (SyntaxError). const must be initialised and cannot be reassigned, but an object or array it holds can still be mutated. Object.freeze stops that, and it is shallow.
  4. Show the loop case: for (var i = 0; i < 3; i++) setTimeout(() => console.log(i)) prints 3, 3, 3, while let creates a new binding per iteration and prints 0, 1, 2. A top-level var in a classic script also becomes a property of globalThis; let and const do not.
  5. State a default: const everywhere, let only when the value is reassigned, and no var in new code.

Follow-up

  • Why does typeof throw for a let variable read before its declaration, when typeof on an undeclared name returns "undefined"?
  • How would you make a nested config object fully immutable, given that Object.freeze is shallow?
  • What does a top-level var do inside an ES module compared with a classic script?

Explain how the event loop works in JavaScript.

Medium · Technical / Domain Questions

Approach

  1. Start with the model: one call stack runs synchronous code to completion. Timers, network and I/O are handled outside the stack by the browser (or libuv in Node), and their callbacks are queued.
  2. Separate the two queues. Tasks (macrotasks) include setTimeout, setInterval, I/O and UI events. Microtasks include promise reactions, await continuations, queueMicrotask and MutationObserver. After each task the engine drains the whole microtask queue, including microtasks added during the drain, before the next task; the browser may render between tasks.
  3. Work an example out loud: console.log('A'); setTimeout(() => console.log('B'), 0); Promise.resolve().then(() => console.log('C')); console.log('D') prints A, D, C, B.
  4. Give the practical consequences: a long synchronous loop blocks input and painting, and a microtask that keeps scheduling microtasks starves rendering. Fix it by chunking the work across tasks, yielding with setTimeout or scheduler.yield where supported, or moving it to a Web Worker. setTimeout(fn, 0) is a minimum delay, not a guarantee.
  5. For Node, add the phases (timers, poll, check for setImmediate, close callbacks), and note that process.nextTick callbacks run before promise microtasks.

Follow-up

  • Predict the output of a snippet that mixes async/await, setTimeout and Promise.then, and explain each line.
  • Where do requestAnimationFrame callbacks run relative to tasks and microtasks?
  • How would you keep the UI responsive while parsing a very large file in the browser?

Design a function that checks if two strings are anagrams.

Medium · Coding / Algorithms

Approach

  1. Clarify the rules before coding: case sensitivity, whether spaces and punctuation count, and whether input can contain Unicode beyond ASCII. Then normalise (for example lowercase and strip non-letters) as agreed.
  2. Exit early when the normalised lengths differ.
  3. Sorting approach: sort the characters of both strings and compare. O(n log n) time, O(n) space, short and easy to verify.
  4. Counting approach: one Map, or an array of 26 ints for lowercase a-z. Increment for each character of the first string, decrement for the second, and return false as soon as a count goes negative. O(n) time, O(k) space for an alphabet of size k. Iterate with for...of so astral characters count as one code point.
  5. Test the edge cases: two empty strings, identical strings, same letters with different counts (aab vs abb), and mixed case.

Follow-up

  • Group a list of words into sets of anagrams. What key would you use, and what is the complexity?
  • Find every start index in a long string where a substring is an anagram of a short pattern (sliding window with counts, O(n)).
  • How would your function change if the strings arrived as streams too large to hold in memory?

Design a chat application. What are the key components you would consider?

Medium · System Design / Architecture

Approach

  1. Pin down scope: one-to-one and group chat, message history, delivery and read receipts, online presence, push notifications for offline users, and attachments. State scale numbers as your own assumptions.
  2. Connections: clients hold WebSocket connections to a stateless gateway tier. A session registry (for example Redis, user to gateway) lets any service find where a recipient is connected.
  3. Send path: the client attaches a client-generated message id for idempotency. The chat service assigns a per-conversation sequence number and persists the message to a store partitioned by conversation_id and ordered by sequence (a wide-column store suits this). It then publishes the message to the recipients' gateways and acks the sender.
  4. Offline and reconnect: undelivered recipients get a push through APNs or FCM. On reconnect the client asks for messages after the last sequence it saw in each conversation, so delivery is at-least-once with dedup by message id.
  5. Trade-offs to name: a group message is written once and fanned out to members, presence uses heartbeats with a TTL and throttled updates, and end-to-end encryption limits server-side search. Attachments go to object storage, and only their URLs travel through the chat path.

Follow-up

  • How do you keep messages in order within a conversation when two members send at the same moment through different gateways?
  • What changes for a group with a hundred thousand members, both for fan-out and for presence?
  • A gateway node crashes. What happens to its connected users and to messages in flight?

How would you architect a system to handle image uploads in a web application?

Medium · System Design / Architecture

Approach

  1. Keep large bytes off the app servers. The client asks the API for an upload, and the API creates a metadata row with status pending and returns a pre-signed PUT URL for object storage (S3 or GCS). Large files use multipart or resumable uploads.
  2. Validate on both sides: size and dimension limits, file type checked from magic bytes rather than the extension or the client's Content-Type, malware scanning, and EXIF stripping so location data does not leak. Decode in a sandboxed worker so a malformed image or a decompression bomb cannot take down the service.
  3. Process asynchronously. The object-created event goes onto a queue, and workers generate thumbnails and resized variants, convert to WebP or AVIF, and then mark the row ready. Workers must be idempotent, with retries and a dead-letter queue.
  4. Serve through a CDN using content-hashed keys and long immutable Cache-Control headers. Private images use short-lived signed URLs.
  5. Clean up and save storage: a lifecycle rule removes abandoned pending uploads, and a content hash can dedupe identical files. Weigh pre-generating variants against resizing on demand with caching.

Follow-up

  • How would you support a very large upload over an unreliable mobile connection, with progress and resume?
  • A user deletes an image. How do you make sure it stops being served from storage and from CDN caches?
  • Would you pre-generate every size or resize on demand? What decides it?

Discuss how you would ensure data consistency in a distributed system.

Medium · System Design / Architecture

Approach

  1. Start from the invariant, not the tooling: what must never be violated (no double charge, no lost edit, a user sees their own write)? Then pick the weakest model that protects it, from linearizable through causal and read-your-writes to eventual. Use CAP and PACELC to frame the cost in availability and latency.
  2. Inside one data store, use a single leader with synchronous replication, or consensus (Raft or Paxos), for data that must be strongly consistent. In leaderless replication, R + W > N makes read and write quorums overlap, though sloppy quorums and concurrent writes weaken that guarantee.
  3. Across services, avoid two-phase commit where possible because a failed coordinator blocks participants. Use a saga with compensating actions, plus a transactional outbox so the state change and its event commit together. Consumers must be idempotent and keyed by an event id, since delivery is at-least-once.
  4. For concurrent updates, use optimistic concurrency with a version number or conditional write (compare-and-set). Last-write-wins silently loses updates and depends on clocks that skew. For collaborative edits, CRDTs or operational transformation make replicas converge.
  5. Show how you would detect drift: replication-lag metrics, periodic reconciliation jobs comparing sources of truth, and fault-injection tests that partition the network.

Follow-up

  • Walk through a saga where the first step succeeds and the second fails. What does each compensating action do?
  • How would you guarantee read-your-writes when reads go to asynchronously replicated followers?
  • When would you accept two-phase commit despite its blocking behaviour?

Given a product feature that is underperforming, what steps would you take to analyze the situation?

Medium · Problem-Solving / Case Studies

Approach

  1. Define underperforming precisely: which metric (adoption, activation, completion, retention) against which baseline or target, and over what period. A target set without data may be the real problem.
  2. Verify the data before analysing it. Check that tracking events still fire, that their definitions did not change, and line up release, rollout and flag dates against the metric.
  3. Break the funnel into stages: exposure (do users find the feature), first use, successful completion, return use. Find the largest drop, then segment by platform, browser, region, new versus returning users and signup cohort.
  4. Check the engineering side as well as the product side. Load time, error rates and crashes on the feature's code paths can explain a drop in one segment. Add qualitative evidence from support tickets, session recordings or user interviews.
  5. Rank hypotheses by expected impact and cost to test. Run an A/B test with a primary metric and guardrail metrics, then decide whether to iterate, reposition or retire the feature.

Follow-up

  • How would you tell whether the feature is taking usage from another feature rather than failing on its own?
  • The metric dropped the week after a release. How do you separate the release's effect from seasonality?
  • What would make you recommend removing the feature entirely?

How do you approach debugging a complex issue in production?

Medium · Problem-Solving / Case Studies

Approach

  1. Contain first: size the impact (which users, how many, since when). If a recent change correlates with it, roll back or turn off the feature flag before chasing root cause, and post status updates in one incident channel.
  2. Build a timeline: deploys, config changes, flag flips, dependency incidents and traffic shifts, set against when the error rate or latency moved on the dashboards.
  3. Narrow it down with telemetry: slice errors and latency by endpoint, region, release version and browser. Follow a distributed trace to the failing hop, and use structured logs keyed by request or trace id. Confirm the instrumentation is correct before trusting a strange graph.
  4. Reproduce it, either with a captured failing request or production-like data in staging. Then bisect: git bisect across the commits in the bad release, or toggle flags one at a time. Add targeted logging when the existing signals cannot separate the remaining hypotheses.
  5. Close the loop: confirm the fix in the same metrics that showed the problem, add a regression test, and write a blameless postmortem that names the alert or check that would have caught it sooner.

Follow-up

  • The bug affects a small fraction of requests intermittently and you cannot reproduce it locally. What do you do next?
  • How would you debug a memory leak or slowdown that appears only in one browser in production?
  • How do you tell a real cause from a change that merely shipped at the same time?

Suggested practice checklist

Seven days built around the two reported rounds: day 1 for the recruiter conversation, days 2 to 5 for the technical question types candidates report, day 6 for behavioral stories and day 7 for a full mixed rehearsal.

Day 1 — Recruiter screen and loop map

  • Write the career walk-through and pick the two projects that involve JavaScript, React or Vue, or REST back-end work.
  • Write your reason for applying and your answers on notice period, location and salary expectations.
  • List the question types candidates report for the technical interviews and rate yourself on each.

Deliverable: A one-page recruiter-call script plus a ranked list of weakest question types, which sets the time you spend on days 2 to 5.

Day 2 — JavaScript fundamentals out loud

  • Explain the difference between let, const and var with a snippet covering hoisting, the temporal dead zone and a closure in a loop.
  • Trace a snippet mixing synchronous code, setTimeout and Promise callbacks, and predict the output before running it.
  • Explain how garbage collection works in JavaScript and write one example of a memory leak and its fix.

Deliverable: Three spoken answers (scoping, event loop, garbage collection), each with a code sample that you ran and a one-line summary.

Day 3 — Coding problems in plain JavaScript

  • Write reverse-a-string three ways and test it on empty, single-character and non-ASCII input.
  • Write binary search iteratively, then fix the boundary cases (empty array, missing target, duplicates).
  • Write the anagram check with a character count map and again with sorting, and compare complexity.
  • Solve one dynamic programming problem by naming state, recurrence and base cases before writing code.

Deliverable: Four working JavaScript functions with their test cases and a stated time and space complexity for each.

Day 4 — System design: chat, uploads, consistency

  • Design the chat application: connection layer, message storage, delivery and ordering, and what happens when a recipient is offline.
  • Design the image upload path: how the file reaches storage, processing, and what the client sees while it finishes.
  • Describe how you would keep data consistent in a distributed system, naming idempotent writes, retries and where eventual consistency is acceptable.

Deliverable: Three annotated diagrams, each ending with a short list of trade-offs and one failure mode with its mitigation.

Day 5 — Feature analysis and production debugging

  • Write the sequence of steps you would take when a feature is underperforming: define the metric, confirm the data is trustworthy, segment, then form hypotheses.
  • Write a production debugging checklist: what changed and when, what the logs and metrics show, how to narrow it down, and how to separate the trigger from the cause.
  • Practise both aloud with a made-up scenario, ending each with how you would confirm the fix worked.

Deliverable: A one-page analysis outline and a debugging checklist, both used in one spoken scenario.

Day 6 — Behavioral stories

  • Choose one real story for each of: optimizing code, a difficult team member, taking the lead on a project and prioritizing under a deadline.
  • Write each story with situation, your decision, the measured or observed result and one thing you would change.
  • Say each story aloud and cut it until the situation takes two sentences and the rest is your reasoning.

Deliverable: Four written stories with figures or observations that you can defend, each reduced to a spoken outline.

Day 7 — Mixed rehearsal

  • Run a spoken session in this order: one JavaScript fundamentals answer, one coding problem written in JavaScript, one design from your day 4 sketches, then one behavioral story.
  • Redo the question you answered worst this week and note what was missing.
  • Prepare questions for the recruiter and the engineers about the team and the work.

Deliverable: A rehearsal log with the weakest answer rewritten and a list of questions to ask.

Behavioral stories for the Canva loop

Candidates report behavioral questions inside the technical interviews. They ask for concrete episodes: optimizing code, working with a difficult colleague, taking the lead, and prioritizing under deadlines. The role is described as working with product managers and designers and joining code reviews, so stories about collaboration and measured outcomes fit well. Rehearse each story with a baseline, your own decision and a result.

  1. Tell me about a time you changed your approach after feedback in a code review.

Can you describe a time you optimized a piece of code? What was the outcome?

Medium · Technical / Domain Questions

Approach

  1. Choose an optimization where you can name the baseline you measured: page render time, bundle size, a loop over a large array, a slow request. Say which tool produced the number (browser performance profiler, timing logs, a benchmark script) so the story starts with evidence rather than a hunch.
  2. Explain how you found the bottleneck: what the profile showed and what you decided not to touch. Examples are repeated lookups in an array that a Map or Set would make constant time, work repeated on every render, or too many network calls that could be batched.
  3. Describe the change itself in concrete terms (memoization, debouncing, virtualizing a long list, batching requests, moving work off the main thread) and name the cost or complexity change, such as quadratic to linear.
  4. Give the outcome as before and after figures, and say how you verified behavior did not regress, for example tests, a feature flag or a staged rollout. If you lack exact figures, describe what you measured and the relative change. Do not invent numbers.
  5. State the trade-off you accepted (readability, memory, added cache invalidation) so the story shows judgment as well as speed.

Follow-up

  • How did you know the improvement came from your change and not from caching, traffic or a different data size?
  • What did the optimization cost in readability or memory, and would you do it again?
  • How do you decide that an optimization is not worth doing?

Describe a situation where you had to work with a difficult team member. How did you handle it?

Medium · Behavioral / Leadership

Approach

  1. Pick a real, ordinary friction, such as repeated review disputes, missed handoffs or dismissive behavior in meetings, and describe it factually in two sentences: what happened and how it affected the work. Avoid a villain story.
  2. Show your first step: a direct, private conversation where you asked for their view and listened for the constraint behind the behavior, such as workload, unclear ownership or different priorities.
  3. Describe what you changed together: a working agreement like writing down a design decision before code review, clearer ownership of a module, or a shared definition of done. Say when and how you involved a manager, and that it came after trying to resolve it directly.
  4. End with the result for the project and for the relationship, plus what you would do differently. The mistake that sinks this answer is a story where the other person was simply wrong, or a manager fixed it for you.

Follow-up

  • What would you have done if the conversation had changed nothing?
  • How did you keep the work moving while the friction was unresolved?
  • Looking back, was any of the problem caused by you?

Can you give an example of a time you took the lead on a project?

Medium · Behavioral / Leadership

Approach

  1. Choose a project where you owned the outcome, with or without the title. State the goal, what shipped, and why you stepped forward, in a few sentences.
  2. Show the mechanics of leading: you split the work into pieces with named owners, wrote the plan or design document, set a regular check-in, unblocked teammates and kept review turnaround short.
  3. Include cross-functional work, since the role is described as working with product managers and designers: explain how you agreed scope with them and how you handled a change in requirements.
  4. Include one decision you made under disagreement or risk, how you communicated it, and what happened. Close with the result and what the team could do without you.
  5. Avoid two failure modes: describing a project you only participated in, and a story where you did everything yourself, which shows the opposite of leading.

Follow-up

  • How did you handle a teammate who was not delivering their part?
  • What did you decide to cut or defer, and who agreed to it?
  • What would you hand off differently next time?

How do you prioritize your tasks when working under tight deadlines?

Medium · Behavioral / Leadership

Approach

  1. Open with a short method: list everything due, mark hard deadlines against soft ones, find dependencies and blockers, then rank by user impact and risk. Work first on what protects the most value, and defer or cut the rest explicitly.
  2. Prove the method with one real story: a deadline where scope exceeded time. Say what you shipped, what you cut, and how you took the trade-off to the product manager or designer early, as options with consequences rather than as a complaint.
  3. Mention specific techniques you used: shipping the smallest slice that works, putting unfinished parts behind a feature flag, keeping tests on the risky path, and recording deferred items so they were not lost.
  4. Say what happened to the deferred work afterwards. The weak version of this answer is 'I work longer hours' or a framework with no example.

Follow-up

  • Two stakeholders each call their request urgent and the two conflict. How do you decide?
  • What did you refuse to cut, and why?
  • How do you tell whether a deadline is actually movable?