Interview guides · Claryo
Claryo Software Engineer Interview Guide
Claryo Software Engineer interview guide: five reported rounds, full-stack, API design, system design and behavioral questions, with a 7-day plan.
The 60-second brief
Candidate reports describe Claryo engineers as people who connect data-heavy problems to user-facing features, working across the stack from interface to database. No specific product name is reported, so this guide does not guess at one. The work candidates describe covers full-stack feature development and infrastructure improvement, collaboration with Product Managers and Designers, participation in code reviews, and ownership of changes such as CI/CD pipeline improvements or a new microservice.
This guide is for candidates interviewing for a Software Engineer role at Claryo. It covers the five reported rounds, the full-stack, system design and behavioral questions candidates report, the stack named in the role requirements (JavaScript or TypeScript frameworks, relational databases, RESTful APIs, with AWS or GCP and Docker or Kubernetes as extras), and a seven-day plan. It assumes you can already code; the focus is on turning that experience into answers for these specific questions.
Candidates report five rounds over roughly four to six weeks: Initial Screening, Technical Screen, Architectural Deep Dive, Leadership Conversations and Final Interviews. They add that the order can shift by team or seniority.
Focus areas
- Full-Stack Development
- Software Engineering Fundamentals
- Product Development
Overview
The work candidates describe is full-stack: building features with Product Managers and Designers, reviewing code, and improving shared infrastructure such as the CI/CD pipeline or a new microservice. The listed requirements point the same way: JavaScript or TypeScript frameworks, relational databases and RESTful API design, with cloud (AWS or GCP) and containers (Docker, Kubernetes) as bonuses. Preparation therefore has to run from the browser to the database, not stop at one layer.
The reported questions fall into three groups. Full-stack proficiency covers frontend state in a data-heavy application, tuning a slow database query, API design that frontend teams can consume, and server-side versus client-side rendering. System design and architecture covers a high-throughput, low-latency notification system, a multi-tenant schema with data isolation, and handling service failures in a distributed system. Behavioral and leadership covers changing direction when requirements shift, technical disagreements, and trading technical debt against a fast release. Only the notification question is a product-style design; the other two are data modelling and reliability questions, so prepare each differently.
Candidates also report evaluation areas that shape how to answer: technical execution (maintainable code, edge cases, unit, integration and end-to-end testing) and architectural decision-making (SQL versus NoSQL chosen by access pattern, caching to cut latency, high availability and redundancy). In practice that means every design answer should name the access pattern it serves and the trade-off it accepts, and every coding answer should come with the tests you would write. The behavioral questions are best covered by a small bank of real stories, each reusable across several prompts.
The Claryo interview process
Candidates describe five stages, from a first screen to final interviews. The sequence may vary by team or seniority, and no stage-by-stage question list is reported, so the preparation below is grouped by question type.
Initial Screening
Candidates describe Initial Screening as the opening stage, checking basic qualifications and fit. Nothing further about its format is reported, so treat it as a conversation about your background measured against the stated requirements: JavaScript or TypeScript frameworks, relational databases and RESTful API design, with AWS or GCP and Docker or Kubernetes as extras. Arrive with a short career account that lands on one feature you carried from build through deployment and maintenance.
What to demonstrate
- Basic qualifications against the listed requirements
- Fit for the role and team
How to prepare
- Write a short career summary that names where you used TypeScript or JavaScript, a relational database and REST APIs, anchored on one shipped project.
- Check the extras (AWS or GCP, Docker, Kubernetes) against your experience and prepare an honest one-line answer for each gap.
- Ask which stages follow and what each covers, since candidates report the order can change by team or seniority.
Technical Screen
Candidates report the Technical Screen as a check of coding skills and problem solving. Language and platform are not reported, so confirm both beforehand. A coding stage tests working code, and the evaluation areas candidates describe for technical execution are maintainable code, edge-case handling and a testing strategy spanning unit, integration and end-to-end tests. Candidates also report full-stack discussion questions (frontend state, API design, rendering trade-offs, tuning slow queries) without saying which stage asks them, so rehearse those alongside coding.
What to demonstrate
- Working code for a coding problem
- Edge-case handling in the implementation
- Testing strategy across unit, integration and end-to-end levels
- Code quality and maintainability
How to prepare
- Write unit tests for empty input, duplicates and out-of-order data before declaring each solution done.
- Rehearse the frontend state and API design questions aloud, giving the reason behind each choice and the trade-off you accept.
Architectural Deep Dive
Candidates describe the Architectural Deep Dive as in-depth discussion of system design and architectural principles for the role. The reported design questions are a high-throughput, low-latency notification system, a multi-tenant schema with data isolation, and failure handling in a distributed system. Reported topics include choosing between SQL and NoSQL by access pattern, caching to cut latency, and designing for high availability and redundancy. Work each design in the same order: requirements, data model, interfaces, scaling, then what happens when a dependency fails.
What to demonstrate
- System design and architectural principles
- Choice of datastore from access patterns
- Caching strategy and latency
- High availability, redundancy and design for failure
How to prepare
- Outline a notification design end to end: ingest API, queue, fan-out workers, per-channel delivery, retries with backoff, idempotency keys and a dead-letter queue.
- Write the three common multi-tenant options (shared tables with a tenant column and row-level policies, schema per tenant, database per tenant) with isolation, migration and cost trade-offs.
- Prepare a failure-handling answer built from timeouts, retries with jitter, circuit breakers, bulkheads and fallbacks, and say what each one does not protect against.
Leadership Conversations
Candidates describe Leadership Conversations as interviews assessing leadership qualities and cultural fit within the team. Reported themes include mentoring, clear communication, working across functions and explaining technical ideas to non-technical colleagues. The reported behavioral questions cover changing direction when requirements shift, technical disagreements and technical debt against a rapid release; candidates do not say which stage asks which, so prepare all of them for this stage and the final one.
What to demonstrate
- Leadership qualities as shown in real examples
- Cultural fit within the team
- Communication with non-technical stakeholders
How to prepare
- Build a story bank of four to five real episodes, each with a situation, your own decision, the cost and the measured result.
- Map each story to the reported prompts so one episode can serve two questions, and add one story about mentoring a colleague.
- Prepare a plain-language version of one technical trade-off for a Product Manager or Designer.
Final Interviews
Candidates describe Final Interviews as the closing stage, confirming fit for the team and company. No format is reported beyond that. Use it to cover anything weak from earlier stages: revisit the technical area you felt least sure about, keep your story bank fresh, and have specific questions ready about code review, the CI/CD pipeline and how Product Managers and Designers work with engineers, since those are part of the reported role.
What to demonstrate
- Overall fit for the team and company
- Consistency between earlier technical and behavioral answers
How to prepare
- List the two weakest answers from earlier stages and rewrite them with a clearer trade-off or a better example.
- Prepare three questions about engineering practice tied to the reported work: code review, CI/CD and the Product and Design handoff.
- Re-run your four main stories aloud so details such as dates, scope and outcomes stay consistent.
Where candidates lose points
Giving one multi-tenant schema pattern with no alternatives
Present shared tables with a tenant column and row-level policies, schema per tenant and database per tenant, then pick one based on isolation needs, migration effort and tenant count. State how a missed tenant filter would be caught.
Designing the notification system as a single synchronous service
Separate ingestion from delivery with a queue, say how retries with backoff and idempotency keys prevent duplicate sends, and where failed messages go. Name what you accept: at-least-once delivery, stale preferences or delayed low-priority messages.
Telling the slow-query story without a measurement
Bring a baseline, the query plan finding, the specific change and the after numbers. If the real story has no numbers, reconstruct from logs or dashboards beforehand rather than saying it just got faster.
Answering the rendering and state questions as trivia
Tie server-side versus client-side rendering to page types (public content versus authenticated dashboard) and state management to server state versus UI state. Finish each answer with the trade-off you accept.
Behavioral stories that never show your own decision
Use first-person verbs for what you decided and did, include the cost or what you gave up, and end with a result. Prepare a story where you were wrong, since the disagreement and technical-debt prompts invite one.
Questions & practice
Collapse a redelivered event batch into per-aggregate high-water marks
Easy · hashing · at-least-once · aggregation
You drain a batch of up to 5,000,000 events, each (aggregate_id BIGINT, aggregate_version INT, event_type, payload). The log guarantees order within one aggregate only; the batch merges 64 partitions, and a relay failover has redelivered a range, so an older version for an aggregate can appear after a newer one. Given a map of last_applied_version per aggregate, produce the events worth applying, at most one per (aggregate_id, version), plus the count discarded. Target O(n) time. State the memory for 2,000,000 distinct aggregates and what you do when it does not fit.
Approach
- One pass, one hash map from aggregate_id to the highest version kept, and a discard counter. An event whose version is at or below last_applied_version for its aggregate is dropped without further work, which is the whole reason the event carries its version rather than a delta. O(n) expected time, O(d) space in distinct aggregates.
- Keep the maximum, never the last occurrence. The redelivered range means the final appearance of an aggregate in the batch can be an older version than one seen earlier in the same batch, so last-wins applies stale state over newer state and the projection regresses with no error anywhere.
- Cost the memory instead of calling it large: an 8-byte key plus a 4-byte version is 12 bytes of payload, and an open-addressed table held at a 0.7 load factor costs roughly 17 bytes per entry before per-slot metadata, so 2,000,000 aggregates is tens of megabytes in a native layout and several times that in a runtime that boxes both key and value.
- If the distinct set exceeds memory, partition on hash(aggregate_id) mod P and reduce each partition independently. Every event for one aggregate hashes to the same partition, so the per-partition result is exact and the merge is concatenation rather than a second reduction.
Follow-up
- The payload is a patch rather than a snapshot, so applying only the highest version loses the intermediate changes. What changes in your reduction?
- How do you detect that version 7 arrived while version 6 was never delivered, and what should the consumer do about the gap?
Canonicalise a request body into a stable idempotency fingerprint
Medium · parsing · canonicalisation · hashing
idempotency_key.request_fingerprint is a SHA-256 over the method, path and canonicalised body, and a retry whose fingerprint differs must be rejected with 422 rather than served the stored response. Write the canonicaliser. Bodies are JSON up to 256 KB nested at most 32 levels; clients vary key order, whitespace and unicode escaping, and some send 64-bit ids as JSON numbers. Produce a deterministic byte string such that semantically identical bodies match and any semantic difference does not. State your complexity and name two normalisations you refuse to perform.
Approach
- Parse once into a tree, then re-serialise under fixed rules: object keys sorted, array order preserved, one escaping convention, no insignificant whitespace. Parsing is O(n) and sorting keys is O(k log k) per object, so O(n log n) overall with O(depth) stack, and the 32-level cap is enforced during parsing because hostile nesting is how a canonicaliser becomes a stack overflow.
- Sort keys by their UTF-8 bytes and say why the obvious implementation is wrong in some runtimes: a default string comparison that orders by UTF-16 code units places surrogate pairs, meaning code points from U+10000 up, below U+E000 to U+FFFF, which is not UTF-8 byte order, so two services written in different languages disagree on the same document.
- Do not re-encode numbers through a double. IEEE-754 binary64 represents integers exactly only up to 2^53, so normalising a 19-digit id through a float changes it, and 1 against 1.0 cannot be reconciled without deciding whether they are the same value. Preserve the literal token, and require ids as strings at the API boundary if you want them comparable.
- Reject duplicate keys rather than picking one. JSON permits them and parsers disagree, most keeping the last, so any choice you make ties the fingerprint to a parser detail that the code handling the request does not necessarily share.
Follow-up
- A client sends the same logical request with an extra field your API ignores. Same key, different fingerprint, so you return 422. Is that the right answer?
- Where does the fingerprint get computed relative to request decompression and the body-size limit?
Merge partitioned event streams into one ordered feed with bounded lateness
Hard · k-way merge · watermarks · out-of-order streams
The read-model service consumes 64 log partitions carrying about 4,000 events per second in total. Each partition is ordered within itself, but partitions drift by up to 30 seconds, and the activity feed must present a tenant's events in occurred_at order. Produce the merge. State its complexity, the buffer it requires in events and in bytes, what happens when one partition is idle, and what you do with an event that arrives after you have already emitted its position. Payloads average 1 KB.
Approach
- Merge with a min-heap over the 64 partition heads keyed on (occurred_at, event_id): O(log P) per event and O(n log P) overall. The tie-break on event_id is what makes the output deterministic when two partitions carry the same millisecond, which matters because the feed is paginated and a non-deterministic order reorders pages under the reader.
- Emitting the heap head is only correct once every partition has produced everything up to that timestamp, so the emit condition is a watermark: the minimum across partitions of the highest occurred_at seen, less the allowed lateness. Events are held until the watermark passes them, which is what turns individually ordered streams into a jointly ordered one.
- Size the buffer from the lateness rather than guessing: 4,000 events per second times 30 seconds is 120,000 buffered events, and at 1 KB each about 120 MB of heap. That number is the real price of the ordering guarantee and belongs in front of whoever asked for it.
- Handle the idle partition explicitly, because it fails the feed rather than corrupting it: a partition with no traffic never advances its own maximum, so the watermark freezes and output stops entirely. Either every partition emits a periodic idle marker carrying the broker's current time, or the watermark falls back to wall clock for a partition silent beyond a threshold.
Follow-up
- The lateness budget is raised to five minutes. What is the new buffer, and what besides memory changes?
- The consumer restarts. Where does it resume from, and what does the feed look like for the first 30 seconds?
How would you structure a multi-tenant database schema to ensure data isolation?
Medium · System Design and Architecture
Approach
- Lay out the three models and their trade-offs: database per tenant (strongest isolation, per-tenant backup and restore, but N migrations and high operational cost), schema per tenant (middle ground, catalog and migration overhead grows with thousands of tenants), and shared tables with a tenant_id column (densest and cheapest, isolation depends on enforcement).
- For shared tables: tenant_id NOT NULL on every tenant-owned table, composite keys such as (tenant_id, id), foreign keys that include tenant_id so a row cannot reference another tenant's row, uniqueness scoped per tenant like UNIQUE (tenant_id, email), and indexes that lead with tenant_id.
- Enforce in the database, not only in the ORM: PostgreSQL row-level security with a policy like USING (tenant_id = current_setting('app.tenant_id', true)::uuid). With the missing_ok flag an unset tenant yields NULL and returns no rows instead of everything. Table owners skip RLS unless FORCE ROW LEVEL SECURITY is set, and superusers or BYPASSRLS roles always skip it, so the app must connect as a separate role.
- Set the tenant per transaction with SET LOCAL (or set_config with is_local true) so a pooled connection, for example PgBouncer in transaction mode, cannot carry one tenant's setting into another request.
- Plan for noisy neighbours and growth: a hybrid where large tenants move to a dedicated database behind a tenant-to-shard routing table, per-tenant export and deletion, and automated tests that query as tenant A and assert zero rows from tenant B.
Follow-up
- A customer requires their data in a specific region and separately encrypted. How does the schema and routing change?
- How do you run analytics across all tenants without weakening the isolation guarantees?
- A background job forgets to set the tenant context. What happens under your design?
Keep soft-deleted accounts from blocking re-registration
Easy · soft delete · unique constraints · engine differences
app_user holds user_id, tenant_id, email CITEXT, password_hash (NULL for SSO principals), email_verified_at, auth_version, status ('invited','active','suspended','deactivated'), created_at, updated_at, deleted_at. Two live accounts for one address inside a tenant must be impossible, but an address freed by a soft delete must be reusable, and the same tenant may delete and re-register it repeatedly. Write the uniqueness DDL for PostgreSQL 16, then the equivalent for MySQL 8 where partial indexes do not exist, and say what each permits once three deleted rows already hold that address.
Approach
- Start from what is actually unique: not (tenant_id, email), but (tenant_id, email) among live rows. PostgreSQL says that directly — CREATE UNIQUE INDEX app_user_live_email ON app_user (tenant_id, email) WHERE deleted_at IS NULL. A full constraint over the same two columns burns the address permanently the first time someone deletes an account.
- Keep case-insensitivity in the type or the index, never in the application: CITEXT as given, or UNIQUE (tenant_id, lower(email)) as an expression index where the extension is unavailable. A case-sensitive unique column is exactly how two accounts for one human appear.
- For MySQL 8 the predicate has to move inside the key: add a discriminator column that is a constant 0 while the row is live and is set to user_id on delete, with UNIQUE (tenant_id, email, deleted_marker). Live rows share the constant and still collide; deleted rows differ from each other and stop colliding.
- State the NULL variant and its dependency: leaving the marker NULL for deleted rows also works, because a unique index treats NULLs as distinct — true in MySQL, and true in PostgreSQL only under the default NULLS DISTINCT, which PostgreSQL 15 lets you reverse. Check the polarity against the three existing deleted rows: constant-on-live is what preserves the collision you want, and reversing it silently admits duplicate live accounts.
Follow-up
- A deleted account re-registers with the same address the next day. Do the old resource rows follow the new user_id, and how does the API keep the two principals apart?
- How do you honour an erasure request while resource_revision.actor_user_id still references this table?
How do you manage state in a complex, data-heavy frontend application?
Medium · Full-Stack Technical Proficiency
Approach
- Split state by owner before naming a library: server state (data fetched from APIs), URL state (filters, sort, page), form state, local UI state (open panels, hover) and the small remainder of truly global client state (current user, feature flags). Most data-heavy apps go wrong by putting server data into a global store.
- Server state goes in a query cache such as TanStack Query, SWR or RTK Query: cache keys per resource and filter set, stale-while-revalidate, request deduplication, and explicit invalidation after mutations. Optimistic updates keep a snapshot so a failed write rolls back.
- Normalise entities by id (for example RTK createEntityAdapter) so one record edited in a table and a detail pane stays consistent, and read through memoised selectors. Note that a React Context re-renders every consumer when its value changes, so it suits rarely-changing values, not a fast-moving grid.
- Render cost: paginate or cursor-load on the server rather than shipping every row, and virtualise long lists (react-window or similar) so only visible rows mount. Keep derived data (totals, grouping) in selectors, not duplicated in state.
- Edge cases to name: out-of-order responses when filters change quickly (cancel with AbortController or ignore stale responses by key), two tabs editing the same record, and keeping shareable filter state in the URL so reload and back-button work.
Follow-up
- A table with 50,000 rows becomes sluggish when one cell is edited. How do you find and fix the extra re-renders?
- When would you still choose Redux or Zustand over a query cache alone?
- How do you handle a mutation that succeeds on the server but whose optimistic update conflicts with a newer refetch?
How do you approach API design to ensure it is both scalable and easy for frontend teams to consume?
Medium · Full-Stack Technical Proficiency
Approach
- Start from the screens and callers: list the views the frontend renders and the calls each needs, so resources and response shapes match real use and a page does not need N chatty requests. A backend-for-frontend or an include/expand parameter covers aggregated views without bloating every endpoint.
- Resource-oriented REST with consistent naming, correct status codes and verbs, and one error format for every endpoint (RFC 9457 problem details is a ready-made shape). Publish an OpenAPI spec and generate TypeScript types and clients from it so frontend teams get compile-time checks.
- Pagination: prefer cursor (keyset) pagination over offset for large or fast-changing collections; offset forces the database to skip rows (cost grows with the offset) and duplicates or skips items when rows are inserted between pages. Return the next cursor in the response.
- Scaling and safety: stateless handlers behind a load balancer, ETag with If-None-Match for 304 responses and Cache-Control for cacheable reads, rate limits that return 429 with Retry-After, and an Idempotency-Key header on POSTs that create money or records so client retries do not double-write.
- Evolution: additive changes only within a version (new optional fields, never renamed or retyped ones), deprecate with a sunset date, and version in the path or a header when a breaking change is unavoidable.
Follow-up
- Two frontend teams need different fields from the same resource. Do you add sparse fieldsets, a BFF, or GraphQL, and why?
- How would you change a field's type without breaking clients already in production?
- A list endpoint's p99 latency doubles as the table grows. Where do you look first?
What are the trade-offs between server-side rendering and client-side rendering in the context of our product?
Medium · Full-Stack Technical Proficiency
Approach
- Define the options precisely: CSR ships a JS shell and renders in the browser; SSR renders HTML per request then hydrates; SSG and incremental regeneration (as in Next.js) prerender at build or on a schedule; streaming SSR and React Server Components send HTML in chunks and keep server-only components out of the client bundle.
- SSR gives faster first contentful paint and crawlable HTML for SEO and link previews, but adds server CPU per request, raises TTFB when data fetches are slow, makes personalised pages hard to cache at a CDN, and still pays hydration cost before the page is interactive.
- CSR serves a static shell cheaply from a CDN and suits authenticated, highly interactive views where SEO does not matter, but shows little until JS downloads and the first API calls return, so bundle size and request waterfalls drive LCP.
- Decide per route, not per app: public marketing or content pages lean SSG/SSR, logged-in dashboards lean CSR or SSR of the shell plus client data fetching. Since the question asks about the product, ask which surfaces are public and which sit behind login before choosing.
- Name the measurable signals (LCP, INP, CLS, TTFB) and SSR pitfalls: hydration mismatches from Date, locale or window access during render, and leaking per-user data into a shared cache.
Follow-up
- A server-rendered dashboard has good LCP but feels unresponsive for the first seconds. What is happening and how do you fix it?
- How do you cache an SSR page that is mostly shared but shows the user's name in the header?
- When would you move a page from SSR to static generation, and what do you lose?
Design a notification system that handles high throughput with low latency.
Medium · System Design and Architecture
Approach
- Pin requirements: channels (in-app, push, email, SMS), transactional versus bulk traffic, target end-to-end latency, peak events per second, largest fan-out per event, and delivery semantics. At-least-once delivery with deduplication is the realistic target; exactly-once to an external provider is not available.
- Write path: an ingest API validates and persists the event, then publishes to a durable log such as Kafka partitioned by recipient id (per-user ordering). Fan-out workers resolve recipients, check preferences and quiet hours from a cache, render templates and enqueue to per-channel queues.
- Channel senders call providers (APNs, FCM, an email or SMS gateway) with per-provider rate limits, retries with exponential backoff and jitter, and a dead-letter queue. A notification id used as an idempotency key, stored with a TTL, stops a retried message being shown twice.
- Low latency under load: separate queues or priorities so a marketing blast cannot delay password-reset or alert traffic, autoscale consumers on queue lag, and deliver in-app messages over WebSocket or SSE through a gateway that keeps a connection registry, with an inbox table keyed by user id for offline users.
- Large fan-out (a broadcast to every user) is chunked into batches of recipient ranges instead of one giant task. Track p99 enqueue-to-delivery latency, consumer lag and provider error rates per channel.
Follow-up
- A push provider starts returning errors for an hour. What happens to the backlog, and how do you avoid flooding users when it recovers?
- How do you guarantee a user never receives the same notification twice across retries and worker restarts?
- How would the design change to support per-user digests instead of instant sends?
Explain your strategy for handling service failures in a distributed system.
Medium · System Design and Architecture
Approach
- Every remote call gets a timeout, and deadlines propagate downstream so a caller does not wait on work it has already abandoned. Unbounded waits exhaust thread or connection pools and turn one slow dependency into a full outage.
- Retries only for transient errors and only on idempotent operations (or with idempotency keys), using exponential backoff with jitter and a retry budget. Retrying at every layer multiplies load: three attempts at each of three layers can mean 27 calls at the bottom.
- Contain failure: circuit breakers (closed, open, half-open) to fail fast on a dependency that is down, bulkheads that give each dependency its own pool, and load shedding or rate limiting so an overloaded service rejects early rather than timing out everyone.
- Degrade instead of failing: serve cached or stale data, hide a non-essential widget, or queue writes for later processing with a dead-letter queue. For cross-service writes, use the transactional outbox for reliable event publishing and sagas with compensating actions instead of distributed transactions.
- Detect and recover: separate liveness from readiness probes, run redundant instances across availability zones, trace requests end to end, and alert on SLO burn rate rather than on single errors.
Follow-up
- A downstream service is slow rather than down. Which of these mechanisms trigger, and which do not?
- How do you pick the timeout and the circuit-breaker thresholds for a specific dependency?
- An order service charged a card but crashed before recording the order. How does your design recover?
Edge instances grow 400 MB per hour until the nightly restart
Hard · memory leak · heap analysis · metric cardinality
Edge API instances start at 700 MB resident and grow about 400 MB/hour; a nightly rolling restart has hidden it for weeks. Growth continues unchanged when request rate halves overnight, p99 degrades in the last hours before an instance is recycled, and heap used immediately after a forced full GC rises monotonically. The service holds no product state. Name the discriminating measurement that separates the plausible causes, give the most likely cause, and give the fix and how you would verify it.
Approach
- Separate resident memory from live heap first, because they fail differently. Resident size can grow from fragmentation, native buffers or thread stacks while the heap is flat; heap used after a full GC rising monotonically is the measurement that says objects are reachable and not being released. You already have it, so this is retention, not fragmentation, and that closes off half the candidate list.
- Use the rate's independence from traffic as the discriminator. Growth that continues at half the request rate rules out per-request objects that are merely slow to collect and points at a structure that grows with distinct values observed rather than with call volume. Write the candidates that have that property: a metrics registry keyed on a high-cardinality label, an unevicted cache, an interner, a per-key lock map.
- Take two heap snapshots an hour apart and diff by retained size, reading the dominator tree, not by allocation count or instance count. Expect one root holding a map with millions of entries, then follow the reference chain to the code that inserts and never removes. Allocation profilers point at churn, which is the wrong signal here.
- The candidate that fits this service is an observability label carrying an identifier, such as a request path recorded before templating so that /v1/resources/48213 becomes its own metric series. That grows with distinct ids seen, is independent of rate, and explains the late p99 degradation, since GC cost rises with the size of the live set.
Follow-up
- Post-GC heap is now flat but resident size still creeps. What are you looking at, and does it matter?
- How would you have detected this before an OOM, given the nightly restart masked the trend?
Suggested practice checklist
Each day targets a group of reported questions or a reported round, from frontend and API design through system design to the story bank.
Day 1 — Map the five rounds and your stack evidence
- List the five reported rounds in order and note the evidence you can offer for each: a shipped feature, a design you owned, a leadership example.
- Compare your experience with the stated requirements (JavaScript or TypeScript, relational databases, REST, then AWS or GCP and Docker or Kubernetes) and mark each gap.
- Pick the four or five projects you will draw from for every later answer.
Deliverable: A one-page loop map plus a project inventory marked with stack gaps.
Day 2 — Frontend state and rendering trade-offs
- Outline an answer on managing state in a data-heavy frontend: server state (fetched, cached, invalidated) versus UI state (filters, selection, open panels), where each lives, and large lists handled with pagination or virtualization.
- Build a comparison of server-side and client-side rendering for a public content page versus an authenticated dashboard: first load, interactivity, caching, SEO and server cost.
- Say both answers aloud, each ending with the trade-off you would accept.
Deliverable: Two spoken answers and a rendering comparison table, each closing on a stated trade-off.
Day 3 — API design and relational data modelling
- Write a REST contract for a resource you know: names, cursor versus offset pagination, filtering, error format, versioning and idempotent writes, with how a frontend developer would use it without extra round trips.
- Write the three multi-tenant schema options with isolation, migration and cost trade-offs, and choose one for a stated tenant count.
- Work the practice-set SQL drill on soft-deleted accounts and note how a uniqueness constraint interacts with a deletion flag.
Deliverable: An API contract page, a three-option tenancy table and one solved uniqueness drill.
Day 4 — Coding reps with tests
- Solve the practice-set drills on per-aggregate high-water marks and the idempotency fingerprint in your interview language.
- Solve the ordered stream merge drill and state its time and memory cost.
- For each solution, write unit tests for empty input, duplicates and out-of-order data, then sketch one integration-level test.
Deliverable: Three working solutions, each with a unit test file and one integration test sketch.
Day 5 — System design: notifications and failure handling
- Outline the notification system: ingest API, queue, fan-out workers, per-channel delivery, retries, idempotency keys, dead-letter queue and a preferences store, then justify SQL versus NoSQL and where caching helps.
- Write a failure-handling answer covering timeouts, retries with jitter, circuit breakers, bulkheads and fallbacks, and what each fails to cover.
- Work the practice-set debugging drill on memory growth in edge instances, writing the sequence you would follow.
Deliverable: A notification design outline, a failure-handling answer and a written debugging sequence.
Day 6 — Build the story bank
- Write four stories in situation, task, action, result form: a tuned slow query with before and after numbers, a changed direction, a technical disagreement, and a debt-versus-release decision.
- Add one mentoring story and one story about explaining a trade-off to a non-technical colleague.
- Say each story aloud and cut anything that does not show your own decision or its cost.
Deliverable: Six rehearsed stories mapped to the four reported behavioral prompts.
Day 7 — Full run in the reported order
- Run a pass in the reported order: your career summary, a coding drill, a design answer, then two behavioral stories.
- Rewrite the two weakest answers with a clearer trade-off or example.
- Write three questions about code review, CI/CD and the Product and Design handoff for the final stage.
Deliverable: A scored self-review of the full run, two rewritten answers and three prepared questions.
Stories for the Claryo leadership rounds
Candidates report Leadership Conversations and Final Interviews as stages assessing leadership qualities and fit with the team, and mention themes of mentoring, clear communication and cross-functional work with Product Managers and Designers. For an engineer, that means stories where you made a decision, accepted a cost and can show the result.
- Tell me about a time you explained a technical trade-off to a Product Manager or Designer.
- Tell me about a time you helped a teammate grow or improve how they work.
Describe a time you had to optimize a slow database query. What was your process?
Medium · Full-Stack Technical Proficiency
Approach
- Choose a query you tuned yourself and open with the baseline: the endpoint or job it slowed, the latency you measured, and how you found it (slow query log, APM trace or a user complaint). A story without a measured starting point sounds like guesswork.
- Walk through diagnosis in order. Read the plan with EXPLAIN ANALYZE (in PostgreSQL, add BUFFERS), compare rows scanned with rows returned, and look for sequential scans, a function wrapped around an indexed column, stale statistics, an N+1 pattern from an ORM, wide SELECT lists, or OFFSET pagination.
- State the fix and why it fit: a composite index ordered for the filter and sort, a rewritten join or keyset pagination, or ANALYZE after bad estimates. Mention the cost of the fix (write overhead, index size, building it without blocking writes) and that caching was a last resort, not the first move.
- Close with the result in numbers and how you verified it: before and after timings on production-like data, the plan now using the index, and no regression on writes or other queries.
Follow-up
- How did you confirm the planner actually used the new index?
- What did the index cost on writes, and how did you decide that was acceptable?
- What would you do if the query was fast in staging but slow in production?
Tell me about a time you had to pivot a project due to changing business requirements.
Medium · Behavioral and Leadership
Approach
- Pick an episode where the requirement changed after real work was done, and say who changed it and why in one or two sentences. Spend the rest on your decisions, not on the backstory.
- Show the accounting: what you kept (shared components, data model, tests), what you threw away, and how you avoided sunk-cost thinking. Name the concrete signal that made you stop rather than continue.
- Describe how you re-planned and communicated: a smaller first slice, a feature flag or a thin vertical cut, and the conversation with the Product Manager or Designer about scope and dates.
- State the result and the lesson. A strong ending includes something you now do earlier, such as confirming the success metric at kickoff. Do not blame the stakeholder or claim the change cost nothing.
Follow-up
- How did you decide what to keep and what to discard?
- How did you tell the team and stakeholders, and what pushback did you get?
- Could you have caught the change earlier, and what do you do differently now?
How do you handle technical disagreements within your team?
Medium · Behavioral and Leadership
Approach
- Choose a disagreement with real technical stakes, such as synchronous calls versus a queue, a schema choice, or a framework decision. State both positions fairly in your opening sentences, including the one you did not hold.
- Show how you moved from opinions to evidence: write down the decision criteria (latency, operability, delivery risk), run a small spike or benchmark, or check the decision against a documented requirement. Mention time-boxing the discussion.
- Explain how it closed: a decision with a named owner, and disagree-and-commit if you lost. The relationship afterward matters, so say what the working dynamic looked like once the decision was made.
- Include one case where you were wrong or partly wrong. A story in which you were simply right and persuaded everyone reads as a win-lose account.
Follow-up
- What would you have done if the other person outranked you?
- What if the data had not settled it either way?
- Tell me about a time you changed your mind because of a colleague.
Describe a situation where you had to balance technical debt against the need for a rapid feature release.
Medium · Behavioral and Leadership
Approach
- Name the debt concretely: for example copy-pasted validation, missing tests around a payment-like module, or a schema shortcut. Then state the deadline pressure and what was at stake for the product if the release slipped.
- Show the reasoning, not the compromise: you weighed the cost of delay against the interest the debt would accrue, and decided which shortcuts were safe (isolated, reversible, behind a flag) and which were not (data model, security, anything hard to migrate).
- Describe the guardrails: tests on the risky path, a feature flag, a ticket with an owner and a trigger, and how you explained the trade-off to the Product Manager in product terms such as support load or delivery risk for the next feature.
- Finish with repayment: when it was scheduled, whether it actually happened, and the evidence it paid off. A story with no repayment suggests debt that was only deferred.
Follow-up
- How did you decide which shortcuts were safe to take?
- Did the repayment happen, and how did you protect time for it?
- How would you explain this trade-off to a non-technical stakeholder?