cswork / libraryOpen practice workspace

Interview guides · Acumen Solutions

Acumen Solutions Software Engineer Interview Guide

Acumen Solutions Software Engineer interview guide: the 3 reported rounds, OOP, linked list, REST and system design answers, and a 7-day plan.

The 60-second brief

The role description candidates read mentions client projects in various industries. It describes Software Engineers working on both the front end and the back end, on projects that range from web applications to integrations between existing systems, and taking part in every stage: gathering requirements with cross-functional teams, design, implementation, code review, debugging and deployment. Candidates describe a core stack of Java, C# or Python, web frameworks with RESTful APIs, Agile or Scrum delivery, and SQL or NoSQL databases. AWS or Azure, React or Angular, and DevOps practices are listed as extras rather than requirements.

This guide is for engineers interviewing for a Software Engineer role at Acumen Solutions who write code in a language such as Java, C# or Python and build web applications and REST APIs. It covers the three reported stages and all 25 questions candidates report. They fall into five groups: programming concepts (OOP, synchronous vs asynchronous code, error handling), coding (reversing a linked list, complexity analysis), engineering practice (code quality, Git, debugging a failing test), design (a scalable web app, database design, architecture patterns, microservices vs monolith, security) and behavioral or case questions.

Candidates report three stages over about 3-5 weeks: a Phone Screening on background and fit, a Coding Assessment built on coding challenges, and one or more In-Person Interviews with team members, where candidates report technical and cultural-fit questions.

Focus areas

  • Coding Challenges
  • Programming Concepts
  • Object-Oriented Programming (OOP)

Overview

The reported list is broad, and each topic needs a concrete example. There is one classic data-structure problem (reversing a linked list), a follow-up on time complexity, and many concept questions: OOP principles, synchronous vs asynchronous programming, error handling, and the difference between Java and Python. Prepare each concept answer as a short definition followed by a small, concrete example in your own language. Choose Java, C# or Python, since those are the languages candidates see listed, and prepare every concept answer in that language.

The work described for the role spans front-end and back-end code on client projects, from web applications to integrations between systems. It includes code reviews and debugging, so prepare for those topics as well as the algorithms: how you keep code maintainable, how you use Git, and how you track down a failing test. Code Review / Code Evaluation and Live Coding also appear among the reported topics. Practise reading someone else's code and commenting on it, as well as writing your own while explaining it aloud.

Prepare the design questions at the level of an ordinary web application: a scalable web application for a use case you choose, database design for a new application, the architecture patterns you prefer, microservices vs monolith, and security. Prepare one complete design for an ordinary web product: REST endpoints, relational schema, cache, background jobs, authentication. Be ready to argue its trade-offs. The listed must-haves (RESTful APIs, SQL and NoSQL) and nice-to-haves (AWS or Azure, React or Angular, DevOps) tell you which vocabulary to have ready.

The case and behavioral questions cover turning requirements into a solution, working with an ambiguous spec, taking over a legacy system, explaining a technical idea to a non-technical stakeholder, conflict, prioritisation and feedback. Candidates report that the in-person stage covers cultural fit as well as technical skill. Prepare specific stories in which you made the decisions, with an outcome you can state.

The Acumen Solutions interview process

Candidates report these three stages in this order. Little is reported about the internal format of each stage, so ask the recruiter during the Phone Screening how the Coding Assessment is run and how many in-person interviews to expect.

Phone Screening

Candidates describe the Phone Screening as a first call about their background and fit for the role. Nothing beyond that is reported for this stage. Prepare a short, ordered account of your experience that matches the requirements candidates describe: which of Java, C# or Python you write daily, the web frameworks and REST APIs you have built, how your teams ran Agile or Scrum, and which SQL or NoSQL databases you have used. A project walkthrough is also useful preparation for the loop as a whole, so have one project ready to discuss in depth. Use the end of the call to ask how the Coding Assessment is delivered and what the in-person stage contains.

What to demonstrate

  • Your background
  • Your fit for the role

How to prepare

  • Write a walkthrough of your background that names your main language, one web framework, one API you built, one database you designed or tuned and how your team ran Agile or Scrum, and say it aloud until it runs without notes.
  • Choose the two technologies on your CV that you would most like to discuss, since the reported project question has a bracketed slot for one. For each, prepare one design decision, one problem you hit and one measurable result.
  • Write three questions for the recruiter: whether the Coding Assessment is live or done on your own, which language it allows, and how many in-person interviews follow.

Coding Assessment

Candidates report a Coding Assessment that tests technical ability through coding challenges. The format (live, timed online test or take-home) is not reported, so prepare for both writing code while explaining it and writing it alone. The coding question types to practise for a stage like this are the reported ones: reversing a linked list, solving a problem in a preferred language, giving and improving its time complexity, and handling errors in your code. Live Coding and Code Review also appear among the reported topics. Go in able to write correct code in one language without an IDE's help, state its complexity without being asked, and test it on edge cases before you call it finished.

What to demonstrate

  • Technical capabilities
  • Coding challenges as the way they are tested

How to prepare

  • Write iterative and recursive linked-list reversal from memory, then the variants: reversing a sublist between two positions and reversing in groups of k. Trace each one on a three-node list.
  • Solve 15-20 array, string and hash-map problems in your interview language. For each, write the brute-force complexity, the improved complexity and the data structure that made the improvement possible.
  • For every solution, add input validation and decide out loud what happens on empty, null and very large input, so the reported error-management question has examples behind it.

In-Person Interviews

Candidates describe this stage as one or more interviews with team members, where they report technical and cultural-fit questions. Reports do not place particular questions in particular stages, so treat the reported question areas as material for the whole loop: programming concepts and engineering practice, design, problem-solving cases and behavioral questions. Prepare each area and bring a concrete example to every concept answer.

What to demonstrate

  • Technical skills, as discussed with team members
  • Cultural fit

How to prepare

  • Write one complete design for a web application of your choice (REST endpoints, relational schema with indexes, cache, background queue, authentication) and present it aloud, including what changes when traffic grows tenfold.
  • Prepare a small class hierarchy in your language that shows encapsulation, an interface, polymorphism and one case where composition is better than inheritance.
  • Prepare six STAR stories: a team conflict, learning a technology fast, critical feedback, two competing projects, a hard technical problem, and taking over a legacy system. Each should state your own decisions and a result.

Where candidates lose points

Listing the four OOP pillars as definitions without showing them in code, then failing to explain an interface vs an abstract class or when inheritance is the wrong choice.

Prepare a small class example in your interview language that uses an interface, overriding and encapsulated state. Have one case ready where composition replaces inheritance, and one Liskov violation such as Square extending Rectangle.

Overwriting curr.next before saving the next node when reversing a linked list, or returning the old head, then not tracing the code to catch the mistake.

Write the three-pointer loop from memory several times. Trace it on a three-node list and check the empty and single-node cases before saying you are done. Practise the sublist and k-group variants so a follow-up does not catch you out.

Giving a time complexity by counting loops while missing hidden O(n) operations such as list.insert(0), in on a list, slicing or string concatenation, and leaving out space complexity.

For every practice solution, write the cost of each data-structure operation next to the line that uses it. State both time and space, and explain the improvement in terms of the waste removed (a repeated search replaced with a hash set, repeated sums replaced with prefix sums).

Answering the scalable web app or microservices question with a fixed infrastructure list (Kubernetes, Kafka, many services) without stating requirements, a data model or what the complexity costs.

Start from requirements and expected load, sketch the REST API and schema, and begin with a monolith, database, cache and queue. Add a component only when a stated number calls for it, and name the cost of each addition.

Behavioral and case stories told as 'the team did it', or conflict stories where you were simply right, with no result and no lesson.

Write each STAR story in the first person singular, with the decision you made, the evidence you used and a result you can state. In the conflict story, include the point where you changed your mind or found a middle option.

Questions & practice

What are the differences between synchronous and asynchronous programming?

Medium · Technical / Domain Questions

Approach

  1. Define both terms. Synchronous code blocks the caller until the operation returns. Asynchronous code starts the operation and gives control back, and the result arrives later through a callback, a promise or future, or an awaited task.
  2. Separate asynchrony from parallelism. A single-threaded event loop (Node.js, Python asyncio) runs many I/O waits concurrently without running code in parallel. Threads and processes give parallelism for CPU-bound work. On the standard CPython build, the GIL means pure-Python CPU-bound work needs processes rather than threads; C extensions that release the GIL (NumPy) and the free-threaded build in Python 3.13+ are exceptions.
  3. Map the idea to your language: C# async/await with Task, Java CompletableFuture or virtual threads, Python async def with await and asyncio.gather. Give a concrete case: calling three independent REST services concurrently instead of one after another, so total latency is close to the slowest call rather than the sum.
  4. Name the pitfalls: a blocking call such as time.sleep or a synchronous DB driver inside a coroutine stalls the whole event loop; exceptions in un-awaited tasks get lost; completion order is not guaranteed; unbounded fan-out can exhaust connections, so cap it with a semaphore or a connection pool.

Follow-up

  • What happens if you call a blocking function inside an async handler, and how would you find it?
  • How would you limit an async job to 10 concurrent outbound requests?
  • When is async the wrong choice?

Solve a given coding problem using [preferred programming language].

Medium · Coding / Algorithms

Approach

  1. Before coding, restate the problem and pin down input size, types, whether input can be empty or contain duplicates or negatives, and the expected output for one example you write down.
  2. Say the brute-force solution and its complexity first, then improve it using the usual tools: a hash map or set for O(1) average lookups, sorting plus two pointers, a sliding window for contiguous ranges, a stack for nesting, and prefix sums for range totals.
  3. Write the code in the language you know best among Java, C# and Python, with clear names and small helper functions. Avoid language tricks you cannot explain.
  4. Test by tracing your example, then the edge cases: empty input, a single element, all duplicates, the largest size. Finish by stating time and space complexity.

Follow-up

  • Can you reduce the extra space to O(1)?
  • How does the solution change if the input arrives as a stream?
  • Which line would fail first on input you did not expect?

What is the time complexity of your solution? Can you optimize it?

Medium · Coding / Algorithms

Approach

  1. Derive the complexity from the code rather than recalling it: count nested loops over the input, then multiply by the cost of each operation inside. A hash map lookup is O(1) on average and O(n) in the worst case; a sort is O(n log n); Python list.insert(0, x) and the in operator on a list are O(n).
  2. Look for hidden costs: repeated string concatenation in a loop is O(n^2) in Java and C# (use StringBuilder or a list join); slicing copies; recursion uses stack space proportional to depth. Always state space as well as time.
  3. Optimise by naming the waste. Repeated searches become a hash set or map (two-sum goes from O(n^2) to O(n) time with O(n) space). Repeated range sums become prefix sums. Unsorted pair searches can become sort plus two pointers in O(n log n) time. The extra space is O(1) only if you sort in place (Python's sort and Java's object sort use O(n) auxiliary space), and returning the original indices needs O(n) to keep them.
  4. Mention amortised cost where it applies (a dynamic array append is O(1) amortised), and say when the theoretical lower bound means no further improvement is possible, such as needing to read every element at least once.

Follow-up

  • What is the worst case for your hash map version, and when could it happen?
  • Can you trade the extra memory back for time?
  • Is O(n log n) the best possible here? Why?

How would you handle error management in your code?

Medium · Coding / Algorithms

Approach

  1. Separate expected failures (invalid input, record not found, a conflict) from unexpected ones (bugs, an unavailable dependency). Validate at the boundary and fail fast with a clear message. Let real bugs surface instead of hiding them.
  2. Use your language's tools correctly. Catch specific exception types, never a bare catch-all that swallows errors. Keep the cause when re-raising (raise ... from e in Python, the inner exception in C# and Java). Release resources with try-with-resources, using, or with.
  3. In a REST API, map errors to status codes in one global handler: 400 for validation, 404 for not found, 409 for conflict, 500 for unexpected errors. Return a consistent error body and never leak stack traces or SQL to the client.
  4. Retry only transient failures on idempotent operations, with exponential backoff and jitter. Use an idempotency key for POST requests that may be retried. Log errors once, with a correlation ID and enough context to reproduce them.

Follow-up

  • When would you return an error value instead of throwing an exception?
  • How would you make a payment POST safe to retry?
  • What do you do with an exception you cannot handle at the current level?

Write a function to reverse a linked list.

Medium · Coding / Algorithms

Approach

  1. Iterative solution with three pointers. Start with prev = null and curr = head. While curr is not null: save next = curr.next, point curr.next at prev, then advance prev = curr and curr = next. Return prev as the new head. This is O(n) time and O(1) extra space.
  2. Saving next before relinking is the step that matters. Overwriting curr.next first loses the rest of the list. Returning head instead of prev is the other common bug.
  3. Recursive version: reverse the rest, set head.next.next = head and head.next = null, then return the new head from the recursion. It is also O(n) time but uses O(n) stack space and can overflow on long lists, so prefer the iterative version in production.
  4. Test on an empty list, a single node, two nodes, and a longer list traced on paper. Check that the old head now points to null so you have not created a cycle.

Follow-up

  • Reverse only the nodes between positions m and n.
  • Reverse the list in groups of k nodes.
  • How would you reverse a doubly linked list, and what changes?

How would you approach a project with ambiguous specifications?

Medium · Problem-Solving / Case Studies

Approach

  1. List explicitly what is unknown, then sort the unknowns into those you can resolve by asking and those you can only resolve by building something and showing it.
  2. Ask targeted questions of the right people, and record every assumption in writing so stakeholders can confirm or correct it, for example in the ticket or a short design note.
  3. Build the smallest end-to-end slice or prototype and show it early. Feedback on something concrete resolves ambiguity faster than more meetings. Keep the parts most likely to change behind interfaces so changing them is cheap.
  4. Give a real example: the ambiguity, the assumption you made, how you checked it, and what changed as a result.

Follow-up

  • The stakeholder is not available to answer questions. What do you do?
  • Your prototype turned out to be the wrong direction. How did you recover?
  • How do you stop the scope from growing while requirements are still unclear?

Find version gaps and relay lag with window functions

Medium · window functions · event tables · frame semantics

outbox_event holds event_id, aggregate_type, aggregate_id, aggregate_version, event_type, payload, status ('pending','published','dead'), attempts, created_at, published_at. A projection is missing rows and you must decide whether the relay skipped events or the consumer dropped them. Write three queries over the last seven days: one listing every aggregate_id whose published aggregate_version sequence has a hole, one giving per-day counts with a running total, and one returning the newest published event per aggregate. For each, say where the window function is evaluated relative to WHERE and LIMIT. PostgreSQL 16.

Approach

  1. Gaps: compute lead(aggregate_version) OVER (PARTITION BY aggregate_id ORDER BY aggregate_version) in a subquery, then filter next_version <> aggregate_version + 1 in the outer query. Window functions are evaluated after WHERE, GROUP BY and HAVING and before the outer ORDER BY and LIMIT, so the predicate cannot sit in the same WHERE clause and PostgreSQL 16 has no QUALIFY.
  2. Say what the seven-day filter does to the answer: it truncates every partition, so the first row per aggregate has no predecessor inside the window and a hole spanning the boundary is invisible. Widen the window, or join to resource.version as the authority for the true maximum.
  3. Running total: SELECT date_trunc('day', created_at) AS d, count() AS n, sum(count()) OVER (ORDER BY date_trunc('day', created_at) ROWS UNBOUNDED PRECEDING). An aggregate inside a window call is legal because grouping runs before windowing. The grouping key is unique per row here so ROWS and RANGE agree, but write the frame anyway — over ungrouped rows with tied timestamps the default RANGE frame pulls in every peer row and the total jumps.
  4. Newest per aggregate: DISTINCT ON (aggregate_id) ... ORDER BY aggregate_id, aggregate_version DESC is the cheap PostgreSQL-only form when an index matches that order; row_number() OVER (PARTITION BY aggregate_id ORDER BY aggregate_version DESC) = 1 is the portable form and needs a subquery for the same evaluation-order reason as the gap query.

Follow-up

  • Relay failover redelivers events. Does a duplicate break the gap query, and how would you detect one from this table alone?
  • Turn the gap check into a continuous monitor rather than a query someone runs after an incident. What does it watch?

Write the update path that detects a concurrent edit

Medium · optimistic concurrency · transactional outbox · audit history

resource carries version INT NOT NULL DEFAULT 1. resource_revision holds revision_id, resource_id, version, actor_user_id, change_kind, patch JSONB, request_id, created_at with UNIQUE (resource_id, version). outbox_event holds aggregate_type, aggregate_id, aggregate_version, event_type, payload, status. A PUT carries the version the client read. Write the exact statements for the single transaction that applies the edit, records the revision and enqueues 'resource.updated', and give the handler's branch on zero affected rows. Then say what PostgreSQL 16 does under READ COMMITTED when two of these updates hit one row at once.

Approach

  1. One transaction, three writes, no network call inside it: UPDATE resource SET title = $3, version = version + 1, updated_at = now() WHERE resource_id = $1 AND tenant_id = $4 AND version = $2; then INSERT the resource_revision row at version $2 + 1; then INSERT the outbox_event row at the same aggregate_version. The event goes to a table rather than a broker because no transaction spans both.
  2. Branch on the affected-row count before doing anything else. Zero has three causes — stale version, wrong tenant, row gone — so re-read once and map to 409 carrying the current version, or 404 for an id outside the caller's tenant, which also stops the endpoint confirming that another tenant's id exists.
  3. State the engine behaviour instead of assuming it. Under READ COMMITTED the second UPDATE blocks on the row lock, and when the first commits PostgreSQL re-evaluates the WHERE clause against the newly committed row, so the version predicate now fails and the statement reports zero rows. Under REPEATABLE READ the identical collision raises SQLSTATE 40001 instead, so the handler must fold both shapes into one conflict response.
  4. Keep UNIQUE (resource_id, version) even though the predicate already serialises writers. It is what makes a lost update unwritable if any other path ever reaches the revision table, and it converts a logic bug into 23505 rather than into a silently missing history row.

Follow-up

  • A client sends the version it read ten minutes ago and the resource has moved three versions. What is in your 409 so it can resolve the conflict without a full re-fetch?
  • Two editors, two disjoint fields, no overlap. Does your answer still refuse the second write, and should it?

Explain the concept of Object-Oriented Programming and its principles.

Medium · Technical / Domain Questions

Approach

  1. Name the four principles, then show each in one small example in your language. Encapsulation: private state behind methods, such as an Account whose balance changes only through deposit and withdraw. Abstraction: callers depend on a PaymentMethod interface, not its internals. Inheritance: CardPayment extends a base class. Polymorphism: process() is called through the interface and runs the subclass's version.
  2. Separate compile-time polymorphism (overloading in Java or C#) from runtime polymorphism (overriding plus dynamic dispatch). Python has no signature-based method overloading: a later def with the same name replaces the earlier one, so use default or keyword arguments or functools.singledispatch. Operator overloading through dunder methods does exist, and polymorphism there leans on duck typing.
  3. Say where inheritance hurts. Deep hierarchies couple subclasses to base-class internals, and a Square that extends Rectangle breaks the Liskov substitution principle. Prefer composition when the relationship is 'has-a' or when behaviour needs to vary at runtime.
  4. Link the principles to SOLID briefly, especially single responsibility and dependency inversion. Then say what OOP gives a team in practice: change one class without touching its callers, and test it through its interface with a mock.

Follow-up

  • What is the difference between an abstract class and an interface, and when would you choose each?
  • Give an example where inheritance caused a bug or a refactor you had to undo.
  • How does encapsulation work in Python, given that there are no private access modifiers?

Can you describe a project where you used [specific technology or framework]?

Medium · Technical / Domain Questions

Approach

  1. Fill the slot with a technology on your CV that matches the listed stack (a Java, C# or Python web framework, a REST API, a SQL or NoSQL database, or React or Angular). Pick the project where you made design decisions with that technology yourself.
  2. Structure: the problem the project solved and for whom; your part in it; one decision that depended on the technology, the alternative you considered and why you rejected it; one problem you hit and how you solved it; the measurable result.
  3. Show you understand how the framework works, not only its API. For example: how Spring or ASP.NET Core dependency injection resolves services, how Django's ORM causes N+1 queries and how select_related fixes them, or how React re-renders on state changes.
  4. Finish with what you would change now. It shows you assessed the technology rather than simply used it.

Follow-up

  • Why did you choose that framework over the obvious alternative?
  • How was the project tested and deployed?
  • What was the hardest bug you hit with that technology?

How do you ensure code quality and maintainability in your projects?

Medium · Technical / Domain Questions

Approach

  1. Answer in layers, each with a concrete practice. Before merge: small pull requests, code review against a short checklist (naming, error handling, tests, no duplicated logic), and linters and formatters enforced in CI. In design: single-responsibility classes, dependency injection so units can be tested, clear module boundaries.
  2. Tests: many fast unit tests, fewer integration tests against a real database or API, and a few end-to-end tests on critical paths. Treat coverage as a floor that catches untested code, not a target that proves quality.
  3. Maintainability over time: record why a decision was made (README notes or architecture decision records), keep dependencies updated, and track technical debt in the backlog instead of leaving unfinished-work comments scattered in the code.
  4. Give one real example, such as a review comment you wrote that caught a bug, or a refactor that made a module testable. Say what it prevented or what got easier.

Follow-up

  • How do you handle a code review where you and the author disagree?
  • What coverage target would you set, and why?
  • How do you decide when technical debt is worth paying down?

Design a scalable web application for a specific use case.

Medium · System Design / Architecture

Approach

  1. Choose a concrete use case and fix the scope before drawing anything, for example an appointment-booking app. Cover core features, number of users, read/write ratio, latency needs, and which data must never be wrong (no double bookings).
  2. Outline the REST API (for example POST /bookings, GET /slots?date=) and the data model. Then the components: a load balancer, stateless app servers that scale horizontally, a relational primary database with read replicas, a cache such as Redis for hot reads, a CDN for static assets, a queue with workers for email and slow jobs, and object storage for files.
  3. Handle correctness explicitly. Prevent double booking with a unique constraint or a transaction with row locking, or with optimistic concurrency using a version column. Explain how the cache is invalidated when a booking changes.
  4. Scale in steps and say what breaks first at ten times the load: usually database reads (add replicas and cache), then writes (partition by tenant or region). Mention health checks, autoscaling and monitoring. If you know AWS or Azure, map each component to its managed service.

Follow-up

  • Where do user sessions live if the app servers are stateless?
  • What happens when the cache goes down?
  • How would you deploy a new version with no downtime?

How would you approach database design for a new application?

Medium · System Design / Architecture

Approach

  1. Start from entities and access patterns: list the main entities and their relationships, then the most frequent queries and writes. The schema should serve those, not just mirror the domain.
  2. Normalise to roughly third normal form to avoid update anomalies. Use primary keys, foreign keys, NOT NULL, UNIQUE and CHECK constraints so the database enforces invariants. Model many-to-many relationships with a join table.
  3. Add indexes for real query patterns, with composite index column order matching the filters (equality columns first, then range). Remember that every index slows writes. Denormalise or add a read model only when a measured read path needs it.
  4. Choose SQL or NoSQL by need: relational for transactions, joins and integrity; a document store for flexible or nested records read as a whole; key-value for simple fast lookups. Mention versioned migrations and transaction isolation for concurrent updates.

Follow-up

  • When would you denormalise, and how do you keep the copies consistent?
  • How would you add a column or index to a large live table safely?
  • How do you prevent two users overwriting each other's edits?

What architectural patterns do you prefer, and why?

Medium · System Design / Architecture

Approach

  1. Choose one or two patterns and justify them by context. A layered architecture (controller, service, repository) fits most REST back ends: it is simple, familiar, and keeps business logic testable apart from HTTP and the database.
  2. Name the code-level patterns that support it: dependency injection so services can be tested with fakes, the repository pattern to isolate data access, and strategy or adapter where behaviour or an external system varies, which is common in system integrations.
  3. Name larger patterns and when you would choose them: hexagonal (ports and adapters) when many external systems plug in, event-driven with a message queue when work can be asynchronous and services should be decoupled, MVC on the web tier.
  4. Say where your preferred pattern stops working, for example layers that only pass calls through, or event-driven flows that are hard to trace. A preference with its limits stated is more convincing than a list of patterns.

Follow-up

  • How does dependency injection make your code easier to test?
  • When would you choose an event-driven design over direct API calls?
  • Which pattern have you seen used badly?

Discuss trade-offs between microservices and monolithic architectures.

Medium · System Design / Architecture

Approach

  1. Monolith strengths: one deployable unit, in-process calls, ACID transactions across the whole data model, and easier debugging and local setup. Weaknesses: every change ships together, the whole application scales as one, and boundaries erode without discipline.
  2. Microservice strengths: independent deployment and scaling, teams owning services, and isolated failures if designed for it. Costs: network latency and partial failure, no cross-service transactions (use sagas or an outbox for consistency), distributed tracing and monitoring, and much more CI/CD and infrastructure work.
  3. Give a decision rule: start with a modular monolith with clear internal boundaries, and split out a service when a module needs independent scaling, a different release cadence or a separate team, and the operational maturity exists.
  4. For migration, use the strangler-fig approach: put a routing layer in front, move one bounded area at a time behind an API, and give each extracted service its own data rather than a shared database.

Follow-up

  • How would you split an existing monolith, and which piece would you extract first?
  • How do you keep data consistent when an order spans two services?
  • What problems appear when several microservices share one database?

How do you ensure security in your software design?

Medium · System Design / Architecture

Approach

  1. Start with a threat model: what you protect (user data, credentials, payments), where input enters (APIs, forms, file uploads, integrations) and who might attack. Then apply defence in depth.
  2. Cover the common web risks with concrete fixes. SQL injection: parameterised queries with bind parameters or an ORM, never string concatenation. XSS: output encoding plus a Content Security Policy. CSRF: tokens or SameSite cookies.
  3. Authentication and authorisation: hash passwords with bcrypt or Argon2, support MFA, use short-lived tokens, and check authorisation on the server for every resource to prevent insecure direct object references. Apply least privilege to service accounts and database users.
  4. Operations: TLS everywhere, secrets in a secrets manager rather than in code or Git, dependency vulnerability scanning in CI, input validation at boundaries, and logs that record security events without passwords or personal data.

Follow-up

  • How exactly would you store user passwords?
  • What is the difference between authentication and authorisation, and where do bugs usually appear?
  • How would you secure an API that a partner system calls?

Given a set of requirements, what steps would you take to develop a solution?

Medium · Problem-Solving / Case Studies

Approach

  1. Clarify first: who the users are, what problem they have, the acceptance criteria for each requirement, and the non-functional needs (load, security, integrations, deadline). Write down open questions and assumptions.
  2. Break the requirements into user stories and order them by value and risk, so the riskiest unknown, often an integration, is tackled early. Estimate them and plan iterations as an Agile or Scrum team would.
  3. Design the data model, API contracts and component boundaries. Review the design with peers, then implement in small increments with unit and integration tests and code review.
  4. Deploy through CI/CD, demonstrate each increment to stakeholders, collect feedback and adjust. Illustrate the steps with one project you delivered this way.

Follow-up

  • A key requirement changes halfway through a sprint. What do you do?
  • How do you estimate work you have never done before?
  • Two requirements contradict each other. How do you resolve it?

Discuss a challenging technical problem you solved and your approach.

Medium · Problem-Solving / Case Studies

Approach

  1. Choose a problem with real technical depth, such as a performance issue, a production bug, a data inconsistency or a difficult integration, and make sure you led the investigation or the fix.
  2. Give the symptom and the constraints, then show your reasoning: the hypotheses you formed, the evidence you collected (logs, metrics, a profiler, a reproduction) and how each step eliminated possibilities.
  3. Explain the fix and its trade-offs, the alternatives you rejected, and the measured result (latency, error rate, time saved).
  4. Finish with what you changed so the problem cannot recur, such as a test, an alert or a design change, and what you would do differently.

Follow-up

  • What other solutions did you consider?
  • How did you confirm the fix worked in production?
  • What would you have done with twice the time?

How would you explain a complex technical concept to a non-technical stakeholder?

Medium · Problem-Solving / Case Studies

Approach

  1. Start from what the stakeholder needs to decide or worry about, not from the technology. Choose the level of detail that serves that decision.
  2. Use one familiar analogy and test it: an API as a waiter carrying orders between the customer and the kitchen, or technical debt as a loan whose interest is slower future changes.
  3. Express trade-offs in business terms such as cost, risk, time and user impact. Avoid jargon, or define a term the first time you use it.
  4. Check understanding by asking them to restate the decision. Give a real example where your explanation led to a decision.

Follow-up

  • Explain what a REST API is to me as if I were the client's finance lead.
  • The stakeholder disagrees with your recommendation. What do you do?
  • How would you explain a delay caused by technical debt?

If you were given a legacy system to maintain, how would you approach it?

Medium · Problem-Solving / Case Studies

Approach

  1. Understand before changing anything. Get it running locally, read any documentation and ticket history, map the architecture and data flows, and find the people who know its history.
  2. Make it safe to change: add characterisation tests that capture current behaviour around the code you need to touch, plus logging and monitoring so you can see the effect of changes.
  3. Change it in small steps. Refactor the code you touch, prioritise by risk and how often each area changes, and upgrade unsupported dependencies when security requires it.
  4. Use the strangler-fig approach to replace parts behind stable interfaces, rather than a full rewrite that has to match years of undocumented behaviour. Record what you learn as you go.

Follow-up

  • There are no tests and an urgent bug arrives on your first week. What do you do?
  • When would you argue for a rewrite instead of incremental refactoring?
  • How would you upgrade a framework version that is several major releases behind?

Explain how you would approach debugging a failing test case.

Medium · Coding / Algorithms

Approach

  1. Reproduce the failure first. Run the single test locally and read the assertion message and stack trace. Decide whether the code is wrong or the test's expectation is out of date, and never just change the expected value to make it pass.
  2. Find what changed: recent commits with git log, dependency updates, environment differences between local and CI. Use git bisect when the failure appeared somewhere in a range of commits.
  3. Check for flakiness: run the test repeatedly and in isolation versus in the full suite. Look for shared state between tests, order dependence, time and timezone assumptions, unseeded randomness, async timing and network calls that should be mocked.
  4. Narrow the problem with a debugger or targeted logging until you can state the root cause. Fix that cause, keep or add a regression test, and say how you confirmed the fix, for example by running the test many times or across the whole suite.

Follow-up

  • The test passes locally but fails in CI. What do you check?
  • The test fails one run in twenty. How do you find out why?
  • When is it right to delete or rewrite a failing test?

Suggested practice checklist

Each day covers one group of the 25 reported questions, in an order that builds toward the three reported stages. Coding and concepts come first for the Coding Assessment, then design and practice for the in-person interviews, then stories and a full run-through.

Day 1 — Linked lists, complexity and the coding routine

  • Write iterative and recursive linked-list reversal in your interview language from memory, then reverse the nodes between two positions, and test every version on an empty list, one node and three nodes.
  • Solve 4 hash-map or two-pointer problems, saying the brute-force solution and its complexity out loud before improving it.
  • For each solution, write the time and space complexity and the specific waste the improvement removed.

Deliverable: Three working linked-list functions with test cases, and four solved problems each annotated with brute-force and improved complexity.

Day 2 — Programming concepts in your language

  • Write a small class hierarchy that shows encapsulation, an interface, overriding and one composition-instead-of-inheritance refactor, and explain it aloud.
  • Write a script that runs three slow I/O-bound functions (asyncio.sleep, an HTTP call or Task.Delay, not time.sleep or CPU work) first synchronously, then concurrently with async/await or futures, and measure the difference. Then add a CPU-bound version to see where async gives no speed-up, the pitfall the synchronous vs asynchronous question warns about.
  • Add error handling to one earlier solution and a small REST handler: specific exceptions, chained causes, and a mapping to 400, 404 and 500 status codes.

Deliverable: An OOP example file, a sync-vs-async timing script with I/O-bound and CPU-bound results, and an error-handling refactor with a status-code map.

Day 3 — Engineering practice: code quality, Git, debugging

  • In a scratch repository, practise revert, reset on a local branch, reflog recovery, cherry-pick and bisect to find a bug you planted on purpose.
  • Take a test that fails because of shared state or time dependence, debug it step by step, and write down the sequence you followed.
  • Review a pull request from an open-source project or an old one of your own, and write five review comments, separating required changes from suggestions.

Deliverable: Notes on the Git recovery commands with what each one did, a written debugging sequence for the failing test, and five code review comments.

Day 4 — Design a web application, its database and its REST API

  • Design a booking-style web application: REST endpoints, schema with keys and indexes, cache, queue and load balancer, and present it aloud. Add what breaks first at ten times the traffic and the change that fixes each bottleneck.
  • Practise the concurrent-edit update path with a version column and explain how it prevents double booking or lost updates.
  • Write the 3-4 queries the booking design needs: a join across bookings and customers, a GROUP BY count per slot or day, and a date-range filter that uses your composite index. Check each plan with EXPLAIN and confirm the index is used.
  • Answer the reported example question 'How would you implement a RESTful API?' on one page: resource naming, verb semantics and idempotency (GET, PUT and DELETE versus POST), status codes, pagination, versioning and authentication.

Deliverable: A one-page design diagram with API and schema and a bottleneck list, an optimistic-locking update query, the booking queries with their EXPLAIN output, and a one-page REST API answer sheet.

Day 5 — Architecture trade-offs and security

  • Write a comparison table of monolith, modular monolith and microservices covering deployment, transactions, debugging and operational cost, and the conditions under which you would split a service.
  • Prepare a two-minute explanation of the layered architecture you prefer, with the point where it stops working.
  • Go through your day 4 design for security: parameterised queries, password hashing, authorisation checks on every resource, secret storage and TLS.

Deliverable: An architecture comparison table, a spoken pattern explanation, and a security checklist applied to your own design.

Day 6 — Problem-solving cases and project stories

  • Outline your requirements-to-delivery process using one real project, including one point where requirements changed.
  • Prepare stories for an ambiguous spec, taking over a legacy system and a hard technical problem, each with evidence and a measurable result.
  • Prepare two versions of the 'project using a specific technology' answer for the main technologies on your CV, and explain one of them to a non-technical friend using an analogy.

Deliverable: Four written outlines (requirements process, ambiguous spec, legacy system, hard technical problem) plus two technology project answers, one of them tested on a non-technical listener.

Day 7 — Behavioral stories and a full run-through

  • Write STAR outlines for conflict, motivation, prioritisation, learning a technology fast and handling feedback, each in the first person with a result.
  • Rehearse your Phone Screening walkthrough and your questions for the recruiter.
  • Run a mock loop: one timed coding problem, one design question and three behavioral prompts, then note which answers were weakest.

Deliverable: Five STAR outlines, a rehearsed screening walkthrough, and a mock-loop review listing the weakest answers to revise.

Behavioural preparation

Candidates report behavioral questions on team conflict, motivation, prioritisation, learning a technology quickly and handling feedback, and describe the in-person stage as covering cultural fit as well as technical skill. For a role built around client projects and cross-functional teams, prepare stories that show your own decisions, how you worked with other people, and a result you can state.

  1. How do you handle disagreements within a team?

Discuss your experience with version control systems like Git.

Medium · Technical / Domain Questions

Approach

  1. Describe the workflow you have used, and say why it fit that team: feature branches with pull requests into a protected main branch, trunk-based development with short-lived branches and feature flags, or GitFlow with release branches.
  2. Explain merge vs rebase. Merge preserves history and adds merge commits. Rebase gives a linear history but rewrites commits, so never rebase a branch others have pulled. Squash merging keeps main readable at the cost of losing fine-grained commits.
  3. Show recovery skills: git revert to undo a pushed commit safely; git reset only on local, unshared work; git reflog to recover lost commits; git cherry-pick to move a hotfix; git bisect to find the commit that introduced a regression in O(log n) steps.
  4. Mention conflict resolution: understand both sides' intent before choosing lines, then run the tests after resolving. Add one short story where Git saved you or where a bad merge taught you something.

Follow-up

  • A bad commit is already on main and others have pulled it. What do you do?
  • How would you find which of the last 200 commits broke a test?
  • When would you rebase, and when would you merge?

Describe a time when you faced a conflict within your team. How did you resolve it?

Medium · Behavioral / Leadership

Approach

  1. Choose a real disagreement with a concrete subject, such as a design choice, a code review dispute or a missed handoff, where you were one of the parties and not a bystander.
  2. Situation in two sentences, then most of the answer on actions. How you learned the other person's reasons, how you separated the technical question from personal friction, what evidence or experiment you suggested (a spike, a benchmark, a small prototype), and how a decision was reached or escalated.
  3. Give the outcome for the work and for the working relationship. A story where you were simply right and the other person gave in shows less than one where you changed your mind on something or found a third option.
  4. Avoid blaming the other person or describing them negatively, and avoid stories with no resolution.

Follow-up

  • What would you have done if they had not agreed?
  • Looking back, what part of the conflict was your fault?
  • How did you work with that person afterwards?

What motivates you to perform well in your job?

Medium · Behavioral / Leadership

Approach

  1. Give a specific answer tied to work this role involves: building software that a client actually uses, working across front end and back end, seeing a project through from requirements to deployment, or learning new technologies.
  2. Back it with evidence from a past episode, for example when you were most engaged on a project and what made that so, rather than a list of adjectives.
  3. Connect it to the role: say why client-facing project work across different industries fits what motivates you.
  4. Avoid generic lines such as 'I love coding' or answers built only around pay or titles.

Follow-up

  • Tell me about a time you were not motivated. What did you do?
  • What kind of work drains you?
  • What would make you leave a job?

How do you prioritize tasks when working on multiple projects?

Medium · Behavioral / Leadership

Approach

  1. State your method. List every commitment with its deadline, its impact and who depends on it. Separate urgent from important. Identify tasks that unblock others and do those first.
  2. Show how it works in an Agile or Scrum setting: work goes through the backlog, you protect sprint commitments, and new requests are traded off against them rather than silently added.
  3. Make communication part of the answer. When two commitments collide, tell the stakeholders early, explain the trade-off, and agree on a new order or deadline. Do not miss a deadline quietly.
  4. Give one real example of two projects competing for your time, with the decision you made and its result.

Follow-up

  • Two stakeholders both say their task is the top priority. What do you do?
  • Tell me about a deadline you missed. What happened?
  • How do you stop small interruptions from taking over your week?

Share an experience where you had to learn a new technology quickly.

Medium · Behavioral / Leadership

Approach

  1. Pick a technology relevant to the role if you can, such as a cloud platform (AWS or Azure), a front-end framework (React or Angular), a new web framework or a database. State the deadline that made speed necessary.
  2. Describe the learning method: read the official getting-started guide and core concepts first, build a small throwaway spike that mirrors the real task, read existing production code that uses it, and ask an experienced colleague to review early.
  3. Explain how you checked your understanding was good enough to ship: tests, a code review, or a small rollout. Name one mistake you made early and how you caught it.
  4. Give the result, then what you would do the same way next time.

Follow-up

  • How did you know you had learned enough to start building?
  • What did you get wrong at first?
  • How do you keep up with new technologies when no project requires them?

How do you handle feedback and criticism?

Medium · Behavioral / Leadership

Approach

  1. Use a real piece of critical feedback that stung a little, for example on pull request size, missing tests, estimates or communication. Avoid choosing praise disguised as criticism.
  2. Show the sequence: listen without defending, ask questions until you understand the concrete behaviour behind the feedback, decide what to change, change it, and later check with the person whether it helped.
  3. Include the other direction, since the role includes code reviews: how you give feedback. Be specific, comment on the code rather than the person, explain why, and separate required changes from suggestions.
  4. Mention one case where you disagreed with feedback, and how you discussed it with evidence instead of ignoring it.

Follow-up

  • Tell me about feedback you disagreed with.
  • How do you give critical feedback to a more senior engineer?
  • What feedback have you received more than once?