cswork / libraryOpen practice workspace

Interview guides · Andela Products

Andela Products Software Engineer Interview Guide

Andela Products Software Engineer interview guide: four reported rounds, coding and React questions, system design, behavioral prep and a 7-day plan.

The 60-second brief

Candidates describe Andela Products as a team that builds and maintains platforms connecting technical talent with job opportunities, alongside product work for partner organisations. Engineers are described as remote-first and spread across time zones, working with product managers and designers. The responsibilities reported for the role include writing and testing application code, building REST APIs, working on React frontends, reviewing code, pair programming, and carrying a feature from first commit to deployment, including CI/CD and production monitoring. The stacks named are React, Node.js, Python (including Flask), Ruby and Java.

This guide is for engineers interviewing for the Software Engineer role at Andela Products, whether you lean frontend (React), backend (Node.js or Python) or full stack. It covers the four reported stages, the 15 reported questions across algorithms, React and API work, databases and system design, and behavioral and remote work, plus a 7-day plan that ends with spoken practice. Candidates describe the requirements as 3+ years of professional experience, one core language, data structures, OOP, REST APIs, Git and B2-or-higher English.

Candidates report four stages over about 3-5 weeks: an Automated English Assessment, an Online Coding Challenge, Core Technical Rounds with live coding, and a Behavioral Interview.

Focus areas

  • Python
  • Live Coding
  • Coding Assessments (Online Tests)

Overview

The loop starts before any engineer speaks to you. The first stage is an automated check of listening and speaking English, and the second is a timed coding challenge, reported on platforms such as HackerRank or Codewars. Preparation therefore covers three separate skills: speaking in full, clear sentences on demand, solving medium-to-hard algorithm problems against a clock, and then explaining your reasoning to people once you reach the live rounds.

The reported technical questions fall into three groups. The algorithm group is small and concrete: converting a string to camelCase and back, removing duplicates from an array and sorting it, a state machine that turns a string of events into a final state, and how to work out the time and space complexity of a recursive function. The stack group covers a React filtering component over a data table, state versus props with React Testing Library, a secure REST API in Node.js or Python/Flask, and the core ideas of OOP. The architecture group covers partitioning versus sharding, surviving a sudden traffic spike, and normalization versus deliberate denormalization.

Candidates also report being asked to code in a plain text editor, with tools like Repl.it or CoderPad named, and in some stages without autocomplete or web search. That changes how you practise: write the camelCase converter and the dedupe-and-sort function from memory in a bare editor, including the standard-library calls, before you rely on any editor help. For the stack rounds, expect to use the language of the role (React, Node.js or Python) rather than a free choice.

The last stage is about remote work and past projects, and candidates report deep questions on their resume. Have four stories ready, each with a decision you made and a result you can describe: learning something new, working remotely, disagreeing on a technical decision, and where you want your career to go. The plan below spends the first four days on English and algorithms, then moves to React, APIs and databases, and finishes with spoken practice.

The Andela Products interview process

Candidates describe four stages, from automated screens to live technical sessions and a final behavioral conversation. The descriptions below say what is reported for each stage and how to prepare for it.

Automated English Assessment

Candidates describe an automated assessment of spoken and listening English, often run through an AI-driven platform, that comes before any coding. Reported tasks include repeating complex sentences back accurately and answering open-ended prompts such as "What is your favorite book and why?". Candidates are advised to speak clearly, reduce background noise and expand on open-ended answers, since one-sentence replies may lower a fluency score. Approach it as a speaking drill: practise giving a claim, a reason and an example in every answer, and rehearse your setup in advance.

What to demonstrate

  • Listening comprehension, shown by repeating long sentences accurately
  • Speaking fluency over an extended answer
  • Clarity when you explain your thinking out loud

How to prepare

  • Read long, multi-clause technical sentences aloud once, then repeat them from memory and compare against the text
  • Record yourself answering an open-ended question such as your favorite book and why, and aim for several connected sentences instead of one
  • Test your microphone, room noise and connection before the day, and answer in a quiet space

Online Coding Challenge

Candidates describe a timed online coding challenge, reported on platforms such as HackerRank or Codewars, with medium-to-hard problems where brute force rarely passes every test. The task types candidates mention are string and array manipulation (camelCase conversion, removing duplicates, custom sorting), simulating a system with a state machine, and complexity analysis. For algorithmic assessments candidates generally report a free choice of language, so pick the one where you know the standard library best. Practise with a visible clock, read the full statement before coding, and test edge cases before you submit.

What to demonstrate

  • Working code under a time limit
  • Choosing an efficient approach with hash maps, two pointers or dynamic programming
  • Stating time and space complexity for your solution

How to prepare

  • Write the camelCase converter and its reverse, and the dedupe-and-sort function, in your chosen language without autocomplete
  • Build the event-string state machine from the reported door example and run it on empty input, repeated events and an unknown event
  • Do timed sets on HackerRank or Codewars and keep a log of the mistakes that cost you the most time
  • Practise stating the complexity of a recursive function out loud using a recurrence

Core Technical Rounds

Candidates describe live screen-sharing sessions with live coding, pair programming and technical discussion with senior engineers, covering coding proficiency and architectural decisions. Whether you are applying as frontend (React), backend (Node.js or Python) or full stack, the stack questions use the role's language. Candidates report plain text editors such as Repl.it or CoderPad, with no syntax highlighting, debugger or autocomplete, and say access to web search depends on the stage. For mid-to-senior roles, reported topics include normalization, partitioning, sharding and RESTful API design. Prepare by coding under those conditions and by explaining each decision as you make it.

What to demonstrate

  • Working code written live in a plain editor
  • Stack knowledge, reported as React hooks and state, the Node.js event loop and testing with React Testing Library
  • Explaining architectural and database choices, including partitioning, sharding and schema design

How to prepare

  • Build the multi-criteria filter over a table of books in React, then write two React Testing Library tests for it
  • Sketch a Flask or Node.js REST API with authentication, input validation, a schema and a deployment story, and say it aloud
  • Prepare crisp definitions of the four OOP ideas with a short example in your language
  • Practise partitioning versus sharding and the traffic-spike design as a spoken whiteboard answer

Behavioral Interview

Candidates describe a final interview about cultural fit, remote work capabilities and past project experiences, with detailed questions drawn from the resume: specific projects, technical conflicts and the realities of working remotely. Candidates are advised to use the STAR structure (Situation, Task, Action, Result) and to show ownership, mentoring and adapting to changing requirements. Prepare stories rather than slogans: each should name a decision you made, the alternatives you weighed and what happened afterwards.

What to demonstrate

  • Past project experience and the decisions you personally made
  • Remote work habits and communication across time zones
  • Handling technical disagreement and changing requirements

How to prepare

  • Pick two or three projects from your resume and be ready to explain the design, your own contribution and one thing you would change
  • Write STAR outlines for learning a new technology, a technical disagreement and a stretch of remote work
  • Prepare a specific answer for your five-year direction that connects to code review, ownership and collaboration
  • Practise delivering each story aloud in plain English, in first person, with the result stated

Where candidates lose points

Giving one-sentence answers in the automated English assessment

Candidates are told that very short answers can reduce a fluency score, so practise answering open-ended prompts with a claim, a reason and an example. Record yourself before the day and also rehearse your microphone, room and connection.

Sorting numbers with a default sort that compares them as text, or deduplicating in a way that loses order or mixes types

For the dedupe-and-sort question, say the element type first, then use a set or hash map to remove duplicates and sort with an explicit numeric comparator where the language needs one (JavaScript's default sort is lexicographic). Quote O(n log n) for the sort and O(n) extra space, and test empty input and all-equal input.

Writing the event state machine as one long chain of if statements with no defined behaviour for unknown or repeated events

Name the states and events up front, write the transition table as a dictionary or map, and decide what an unknown event or an empty string does before coding. Walk one sample string through your loop by hand before you run it.

Building the React filter by copying the filtered list into state, or mutating the data array while sorting

Keep the raw rows and the selected criteria in state, and derive the visible rows during render, with a copy before sorting. Then name which behaviour you would test with React Testing Library, such as selecting two criteria and checking the visible rows.

Depending on autocomplete and a debugger, then losing minutes on syntax in a plain text editor

Practise the camelCase converter, the dedupe-and-sort and a small Flask or Express route in a bare editor, without search, until you do not need to look up the standard-library calls. Say what you would check before you run the code, since there may be no debugger.

Questions & practice

Write a function that transforms a standard string into a camelCased string, and another to reverse the proces

Medium · Data Structures and Algorithms

Write a function that transforms a standard string into a camelCased string, and another to reverse the process.

Approach

  1. Pin down the input before coding: which separators count (spaces, hyphens, underscores, runs of them), leading or trailing separators, digits, and whether the first word is lowercased. State the round trip is lossy: 'Hello-World' and 'hello world' both become 'helloWorld', so the reverse can only produce one canonical form.
  2. To camelCase: split on runs of non-alphanumeric characters (Python re.split(r'[^A-Za-z0-9]+', s)), drop empty tokens, lowercase the first token, then uppercase the first letter of each later token and lowercase the rest. O(n) time and O(n) space.
  3. Build the result with a list and ''.join (or an array join in JavaScript) rather than repeated string concatenation in a loop, which can degrade to quadratic copying.
  4. To reverse: scan once and, before every uppercase letter after index 0, emit the separator and the lowercased letter (or re.sub(r'(?<!^)([A-Z])', r'_\1', s).lower()). Handle acronyms such as 'parseHTTPResponse' with two rules: split between a lowercase letter or digit and an uppercase letter, and between an uppercase run and an uppercase letter followed by lowercase.
  5. Test the edges out loud: empty string, a single word, only separators, consecutive separators, a string already in camelCase, and digits next to letters ('version2Update').

Follow-up

  • How would you keep acronyms intact so 'HTTP response' round-trips as 'HTTPResponse' or 'httpResponse', and which would you choose?
  • What changes for non-ASCII input, for example a letter whose uppercase form is two characters?
  • How would you generalise both functions to snake_case, kebab-case and PascalCase without duplicating the logic?

Implement an algorithm to remove duplicates from an array and sort it in ascending order.

Medium · Data Structures and Algorithms

Approach

  1. Start with the one-liner and its cost: sorted(set(arr)) in Python, O(n) to deduplicate plus O(k log k) to sort the k distinct values, O(n) extra space. In JavaScript, [...new Set(arr)].sort((a, b) => a - b): without the comparator, Array.prototype.sort compares as strings, so [10, 9, 1] sorts to [1, 10, 9].
  2. Offer the no-hash version: sort first, then compact in place with a write pointer that copies a value only when it differs from the last value written. O(n log n) time and no hash set; return the prefix up to the write pointer.
  3. If the values are integers in a small known range R, use a boolean or count array: mark each value, then walk the range in order. O(n + R) time, which beats comparison sorting when R is not much larger than n.
  4. If built-ins are banned, write merge sort and skip a value during the merge when it equals the last value emitted, so deduplication costs nothing extra.
  5. Cover the edges: empty array, one element, all duplicates, negatives, and mixed types (Python 3 raises TypeError when sorting int with str), and say whether the input may be mutated.

Follow-up

  • How would you deduplicate while keeping first-occurrence order instead of sorting (dict.fromkeys in Python, a Set walk in JavaScript)?
  • The array is too large for memory: how do you deduplicate and sort it (external merge sort, dropping duplicates during the k-way merge)?
  • Which version would you pick if the array is already nearly sorted, and why?

Given a string representing a sequence of events over time, write a state machine that calculates the final st

Medium · Data Structures and Algorithms

Given a string representing a sequence of events over time, write a state machine that calculates the final state of the system.

Approach

  1. Clarify the contract first: the event alphabet and what each character means, whether each character is one time step, the initial state, what happens to unknown characters, and whether the output is only the final state or the state after every step. Candidates describe a door-style variant driven by button presses and obstacle detections, so ask how position and direction evolve per step.
  2. Model states as an enum and transitions as a table keyed by (state, event) returning the next state, with an explicit rule for pairs not in the table (stay put or raise). The main loop is then a single lookup per character: O(n) time, O(1) extra space for the final state, O(n) if you return the per-step trace.
  3. For time-based systems the state is more than a label: keep position, direction and a moving or paused flag, and fix the order within a step (apply the event, then advance one unit). Saying that order explicitly prevents off-by-one traces.
  4. Walk the edge cases before coding: empty input, an event arriving at a boundary (fully open or closed), a press while paused resuming in the same direction, an obstacle reversing direction, and repeated events in a terminal state.
  5. Write a small table of inputs and expected traces first and run the code against it; in a plain editor without a debugger, printing the state after each step is the fastest way to find a wrong transition.

Follow-up

  • How would you add a new event type without touching the main loop?
  • How does the code change if events arrive as a stream instead of a complete string?
  • What would you return for an invalid character: skip it, raise, or report its position?

How do you determine the time and space complexity of a recursive function?

Medium · Data Structures and Algorithms

Approach

  1. Write the recurrence from the code: T(n) = (number of recursive calls) x T(subproblem size) + (work done outside the calls). Then expand it as a recursion tree: nodes per level times work per node, summed over the levels.
  2. For divide-and-conquer shapes T(n) = aT(n/b) + f(n), compare f(n) with n^(log_b a) (master theorem). Anchor it with examples: binary search T(n) = T(n/2) + O(1) is O(log n); merge sort T(n) = 2T(n/2) + O(n) is O(n log n).
  3. For decrease-by-one shapes, count the calls directly: naive Fibonacci T(n) = T(n-1) + T(n-2) + O(1) grows as O(phi^n), about 1.618^n, commonly bounded as O(2^n); T(n) = 2T(n-1) + O(1) is O(2^n). Memoising Fibonacci cuts it to O(n) time with O(n) space.
  4. Space is the deepest chain of simultaneous frames times the space per frame, plus any allocations alive at once. Naive Fibonacci is exponential time but only O(n) stack; merge sort uses O(log n) stack plus O(n) auxiliary arrays.
  5. Name the hidden costs: Python list slicing in each call copies data (slicing in binary search adds O(n) total work), CPython has no tail-call optimisation, and the default recursion limit is 1000, so deep recursion needs an iterative rewrite.

Follow-up

  • Convert one of these recursive functions to an iterative one with an explicit stack and compare the space used.
  • What is the complexity of generating all permutations of n items recursively, and where does the n! come from?
  • When does the master theorem not apply, and what do you do instead?

Build a dynamic filtering component in React that updates a data table based on multiple selected criteria.

Medium · Domain-Specific and Live Coding (React /

Approach

  1. Hold one state object for the selected criteria, for example { genre: [], author: [], minYear: null }, receive the rows as props or from a fetch, and derive the visible rows with useMemo from (rows, filters). Storing a filtered copy in state invites the two copies drifting apart.
  2. State the filter semantics before coding: AND across different criteria, OR within the options of one multi-select, and an empty selection means that criterion is ignored. Normalise case for text matches.
  3. Use controlled inputs and immutable updates: setFilters(prev => ({ ...prev, [key]: next })). Build each option list from the distinct values in the data, and add a clear-all control.
  4. Render the table with a stable key from the row id, not the array index, show an empty-state row when nothing matches, and if sorting by several keys is required, chain comparators (compare the first key, fall back to the next on a tie).
  5. Each filter change costs O(n x k) for n rows and k criteria. For large tables, debounce free-text input or use useDeferredValue, virtualise the rows, or move filtering to the server with query parameters; mirroring filters into the URL also makes a view shareable.

Follow-up

  • How would you test this component with React Testing Library?
  • The dataset grows past what the browser can hold: what moves to the server and what does the API look like?
  • How would you persist the selected filters across a page reload?

Explain the differences between state and props in React, and describe how you would test a component using Re

Medium · Domain-Specific and Live Coding (React /

Explain the differences between state and props in React, and describe how you would test a component using React Testing Library.

Approach

  1. Props are inputs a parent passes down; the child treats them as read-only. State is data a component owns through useState or useReducer, and setting it schedules a re-render. When two siblings need the same data, lift the state to their common parent and pass values and callbacks down as props.
  2. Cover the update rules: never mutate state in place (create a new object or array so React sees a new reference), use the functional updater setCount(c => c + 1) when the next value depends on the previous one, and expect updates to be batched (React 18 batches automatically, including in timeouts and promises).
  3. Keep derived values out of state: if it can be computed from props or other state during render, compute it (with useMemo if expensive).
  4. Testing with React Testing Library: render the component, query the way a user finds things (getByRole with a name, getByLabelText), act with @testing-library/user-event, and assert on what is visible (with jest-dom matchers such as toBeInTheDocument), not on internal state.
  5. Use queryBy* to assert something is absent (it returns null instead of throwing) and await findBy* for content that appears asynchronously; pass jest.fn() as a callback prop to assert it was called with the right arguments, and mock network calls (for example with MSW) for components that fetch.

Follow-up

  • When would you reach for context or a state library instead of passing props down several levels?
  • Why does React Testing Library discourage testing implementation details, and what breaks when tests check internal state?
  • How would you test a component that shows a loading state and then fetched data?

What are the core concepts of Object-Oriented Programming, and how do you implement them in your language of c

Medium · Domain-Specific and Live Coding (React /

What are the core concepts of Object-Oriented Programming, and how do you implement them in your language of choice?

Approach

  1. Name the four concepts with one line each and a concrete example: encapsulation (state behind methods), abstraction (callers use an interface, not the internals), inheritance (a subclass reuses and extends a base class), polymorphism (one call, behaviour chosen by the object's type).
  2. In Python: there is no enforced private; a single underscore is a convention and a double underscore triggers name mangling. Use @property for controlled access, abc.ABC with @abstractmethod for abstraction (the class cannot be instantiated until the methods are implemented), super() for inheritance, and duck typing plus method overriding for polymorphism.
  3. In JavaScript or TypeScript: class syntax sits on prototypes, #field gives real private fields, and TypeScript adds interfaces and abstract classes. In Java: access modifiers, interfaces, and the difference between overloading (resolved at compile time) and overriding (resolved at runtime).
  4. Show it in a few lines: a Shape base with area(), Circle and Rectangle overriding it, and a loop summing area() over a mixed list without any type checks.
  5. Close with design judgement: prefer composition when the relationship is has-a, and watch the Liskov substitution principle (a Square subclass of Rectangle breaks callers that set width and height independently).

Follow-up

  • When would you use composition instead of inheritance? Give an example from your own code.
  • What is the difference between an abstract class and an interface in your language?
  • How does Python resolve a method under multiple inheritance (the MRO and C3 linearisation)?

Walk me through the database normalization process and explain when you might intentionally denormalize data.

Medium · System Architecture and Databases

Approach

  1. Walk the normal forms with one example: 1NF means atomic values and no repeating groups; 2NF removes attributes that depend on only part of a composite key; 3NF removes attributes that depend on another non-key attribute; BCNF requires every determinant to be a candidate key.
  2. Use a concrete table: an orders sheet repeating customer name, email, product name and price on every row becomes customers, products, orders and order_items. Keep unit_price on order_items, since the price at purchase time is a separate fact, not a duplicate.
  3. State what normalisation buys: no update anomalies (changing an email in one row but not another), no insert anomalies (a product cannot exist without an order) and no delete anomalies (deleting the last order erases the customer).
  4. Denormalise deliberately when reads dominate and joins or aggregates are the measured bottleneck: a stored like_count, a reporting star schema, a materialised view, or an embedded document in a document store.
  5. Name the cost of each copy and how it stays correct: every write must update it (in the same transaction, by trigger, or by an async job that tolerates staleness), and an atomic UPDATE ... SET n = n + 1 avoids lost updates under concurrency.

Follow-up

  • How would you keep a denormalised counter correct when many users update it at once?
  • When would you choose a materialised view over a denormalised column, and how is it refreshed?
  • Is 3NF always the target for an analytics warehouse? Why or why not?

Hold a per-tenant active cap against concurrent creates

Hard · write skew · isolation levels · constraints

A tenant on the standard plan may hold at most 50 resources with status='active'. The create handler runs SELECT count(*) FROM resource WHERE tenant_id = $1 AND status = 'active', compares to 50, then inserts. Two creates arrive 3 ms apart on different instances and the tenant lands at 51. Name the anomaly, say whether PostgreSQL 16 READ COMMITTED or REPEATABLE READ prevents it and why, then give an implementation that holds the cap at READ COMMITTED with the exact statements. Finally, say what changes when the cap is 'at most one running export per tenant' on job_run.

Approach

  1. Name it: write skew. The two transactions read an overlapping set and write disjoint rows, so there is no row-level conflict for the engine to detect and each commit is individually legal.
  2. Rule out the levels precisely. READ COMMITTED takes a fresh snapshot per statement and takes no lock on the counted rows, so both see 49. PostgreSQL's REPEATABLE READ is snapshot isolation: it removes non-repeatable reads and phantoms within the snapshot but still admits write skew, because the anomaly is not a re-read of a changed row, it is a read of a set that a concurrent transaction invalidates. Only SERIALIZABLE closes it, by tracking the read dependency and aborting one transaction with SQLSTATE 40001 — a guarantee that exists only if the application re-runs the whole transaction from the read.
  3. Convert the set predicate into a single-row conflict: keep tenant.active_resource_count and run UPDATE tenant SET active_resource_count = active_resource_count + 1 WHERE tenant_id = $1 AND active_resource_count < 50 in the same transaction as the INSERT. Zero affected rows is the cap, returned as 409. The row lock serialises the decision at any isolation level, and contention is bounded to one tenant's row — which is also the fair-scheduling unit, unlike a global counter that would convoy every tenant behind one row.
  4. State the cost you just took on: a counter is a second source of truth that can drift, so every path that changes status must adjust it inside the same transaction, and a periodic reconciliation has to exist, with resource_revision as the authority for what the count should have been.

Follow-up

  • A resource moves from archived back to active. Which statements change, and what breaks if the counter update and the status change land in different transactions?
  • The cap becomes plan-dependent and a plan can change mid-month. Where does the number 50 live, and who reads it?

Walk me through how you would build a robust, secure REST API using Node.js or Python/Flask.

Medium · Domain-Specific and Live Coding (React /

Approach

  1. Design the resources first: plural nouns, the right methods (GET, POST, PUT or PATCH, DELETE), and precise status codes: 201 with a Location header on create, 400 or 422 for validation errors, 401 when unauthenticated versus 403 when not allowed, 404, and 409 for conflicts. Add a version prefix and pagination on list endpoints.
  2. Layer the code: route handler, input validation (marshmallow or pydantic in Flask, zod or Joi in Express), a service layer for business rules, and a data layer using an ORM or parameterised queries so user input never reaches SQL as text.
  3. Security checklist: HTTPS only; authentication with short-lived JWTs plus refresh tokens, or session cookies marked HttpOnly, Secure and SameSite; an authorisation check on every object access, not just at login (prevents one user reading another user's records by changing an id); passwords hashed with bcrypt or argon2; rate limiting on login and write endpoints; a CORS allowlist; secrets from environment variables.
  4. Reliability: one consistent error body, no stack traces in responses, structured logs with a request id, idempotency keys on POSTs that clients may retry, database migrations (Alembic for SQLAlchemy), and tests with the Flask test client or supertest.
  5. For deployment, run Flask under gunicorn rather than its development server (or Node under a process manager), behind a reverse proxy, packaged in Docker with CI running tests before release; add a health-check endpoint for the load balancer.

Follow-up

  • How do you revoke a JWT before it expires?
  • A client times out on a POST and retries: how do you avoid creating the record twice?
  • How would you change a column used by the API without downtime?

Explain the concepts of database partitioning and sharding. When would you use one over the other?

Medium · System Architecture and Databases

Approach

  1. Define both terms precisely: partitioning splits one table into pieces inside a single database instance (in PostgreSQL, declarative range, list or hash partitions); sharding spreads data across several database servers, each owning a subset of the keys. Mention vertical partitioning (splitting columns) as distinct from horizontal (splitting rows).
  2. Partitioning gains: partition pruning when queries filter on the partition key, smaller per-partition indexes, and cheap retention by detaching or dropping an old partition instead of a mass DELETE. It does not add write capacity or storage beyond one machine.
  3. Sharding gains horizontal write and storage capacity, at a cost: choosing a shard key, cross-shard joins and transactions, rebalancing when shards fill, and hot spots. Range sharding keeps range scans cheap but concentrates writes on a monotonically increasing key; hash sharding spreads load but makes range queries scatter-gather.
  4. Decision order: index and tune, then partition when tables are large or time-based but one server still copes, then add read replicas and caching, and shard only when write throughput or data size outgrows the largest practical primary.
  5. Pick a key that matches the main access path, for example tenant_id in a multi-tenant system so most queries hit one shard, and say which query that key makes expensive (a report across all tenants).

Follow-up

  • A frequent query does not include the shard key: what are the options (scatter-gather, a global secondary index, a lookup table)?
  • How do you add shards without downtime, and how does consistent hashing reduce the data moved?
  • How would you keep a transaction correct when it touches two shards?

How would you design a scalable backend to handle a sudden massive spike in user traffic?

Medium · System Architecture and Databases

Approach

  1. Clarify the spike: read-heavy or write-heavy, a planned event or a surprise, how large relative to normal, and which endpoints must stay up. The answer differs for a launch-day read surge and a write burst.
  2. Make the application tier stateless behind a load balancer with autoscaling, keeping sessions in a shared store. Autoscaling adds capacity only after new instances boot, so pre-scale for known events and keep headroom.
  3. Absorb reads before they reach the database: a CDN for static and cacheable responses, an in-memory cache such as Redis for hot keys, with stampede protection (request coalescing, jittered TTLs). Add read replicas and a connection pooler such as PgBouncer, since database connections are often the first resource exhausted.
  4. Absorb writes with a queue (SQS, RabbitMQ or Kafka) and worker pools that drain at a rate the database can sustain; make consumers idempotent because messages can be delivered more than once.
  5. Protect the core: rate limiting per client, load shedding with 429 or 503 plus Retry-After, circuit breakers and timeouts on dependencies, and switching off non-essential features. Prove it with load tests and watch p99 latency, error rate, saturation and queue depth.

Follow-up

  • Which component fails first in your design, and how would you know before users do?
  • The cache cluster goes down at peak: what happens to the database, and how do you prevent the herd?
  • How would you load test this without affecting production users?

Every query on one table stalls for forty seconds mid-deploy

Medium · lock contention · ddl · migrations

During a release on PostgreSQL, every query touching resource times out for about 40 seconds and then recovers with no intervention. The release ran one migration, ALTER TABLE resource ADD COLUMN archived_reason TEXT, and the migration log shows it completing in 6 ms. Unrelated tables showed no change in error rate. Explain how a 6 ms statement caused a 40-second stall, give the ordered checks you would run on a live system to confirm it, and give the migration procedure that prevents a repeat.

Approach

  1. Separate the statement's duration from the lock's duration. ADD COLUMN with no default is a catalogue-only change and genuinely runs in milliseconds, but it requires ACCESS EXCLUSIVE, and it cannot acquire that until every transaction already touching the table has finished.
  2. Account for the queueing, which is the part that surprises people. A lock request that is waiting blocks later requests for conflicting modes behind it rather than letting them overtake, so one long-open transaction holds the DDL and the DDL holds all the traffic. The stall length is set by the longest open transaction, not by the size of the change.
  3. Confirm on a live system in this order: pg_stat_activity for that table ordered by xact_start, looking for the oldest transaction and specifically for state = idle in transaction; then pg_locks where granted = false to find the waiter; then join them on pid to name blocker and blocked. pg_blocking_pids() does that join for you and is the fastest single call.
  4. Prevent rather than merely time it better. Set lock_timeout to a second or two on the migration session so the DDL abandons the queue after a bounded wait and is retried, instead of holding it for as long as the oldest transaction lives. Be exact about what that buys: queries arriving during the wait still queue behind the pending ACCESS EXCLUSIVE request, so each attempt costs them up to one lock_timeout of added latency. The outage goes from 40 seconds to about one second per attempt, not to zero. Also run migrations away from deploy-time peaks, and put a statement timeout and an idle-in-transaction timeout on the analytics role that opens the long transactions.

Follow-up

  • The same release also wants NOT NULL on that column. What is the sequence that gets there without a long lock?
  • Your lock_timeout retry fails ten times in a row because the analytics transaction is always open. What do you change?

Suggested practice checklist

The plan follows the four reported stages: speaking practice first, then algorithms under time pressure, React and API work, and databases, with behavioral stories in the final days. Each day names the reported questions it uses.

Day 1 — Spoken English and the loop map

  • Write the four reported stages in order and mark which one you are least ready for.
  • Record yourself repeating three long technical sentences from memory, then compare with the text.
  • Record a multi-sentence answer to an open-ended question such as your favorite book and why, and listen for filler words and one-sentence endings.

Deliverable: A one-page stage map with the weakest stage marked, a recording of the repeated sentences and one open-ended answer, and a short list of speaking habits to fix.

Day 2 — Strings and arrays in a plain editor

  • Write the camelCase converter and the reverse function from memory in your chosen language, handling spaces, underscores, hyphens, empty strings and acronyms.
  • Write dedupe-and-sort for integers and for strings, state the complexity, and fix the default-sort pitfall for numbers.
  • Add five assert-style tests for each function without autocomplete or search.

Deliverable: Four working functions (camelCase, reverse, dedupe, sort), each with its tests and a stated complexity.

Day 3 — State machines and recursion complexity

  • Write the event-string state machine for a door controller where button presses and obstacle detections change its state, with the state output second by second.
  • Add behaviour for an unknown event, an empty string and repeated events, and write a transition table.
  • Work out time and space for factorial, naive Fibonacci, memoized Fibonacci and merge sort using recurrences, and include recursion stack depth.

Deliverable: A working state machine with its tests, plus a table of four recursive functions with recurrence, time and space.

Day 4 — Timed online-assessment simulation

  • Sit a timed set on HackerRank or Codewars with the clock visible and no autocomplete.
  • Redo any problem you missed using a hash map, two pointers or dynamic programming, whichever the problem needs.
  • Review your log and note the mistake type that cost you the most time.

Deliverable: A scored timed set, one re-solved problem, and a log of your three most expensive mistakes.

Day 5 — React filtering and testing

  • Build a table of books filterable by several keys at once, such as author and year, with sort by any key.
  • Write two React Testing Library tests for it, one for selecting criteria and one for the empty result.
  • Practise explaining state versus props in your own words, using your component as the example.

Deliverable: A working filter component, two passing tests and a spoken explanation of state versus props.

Day 6 — APIs, OOP and schema design

  • Sketch a REST API in Flask or Node.js with authentication, input validation, error responses, a database schema and a deployment path.
  • Normalize that schema, then name one place you would denormalize and why.
  • Prepare a spoken answer on the core OOP ideas with one example in your language.

Deliverable: An API sketch with schema, a normalization-and-denormalization note and an OOP script.

Day 7 — Scale, practice drills and behavioral stories

  • Answer aloud how partitioning differs from sharding, and how you would design a backend for a sudden traffic spike.
  • Write STAR outlines for learning a new technology, working remotely, disagreeing with a senior engineer and your five-year direction, then say each aloud.

Deliverable: Two spoken design answers, two worked practice exercises and four STAR outlines delivered once aloud.

Behavioral and remote-work preparation

Candidates describe this stage as focused on cultural fit, remote work capabilities and past project experiences, with questions drawn from your resume. The structure candidates are advised to use is Situation, Task, Action, Result. Prepare stories where you made the decision, can explain the alternatives and can state what happened afterwards.

  1. Walk me through a project on your resume where you owned a feature from first commit to deployment.
  2. Tell me about a time you changed your approach when the requirements shifted.

Tell me about a time you had to learn a completely new technology or framework to complete a project.

Medium · Behavioral and Remote Work

Approach

  1. Choose a story with real stakes: a deadline, a project that depended on a tool you had not used, and a decision that was yours. For this stack, picking up React hooks from a Python background, or Flask from Node.js, is the kind of example that fits.
  2. Show your learning method, not just the outcome: read the official docs, build a small throwaway spike to test the riskiest assumption, ask a teammate one targeted question after you tried it yourself, then move the result into the real codebase behind tests.
  3. State how you verified you had it right, such as tests passing, code review feedback, or a feature running in production, and give the result in terms of what shipped or what improved.
  4. Close with what you got wrong early and what you changed. The story sinks when it only says you watched tutorials or when you claim instant mastery with no mistakes.

Follow-up

  • How did you decide what to learn first and what to postpone so you could still ship on time?
  • What did you misunderstand at the start, and who or what caught it?
  • How would you ramp up on an unfamiliar stack in a distributed team where teammates are offline for part of your day?

How do you manage your time and stay productive in a fully remote work environment?

Medium · Behavioral and Remote Work

Approach

  1. Answer with a system you actually run, not a personality trait. Name a daily written plan, a task broken into pieces small enough to finish in a day, and protected blocks for focused work.
  2. Cover asynchronous communication: pull request descriptions with context and test notes, status updates written so a teammate in another time zone can act without a call, and decisions recorded in a thread.
  3. Describe what you do when blocked: post the question with what you already tried and the log or error, then switch to another task instead of waiting for a reply.
  4. Give one real example from remote or hybrid work with a visible result, such as a feature delivered across time zones, and say how you kept others informed. Avoid the answer that is only I am self-disciplined.

Follow-up

  • A review is blocked on someone eight hours away. What do you do so the work keeps moving?
  • How do you make your progress visible without constant meetings?
  • What do you change about your routine when a deadline slips and you are working alone?

Describe a situation where you disagreed with a senior engineer or product manager on a technical decision. Ho

Medium · Behavioral and Remote Work

Describe a situation where you disagreed with a senior engineer or product manager on a technical decision. How did you resolve it?

Approach

  1. Set the scene briefly: the decision (for example a data model, a library choice or an API shape), who disagreed, and what was at stake. Then spend most of the answer on how you handled the disagreement.
  2. Describe how you made the disagreement about evidence: write the options with their trade-offs, run a benchmark or small prototype, and ask what the other person was optimising for.
  3. Show how it was settled: you were persuaded, they were persuaded, or a tie-break from the team. A strong story admits a point the other person got right.
  4. Finish with the outcome and the relationship afterwards, including how you committed to the decision even if it went against you. The story sinks when the other person is simply wrong, or when you gave in without ever raising the concern.

Follow-up

  • What if the evidence had not settled it? Who decides and how do you accept that?
  • If the decision went against you and you still disagreed, what did you do next?
  • What did you learn about presenting a technical disagreement to a senior engineer or a product manager?

Where do you see your technical career heading in the next five years, and how does this role align with that

Medium · Behavioral and Remote Work

Where do you see your technical career heading in the next five years, and how does this role align with that vision?

Approach

  1. Pick a direction that you can describe in skills, such as deeper backend and database design, stronger system design, or leading code review and mentoring, rather than only a job title.
  2. Link it to the work candidates describe for the role: owning features from inception to deployment, code review, pair programming, and collaborating with a distributed team. Say which of those would build the skills you want.
  3. Show you are already moving that way with one or two recent examples, such as a design you led, a person you mentored or a course you finished and applied.
  4. Keep the answer honest and tied to this job. Answers that treat the role as a stepping stone to something unrelated, or that are only buzzwords, are the ones that fall flat.

Follow-up

  • What have you done in the last year that moves you toward that goal?
  • If the project here used a stack you had not chosen, how would you still make it count for your plan?
  • Would you choose a specialist path or a lead path, and what would change your mind?