The responsibilities candidates describe are ordinary product engineering: building and maintaining applications, agreeing requirements with product managers, designers and other engineers, joining code reviews, and troubleshooting production problems while juggling several projects. The reported questions mirror that list closely. There is a debugging question, a code-review exercise, a prioritisation question and a question about measuring a product's success, so a loop that looks like a plain algorithms screen also tests how you work day to day.
The stack named for the role is general. Must-have skills are one or more programming languages (Python and Java are named, C++ appears in the technical-expertise list), software frameworks and tools, and algorithms and data structures. React, Django, Docker and Kubernetes appear as examples of frameworks and tools, and AWS, Azure and Google Cloud as cloud examples. Machine learning and data analysis are listed as nice-to-have and as less common topics, so give them a small share of your time: be able to describe how you would explore a dataset, but spend most hours on code and design.
The 25 reported questions fall into five groups. Technical fundamentals: polymorphism, debugging a complex issue, REST versus SOAP, a hard problem you solved, Git experience. System design: a web application for millions of users, the architecture of your own project, application security, data-flow patterns, microservices versus a monolith. Problem solving: finding trends and anomalies in a dataset, optimising an algorithm, improving an underperforming product, designing a feature, measuring success. Coding: reversing a linked list, binary search, dynamic programming, complexity analysis, reviewing code. Behavioral: pressure, prioritising, team contribution, conflict, adapting to change. Reports call these representative and team-dependent, so learn the technique behind each rather than memorising answers.
Screening Interviews
reportedCandidates describe Screening Interviews as the first stage, an initial check of qualifications and fit for the role. Prepare a short, concrete account of your experience: your main language, the projects you shipped, the tools you used day to day. Short fundamentals questions, such as explaining polymorphism or describing how you debug, are good material to rehearse for this stage because they reward a structured answer with one real example.
What to demonstrate
- Qualifications and fit for the role, as the stage is described
- Clear explanation of core fundamentals in your main language
- How your past projects line up with the requirements candidates describe: languages, frameworks, algorithms and data structures
How to prepare
- Write a short account of your background that names your main language (the role lists Python and Java) and two projects where you made a decision you can defend.
- Rehearse the polymorphism and debugging questions aloud, each with one code example or one real bug story.
- Be ready to describe your Git workflow and the frameworks or tools you have used, in plain words.
Technical Assessments
reportedTechnical Assessments are described as evaluations of the technical skills the software engineering position needs. The reported question set covers coding and algorithms, system design, web-service fundamentals and case-study reasoning, and one report singles this stage out as the challenging part. A coding stage means working code plus a complexity statement, and a design stage means components and trade-offs, so prepare both in the language you will interview in.
What to demonstrate
- Technical skills relevant to software engineering, as the stage is described
- Working code and time and space complexity when a coding problem appears
- Design reasoning and trade-offs when an architecture question appears
How to prepare
- Write the linked-list reversal and binary search from memory in your main language, and run empty and single-element inputs by hand.
- Solve one dynamic programming problem from brute-force recursion to memoisation to a table, stating complexity at each step.
- Prepare spoken comparisons for REST versus SOAP and microservices versus a monolith, each ending in when you would choose which.
- Practise an optimisation walk-through: take a slow solution, name the bottleneck, and improve it.
Behavioral Interviews
reportedBehavioral Interviews are described as focused on cultural fit and teamwork. The reported prompts cover working under pressure, prioritising across projects, contributing to a team, handling conflict and adapting to change, and reports mention collaboration, adaptability and working through ambiguity as themes. Build a bank of distinct stories rather than one all-purpose story.
What to demonstrate
- Cultural fit and teamwork, as the stage is described
- Your own role and decisions in past team situations
- Communication, including explaining technical ideas to non-technical colleagues
How to prepare
- Write six stories, one for each reported behavioral prompt, using situation, your decision, the result and what you changed afterwards.
- Give each story a number or an observable outcome, such as an incident resolved or a release shipped on a date.
- Practise one story about explaining a technical concept to a non-technical audience.
Final Interviews
reportedFinal Interviews are described as concluding conversations that may involve various stakeholders, to finalise fit. Because the audience can be mixed, prepare to explain your work at two levels: the architectural decisions for engineers, and the outcome and trade-offs for someone outside your discipline. The architecture-of-your-project and application-security questions are the natural material to rehearse for a stage like this.
What to demonstrate
- Overall fit for the role, as the stage is described
- Ability to explain design decisions and trade-offs to different audiences
- Consistency between what you claimed earlier and what you can defend in detail
How to prepare
- Prepare a walk-through of one project you built: components, data flow, the decisions you made, what you would change.
- Write a security checklist for a web application you know (authentication, authorisation, input validation, secrets, dependencies, logging) and tie each item to your project.
- Prepare questions about the team, the work and how the role connects to the Deployment or Integration work in the topic labels.
- Rehearse a two-level explanation of one technical decision, once for an engineer and once for a non-technical stakeholder.
PracHub editorial advice for the preparation topics above.
Writing the linked-list reversal or binary search quickly and never testing it, then missing the empty list, a single node, an off-by-one in the midpoint or the lower-bound variant with duplicates.
State the loop invariant before coding, then walk empty, one-element and two-element inputs through your code by hand, and say the complexity (O(n) time and O(1) space for the iterative reversal, O(log n) time for binary search).
Answering REST versus SOAP or microservices versus a monolith as a list of features, with no sense of when each choice wins.
End each comparison with explicit conditions, for example a small team with one deployable favours a monolith, while independent scaling and ownership boundaries favour services at the price of network failures and operational load.
Meeting the millions-of-users design question by naming caches, queues and sharding straight away, without scope or numbers.
Start with the request mix, read and write paths and data size, find the first bottleneck, and add each component only to fix a named problem. Say which parts you would keep simple at the beginning.
Telling behavioral stories in the team's voice, so no individual decision is visible, or reusing one story for pressure, conflict and adapting to change.
Keep six distinct stories mapped to the six reported behavioral prompts, and write the sentence beginning with I that names your decision and the alternative you rejected.
Treating the code-review exercise as a style pass that lists naming and formatting remarks but misses a logic error, an unchecked input or a query inside a loop.
Review in order: correctness, security, performance, then readability. Label which comments block the merge, and give an example input that triggers each bug.
Choose a category, try a prompt, then open its approach, worked solution or follow-up when you need it.
How would you approach optimizing an existing algorithm?
How would you approach optimizing an existing algorithm?
Approach
- Measure before changing anything: profile with cProfile, perf or a flame graph on realistic input, find the hotspot, and record a baseline. Lock in correctness with tests first.
- Analyse the complexity of the hot path and look for repeated work: replace nested-loop lookups with a hash map (O(n²) to O(n) on average), sort and use two pointers, precompute prefix sums, or memoise repeated subproblems.
- Pick data structures from the access pattern: a heap for top-k (O(n log k)), a deque for queue operations, a set for membership tests instead of a list.
- Then reduce constant factors: fewer allocations, batched I/O and database calls, vectorised operations, better cache locality, and parallelism if the work splits cleanly.
- Re-benchmark against the baseline and state the trade-off you accepted (memory for speed, readability, or precomputation that goes stale).
Follow-up
- When would you decide an optimisation is not worth doing?
- How would you reduce memory use instead of running time?
- Describe an O(n²) step you have reduced, and how you proved the result was still correct.
Write a function to reverse a linked list.
Write a function to reverse a linked list.
Approach
- Iterative version with three pointers: prev = None, curr = head; in a loop, save nxt = curr.next, set curr.next = prev, then advance prev = curr and curr = nxt; return prev. O(n) time, O(1) extra space.
- Recursive version: reverse the rest of the list, then set head.next.next = head and head.next = None. Also O(n) time, but it uses O(n) stack space, and CPython's default recursion limit (about 1000) makes it fail on long lists.
- Edge cases to test aloud: an empty list, one node, two nodes. Check that the original head ends with next = None so no cycle is left.
- Mention the related versions: for a doubly linked list, swap prev and next on every node; reversing a sublist between two positions and reversing in groups of k reuse the same pointer loop with careful reconnection of the ends.
Follow-up
- Reverse only the nodes between positions left and right in a single pass.
- Reverse the list in groups of k, leaving any final group shorter than k unchanged.
- Check whether a linked list is a palindrome using O(1) extra space.
How would you implement a binary search algorithm?
How would you implement a binary search algorithm?
Approach
- State the precondition: the array is sorted, or more generally the predicate is monotone. Closed-interval version: lo = 0, hi = n - 1; while lo <= hi, take mid = lo + (hi - lo) // 2, return it on a match, otherwise move lo = mid + 1 or hi = mid - 1; return -1. O(log n) time, O(1) space.
- Explain the midpoint formula: (lo + hi) / 2 can overflow fixed-width integers in Java or C++, and lo + (hi - lo) / 2 cannot. Python integers do not overflow.
- Pick one invariant, closed [lo, hi] or half-open [lo, hi), and keep it throughout. Mixing them causes off-by-one errors and infinite loops when lo = mid never shrinks the range.
- Cover the lower-bound version, which returns the first index with a[i] >= target and so handles duplicates and insertion points (Python's bisect_left and bisect_right). Also cover binary search on the answer with a monotone feasibility check, such as the minimum capacity that ships all packages in D days.
- Test an empty array, one element, a target below or above every value, a missing target, and runs of duplicates.
Follow-up
- Search for a target in a sorted array that has been rotated.
- Return the first and last positions of a target in a sorted array with duplicates.
- How would you search a sorted sequence whose length is unknown (exponential search)?
Solve a problem involving dynamic programming.
Solve a problem involving dynamic programming.
Approach
- Recognise when DP applies: optimal substructure plus overlapping subproblems, which shows up in prompts that count ways, minimise cost or ask for the longest or shortest valid sequence.
- Define the state precisely, then the recurrence, the base cases and where the answer is read. Example: minimum coins, dp[a] = min over coins c ≤ a of dp[a - c] + 1, with dp[0] = 0 and unreachable amounts set to infinity. That is O(amount × number of coins) time and O(amount) space.
- Choose top-down memoisation (natural to write, but limited by recursion depth) or bottom-up tabulation (iterate so every dependency is computed first).
- Reduce space when each row depends only on the previous one. Longest common subsequence takes O(m·n) time and can use O(min(m, n)) space with two rows, but you then lose the ability to rebuild the sequence unless you keep more state.
- Rebuild the actual solution with parent pointers or by backtracking through the table, and check small inputs against a brute-force version.
Follow-up
- Return the actual coins or subsequence, not just the optimal value.
- Why does greedy fail for coins {1, 3, 4} and amount 6? (Greedy takes 4+1+1, three coins; the optimum is 3+3, two coins.)
- How does the loop order differ between 0/1 knapsack and unbounded knapsack with a one-dimensional array?
Discuss the time and space complexity of your solutions.
Discuss the time and space complexity of your solutions.
Approach
- Use a variable for each input dimension (n, m, k) instead of collapsing everything into n, and identify the dominant operation. Big-O is an upper bound on growth; say whether you are quoting the worst, average or amortised case.
- Quote the standard costs correctly: hash map lookup is O(1) on average and O(n) in the worst case; comparison sorting is O(n log n); heap push and pop are O(log n); binary search is O(log n). Merge sort's T(n) = 2T(n/2) + O(n) gives O(n log n) by the master theorem.
- Count space honestly: auxiliary structures plus the recursion stack (O(depth)), and say whether the output itself is included.
- Explain amortised cost: appending to a dynamic array that doubles its capacity is amortised O(1) even though a single resize is O(n).
- Call out hidden costs in your own code: Python slicing copies O(k) elements,
x in listis O(n), list.pop(0) is O(n) (use collections.deque), and building a string by repeated concatenation in a loop can become quadratic (use ''.join).
Follow-up
- Show why appending to a doubling dynamic array is amortised O(1).
- What is the complexity of naive recursive Fibonacci, and what does memoisation change it to?
- Give quicksort's best, average and worst cases, and say what causes the worst case.
Hold a per-tenant active cap against concurrent creates
A tenant on the standard plan may hold at most 50 resources with status='active'. The create handler runs SELECT count(*) FROM resource WHERE tenant_id = $1 AND status = 'active', compares to 50, then inserts. Two creates arrive 3 ms apart on different instances and the tenant lands at 51. Name the anomaly, say whether PostgreSQL 16 READ COMMITTED or REPEATABLE READ prevents it and why, then give an implementation that holds the cap at READ COMMITTED with the exact statements. Finally, say what changes when the cap is 'at most one running export per tenant' on job_run.
Approach
- Name it: write skew. The two transactions read an overlapping set and write disjoint rows, so there is no row-level conflict for the engine to detect and each commit is individually legal.
- Rule out the levels precisely. READ COMMITTED takes a fresh snapshot per statement and takes no lock on the counted rows, so both see 49. PostgreSQL's REPEATABLE READ is snapshot isolation: it removes non-repeatable reads and phantoms within the snapshot but still admits write skew, because the anomaly is not a re-read of a changed row, it is a read of a set that a concurrent transaction invalidates. Only SERIALIZABLE closes it, by tracking the read dependency and aborting one transaction with SQLSTATE 40001 — a guarantee that exists only if the application re-runs the whole transaction from the read.
- Convert the set predicate into a single-row conflict: keep tenant.active_resource_count and run UPDATE tenant SET active_resource_count = active_resource_count + 1 WHERE tenant_id = $1 AND active_resource_count < 50 in the same transaction as the INSERT. Zero affected rows is the cap, returned as 409. The row lock serialises the decision at any isolation level, and contention is bounded to one tenant's row — which is also the fair-scheduling unit, unlike a global counter that would convoy every tenant behind one row.
- State the cost you just took on: a counter is a second source of truth that can drift, so every path that changes status must adjust it inside the same transaction, and a periodic reconciliation has to exist, with resource_revision as the authority for what the count should have been.
Follow-up
- A resource moves from archived back to active. Which statements change, and what breaks if the counter update and the status change land in different transactions?
- The cap becomes plan-dependent and a plan can change mid-month. Where does the number 50 live, and who reads it?
Denormalise tenant onto revisions and backfill it live
resource_revision (revision_id, resource_id, version, actor_user_id, change_kind, patch, request_id, created_at) has 400M rows and no tenant column; tenant_id lives only on resource. Two reads need it: a tenant-scoped audit feed ordered by created_at DESC, and an offboarding purge. Both join back to resource today. Justify adding tenant_id to resource_revision against those two reads, name the anomaly the copy introduces and the constraint that prevents it, then give the ordered migration for a live table taking 1.2k writes/second — the lock each step takes, how the backfill is batched, and where each step stops being reversible. PostgreSQL 16.
Approach
- Justify from the access path rather than from taste. Without the column, the audit feed either scans resource_revision by created_at and discards other tenants' rows, or resolves the tenant's resource_ids first and probes with them — both proportional to the tenant's whole history rather than to one page. With (tenant_id, created_at DESC, revision_id DESC) it is a seek that stops at 50 rows, and the purge becomes a ranged delete instead of a join.
- Name the cost exactly: a second copy of a fact can disagree with the first. Make the disagreement unwritable rather than documented — add UNIQUE (resource_id, tenant_id) on resource so it can serve as a foreign-key target, then FOREIGN KEY (resource_id, tenant_id) REFERENCES resource (resource_id, tenant_id) on the revision table. A revision can then only ever carry its parent's tenant.
- Step one, expand: ALTER TABLE resource_revision ADD COLUMN tenant_id BIGINT NULL, with no default, so it is a catalogue change and no rewrite. It still needs ACCESS EXCLUSIVE for an instant, and that instant queues behind the longest open transaction on the table while every later query queues behind it — set lock_timeout to 2s and retry rather than wait.
- Step two, dual-write: deploy the writer that populates tenant_id on every new revision while reads still use the join. Reversible by redeploying the previous build, because nothing reads the column yet.
Follow-up
- The backfill is half finished and a rollback is required. What state is the table in, and what does the previous build do with a half-populated column?
- How do you verify the backfill actually finished, given rows are still being inserted while it runs?
Explain the concept of polymorphism in object-oriented programming.
Explain the concept of polymorphism in object-oriented programming.
Approach
- Define it in one line: code written against a base type or interface works with any object that satisfies it, and the method that runs is chosen by the object's actual type. Use a concrete example, such as a Shape base with area() overridden by Circle and Rectangle, called in one loop over a list of shapes.
- Separate the kinds: subtype polymorphism (overriding, resolved at runtime), ad hoc polymorphism (overloading, resolved at compile time in Java and C++) and parametric polymorphism (Java generics, C++ templates).
- Explain the mechanism. In Java, instance methods dispatch dynamically unless they are static, private or final. In C++, only virtual member functions do, through a vtable, and passing a derived object by value slices it to the base. Python relies on duck typing: any object with the method works, and there is no overloading by signature.
- Say why it matters: it replaces type-switch conditionals and lets new types be added without editing callers (open/closed). Subclasses must honour the base contract (Liskov substitution), or callers break.
- Name the costs: an indirect call per dispatch, and control flow that is harder to trace. Deep hierarchies are often better replaced with composition plus small interfaces.
Follow-up
- What is the difference between overloading and overriding, and when is each resolved?
- What happens when a C++ constructor calls a virtual function?
- How do you get interface-like checks in Python (abstract base classes, typing.Protocol)?
What are the differences between RESTful and SOAP web services?
What are the differences between RESTful and SOAP web services?
Approach
- SOAP is a protocol: an XML envelope (Envelope, optional Header, Body, Fault) with a contract usually described in WSDL. It is typically sent as HTTP POST but does not depend on HTTP, and it comes with WS-* extensions such as WS-Security and WS-ReliableMessaging.
- REST is an architectural style: resources named by URIs, a uniform interface through HTTP methods, stateless requests and cacheable responses. Any representation can be used, most often JSON, and a contract (OpenAPI) is optional.
- Compare semantics. In REST, GET is safe and idempotent, PUT and DELETE are idempotent, POST is not, and GET responses can use ordinary HTTP caching. SOAP sends nearly everything through POST to one endpoint, so HTTP caching rarely helps.
- Compare errors and security. REST uses HTTP status codes. SOAP returns a Fault element (SOAP 1.1 over HTTP uses status 500). REST relies on TLS plus tokens such as OAuth 2.0, while WS-Security can sign and encrypt the message itself, end to end through intermediaries.
- Give the choice: SOAP fits strict-contract enterprise or legacy integrations that need message-level guarantees, and REST fits public, web and mobile APIs with lighter payloads. Mention gRPC and GraphQL as other options with their own trade-offs.
Follow-up
- How would you make a POST that creates a payment safe to retry?
- How would you version a REST API without breaking existing clients?
- What is the difference between transport-level and message-level security?
Describe a challenging technical problem you encountered and how you solved it.
Describe a challenging technical problem you encountered and how you solved it.
Approach
- Pick a problem with a real technical crux (a performance cliff, data corruption, a race condition, a scaling limit) in which you made the key decisions. Give the context in two sentences.
- Quantify the symptom (p99 latency, error rate, memory growth, job duration) so the impact is concrete.
- Walk through the diagnosis: the hypotheses you considered, the evidence that ruled each in or out, and the tools you used (profiler, query plan, traces, bisect).
- Explain the fix and the alternatives you rejected, with the trade-off behind the choice (complexity, memory, consistency, delivery time).
- End with a measured result and the lasting change, such as a test, alert, runbook or design rule. The story fails if it is told as 'the team did it' and your own part is never clear.
Follow-up
- Which alternative did you reject, and would you choose differently now?
- How did you confirm the fix worked, and that it did not break anything else?
- What would have caught this problem earlier?
How would you design a scalable web application to handle millions of users?
How would you design a scalable web application to handle millions of users?
Approach
- Clarify scale and shape: daily active users, peak requests per second, read/write ratio, latency target, data size and growth. Do the arithmetic out loud: 10M daily users making 20 requests each is 200M requests a day, about 2,300 per second on average, with peaks several times that.
- Keep the app tier stateless behind a load balancer with autoscaling. Store sessions in Redis or use signed tokens, and serve static assets and media through a CDN.
- Scale the data layer step by step: one primary with read replicas (plan for replica lag and read-your-writes), cache-aside in Redis with TTLs and explicit invalidation, then shard by a key such as user_id once write volume outgrows a single primary.
- Move slow work (email, media processing, fan-out) onto a message queue with idempotent consumers, so request latency does not depend on it.
- Cover reliability: multi-AZ deployment, health checks, rate limiting, timeouts and circuit breakers, and metrics, logs and tracing. Say which component you expect to break first, usually database writes or a hot key.
Follow-up
- A hot cache key expires and thousands of requests hit the database at once. How do you prevent that?
- How would you choose a shard key, and how would you rebalance when adding shards?
- What changes if the application must serve users from several regions?
Describe the architecture of a project you worked on and the design decisions you made.
Describe the architecture of a project you worked on and the design decisions you made.
Approach
- Start with one sketch of the system: clients, services, data stores, queues and external dependencies, then trace the main request or data path end to end.
- Give the numbers that shaped the design (traffic, data volume, latency or freshness needs, team size), because decisions only make sense against constraints.
- Present two or three decisions as choices: what you picked, the alternatives, and why you rejected them (for example Postgres over a document store for transactional integrity, or a queue over synchronous calls for burst tolerance).
- Make clear which parts you designed or owned and which you inherited.
- Close with what happened in production and what you would change, such as a bottleneck you hit or a decision you would reverse, with the reason.
Follow-up
- What broke first in production, and how did you find out?
- What would have to change for this system to handle ten times the load?
- Which decision would you reverse today, and what would the migration cost?
How do you ensure the security of an application?
How do you ensure the security of an application?
Approach
- Start with a threat model: the assets, the likely attackers and the trust boundaries. STRIDE gives a quick checklist, and the OWASP Top 10 covers common web flaws.
- Authentication and authorization: hash passwords with bcrypt, scrypt or Argon2, offer MFA, use short-lived tokens, and check on the server that the caller may access each specific object (to prevent IDOR). Give every service and credential least privilege.
- Input and output: use parameterised queries with bind parameters against SQL injection, context-aware output encoding plus a Content-Security-Policy against XSS, CSRF tokens or SameSite cookies, and server-side validation of every input.
- Data and secrets: TLS everywhere with HSTS, encryption at rest for sensitive data, and secrets kept in a secrets manager (never in the repository) and rotated.
- Process: dependency and container scanning, prompt patching, SAST/DAST in CI, audit logs, rate limiting on authentication endpoints, and an incident response plan.
Follow-up
- An API key was committed to a public repository. What do you do, and in what order (rotate first, then clean history)?
- How do you revoke a JWT before it expires?
- How would you store user passwords, and why not use SHA-256 alone?
What patterns do you use for managing data flow in large applications?
What patterns do you use for managing data flow in large applications?
Approach
- Ask which layer is meant, then cover both briefly. On the frontend, use unidirectional data flow (Flux/Redux: action, reducer, store, view), keep state in its lowest common owner, and hold server state in a fetching cache such as React Query rather than a hand-rolled global store.
- On the backend, contrast synchronous request/response with asynchronous messaging: queues for work distribution, and publish/subscribe or event streams (Kafka, RabbitMQ) so producers and consumers can change independently.
- Prevent dual writes with the transactional outbox: write the event to an outbox table in the same database transaction, and have a relay publish it. Separate read models from the write model (CQRS) when query shapes differ a lot.
- Design for delivery semantics: most brokers give at-least-once delivery, so consumers must be idempotent (dedupe keys), handle reordering where it matters, and use versioned schemas for events.
- State the trade-off: event-driven flows reduce coupling but add eventual consistency and make debugging harder, so propagate correlation IDs and use distributed tracing.
Follow-up
- How do you make sure an event is published if and only if the database commit succeeds?
- A consumer receives the same message twice, or out of order. What happens in your design?
- When is a global store such as Redux more trouble than it is worth?
Discuss the trade-offs between microservices and monolithic architectures.
Discuss the trade-offs between microservices and monolithic architectures.
Approach
- Monolith strengths: one deployable, in-process calls, single-database ACID transactions, and simpler local development, testing and debugging. Weaknesses appear with growth: coupled releases, scaling everything to scale one part, long builds, and teams contending over one codebase.
- Microservices strengths: independent deploys and scaling per service, clear team ownership, fault isolation and freedom of stack. Costs: network latency and partial failure, no cross-service transactions (sagas with compensating actions), eventual consistency, and a heavy operational load (CI/CD per service, service discovery, tracing, often Kubernetes).
- Mention Conway's law: service boundaries tend to mirror team boundaries, so splitting before the team structure calls for it adds cost without benefit.
- Suggest the middle path: a modular monolith with enforced module boundaries, then extracting services along bounded contexts when deploy or scaling pain justifies it, using the strangler fig pattern.
- Name the anti-pattern to avoid: a distributed monolith, meaning services that share one database or must deploy together.
Follow-up
- How would you handle an order that must reserve stock in one service and charge a card in another?
- How do you decide where one service ends and another begins?
- What is wrong with several services sharing a single database?
Given a dataset, how would you go about identifying trends and anomalies?
Given a dataset, how would you go about identifying trends and anomalies?
Approach
- Clarify the data and the goal: is it a time series, at what grain, what counts as an anomaly, and are there labelled past incidents to validate against?
- Check data quality first: missing values, duplicates, unit or time-zone mismatches, schema changes and late-arriving data. Many apparent anomalies turn out to be pipeline bugs.
- For trends, aggregate to a sensible grain, plot it, smooth with moving averages, and remove seasonality with week-over-week comparisons or STL decomposition. Then segment by key dimensions to find where the change comes from.
- For anomalies, start simple: z-scores (|z| > 3) if the data is roughly normal, or robust rules such as median ± k·MAD or 1.5×IQR fences when it is skewed. For time series, score the residual after removing trend and seasonality. For many dimensions, consider Isolation Forest.
- Validate flagged points against known events, tune thresholds to an acceptable false-positive rate, and report each flag with its likely cause.
Follow-up
- How would you run this on a live stream instead of a static dataset?
- Your detector fires every Monday morning. What is going on and how do you fix it?
- How do you keep alerts useful and avoid alert fatigue?
If tasked with improving an underperforming product, what steps would you take?
If tasked with improving an underperforming product, what steps would you take?
Approach
- Define 'underperforming' with a metric and a baseline: adoption, activation, retention, conversion, latency, errors or revenue. Each points to a different fix.
- Diagnose before building: run a funnel analysis to find the biggest drop-off, segment by platform, cohort and region, check engineering health (p95 latency, error and crash rates), and read support tickets and user feedback.
- Turn findings into a short list of hypotheses ranked by expected impact against effort (an ICE-style score), and pick the top few instead of starting many changes at once.
- Ship changes behind feature flags and test them with an A/B experiment: one primary metric, guardrail metrics, and a sample size worked out before launch.
- Read the results honestly, roll out the winners, remove what did not help, and repeat.
Follow-up
- The primary metric improved but a guardrail metric fell. What do you do?
- How do you choose between fixing technical debt and building a new feature?
- How would you evaluate a change when traffic is too low for an A/B test?
Walk us through your thought process for designing a new feature.
Walk us through your thought process for designing a new feature.
Approach
- Start with the problem: who the user is, what they are trying to do, how success will be measured, and what is explicitly out of scope.
- Write requirements: functional behaviour, non-functional targets (latency, scale, availability), constraints, and edge cases such as empty states, permissions, concurrency and failure modes.
- Design the change: API contract, data model and migrations (expand, migrate, contract so old and new code can run side by side), affected components, and at least one alternative with the reason it lost.
- Plan delivery: unit and integration tests, a feature flag, gradual rollout, dashboards and alerts on the success metric and error rates, and a rollback path.
- Get the design reviewed early, then revisit it with post-launch data and record what to change in the next iteration.
Follow-up
- How would you add a non-nullable column to a large table without downtime?
- The deadline moves up by half. What do you cut, and how do you decide?
- How would you know a month later whether the feature was worth building?
How would you measure the success of a software product?
How would you measure the success of a software product?
Approach
- Tie the metrics to the product's goal: choose one north-star metric that reflects value delivered to users, plus the input metrics that drive it.
- User metrics: activation rate, DAU/MAU stickiness, cohort retention curves (for example D1, D7, D30), funnel conversion, depth of use of core features, and satisfaction measures such as CSAT or NPS.
- Business metrics where relevant: revenue, churn, and customer lifetime value against acquisition cost.
- Quality and delivery metrics: availability against an SLO, p95/p99 latency, error and crash rates, and the DORA metrics (deployment frequency, lead time for changes, change failure rate, time to restore service).
- Guard against misleading numbers: avoid vanity metrics such as cumulative sign-ups, pair each target with a guardrail (Goodhart's law), and use experiments to attribute changes to a cause.
Follow-up
- If you could track only one metric for a developer tool, which would it be and why?
- Usage is rising but support complaints are rising too. How do you interpret that?
- Which of your metrics are leading indicators and which are lagging?
How do you approach debugging a complex issue in your code?
How do you approach debugging a complex issue in your code?
Approach
- Reproduce it reliably first and shrink it to a minimal case, ideally a failing automated test. A bug you cannot trigger on demand cannot be confirmed fixed.
- Collect evidence before theorising: stack traces, logs, metrics and exact inputs, plus what changed recently (commits, deploys, config, dependency versions, data).
- Bisect the search space. git bisect between a known-good and a known-bad commit needs about log2(n) test runs, and the same halving works on input data or code paths.
- Test one hypothesis at a time with a debugger, breakpoints or targeted logging, and check your assumptions about the inputs. For intermittent or concurrency bugs, extra logging can change the timing, so use thread dumps and race detectors (ThreadSanitizer, go test -race).
- Fix the root cause rather than the symptom, keep the failing test as a regression test, and write down what made the bug hard to find (missing logs or alerts) so it gets fixed too.
Follow-up
- The bug only happens in production and you cannot reproduce it locally. What do you do?
- How do you tell whether your fix addressed the root cause or only hid it?
- How would you debug a test that fails about one run in fifty?
Seven days built from the four reported rounds and the 25 reported questions: coding fundamentals first, then fundamentals and design, then case studies and code review, then behavioral stories and a full run-through.
Prepare, practise & reflect
One practical outcome each day. Spend longer where you need it.
0 / 7 done01Map the loop and your gaps
- Write the four reported rounds in order and, beside each, the reported question types that fit it: fundamentals, design, coding, case studies, behavioral.
- List the 25 reported questions by group and mark each green, amber or red for how well you could answer it today.
- Inventory your languages and tools against the role listing (Python, Java, C++, frameworks such as React or Django, Docker, Kubernetes, a cloud provider) and choose the one language you will code in.
Deliverable: A one-page loop map, a colour-coded question list and a chosen interview language with a short list of tools you can discuss.
02Coding fundamentals
- Write the iterative linked-list reversal, then the recursive version, and test empty, one-node and two-node lists.
- Write binary search with a clearly stated invariant, then a lower-bound variant that handles duplicates and a not-found result.
- Say the time and space complexity of each solution aloud, including the recursion stack for the recursive reversal.
Deliverable: Three working functions (iterative reversal, recursive reversal, binary search with lower-bound variant) with a test list and a spoken complexity statement for each.
Practice prompt ↗Practice prompt ↗Practice prompt ↗03Dynamic programming and optimisation
- Solve two dynamic programming problems of different shape (for example a one-dimensional counting problem and a two-dimensional table problem), moving from brute-force recursion to memoisation to a table.
- Take a quadratic solution you wrote earlier, name its bottleneck, and replace it with a hash map, sort or two-pointer approach, stating the new complexity.
- Write the optimisation walk-through as a script: measure, find the hot spot, change one thing, measure again.
Deliverable: Two dynamic programming solutions with the recurrence written out, one optimised solution before and after, and a short optimisation script.
Practice prompt ↗Practice prompt ↗04Fundamentals, debugging and Git
- Write a polymorphism example in your language (an interface or base class, two overrides, calls through the base type) and explain compile-time overloading versus runtime overriding.
- Make a REST versus SOAP table covering message format, contract description, transport, state and error handling, and add a line on when you would choose each.
- Write a debugging script: reproduce, narrow with bisection or logging, form one hypothesis at a time, fix, add a regression test.
- Rehearse the Git answer: your branching flow, merge versus rebase, bisect, reflog and a safe undo.
Deliverable: A polymorphism code example, a REST versus SOAP comparison table, a one-page debugging script and a rehearsed Git answer with one story.
Practice prompt ↗Practice prompt ↗Practice prompt ↗Practice prompt ↗05System design and architecture
- Outline a design for a web application serving millions of users: requirements, read and write paths, data store, caching, load balancing and what breaks first.
- Write a microservices-versus-monolith comparison and decide which you would pick for a small team, then for several independent teams.
- Write the security checklist and map it onto a project you built; then draw the data flow in that project and name the pattern at each hop (request-response, queue, event).
- Optional extra reps with PracHub's SQL practice set on enforcing a per-tenant limit under concurrent writes and on backfilling a column on a live table.
Deliverable: A design outline with a bottleneck analysis, a trade-off comparison, a security checklist, a data-flow diagram of your own project and notes on the two practice exercises.
Practice prompt ↗Practice prompt ↗Practice prompt ↗Practice prompt ↗Practice prompt ↗Practice prompt ↗Practice prompt ↗06Case studies and code review
- Take any public dataset and write the steps you would use to find trends and anomalies: check data quality, plot distributions and time series, compare segments, test whether an outlier is an error or a real event.
- Pick a product you know, define how you would judge its success (a primary metric, guard-rail metrics) and write the steps you would take to improve it if the metric lagged.
- Walk through designing a new feature: users, requirements, options, trade-offs, rollout and measurement.
- Review a snippet of about 40 lines with seeded bugs, in the order correctness, security, performance, readability, marking blocking versus optional comments.
Deliverable: A written anomaly-hunting procedure, a metrics sheet for one product, a feature-design outline and a labelled review of the seeded snippet.
Practice prompt ↗Practice prompt ↗Practice prompt ↗Practice prompt ↗Practice prompt ↗07Behavioral stories and a full run-through
- Write the six reported behavioral stories (Git or tooling, pressure, prioritising, team contribution, conflict, adapting to change) with your decision and a measurable outcome in each.
- Write the challenging technical problem story: the problem, the options you rejected, the fix and the evidence it worked.
- Do a full mock session with a friend or recording: one fundamentals question, one design question, one coding problem, two behavioral prompts, then review where your answers wandered.
Deliverable: Seven written stories, each with a decision and an outcome, plus notes from one full mock session and a list of three fixes.
Practice prompt ↗Practice prompt ↗Practice prompt ↗Practice prompt ↗Practice prompt ↗Practice prompt ↗Expand any day for tasks and deliverables. Your progress is saved on this device.
Candidates describe the Behavioral Interviews as a check of cultural fit and teamwork, and reports mention collaboration, adaptability and working through ambiguity. For a software engineer that translates into stories about shipping with other people: deadlines, competing requests, disagreements over technical choices and changes of direction. Prepare a separate story for each prompt, with your own decision visible in it.
What is your experience with version control systems, particularly Git?
What is your experience with version control systems, particularly Git?
Approach
- Describe the workflow you actually use: short-lived feature branches off the main branch, small commits whose messages explain why, and pull requests reviewed before merge. Name specific tools such as rebase, cherry-pick, stash, bisect and reflog instead of saying you use Git daily.
- Show the merge versus rebase trade-off. Rebase gives a linear history on a branch only you use; merge commits preserve real history and are safe on shared branches. Never rewrite commits other people have already pulled.
- Tell one story with a decision in it, such as using git bisect to find the commit behind a regression, recovering lost work with git reflog after a bad reset, or untangling a conflict between two long-lived branches.
- Cover undoing mistakes safely: git revert adds an inverse commit and is the right tool on a shared branch, git reset belongs on local work, and a force push on your own branch should use --force-with-lease.
- Mention team-level practice if you have it: protected main branch, required CI checks, small pull requests, and a commit convention.
Follow-up
- When do you rebase and when do you merge?
- A bad commit is already on main and teammates have pulled it. How do you undo it?
- Two branches changed the same function for different reasons. How do you resolve the conflict without losing either intent?
Describe a time when you had to work under pressure. How did you handle it?
Describe a time when you had to work under pressure. How did you handle it?
Approach
- Choose a situation with a real deadline or incident where you were the person deciding, such as a production outage, a release date moved up, or a dependency that failed late. A story where you only followed instructions will not carry the answer.
- Spend little time on the setup and most on triage: what you cut or postponed, what you kept non-negotiable (tests on the risky path, a rollback plan), and why.
- Show communication under stress: who you told, how often, and what you said when the news was bad, for example posting status updates to a channel and agreeing a scope reduction with the product manager.
- Close with the result and a lasting change, such as a runbook, an alert or a smaller release process, which shows you handle pressure by reducing the chance of repeating it. Avoid a hero story built on unplanned all-nighters.
Follow-up
- What did you decide not to do, and who agreed to that?
- Looking back, what should have been caught before the pressure started?
- How do you keep code quality up when the deadline will not move?
How do you prioritize tasks when working on multiple projects?
How do you prioritize tasks when working on multiple projects?
Approach
- Name your method before the example: rank work by impact, urgency, dependencies and the cost of delay, and write the ranking down where stakeholders can see it. Then give one concrete case with at least two competing projects.
- Make the trade-off explicit: say which item you deferred, who it affected and how you told them, rather than implying you did everything.
- Show that you negotiate scope, not just order: for instance, shipping a smaller version of one item to unblock another, or asking a product manager which of two requests matters more this week.
- Explain how you re-prioritise when something urgent arrives, such as an incident interrupting planned work, and how you protect time for the long-term item (a bug backlog, a migration) so it does not slip forever.
Follow-up
- Two senior stakeholders each say their request is the top priority. What do you do?
- How do you tell whether a task is truly urgent or only loud?
- Describe a time your prioritisation was wrong and what you changed.
Provide an example of how you have contributed to a team environment.
Provide an example of how you have contributed to a team environment.
Approach
- Pick contributions that changed how the team works, not only your own output: careful code reviews, onboarding a new hire, writing the runbook, fixing a flaky test suite, or unblocking a teammate on a design problem.
- Say what the team looked like before and after, with something observable such as fewer review round trips, a faster setup for new engineers or a recurring incident that stopped.
- Be specific about your part with the word I, and credit others by role. Do not describe only what the team achieved.
- Include one contribution that was unglamorous, such as documentation or on-call handoffs, which shows you value team health as well as feature work.
Follow-up
- What was the hardest part of getting teammates to adopt it?
- How do you make time for team-level work alongside your own tasks?
- What do you do when a teammate is struggling with their part of a shared deadline?
What strategies do you employ to handle conflict within a team?
What strategies do you employ to handle conflict within a team?
Approach
- Choose a real disagreement about something technical or procedural, such as an API shape, a testing standard or the scope of a release, not a personality clash with no substance.
- Show the steps you took: understand the other person's goal first, restate their position to their satisfaction, agree the criteria for a decision, then use evidence such as a prototype, a benchmark or a past incident.
- Describe how it resolved, including if you were the one who changed your mind. Escalating to a manager is acceptable only after you tried to settle it directly and can say why you escalated.
- End with the working relationship afterwards and what you now do differently, for example writing a short decision record so the same argument does not repeat. Do not paint the other person as wrong.
Follow-up
- What if the data had not settled it? How would you decide?
- Describe a conflict where you were the one who was wrong.
- How do you handle disagreement with a more senior engineer on a design you think is flawed?
Describe a situation where you had to adapt to significant changes.
Describe a situation where you had to adapt to significant changes.
Approach
- Pick a change that was large and outside your control, such as a re-organisation, a new technology stack, a product pivot or requirements that moved mid-project, and state in a sentence what changed.
- Show what you did in the first days: gathered information, re-established priorities, identified what was now wasted effort, and asked the questions that would reduce uncertainty.
- Give evidence that you learned fast, for example picking up an unfamiliar framework by building a small service or pairing with someone, and the point at which you were productive.
- Say what you kept steady for the team while things moved, such as tests, review standards or communication cadence, and what the outcome was. Avoid a story where you only complained about the change.
Follow-up
- What was the first thing you let go of when the plan changed?
- How did you help teammates who were struggling with the same change?
- What would you do to spot that kind of change earlier next time?
Provide a code review of a given piece of code and suggest improvements.
Provide a code review of a given piece of code and suggest improvements.
Approach
- Work in passes, in order of risk: correctness first (edge cases, off-by-one errors, null or empty input, error handling, resource leaks, concurrency), then security (input validation, injection, secrets in code, authorisation checks), then performance (repeated work, queries inside loops, wrong data structure), then readability and tests.
- Say what you would block the merge on and what is optional. A bug or a security hole is blocking; naming, formatting and style belong in a clearly labelled nit comment, ideally left to a linter.
- Make each comment actionable: point to the line, explain the failure with an example input, and suggest a fix or a question rather than a verdict.
- Ask for the context a reviewer needs: what the change is meant to do, how it was tested, and how large it is. For a very large change, ask whether it can be split.
- If the prompt is about your own reviews, tell a short story: a review comment that caught a real defect, and how you wrote it.
Follow-up
- Which of your comments would block the merge, and which would you leave as suggestions?
- The author disagrees with your comment. What do you do?
- How do you review a change that touches several hundred lines across many files?
- 01
What is your experience with version control systems, particularly Git?
- 02
Describe a time when you had to work under pressure. How did you handle it?
- 03
How do you prioritize tasks when working on multiple projects?
- 04
Provide an example of how you have contributed to a team environment.
- 05
What strategies do you employ to handle conflict within a team?
- 06
Describe a situation where you had to adapt to significant changes.
How hard is the Cognition AI Software Engineer interview, and how long should I prepare?
One report calls the interviews challenging, singling out the technical assessments, and says candidates spend several weeks preparing. If you have one week, use the seven-day plan on this page: coding fundamentals first, then fundamentals and design, then case studies, code review and behavioral stories, ending with a full mock session.
Cognition AI Software Engineer candidate reports ↗How long does the process take?
Candidates report four rounds over roughly 3-5 weeks. A separate report puts the time from first screen to final offer at 4-6 weeks, depending on how interviews and feedback are scheduled. Treat both as rough and ask your recruiter for your own timeline.
Cognition AI Software Engineer candidate reports ↗Which languages and tools should I prepare?
The role listing names Python and Java as example languages, lists C++ among familiar languages, and mentions React, Django, Docker and Kubernetes as examples of frameworks and tools, with AWS, Azure and Google Cloud as cloud examples. Pick the one language you code best in, and be ready to talk about any framework or tool you list on your resume.
Cognition AI Software Engineer candidate reports ↗What kinds of questions are reported?
The reported set covers technical fundamentals (polymorphism, debugging, REST versus SOAP, Git), system design (a scalable web application, project architecture, security, data flow, microservices versus a monolith), problem solving (dataset trends and anomalies, optimising an algorithm, improving a product, measuring success), coding (linked list, binary search, dynamic programming, complexity, code review) and behavioral prompts. The reports do not say which round each belongs to, and they describe the questions as representative and team-dependent.
Cognition AI Software Engineer candidate reports ↗How much machine learning should I study?
Machine learning concepts are listed as less common topics and as a nice-to-have, alongside cloud services and performance optimisation. Spend a small share of your time on being able to describe how you would explore a dataset and what a model's data pipeline involves, and spend the rest on code, design and behavioral stories.
Cognition AI Software Engineer candidate reports ↗Is the role remote or hybrid?
Reports say remote or hybrid options depend on the position and location. Ask your recruiter about your specific role early, rather than assuming either arrangement.
PracHub Software Engineer practice ↗Sources & methodology 3 sources ↗
No official company page is cited. Rounds and questions come from candidate reports and PracHub editorial material; each source shows the date it was read.
- 01Cognition AI Software Engineer candidate reports ↗
Company-reported rounds, questions and FAQ.
Candidate reports · Accessed 2026-09-22 - 02PracHub Software Engineer practice ↗
PracHub practice material, not company-reported.
PracHub page · Accessed 2026-09-22 - 03PracHub preparation framework ↗
PracHub preparation guidance.
PracHub page · Accessed 2026-09-22