cswork / libraryOpen practice workspace

Interview guides · Christian Dior Couture

Christian Dior Couture Software Engineer Interview Guide

Christian Dior Couture Software Engineer interview guide: 3 reported rounds, coding, system design and CS foundation questions, plus a 7-day plan.

The 60-second brief

Christian Dior Couture is a luxury fashion brand. The role description candidates see lists three kinds of engineering work: e-commerce platforms, supply-chain and logistics systems, and internal tooling for boutique advisors. It also mentions backend services and APIs that must hold up during product drops and fashion-week events, plus integration work that connects web applications to older enterprise systems, CRM databases and global inventory tools. For you, that means the reported design questions (overselling stock, notifying advisors, serving video) read as retail problems, while the rest of the loop is general engineering.

This guide is for Software Engineer candidates, typically with 3 to 5+ years of production experience according to the requirements candidates describe. It covers the three reported rounds, the coding, system design, computer-science foundation and behavioral questions candidates report, and how to prepare each one in a language you already use at work (the role lists Java, Python and TypeScript).

Candidates report three rounds over roughly 3-5 weeks: an Initial Recruiter Screening by video, a Technical Evaluation made of several rounds, and a Behavioral Assessment. Pace varies by region and team.

Focus areas

  • Professionalism in interview process
  • Interview communication
  • Scheduling and time management

Overview

The reported questions fall into four groups. Coding and language questions: a thread-safe singleton, cycle detection in a directed graph, how garbage collection works in your main language, a script that pulls error patterns out of a massive log file, and optimistic versus pessimistic locking. System design: preventing overselling during a high-traffic product drop, a global strategy for delivering high-resolution video, rate limiting a public API, a real-time notification system for boutique advisors, and zero-downtime database migrations. Foundations: the TLS handshake, virtual memory, hashing algorithms for load balancing, memory leaks in web applications, and the CAP theorem. Behavioral: a missed bug, ambiguous requirements, speed versus perfection, a disagreement with a senior engineer, and written communication.

The foundations group is what makes this loop different from a typical product-company loop. Candidates report that some panels ask in-depth questions on topics far from the job description, and that other teams are short and to the point. The sensible plan is to prepare for the broader version: for each foundation topic, be able to give a tight explanation in a few sentences, then go one level deeper. For example, for TLS give the key exchange and certificate check, and for virtual memory give page tables, the TLB and page faults.

The stack named in the role description is Java, Python or TypeScript, relational and NoSQL databases, API design, and optionally AWS, GCP or Azure and React or Vue. The reported design questions lean on exactly those pieces: an inventory service needs an atomic stock decrement in a database, a rate limiter needs a shared counter, and a notification feed needs a push channel to the browser or app. Practise each design with a concrete database and cache in mind, not an abstract box diagram.

Candidates also describe the recruiting process itself as part of the evaluation: typos in emails, a misspelled interviewer name or a late arrival are reported to count against you. Treat scheduling replies and thank-you notes as writing you will proofread, and keep your technical answers direct: state the answer, then the reasoning, then the edge cases.

The Christian Dior Couture interview process

These are the stages candidates describe for this role, not a published process. Timing and the number of technical rounds vary by region and team.

Initial Recruiter Screening

Candidates report a video conference with the recruiting team that covers your background, your motivations and how you fit the brand. Treat it as a scripted conversation you control: a short account of your career, a specific reason for this role, and clean logistics. Candidates also report that precise written communication and punctuality are noticed from the first contact, so the screen starts with the scheduling emails, not the call.

What to demonstrate

  • How clearly you summarise your background and the systems you have built
  • Why you want this role, as you explain it
  • Precision and punctuality in how you communicate with the recruiting team

How to prepare

  • Write a two-minute career summary that ends on the kind of work the role lists: e-commerce platforms, supply-chain systems or tooling for store staff.
  • Pick one real project from your history that resembles one of those areas and be ready to describe its scale and your part in it.
  • Check the spelling of the recruiter's and every interviewer's name, test your video link beforehand, and proofread each reply before sending.
  • Ask which languages the technical rounds use and how many technical rounds to expect, so you can pick your primary language.

Technical Evaluation

Candidates describe several technical rounds with objective, direct questions. Reports differ by region: some describe quick, to-the-point sessions, others describe panels that go deep into a wide range of computer-science topics unrelated to the job. For teams in France (Courbevoie is the example candidates give), the style is reported as blunt and results-oriented. The question types reported for this stage are coding and language internals, system design for retail scenarios, and foundations such as TLS, virtual memory and the CAP theorem. Answer by stating the result first, then the reasoning, then the edge cases.

What to demonstrate

  • Working code and a correct statement of time and space complexity
  • Language-runtime knowledge in your main language, including memory management and concurrency
  • Design judgment on stock consistency, rate limiting, delivery of large media and safe schema changes
  • Breadth across networking, operating systems and database internals

How to prepare

  • Code the singleton, cycle-detection and log-parsing questions from memory in one language, with tests for the empty, single-node and malformed-line cases.
  • Write a one-page summary of how garbage collection works in your main language, including the knobs and the common causes of pressure.
  • Sketch the inventory, notification and rate-limiting designs end to end, naming the concrete database, cache and queue you would use.
  • Prepare a spoken answer of a few sentences each for the TLS handshake, virtual memory, hashing for load balancing and the CAP theorem.

Behavioral Assessment

Candidates describe a behavioral stage about how you handle pressure, complexity and fit with the brand. The reported questions cover a missed bug and its aftermath, ambiguous technical requirements, balancing shipping speed against quality, disagreeing with a senior engineer, and the quality of your written communication and documentation. Use stories where you made the decision and can name the outcome.

What to demonstrate

  • Ownership of a mistake and what changed afterwards
  • How you act when requirements are unclear or change
  • How you disagree with senior colleagues and settle it with evidence
  • Quality of your written communication and documentation

How to prepare

  • Write four stories in short bullet form: an escaped bug, an ambiguous brief, a speed-versus-quality call, and a disagreement with a senior engineer.
  • For each story, note your decision, the evidence you used and a result you can state concretely.
  • Bring one real document you wrote (a design note, runbook or postmortem) and know what it changed.
  • Practise saying a trade-off aloud in plain words that a product manager or operations colleague could follow.

Where candidates lose points

Giving the singleton as a code snippet with no discussion of visibility, testability or initialization order

Name the safe forms in your language (an initialization holder or enum in Java, a module-level instance in Python), explain why a naive check-then-create races, and mention hidden global state making tests harder.

Designing the product-drop inventory with a read-then-write stock counter that two buyers can pass at once

Use a single atomic conditional decrement in the database or a cache script, add reservations that expire for unpaid carts, and say where you would choose optimistic versioning versus a row lock.

Bluffing through a foundations question (TLS, virtual memory, CAP) that sits outside your daily work

Keep a short, accurate explanation of each reported topic ready. If you reach the edge of your knowledge, say so, then reason from principles aloud, since candidates report broad questions in some panels.

Sending emails with typos or a misspelled interviewer name, or arriving late to a call

Candidates report these as professionalism failures. Keep a checklist: names verified, link tested, reply proofread, a few minutes early. If the recruiter is the one delayed, stay polite in writing.

A behavioral story that ends with a team fix and no clear decision, evidence or prevention step from you

Use 'I' for your own decisions, state a concrete outcome, and finish with the specific test, alert or process change that now exists.

Questions & practice

Implement a thread-safe singleton pattern and explain the potential pitfalls.

Medium · Core Technical and Coding

Approach

  1. Lead with the simplest correct version: in Java, the initialization-on-demand holder idiom (a private static nested class holding the instance) is lazy and thread-safe because the JVM serialises class initialization, so no explicit lock is needed. An enum singleton is the other safe option and also resists reflection and serialization.
  2. If you write double-checked locking, the field must be volatile: check for null, synchronize, check again, then assign. Without volatile, another thread can see a non-null reference to an object whose constructor writes are not yet visible.
  3. Name the equivalents in other languages: a C++11 function-local static is initialised thread-safely by the standard, and a Python module-level instance is created once because a module runs on first import only. A class-level threading.Lock with a second check also works.
  4. Pitfalls: thread-safe creation does not make the instance's own mutable state thread-safe; serialization (fix with readResolve), reflection and multiple classloaders can each produce a second instance; and hidden global state makes tests depend on run order and is hard to mock.
  5. Close with the alternative: let a dependency-injection container own one instance per application, which keeps the single-instance guarantee and lets tests pass in a fake.

Follow-up

  • Why exactly does double-checked locking break without volatile under the Java memory model?
  • How would you reset or replace this singleton between unit tests?
  • What happens if the class is loaded by two different classloaders?

Write a function to detect a cycle in a directed graph and optimize it for space complexity.

Medium · Core Technical and Coding

Approach

  1. Use DFS with three colours: white (unvisited), gray (on the current DFS path) and black (finished). An edge into a gray node is a back edge, so the graph has a cycle. This is O(V + E) time.
  2. For the space part, keep a single colour array (2 bits per node is enough) instead of separate visited and on-stack sets, and make the DFS iterative with an explicit stack of (node, next-neighbour index) so a long path cannot overflow the call stack.
  3. Give Kahn's algorithm as the alternative: compute in-degrees, repeatedly remove nodes with in-degree zero using a queue, and report a cycle if fewer than V nodes are removed. It is O(V + E) with O(V) extra memory, needs no recursion, and gives a topological order when there is no cycle.
  4. Edge cases: a self-loop is a cycle; start a DFS from every still-white node so disconnected components are covered; parallel edges are harmless. The undirected 'visited neighbour that is not my parent' check is wrong for directed graphs.
  5. Special case: if every node has at most one outgoing edge (a functional graph, such as next pointers), Floyd's tortoise-and-hare detects a cycle from a start node in O(1) extra space.

Follow-up

  • Return the nodes of one cycle, not just a boolean.
  • Edges arrive one at a time: how do you reject the first edge that would create a cycle?
  • The graph does not fit in memory. What changes?

How does the garbage collector work in your primary programming language, and how can you optimize for it?

Medium · Core Technical and Coding

Approach

  1. Pick one runtime and be precise. On the JVM: tracing collection from GC roots (thread stacks, static fields, JNI references), so cycles are reclaimed. The heap is generational: a young generation (eden plus survivor spaces) is collected by copying, and survivors are promoted to the old generation. G1 has been the default collector since JDK 9; ZGC and Shenandoah are concurrent, low-pause options.
  2. If your language is Python: CPython frees most objects as soon as their reference count reaches zero, and a separate cycle collector (the gc module) finds reference cycles that counting cannot. Go uses a concurrent, non-moving, non-generational tri-colour mark-and-sweep tuned by GOGC and, since Go 1.19, GOMEMLIMIT. V8 uses a copying scavenger for the young generation and mark-sweep-compact for the old generation.
  3. Measure before tuning: JVM GC logs (-Xlog:gc* on JDK 9+), jstat, Java Flight Recorder allocation profiles; in Python gc.get_stats and tracemalloc; in Go GODEBUG=gctrace=1 and pprof heap profiles.
  4. Optimisations that work: allocate less on hot paths (reuse buffers, avoid boxing, build strings with a builder), size the heap for the live set, choose the collector by goal (throughput or pause time), avoid finalizers, and drop references early, especially from unbounded caches.

Follow-up

  • What triggers a long stop-the-world pause, and how would you diagnose one from the GC logs?
  • How can a garbage-collected program still leak memory?
  • When would you use a weak or soft reference, and what goes wrong if you overuse them?

Given a massive log file, write a script to parse and extract specific error patterns efficiently.

Medium · Core Technical and Coding

Approach

  1. Stream the file instead of loading it: in Python, iterate the file object line by line inside a with block, so memory is bounded by the longest line plus the aggregates and the time is O(file size). Open with errors='replace' so one bad byte cannot kill the run.
  2. Compile the regex once outside the loop and use named groups for the fields you need (timestamp, level, service, error code). Put a cheap substring test such as 'ERROR' in line before the regex, and avoid nested quantifiers like (a+)+ that can backtrack catastrophically.
  3. Aggregate rather than collect: normalise each error into a signature (strip ids, numbers and hex addresses) and count with collections.Counter, then take the top k with most_common or a size-k heap in O(n log k).
  4. Edge cases: multi-line stack traces (attach a line with no leading timestamp to the previous record), a partial last line, mixed encodings, gzip-rotated files (gzip.open in text mode), and time zones in timestamps.
  5. If one pass is too slow, say whether the job is I/O-bound or CPU-bound. For CPU-bound work, split the file at byte offsets moved forward to the next newline, process the chunks in parallel processes and merge the counters. For a one-off, grep -E or ripgrep may be the right answer.

Follow-up

  • The file is still being written and gets rotated. How do you follow it without missing or double-counting lines?
  • Only errors between two timestamps are needed. Can you avoid scanning the whole file?
  • The same logs come from many servers. How does the design change?

Explain the differences between optimistic and pessimistic locking in database transactions.

Medium · Core Technical and Coding

Approach

  1. Pessimistic locking takes the lock before the read: SELECT ... FOR UPDATE in PostgreSQL or InnoDB holds row locks until commit, so other writers wait (NOWAIT fails at once, SKIP LOCKED skips locked rows). It suits frequent conflicts or expensive retries; the costs are blocking, lock waits and deadlocks.
  2. Optimistic locking reads without a lock and checks a version on write: UPDATE item SET qty = ?, version = version + 1 WHERE id = ? AND version = ?. If zero rows were updated, someone else won, so reload and retry or report a conflict. JPA's @Version does this. It suits low contention and edits that span user think-time, where a database lock cannot be held across HTTP requests.
  3. Trade-off: under heavy contention optimistic locking wastes work in retry storms, while pessimistic locking serialises access and lowers throughput. Isolation level matters too: in PostgreSQL under REPEATABLE READ, a concurrent update to the same row raises a serialization failure the application must retry.
  4. Avoid deadlocks with pessimistic locks by locking rows in a consistent order (for example sorted by id), keeping transactions short, and setting lock_timeout.
  5. For a simple counter, a single conditional statement avoids read-then-write altogether: UPDATE stock SET qty = qty - 1 WHERE id = ? AND qty > 0, then check the affected row count.

Follow-up

  • Which would you use to decrement stock during a high-traffic product drop, and why?
  • What is a lost update, and which isolation levels prevent it?
  • Two transactions deadlock in production. How do you find and fix the cause?

How does virtual memory work at the operating system level?

Medium · Broad Foundations and Edge Cases

Approach

  1. Each process gets its own virtual address space. The MMU translates virtual pages (commonly 4 KiB) to physical frames using per-process page tables, multi-level on x86-64 (four levels, or five with 5-level paging). The TLB caches recent translations, and a context switch loads a new page-table base (CR3 on x86); PCIDs avoid flushing the whole TLB.
  2. Page faults: touching a page that is not mapped traps into the kernel. A minor fault resolves without disk I/O (a page already in the page cache, or a first touch backed by a zeroed page); a major fault reads from swap or a file; an invalid access ends in SIGSEGV.
  3. What it enables: isolation and protection bits (read, write, execute, user or kernel), demand paging so a large malloc reserves address space before using RAM, copy-on-write after fork, mmap of files, and shared libraries mapped once in physical memory.
  4. Under memory pressure the kernel reclaims pages with LRU approximations such as the clock algorithm, swapping anonymous pages out; when the working set exceeds RAM the system thrashes. On Linux, overcommit means the OOM killer may end a process later instead of malloc failing.
  5. Performance: TLB misses are expensive for large random-access working sets, and huge pages (2 MiB on x86-64) cut TLB pressure; access locality matters as much as the total size.

Follow-up

  • Walk through what happens after fork() when the child writes to a page.
  • Why can a process's virtual size (VSZ) be far larger than its resident size (RSS)?
  • How would you detect thrashing on a Linux host?

Describe a situation where you had to work with a highly ambiguous set of technical requirements.

Medium · Behavioral and Professionalism

Approach

  1. Treat it as a behavioural question with STAR: describe a real project in two sentences where the requirements were unclear, then spend most of the answer on what you did.
  2. Show concrete moves: I wrote down the open questions and my assumptions, asked the stakeholder to rank them, separated decisions that were cheap to reverse from ones that were costly, and built a thin prototype or spike to get feedback on something real.
  3. Show how you contained the risk: written acceptance criteria agreed before building, a design that isolated the parts most likely to change (behind an interface or a config flag), and checkpoints where scope was re-confirmed.
  4. Close with a measurable result (shipped on what timeline, rework avoided, fewer change requests) and one thing you would do earlier next time.
  5. The mistakes that sink it: blaming the product owner for being vague, a story where you waited for someone else to clarify, or one where you guessed, built, and found out late.

Follow-up

  • Which assumption turned out to be wrong, and how did you find out?
  • How did you decide you had enough clarity to start building?
  • How did you tell stakeholders when the scope changed?

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

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

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?

Design an inventory management system that prevents overselling during a high-traffic product drop.

Medium · System Design and Architecture

Approach

  1. State the invariant first: confirmed orders must never exceed stock. Then size the problem: product-page reads far outnumber purchase attempts, stock is small, and payments can fail or time out.
  2. Make the decrement atomic at one source of truth per SKU, never read-then-write in application code: either UPDATE inventory SET available = available - :n WHERE sku = :s AND available >= :n and check the affected rows, or for a very hot SKU a Redis Lua script that checks and decrements in one step and is persisted afterwards.
  3. Use reservations: create a hold row with an expiry when the shopper reaches checkout, confirm it after payment succeeds, and release expired holds with a sweeper or delayed queue. An idempotency key on the checkout call stops client retries from reserving twice.
  4. Shape traffic in front of the write path: a waiting room or queue before checkout, per-user and bot rate limits, CDN-cached product pages, and an approximate stock badge served from cache. Reads may be stale; the decrement may not.
  5. Name the hot-row problem: one SKU row becomes a lock hotspot. Splitting its stock into N sub-counters and decrementing a random non-empty one spreads contention, at the cost of extra work for the last few units. Plan reconciliation for when the cache counter and the database disagree.

Follow-up

  • The payment provider times out after stock is reserved. What state is the order in, and who releases it?
  • How do you stop bots from buying the whole drop?
  • After a Redis failover the counter and the database disagree. How do you reconcile them?

How would you architect a global content delivery strategy for high-resolution video assets?

Medium · System Design and Architecture

Approach

  1. Ingest path: store the master file in object storage as the origin, then transcode it into an adaptive bitrate ladder (several resolutions and bitrates) packaged as HLS and/or DASH segments with manifests. CMAF lets one set of fragmented MP4 segments serve both protocols.
  2. Delivery through a CDN: segments get long max-age and immutable headers behind content-addressed or versioned URLs; manifests for live streams get short TTLs. An origin shield (mid-tier cache) collapses edge misses so the origin is not stampeded, and a second CDN with DNS steering covers a provider outage.
  3. Client side: an ABR player picks the rendition from measured throughput and buffer level, starting low for fast startup. Codec choice is a trade-off: H.264 plays everywhere, while HEVC and AV1 save bandwidth but have patchier device support.
  4. Access control as required: signed URLs or signed cookies with expiry for embargoed assets, geo-restriction, and DRM (Widevine, FairPlay) only if licensing calls for it.
  5. Measure cache hit ratio, time to first frame, rebuffering ratio and egress cost, and warm edge caches ahead of a launch with known timing.

Follow-up

  • An asset was replaced after publishing. Do you purge the CDN or change the URL, and why?
  • What changes if the video is a live stream rather than on demand?
  • Egress cost is too high. Where do you cut it first?

Explain how you would implement rate limiting for a public-facing API.

Medium · System Design and Architecture

Approach

  1. Define the key and the limit: per API key or user, falling back to IP for anonymous calls, with stricter limits on sensitive endpoints such as login. Reject with HTTP 429 and a Retry-After header so well-behaved clients back off.
  2. Compare algorithms: a fixed window counter is cheap but allows up to twice the limit across a window boundary; a sliding window log is exact but stores every timestamp; a sliding window counter weights the previous window to approximate it cheaply; a token bucket allows bursts up to its capacity while enforcing a steady refill rate. For most public APIs I would choose the token bucket.
  3. Distributed enforcement: keep counters in a shared store such as Redis and make check-and-update atomic with a Lua script. A plain GET then SET races; INCR followed by a separate EXPIRE can leave a key with no expiry if the process dies between the two calls.
  4. Placement and failure mode: enforce at the gateway or edge before application servers, optionally with a local in-memory limiter to absorb floods. Decide whether to fail open or closed when Redis is down (usually open with a local fallback limit, closed for authentication endpoints).
  5. Edge cases: many clients behind one NAT IP, clock differences between nodes (compute windows from one clock, such as the store's), and retries that amplify load during an incident.

Follow-up

  • Show a request sequence where a fixed window lets through twice the limit.
  • How would you enforce one global limit across several regions?
  • Some endpoints are much more expensive than others. How do you limit by cost rather than request count?

Design a real-time notification system for boutique advisors to track high-value client arrivals.

Medium · System Design and Architecture

Approach

  1. Clarify before designing: what signals an arrival (an appointment check-in, staff marking the client in an app, something else), who should be told (the assigned advisor, everyone on duty at that boutique), the latency target, and what client data may appear on a device.
  2. Pipeline: the arrival event goes to a broker (Kafka or a managed pub/sub) partitioned by boutique id, which keeps each boutique's events in order. A notification service resolves recipients from the client record and the staff roster, writes the notification to a store, and pushes it over WebSocket or server-sent events to connected devices, falling back to APNs/FCM push when the app is offline.
  3. Delivery semantics: at-least-once with a unique event id so clients drop duplicates; persisted notifications with acknowledgement state; escalation to other on-duty staff if nobody acknowledges.
  4. Connections: a WebSocket gateway tier keeps a user-to-connection map (for example in Redis) and fans out across nodes through pub/sub. Heartbeats detect dead connections, and on reconnect the client sends its last seen event id to replay what it missed.
  5. Privacy: keep the push payload minimal (that a client arrived, no personal details), fetch details in-app after authentication, scope access by boutique and role, keep an audit log, and apply a retention policy to arrival history.

Follow-up

  • The advisor's tablet is offline when the client arrives. What happens?
  • How do you avoid alerting twice when the same client is checked in twice?
  • How would you load-test this before a busy day across many boutiques?

What architectural patterns would you use to ensure zero downtime during database migrations?

Medium · System Design and Architecture

Approach

  1. Use expand and contract: add the new structure in a backward-compatible way (a nullable column or new table), deploy code that writes both old and new, backfill, switch reads, stop writing the old structure, and drop it in a later release. Every step must work with both the current and the previous app version, so rolling deploys and rollbacks stay safe.
  2. Know which DDL takes heavy locks. In PostgreSQL, CREATE INDEX CONCURRENTLY avoids blocking writes but cannot run inside a transaction block; since PostgreSQL 11, adding a column with a non-volatile default is metadata-only, while a volatile default rewrites the table; add NOT NULL as a CHECK constraint with NOT VALID, then VALIDATE CONSTRAINT. Set lock_timeout so DDL waiting for a lock does not queue every other query behind it.
  3. Backfill in batches by primary key range, throttled and idempotent so it can resume, while watching replication lag and error rates.
  4. A rename is never done in place while old code runs: add the new column, dual-write, backfill, switch reads, then drop the old one. On MySQL, online DDL or tools such as gh-ost and pt-online-schema-change cover large table changes.
  5. For moving to a new database, combine dual writes or change data capture with shadow reads that compare results, then cut over behind a feature flag with a tested way back.

Follow-up

  • The migration fails halfway through the backfill. How do you roll back or resume?
  • How do you prove the backfill is complete and the two columns agree?
  • What changes for a table with billions of rows and heavy write traffic?

Explain the precise steps of a TLS handshake.

Medium · Broad Foundations and Edge Cases

Approach

  1. TLS 1.3 after the TCP connection: the ClientHello carries the supported versions, cipher suites, a random value, SNI, ALPN and a key_share (an ephemeral ECDHE public key such as X25519). The ServerHello returns the chosen suite and the server's key_share. Both sides derive handshake keys from the shared secret with HKDF, so the full handshake takes one round trip.
  2. Everything after the ServerHello is encrypted: EncryptedExtensions, Certificate, CertificateVerify (a signature over the transcript hash made with the certificate's private key) and Finished (a MAC over the transcript). The client validates the chain to a trusted root, the hostname against the SAN and the validity dates, then sends its own Finished, and application data flows.
  3. Say what each piece proves: Certificate plus CertificateVerify show the server holds the private key; ephemeral ECDHE gives forward secrecy; the Finished MACs detect tampering or a downgrade of the handshake.
  4. Contrast with TLS 1.2: two round trips (ClientHello, ServerHello, Certificate, ServerKeyExchange, ServerHelloDone, ClientKeyExchange, ChangeCipherSpec, Finished), and static RSA key exchange without forward secrecy is still allowed; TLS 1.3 removed it.
  5. Extras: resumption with session tickets or PSK; 0-RTT early data in TLS 1.3 can be replayed, so it should carry only idempotent requests; for mutual TLS the server sends CertificateRequest and the client answers with Certificate and CertificateVerify.

Follow-up

  • What exactly does the client check on the server certificate, including revocation?
  • Why can 0-RTT data be replayed, and how do servers limit the damage?
  • Where is HTTP/2 negotiated, and what does SNI expose to an observer?

Discuss the trade-offs between different hashing algorithms used for load balancing.

Medium · Broad Foundations and Edge Cases

Approach

  1. Modulo hashing, hash(key) % N: simple and even, but changing N from N to N + 1 remaps most keys (about N/(N + 1) of them). Fine for stateless round-robin-style spreading, bad for caches or sticky sessions.
  2. Consistent hashing on a ring: servers and keys hash onto a ring and each key goes to the next server clockwise, so adding or removing a node moves only about 1/N of the keys. Without virtual nodes the load is uneven, so give each server many vnodes (which also allows weighting); lookup is a binary search, O(log of the vnode count).
  3. Rendezvous (highest random weight) hashing: score hash(key, server) for every server and pick the highest. Disruption is minimal and the spread is even with no ring to maintain, but lookup is O(N), fine for small server counts.
  4. Jump consistent hash: O(log N) expected time, no memory, very even, but buckets are numbered 0 to N-1 and can only be added or removed at the end, which suits sharded storage more than arbitrary node failure. Maglev hashing builds a lookup table for O(1) lookups with near-minimal disruption, used in L4 load balancers.
  5. Hash function: a fast non-cryptographic hash (MurmurHash3, xxHash) gives a good spread; a keyed hash matters only if clients can choose keys adversarially. No scheme fixes a single hot key; consistent hashing with bounded loads or replicating that key does.

Follow-up

  • How many virtual nodes per server would you use, and what does the number trade off?
  • A server dies. Where do its keys go under each scheme?
  • One key receives a large share of all traffic. What do you do?

Explain the CAP theorem and how it applies to the database systems you have used previously.

Medium · Broad Foundations and Edge Cases

Approach

  1. State it precisely: when a network partition separates nodes, a distributed store must give up either consistency (linearizability: every read sees the latest completed write) or availability (every request to a live node gets a non-error answer). Partitions cannot be ruled out, so the real choice is CP or AP during a partition. 'Pick any two of three' is the common misstatement.
  2. Add PACELC: else, when there is no partition, the trade-off is latency against consistency, for example synchronous replication adds write latency.
  3. Map it to systems you have actually run. A single-primary PostgreSQL setup leans consistent: if the primary is cut off, writes stop until failover, and reads from asynchronous replicas can be stale. etcd and ZooKeeper are CP through consensus (Raft, ZAB): the minority side refuses writes. Cassandra is tunable: consistency level ONE leans available with last-write-wins conflicts, while quorum reads and writes with R + W > RF make read and write sets overlap.
  4. Tie the choice to the data: stock decrements and payments need consistency (overselling is the failure), while catalogue pages, view counts or recommendations can tolerate staleness for availability.

Follow-up

  • What does R + W > N guarantee, and what does it still not guarantee?
  • How does Raft keep the cluster consistent while a partition is in progress?
  • For a shopping cart and for a payment ledger, which side would you pick and why?

What are the common causes of memory leaks in modern web applications, and how do you profile them?

Medium · Broad Foundations and Edge Cases

Approach

  1. Browser causes: event listeners, intervals or subscriptions not removed when a component unmounts (a useEffect without a cleanup function), detached DOM nodes still referenced from JavaScript, closures holding large objects, unbounded Maps or caches keyed by objects (a WeakMap avoids that), and global stores that only ever grow.
  2. Server (Node.js) causes: module-level caches without eviction or TTL, a listener added per request to a long-lived emitter (a MaxListenersExceededWarning is the hint), promises that never settle while holding request objects, and timers that are never cleared.
  3. Profile in the browser with Chrome DevTools: take a heap snapshot, repeat the suspect action several times, take another, and use the Comparison view; filter for 'Detached' to find detached DOM trees and read the retainers path to see what keeps an object alive. The Performance monitor shows heap size and DOM node count trends.
  4. Profile Node with --inspect and DevTools heap snapshots or v8.writeHeapSnapshot(), and track process.memoryUsage() under steady load. A leak is a baseline that keeps rising after each collection, not one high reading; running with --expose-gc and calling gc() before measuring removes the noise.
  5. Fix and prevent: cleanup functions, AbortController signals to remove listeners in one go, bounded LRU caches, and a soak test that alerts on heap growth before release.

Follow-up

  • How do you tell a real leak from a cache that is still warming up?
  • A heap snapshot shows a large retained size under a closure. What is your next step?
  • Memory grows only in production and you cannot attach DevTools there. How do you investigate?

Suggested practice checklist

Seven days built around the three reported rounds: reply and screening polish first, then coding, runtime and database questions, two days of retail-flavoured design, a foundations day, and a behavioral and mock day.

Day 1 — Recruiter screen and correspondence

  • Write your two-minute career summary and a one-sentence reason for the role, referring to the work areas the role lists (e-commerce platforms, supply-chain systems, boutique tooling).
  • Write a short reply template for scheduling emails and proofread it, including a check on how every name is spelled.
  • List the three reported rounds and mark which of the coding, design, foundations and behavioral areas you are weakest in.

Deliverable: A written career summary, a proofread email template, and a one-page list of the three rounds with your weakest areas marked.

Day 2 — Coding questions in your main language

  • Implement a thread-safe singleton in your main language, then list its pitfalls: visibility, initialization order, testability.
  • Write cycle detection for a directed graph twice, with three-colour DFS and with Kahn's in-degree method, and note the extra space each one uses.
  • Write a log-scanning script that streams line by line, compiles its patterns once and counts matches per error signature, and test it with an empty file and malformed lines.

Deliverable: Three tested solutions (singleton, cycle detection in two variants, log scanner) with a complexity note for each.

Day 3 — Runtime internals and database locking

  • Write one page on how garbage collection works in your main language: generations or reference counting, what triggers a collection, and two ways to reduce pressure.
  • Write the same stock-update example with optimistic locking (a version column and a conditional update) and with pessimistic locking (SELECT ... FOR UPDATE), and note when each loses.
  • List the common causes of memory leaks in a web application (unbounded caches, forgotten listeners, detached DOM nodes, timers) and the steps to find them with a heap snapshot.

Deliverable: A GC page, a two-variant locking example with a trade-off table, and a leak-hunting checklist.

Day 4 — Design: stock, rate limits and advisor alerts

  • Design the product-drop inventory service: atomic decrement, reservations that expire, behavior at zero stock, and how the count is reconciled with a downstream warehouse system.
  • Design the public API rate limiter: compare token bucket with sliding window, store counters in a shared cache, and define the 429 response with a retry hint.
  • Design the advisor notification system: an event source, a push channel such as WebSocket or server-sent events, delivery when a device is offline, and what you do if the broker fails.

Deliverable: Three one-page designs, each with a diagram, a data model, a failure case and a first bottleneck.

Day 5 — Design: media delivery, migrations and hashing

  • Design the global delivery strategy for high-resolution video: encoding ladder, adaptive-bitrate streaming, edge caches with an origin shield, and cache invalidation on asset updates.
  • Plan a zero-downtime schema change using expand and contract: add the column, dual write, backfill, switch reads, then remove the old column, with a rollback at each step.
  • Compare modulo hashing, consistent hashing with virtual nodes and rendezvous hashing for load balancing, including what moves when a server is added.

Deliverable: A CDN design, a step-by-step migration plan with rollback points, and a hashing comparison table.

Day 6 — Foundations rapid-fire

  • Write a spoken-length answer on the TLS handshake: client hello with key share, server certificate and verification, key derivation, finished messages.
  • Write an answer on virtual memory: page tables, the TLB, page faults and demand paging, and swapping.
  • Write an answer on the CAP theorem tied to databases you have used, saying what happened to availability or consistency during a partition.
  • Walk through what happens between typing a URL and seeing a page, covering DNS, TCP, TLS and HTTP, and compare a B-Tree index with a hash index.

Deliverable: Four timed spoken answers recorded and checked against your written notes.

Day 7 — Behavioral stories and a full mock

  • Write your stories for the escaped bug, the speed-versus-quality call, the disagreement with a senior engineer and the ambiguous requirements, each with decision, evidence and outcome.
  • Prepare your answer on written communication, with a real document to point to.
  • Run a mock of the screen followed by one coding, one design and one foundations question, answering directly with the result first.

Deliverable: Five written story outlines with measurable outcomes and one recorded mock covering all three rounds.

Behavioral stories for the Christian Dior Couture loop

Candidates describe the final stage as a check on how you handle pressure, complexity and change, plus how you communicate. For a software engineer, the reported prompts ask for a missed bug, unclear requirements, speed versus quality, a disagreement with a senior engineer and your documentation habits. Prepare a story for each, with your own decision, a measurable result and the process change that followed.

  1. Describe a situation where you had to work with a highly ambiguous set of technical requirements.
  2. Tell me about a time you had to pivot your technical approach entirely because of a sudden change in business requirements.

Tell me about a time you missed a critical bug. How did you handle the fallout and prevent it from happening a

Medium · Behavioral and Professionalism

Tell me about a time you missed a critical bug. How did you handle the fallout and prevent it from happening again?

Approach

  1. Choose a bug that reached users and was your responsibility, such as a missed edge case in a release, not a trivial typo and not one you inherited. The story fails if it ends with someone else to blame.
  2. Open with a two-sentence situation, then the impact in measurable terms (users or orders affected, how long, what data was wrong), then how you found out.
  3. Describe the response in order: contain (rollback, feature flag or hotfix), tell the affected people what happened and what you were doing, fix the root cause, and repair the data if needed.
  4. Spend the final third on prevention that is verifiable: a regression test for that case, a CI check, a canary or staged rollout, an alert on the symptom, and a short written postmortem. Say which gap let the bug through (test, review or monitoring), not who.

Follow-up

  • How did you first learn about the bug, and could monitoring have told you sooner?
  • What exactly did you tell stakeholders, and when?
  • Which test or check would have caught it, and where does it run today?

How do you balance the need to ship features quickly with the requirement for absolute technical perfection?

Medium · Behavioral and Professionalism

Approach

  1. Reject the either/or framing in your first sentence: some parts must be exactly right (money, stock counts, data loss, security), while others can ship simple and be refined afterwards. Name which category your example falls in.
  2. Tell one concrete story with a deadline: what you scoped out to keep the date (features, polish, rare configurations), and what you refused to cut (tests on the core path, a migration rollback plan, validation).
  3. Show the mechanics that make speed safe: feature flags, a staged rollout, automated tests in the CI/CD pipeline, monitoring on release day and a defined rollback step.
  4. Close with debt handling: the shortcut you took was written down as a ticket with an owner, and you can say whether it was paid back. Never claim perfection is achievable, and never say you simply move fast.

Follow-up

  • Who agreed to the scope you cut, and how did you get that agreement?
  • What would you do if a stakeholder asked you to skip testing on the core path?
  • Did the shortcut cause any problem later, and how did you find out?

Tell me about a time you disagreed with a senior engineer's architectural decision. How did you resolve it?

Medium · Behavioral and Professionalism

Approach

  1. Pick a real architectural disagreement, such as a data store choice, a service boundary or a sync-versus-async design, where both options were defensible. Avoid a story where the other person was plainly wrong.
  2. State the senior engineer's reasoning first, in terms they would accept, to show you understood it before objecting. Then state your concern as a specific risk (a failure mode, a cost, a scaling limit) rather than a preference.
  3. Resolve with evidence: a small prototype, a load test, a back-of-envelope capacity estimate, or a written comparison of options with the trade-offs. Keep the tone neutral and factual in conversation and in writing.
  4. Give the outcome honestly. If your view won, say what you conceded; if it lost, say that you committed to the decision, and what you did to cover your concern (a metric to watch, a revisit date). Going around the person is the mistake that sinks this story.

Follow-up

  • What would you have done if the senior engineer still disagreed after seeing the data?
  • Was there any part of their argument you later found you had underestimated?
  • How did the working relationship look afterwards?

How do you ensure your written communication and documentation meet the highest professional standards?

Medium · Behavioral and Professionalism

Approach

  1. Answer with concrete artefacts, not an adjective. Name what you write regularly (pull-request descriptions, design notes, runbooks, API documentation, postmortems) and where each lives so the next engineer finds it.
  2. Describe a repeatable check: put the conclusion or the ask in the first lines, list owners and dates for actions, reread for spelling and names before sending, and have a teammate review important documents the way you review code.
  3. Show how documentation stays accurate: keep it in the repository next to the code, update it in the same pull request as the change, and generate API references from the schema where you can.
  4. Give one result: a runbook that let someone else resolve an incident alone, or a decision note that ended a repeated debate. Mention adapting the same content for a non-technical reader, since candidates report that correspondence with the recruiting team is itself noticed.

Follow-up

  • Show me a document you wrote that someone else relied on. What did it change?
  • How do you stop documentation going stale?
  • How do you rewrite a technical trade-off for a non-technical stakeholder?