cswork / libraryOpen practice workspace

Interview guides · C5i

C5i Software Engineer Interview Guide

C5i Software Engineer interview guide: reported rounds, Java, DSA, SQL, system design and behavioral questions, with a 7-day preparation plan.

The 60-second brief

Candidate reports describe C5i as a company that builds software for both internal and external clients. The Software Engineer role is described as covering designing, coding, testing, debugging, deploying and maintaining applications, working alongside product managers, designers and other engineers, and taking part in code reviews. The reports do not name specific products or teams, so this guide does not either. It concentrates on the engineering fundamentals the reported questions cover.

This guide is for candidates applying to C5i as a Software Engineer, typically with a computer science background and one to three years of development experience, as the requirements candidates describe it. It covers the four reported rounds, the reported questions (Java and OOP basics, string and array coding, debugging and security scenarios, system design and behavioral prompts) and a 7-day plan. It also covers the stack the role lists: Java or Python, web basics, SQL or NoSQL databases and Git.

Candidates report four rounds spread over roughly three to five weeks: Initial Screening, Coding Tests, Technical Interviews and Behavioral Evaluations. Reports add that the experience can vary by team and role.

Focus areas

  • Java
  • Data Structures & Algorithms (DSA/DS)
  • Resume-Based Technical Questions

Overview

The reported questions are mostly fundamentals. Candidates describe Java and object-oriented programming (polymorphism, garbage collection), data structures (linked list versus array, stack versus queue, a stack built from queues), short coding tasks (reversing a string, finding the largest element, finding duplicates, binary search, a palindrome check) and SQL. Topic tags attached to the loop list Java, data structures and algorithms, resume-based technical questions, OOP and SQL, so those five areas deserve the most practice time.

Alongside the fundamentals, candidates report scenario and design questions: debugging a complex software issue, securing a web application, handling unclear requirements, prioritizing features with limited resources, a high-traffic e-commerce site, a scalable chat application, database design for many users, data consistency in a distributed system and microservices. For someone with one to three years of experience, the realistic goal is a structured answer with named trade-offs, not an exhaustive architecture. Practise saying what you would build first, what breaks first and what you would measure.

The requirements candidates describe name Java or Python as must-haves, plus web development principles, databases and version control. Cloud services such as AWS or Azure, front-end frameworks such as React or Angular, and DevOps practice appear only as nice-to-haves, so a short working vocabulary in those areas is enough. Pick Java as your coding language if you can, because several reported questions are phrased in Java. Prepare your own projects in detail as well: the topic tags include resume-based technical questions, which means every technology on your CV is fair game.

The C5i interview process

Candidates describe four stages in this order, and say the format can differ by team. The reports do not say which questions belong to which stage, so prepare each question type for every technical round.

Initial Screening

Candidates describe Initial Screening as the first filter on basic qualifications and fit. Reports do not give its format or who runs it. Treat it as the place where your CV is checked against the role's listed requirements: Java or Python, web basics, databases and version control. Expect to explain your projects and technologies in plain terms, and be ready to be asked about Java directly, since it heads the reported topic list.

What to demonstrate

  • Whether your experience lines up with the listed requirements: Java or Python, databases, version control
  • Basic Java and programming knowledge at an introductory level
  • Clear communication about your own projects

How to prepare

  • Write a short summary for each project on your CV: your own contribution, the technologies, one problem you solved
  • Prepare a one-sentence honest statement of your Java or Python level and what you have built in it
  • Review Java basics you can answer cold, such as the difference between a linked list and an array and what polymorphism means
  • Prepare to say why you want this Software Engineer role, tied to the work (building, testing, debugging, deploying) rather than slogans

Coding Tests

Candidates say they may be asked to complete coding tests. Reports do not say whether these are live, timed online or on paper, so practise in more than one setting. The reported coding tasks are small and classic: reverse a string in Java, find the largest element in an unsorted array, find duplicate numbers, binary search and a palindrome check. A stack built from queues also appears among the reported data-structure questions. Correct, compiling code with edge cases handled matters more than cleverness.

What to demonstrate

  • Working code in your chosen language, with correct handling of empty and single-element input
  • Command of arrays, strings and basic data structures
  • The ability to state time and space complexity for your own solution

How to prepare

  • Write the five reported coding tasks in Java without an IDE, then run them on empty, one-element, all-equal and large inputs
  • Implement a stack with two queues, and again with one queue, and state the cost of push and pop in each version
  • Write binary search both iteratively and recursively, using a midpoint formula that cannot overflow
  • Practise on LeetCode or HackerRank in the language you will use, since candidates mention both platforms

Technical Interviews

Candidates describe Technical Interviews as the in-depth stage on technical knowledge and problem solving. Reported questions of this kind include polymorphism in Java, the MVC architecture and its components, the advantages of RESTful APIs, linked list versus array, garbage collection in Java, plus debugging, security and system design scenarios. Topic tags also list SQL and resume-based technical questions. Prepare for definitions that you can back with a small example, and for design questions where you name the trade-offs.

What to demonstrate

  • Depth in Java and OOP concepts, shown through examples rather than definitions
  • Database and SQL fundamentals, including design for many concurrent users
  • Structured reasoning on debugging, security and design scenarios
  • Accurate technical detail about the projects on your CV

How to prepare

  • Prepare a Java example for each OOP idea you may be asked about, for instance an overridden method called through a base-class reference for polymorphism
  • Draw the MVC request flow for a web application you have built and name what each part owns
  • List the REST constraints you can defend (stateless requests, resource URLs, HTTP verbs and status codes) and one weakness of REST
  • Rehearse a debugging sequence and a web-security checklist, then practise two design questions aloud, such as a chat application and a high-traffic e-commerce site, naming the first bottleneck

Behavioral Evaluations

Candidates describe Behavioral Evaluations as the stage on interpersonal skills and cultural fit. The reported prompts are a significant challenge at work, prioritizing across several projects, working effectively in a team, what motivates you and how you handle feedback and criticism. Further reported examples include a conflict with a team member and a project deadline at risk. Prepare stories drawn from engineering work, with a decision you made and an outcome you can name.

What to demonstrate

  • Communication of past work and your own role in it
  • Collaboration and handling of feedback, as the round is described
  • Judgement when priorities or deadlines collide

How to prepare

  • Write five stories on one page each: a challenge, a prioritization call, a team success, a conflict and a piece of feedback you acted on
  • For every story, state your own decision in the first person singular, the alternatives you rejected and the result
  • Rehearse a deadline-at-risk answer: what you told stakeholders, what scope you cut and what happened
  • Prepare a few honest questions about how the team handles code review, deployment and agile practice

Where candidates lose points

Defining polymorphism, MVC or REST in textbook sentences with no example

For each reported concept, prepare a short worked case: an overridden method called through a base-class reference, the MVC flow of a request you built, and a REST endpoint with its verb and status code. Know the contrast, for instance compile-time overloading versus run-time overriding.

Writing the reverse-string, palindrome, duplicates or binary search solution without testing edge cases

State empty, null, single-element and all-equal inputs before you code. For palindromes decide on case and punctuation up front, and for binary search use a midpoint of low plus half the gap so it cannot overflow. Trace one small input out loud.

Building a stack from queues but not stating what push or pop costs

Say that the two-queue version makes either push or pop linear and the other constant, and show the single-queue rotation version. Naming the trade-off is the point of the exercise.

Listing buzzwords such as microservices, sharding or caching on a design question without showing why

For the chat application, e-commerce site and distributed-consistency questions, say who the users are, name the read and write paths, pick one data store with a reason, and state what fails first. Keep to a few components you can defend.

Claiming a technology on your CV that you cannot explain, or telling team stories entirely in the word we

Cut or mark anything you cannot discuss in depth. For each project prepare the decision you made, a problem you debugged and the result. Use I for your own actions and name your specific contribution.

Questions & practice

Explain the difference between a linked list and an array.

Medium · Technical / Domain Questions

Approach

  1. Start from memory layout: an array is one contiguous block, so element i sits at base + i * elementSize and index access is O(1); a linked list is a chain of separately allocated nodes, each holding a reference to the next (and previous, if doubly linked), so reaching index i is O(n).
  2. Compare insert and delete: in an array, inserting or removing in the middle shifts the tail, O(n); in a linked list it is O(1) once you hold the node (or its predecessor in a singly linked list), but finding that position is still O(n).
  3. Bring in the hardware: arrays are cache-friendly because neighbours share cache lines, while list traversal chases pointers across the heap. In Java each LinkedList node is an object with its own header and references, and LinkedList<Integer> also boxes every value, whereas int[] stores primitives inline.
  4. Tie it to Java types: a plain array has fixed length; ArrayList wraps a resizable array and grows by about 1.5x (newCapacity = old + old >> 1), so add at the end is amortised O(1). LinkedList implements Deque, but ArrayDeque is usually the faster choice for queue or stack work.
  5. Close with a decision rule: choose an array or ArrayList for indexed reads and iteration; a linked list only when you splice nodes you already hold, as in an LRU cache built from a hash map plus a doubly linked list.

Follow-up

  • Why is ArrayList often faster than LinkedList even for inserts near the middle of a large list?
  • How does ArrayList resizing work, and why is add at the end amortised O(1)?
  • How would you detect a cycle in a linked list using O(1) extra space?

Write a function to reverse a string in Java.

Medium · Coding / Algorithms

Approach

  1. Note that Java Strings are immutable, so any reversal builds a new string and needs O(n) extra space. The idiomatic answer is new StringBuilder(s).reverse().toString(), O(n) time.
  2. Then write it by hand to show the technique: char[] c = s.toCharArray(); swap c[i] and c[j] with two pointers from both ends while i < j; return new String(c). Even and odd lengths both work because the loop stops when the pointers meet or cross.
  3. Call out the slow version: result += s.charAt(i) in a loop copies the growing string each iteration, O(n^2) overall. A recursive version also risks stack overflow on long input and costs O(n^2) if it uses substring.
  4. Handle edge cases: null (decide whether to throw or return null), empty string, single character. Swapping chars splits Unicode surrogate pairs such as emoji; StringBuilder.reverse keeps surrogate pairs together, but neither approach handles combining characters (grapheme clusters).
  5. Test with "", "a", "ab", "abc" and a string containing an emoji.

Follow-up

  • Reverse the order of words in a sentence, ideally in place on a char array.
  • Reverse only the letters of a string, leaving punctuation in place.
  • Why are Strings immutable in Java, and what does that buy you?

How would you find the largest element in an unsorted array?

Medium · Coding / Algorithms

Approach

  1. Give the single-pass scan: max = a[0], then for i from 1 compare and update. O(n) time, O(1) space, n - 1 comparisons, and that is optimal because any element you skip could be the maximum.
  2. Explain why sorting first is the wrong tool: O(n log n) time to answer an O(n) question, and an in-place sort also mutates the caller's array.
  3. Initialise from the first element, not 0: starting at 0 returns the wrong answer for an all-negative array. Integer.MIN_VALUE works but hides the empty-array case.
  4. Decide the empty or null contract up front: throw IllegalArgumentException or return an OptionalInt. Arrays.stream(a).max() returns OptionalInt; Collections.max on an empty collection throws NoSuchElementException. For double arrays, say how NaN should be treated.
  5. Extend if asked: second largest in one pass by tracking two values (be explicit about duplicates), and kth largest with a min-heap of size k in O(n log k) or quickselect in O(n) on average.

Follow-up

  • Find the second largest distinct value in a single pass.
  • Find the kth largest element; compare the heap and quickselect approaches.
  • Find both the maximum and the minimum with about 3n/2 comparisons instead of 2n.

Solve the problem of finding duplicate numbers in an array.

Medium · Coding / Algorithms

Approach

  1. Clarify the exact task before coding: return any one duplicate, all duplicated values once each, or just a boolean? What is the value range, and may the input be modified?
  2. General case: a HashSet, where set.add(x) returns false when x is already present. O(n) time and O(n) space; for all duplicates once each, collect into a second set or count with a HashMap<Integer, Integer>.
  3. Space-saving alternative: sort, then compare neighbours. O(n log n) time and little extra memory (Arrays.sort on int[] is a dual-pivot quicksort), but it reorders the caller's array, so say so or sort a copy.
  4. Constrained case (n + 1 values, each in 1..n): Floyd's cycle detection treats a[i] as a pointer to the next index and finds the duplicate in O(n) time and O(1) space without modifying the array. If modification is allowed, mark seen values by negating a[|x| - 1]. Both tricks break with zero, negatives or out-of-range values.
  5. Mention the sum trick only with its precondition (every other value appears exactly once) and its overflow risk; test with an empty array, no duplicates, all-equal values and a value repeated three times.

Follow-up

  • Find the duplicate in O(1) extra space without modifying the array.
  • Return every value that appears twice when values are in 1..n.
  • How would you find duplicates in a file of numbers too large to fit in memory?

Demonstrate how to implement a binary search algorithm.

Medium · Coding / Algorithms

Approach

  1. State the precondition (sorted input) and the invariant: if the target exists it lies in [lo, hi]. Iterative version: lo = 0, hi = n - 1, while lo <= hi, compare a[mid] and move lo = mid + 1 or hi = mid - 1, return -1 when the range is empty. O(log n) time, O(1) space.
  2. Compute mid as lo + (hi - lo) / 2 or (lo + hi) >>> 1; plain (lo + hi) / 2 overflows int for large arrays, a bug that once sat in the JDK's own binary search.
  3. Keep one interval convention: a closed range uses lo <= hi and mid plus or minus 1; a half-open range [lo, hi) uses lo < hi and hi = mid. Mixing them produces infinite loops or skipped elements.
  4. Show the lower-bound variant for duplicates: with a half-open range, if a[mid] < target then lo = mid + 1, else hi = mid; return lo as the first index with a[i] >= target. Running it for target and target + 1 gives the first and last occurrence.
  5. Know the Java API: Arrays.binarySearch returns the index, or -(insertionPoint) - 1 when absent, and makes no promise about which duplicate it finds. Test an empty array, one element, a target below the minimum and above the maximum, and duplicates.

Follow-up

  • Search for a target in a sorted array that has been rotated at an unknown pivot.
  • Return the first and last position of a target in a sorted array with duplicates.
  • How would you use binary search on the answer, for example an integer square root?

Write a program to check if a string is a palindrome.

Medium · Coding / Algorithms

Approach

  1. Use two pointers: i from the start, j from the end, compare s.charAt(i) and s.charAt(j) and move inward while i < j. O(n) time and O(1) space, better than building a reversed copy and comparing, which costs O(n) extra.
  2. Clarify the rules first: case-sensitive or not, and whether spaces and punctuation count. For a phrase like "A man, a plan, a canal: Panama", skip characters where Character.isLetterOrDigit is false and compare Character.toLowerCase of each side.
  3. Cover the edge cases: the empty string and a single character are palindromes; decide how to treat null; the i < j condition handles even and odd lengths without special cases.
  4. For non-ASCII text, comparing chars splits surrogate pairs, so compare code points if that input is in scope.
  5. Have the variants ready: palindrome after deleting at most one character (on the first mismatch, check both skip options, O(n) total), longest palindromic substring by expanding around each centre (O(n^2) time, O(1) space), and an integer palindrome check done without converting to a string.

Follow-up

  • Return true if the string can become a palindrome by deleting at most one character.
  • Find the longest palindromic substring of a string.
  • Check whether a singly linked list is a palindrome using O(1) extra space.

Replace offset paging on the resource feed with keyset

Easy · keyset pagination · composite index · sort order

resource holds resource_id, tenant_id, owner_user_id, title, body_ref, version, status ('draft','active','archived','deleted'), created_at, updated_at, deleted_at, with an index on (tenant_id, status, updated_at DESC, resource_id DESC). The listing endpoint returns active resources for one tenant, newest update first, 50 per page, today with LIMIT 50 OFFSET n. Tenants reach page 400 and rows are created while they read. Write the keyset query, define what the cursor carries and how it is encoded, and say which part of the index each predicate uses. Assume PostgreSQL 16.

Approach

  1. Name the two failures separately. OFFSET 20000 makes the server produce and discard 20,000 rows, so page cost grows with depth rather than with page size. Independently, any write that changes how many rows sort above the offset moves the window between two fetches, and the direction decides which anomaly you get: an insert lands at the head of updated_at DESC and pushes already-returned rows down past the boundary, so they are returned a second time; a delete above the offset, or a row whose updated_at is bumped above the cursor, pulls rows up and one is never returned at all. Nothing in the response reveals either.
  2. Write the seek: WHERE tenant_id = $1 AND status = 'active' AND (updated_at, resource_id) < ($2, $3) ORDER BY updated_at DESC, resource_id DESC LIMIT 50. The row-value comparison is one index range rather than a disjunction, and both columns are NOT NULL, which is what makes that comparison well defined.
  3. Map each predicate onto the index: tenant_id and status are equality on the leading columns, (updated_at, resource_id) is the range, and the ORDER BY matches the index order so no Sort node appears and the scan stops after 50 rows. The DESC in the definition only matters for mixed directions — a plain ascending btree on the same columns is read backwards for this query.
  4. Put both sort columns in the cursor and nothing the client can tamper with into another tenant: base64 of (updated_at, resource_id), validated server-side, with tenant_id taken from the principal.

Follow-up

  • The client asks for 'jump to page 400'. What do you offer instead, and what does the honest version cost?
  • Sort order becomes user-selectable across four columns. How many indexes is that, and which would you refuse to add?

Explain why the owner filter ignores the listing index

Medium · composite index · query plans · sort elimination

The only index on resource is (tenant_id, status, updated_at DESC, resource_id DESC). A new endpoint returns one user's resources across all statuses, newest created first: WHERE tenant_id = $1 AND owner_user_id = $2 ORDER BY created_at DESC LIMIT 20. On a tenant with 2M rows it takes 900 ms and EXPLAIN shows a sort above a large scan. Explain precisely why the existing index cannot serve it, give the index that can, and state which of these the new index still will not help: owner_user_id alone across tenants; the same query ordered by updated_at. PostgreSQL 16.

Approach

  1. Separate the two jobs an index does. For filtering, a composite btree is seekable only on a left prefix, so with no predicate on status the scan can at best range over tenant_id and test owner_user_id per row; PostgreSQL 16 has no btree skip scan to jump the unconstrained column.
  2. For ordering, the index is sorted by (status, updated_at) within a tenant and not by created_at, so the LIMIT cannot stop early: every matching row is read and then sorted. That is the 'Sort Method: top-N heapsort' line, and it is why the plan reads 2M rows to answer with 20.
  3. Derive the replacement from the access path — equality, equality, then the ordering column: CREATE INDEX CONCURRENTLY ON resource (tenant_id, owner_user_id, created_at DESC). The scan seeks to the (tenant, owner) range and walks 20 entries in order, so the Sort node disappears along with the row-read.
  4. Treat INCLUDE (title, status) as conditional, not free. An index-only scan still visits the heap for any row whose page is not marked all-visible, so on a table taking 1.2k writes/second the win depends on autovacuum keeping the visibility map current, and the wider index costs more on every insert.

Follow-up

  • 90% of rows are status='active'. Would a partial index WHERE status = 'active' change your answer, and for which of the three queries?
  • A dashboard runs this for 40 owners in one page load. What changes about the design?

What is polymorphism in Java?

Medium · Technical / Domain Questions

Approach

  1. Define the two kinds. Compile-time polymorphism is method overloading: the compiler picks the overload from the static types of the arguments. Runtime polymorphism is overriding: a call through a superclass or interface reference dispatches on the object's actual class.
  2. Give a short example: Shape s = new Circle(); s.area() runs Circle.area(), because the method is chosen from the runtime type, not from the declared type Shape.
  3. State the limits: fields are not polymorphic (they resolve on the reference type); static methods are hidden, not overridden; private and final methods cannot be overridden. Overriding needs the same signature, may use a covariant return type, cannot reduce visibility and cannot throw broader checked exceptions. @Override makes the compiler catch a signature mismatch.
  4. Explain why it matters in real code: you program against interfaces (List<String> names = new ArrayList<>()), swap implementations without touching callers, and replace switch-on-type logic with subclasses or a strategy object, which keeps code open for extension and closed for modification.
  5. Mention generics as parametric polymorphism if there is room, and keep the example compiling in your head: wrong claims about static or private methods are the usual slip.

Follow-up

  • Can you override a static method in Java? What happens if you declare the same static method in a subclass?
  • Which overload is chosen for print(null) when print(Object) and print(String) both exist, and why?
  • What can go wrong when a constructor calls a method that a subclass overrides?

How would you implement a stack using queues?

Medium · Technical / Domain Questions

Approach

  1. Clarify the allowed operations first: only queue operations (offer, poll, peek, size, isEmpty). In Java use Queue<Integer> q = new ArrayDeque<>() and avoid its Deque stack methods, which would defeat the exercise; note ArrayDeque rejects null elements.
  2. Push-costly version with two queues: offer the new element into the empty queue q2, move every element of q1 into q2, then swap the references. The newest element is now at the front, so push is O(n) and pop and top are O(1).
  3. Pop-costly version: push is a plain offer into q1, O(1); pop moves the first n - 1 elements into q2, polls the last one as the result, then swaps the queues, so pop and top are O(n).
  4. Single-queue variant: offer x, then rotate size - 1 times (offer(poll())) so x reaches the front; push O(n), pop O(1), space O(n) in every version.
  5. Cover the edge cases: pop or top on an empty stack should throw (for example NoSuchElementException) or return a value agreed up front, and choose the variant from the workload: push-heavy favours the pop-costly version, pop-heavy the push-costly one.

Follow-up

  • Now implement a queue using two stacks; what is the amortised cost of dequeue and why?
  • If pushes outnumber pops ten to one, which variant would you choose?
  • How would you make this stack safe to use from several threads?

Describe the MVC architecture and its components.

Medium · Technical / Domain Questions

Approach

  1. Name the three parts and their single responsibility: the Model holds domain data and business rules (and talks to persistence), the View renders model state with no business logic, and the Controller receives input, validates it, calls the model or a service, and chooses what to render.
  2. Walk one web request through it, using Spring MVC as an example: the DispatcherServlet front controller routes the request to a @Controller method, which calls a service, puts data into the Model and returns a view name that a ViewResolver maps to a template; a @RestController instead returns an object that is serialised to JSON.
  3. Contrast classic and web MVC: in desktop MVC the view observes the model and redraws on change (observer pattern); in request-response web MVC the controller pulls data and hands it to the view for each request.
  4. State the benefits with specifics: separation of concerns, controllers you can unit test with mocked services, several views (HTML page, JSON API) over one model, and front-end and back-end work proceeding in parallel.
  5. Name the common failure: fat controllers full of business rules. Keep controllers thin with a service layer, and mention related patterns (MVP, MVVM) used by front-end frameworks.

Follow-up

  • Where should input validation live in an MVC application, and why?
  • How does MVVM, as used in front-end frameworks, differ from MVC?
  • How would you unit test a controller without starting the web server?

What are the advantages of using RESTful APIs?

Medium · Technical / Domain Questions

Approach

  1. Define REST before listing benefits: resources identified by URIs, a uniform interface over HTTP methods (GET, POST, PUT, PATCH, DELETE), representations such as JSON, stateless requests and cacheable responses.
  2. Statelessness is the scaling argument: each request carries everything needed (for example a token), so any server instance behind a load balancer can serve it and you add instances horizontally without sticky sessions.
  3. Use HTTP semantics as advantages: GET responses can be cached with Cache-Control and ETag; GET, PUT and DELETE are idempotent and safe to retry while POST is not; standard status codes (201, 400, 404, 409) let any client handle errors uniformly.
  4. Add the ecosystem points: language-agnostic clients, browser and curl friendliness, and contract and documentation tooling such as OpenAPI.
  5. Finish with trade-offs to show judgement: over- or under-fetching and chatty round trips (where GraphQL helps), no streaming or server push (WebSockets, gRPC streaming), and versioning and pagination you have to design yourself.

Follow-up

  • What is the difference between PUT, PATCH and POST, and which are idempotent?
  • How would you version a public REST API without breaking existing clients?
  • When would you choose gRPC or GraphQL over REST?

Describe how you would design a system for a high-traffic e-commerce site.

Medium · Problem-Solving / Case Studies

Approach

  1. Scope it: catalogue browsing and search, cart, checkout and payment, orders, inventory. Ask for traffic numbers and peak events, then note that browsing is read-heavy while checkout needs correctness more than raw speed.
  2. Read path: a CDN for static assets and images, stateless app servers behind a load balancer with autoscaling, a cache such as Redis for product pages and sessions, database read replicas, and a search index (Elasticsearch or OpenSearch) for catalogue search and filters.
  3. Write path: orders and payments in a relational database with ACID transactions. Prevent overselling with a conditional update (UPDATE inventory SET stock = stock - 1 WHERE sku = ? AND stock > 0, then check the affected row count) or a time-limited reservation, and put an idempotency key on checkout so a retried request never charges twice.
  4. Move slow side effects off the request: publish an order event to a queue (Kafka or RabbitMQ) for confirmation emails, warehouse updates and analytics, so checkout latency does not depend on them.
  5. Plan for spikes and growth: rate limiting and a waiting queue for flash sales, pre-warmed caches, carts in Redis with a TTL, sharding orders by user or order id once one primary is the bottleneck, plus monitoring on checkout error rate and latency.

Follow-up

  • How do you stop overselling when thousands of users buy the last items at the same moment?
  • The payment provider times out. What state is the order in, and how do you reconcile it?
  • A product's price changes. How do you keep cached pages from showing the old price?

If given limited resources, how would you prioritize feature development?

Medium · Problem-Solving / Case Studies

Approach

  1. Pin down the goal and the constraint before ranking anything: which outcome matters this quarter (revenue, retention, a compliance date), how many engineers you have, and which dates are fixed.
  2. Score the candidates in a way that can be repeated: RICE (Reach x Impact x Confidence / Effort) or a simple value-versus-effort grid, and MoSCoW to split must-haves from nice-to-haves for a release.
  3. Adjust for dependencies and risk: security and compliance fixes, items that unblock other work, and technical debt that slows every later feature can outrank a feature with a higher raw score.
  4. Cut scope, not quality: ship the smallest slice that tests the idea, hide unfinished work behind feature flags, and use usage data before building the full version.
  5. Make the trade-off visible: write down what is not being built and why, agree it with stakeholders, and revisit the ranking when new data arrives.

Follow-up

  • Two stakeholders each insist their feature comes first. How do you settle it?
  • How do you estimate effort when the work is uncertain?
  • When would you put paying down technical debt ahead of a requested feature?

Discuss how you would ensure the security of a web application.

Medium · Problem-Solving / Case Studies

Approach

  1. Start from a threat model: which assets matter (user data, payments, admin functions), where input enters, and who might attack. Use the OWASP Top 10 as a checklist so nothing obvious is missed.
  2. Injection and XSS: use PreparedStatement with bind parameters or an ORM instead of string-built SQL, validate input against allowlists, encode output for its context (HTML, attribute, JavaScript), and add a Content-Security-Policy header.
  3. Authentication and authorization: hash passwords with bcrypt, scrypt or Argon2, offer MFA, set session cookies HttpOnly, Secure and SameSite, defend state-changing requests against CSRF with tokens, and check authorization on the server for every request so changing an id in the URL cannot expose another user's data (IDOR).
  4. Transport and secrets: TLS everywhere with HSTS, encryption for sensitive data at rest, secrets in a vault or environment config rather than in Git, and least-privilege database and cloud accounts.
  5. Keep it secure over time: scan dependencies for known vulnerabilities, run static and dynamic analysis in CI, rate-limit login and other sensitive endpoints, and log security events with alerts.

Follow-up

  • What is the difference between XSS and CSRF, and how does each defence work?
  • Where would you store a JWT in the browser, and what are the risks of each option?
  • How would you stop one user from reading another user's order at /orders/{id}?

How would you approach a project with unclear requirements?

Medium · Problem-Solving / Case Studies

Approach

  1. Find the outcome before the feature: who the users are, what problem they have, and how success will be measured. Ask stakeholders specific questions and record every assumption you make.
  2. Write a short one-page spec with acceptance criteria (Given / When / Then), an explicit open-questions list and an out-of-scope list, and get it confirmed before building much.
  3. Reduce uncertainty cheaply: mockups, a technical spike or a throwaway prototype, then a thin end-to-end slice demoed early so feedback arrives while changes are still cheap.
  4. Design for the parts most likely to change: keep them behind interfaces, configuration or feature flags, but do not generalise code for requirements nobody has stated.
  5. Keep a decision log and re-estimate whenever the scope moves, so changes in requirements show up as visible trade-offs rather than silent overruns.

Follow-up

  • A stakeholder changes the requirements in the middle of a sprint. What do you do?
  • How do you decide you have enough clarity to start writing code?
  • Tell me about a project where you started with vague requirements. What happened?

How would you design a scalable chat application?

Medium · System Design / Architecture

Approach

  1. Scope it: one-to-one and group chat, message history, online presence, delivery and read receipts, and push notifications for offline users. Ask for daily users and messages per second, then estimate storage and connection counts.
  2. Connections: clients hold persistent WebSocket connections to gateway servers behind a load balancer. A registry (for example Redis mapping userId to gateway) tells the system which server holds each user's connection, and heartbeats drive presence.
  3. Message flow: the client sends a message with a client-generated id so retries can be de-duplicated; the server assigns a per-conversation sequence number, persists the message, acknowledges the sender, then routes it to the recipients' gateways. Offline recipients get a push notification (APNs or FCM) and fetch on reconnect.
  4. Storage: partition messages by conversation_id and order them by sequence number within it (a wide-column store such as Cassandra, or sharded SQL), so loading the latest N messages of a conversation is one partition read. Keep user and group metadata in a separate store.
  5. Fan-out and guarantees: use pub/sub (Kafka or Redis) between gateways. Ordering is guaranteed per conversation, not globally; delivery is at-least-once plus de-duplication by message id. Very large groups need a different fan-out strategy from small ones.

Follow-up

  • A gateway server holding thousands of connections crashes. What happens to those users and their in-flight messages?
  • How do you keep messages in sync across several devices of the same user?
  • How would end-to-end encryption change your design, for example server-side search?

Explain the considerations for database design in a multi-user environment.

Medium · System Design / Architecture

Approach

  1. Integrity first: normalise transactional data (roughly 3NF), declare primary keys, foreign keys, unique and check constraints so concurrent writers cannot break invariants, and denormalise only where a measured read path needs it.
  2. Concurrency: wrap related changes in transactions and choose an isolation level knowingly. Read Committed (the PostgreSQL default) still allows lost updates in read-modify-write code; Repeatable Read and Serializable prevent more anomalies but can abort transactions that must then be retried.
  3. Pick a locking style: pessimistic with SELECT ... FOR UPDATE when conflicts are frequent, or optimistic with a version column (UPDATE ... SET version = version + 1 WHERE id = ? AND version = ?; zero rows updated means someone else won, so retry), as JPA's @Version does.
  4. Avoid deadlocks by taking locks in a consistent order and keeping transactions short; the database aborts one victim when a deadlock happens, so the application needs retry logic.
  5. Access and performance: role-based grants or row-level security, a tenant_id on every row in multi-tenant schemas, audit columns, indexes that match query predicates (column order in a composite index matters), connection pooling such as HikariCP, and read replicas with replication lag in mind.

Follow-up

  • Two users try to book the last seat at the same time. How do you prevent a double booking?
  • When would you choose optimistic locking over pessimistic locking?
  • What is a lost update, and which isolation level or technique prevents it?

What strategies would you employ to optimize system performance?

Medium · System Design / Architecture

Approach

  1. Measure before changing anything: set a target in percentiles (p95 or p99 latency, throughput), profile with a tool such as Java Flight Recorder, async-profiler or tracing, and find whether time goes to CPU, the database, network calls or lock contention. Amdahl's law limits the gain: speeding up a part that takes 10% of the time saves at most 10%.
  2. Database: run EXPLAIN ANALYZE on the slow queries, add or fix indexes, remove N+1 query patterns (fetch joins or batching in JPA), replace deep OFFSET paging with keyset paging, and size the connection pool.
  3. Caching: in-process (Caffeine) for hot small data, distributed (Redis) for shared data, CDN and HTTP caching for static and public responses. Use cache-aside with a TTL, and plan invalidation and stampede protection.
  4. Concurrency and I/O: move slow work to a queue, batch calls, cut round trips and payload size, run independent remote calls in parallel, and size thread pools for the workload. On the JVM, check GC pauses, heap size and allocation rate.
  5. Scale out once the code is efficient: stateless services behind a load balancer, read replicas, then sharding. Confirm every change with a load test (JMeter, Gatling) against the original baseline.

Follow-up

  • p50 latency is fine but p99 is very high. What could cause that, and how would you find out?
  • Adding a cache made users see stale data. How do you handle invalidation?
  • How would you load test a service before a release?

Discuss how you would handle data consistency in a distributed system.

Medium · System Design / Architecture

Approach

  1. Decide per piece of data how strong consistency must be: balances and inventory need strong guarantees, feeds and counters tolerate eventual consistency. Use CAP to frame the partition case (choose consistency or availability) and PACELC for the normal case (latency versus consistency).
  2. Replication: single-leader replication with synchronous or asynchronous followers; asynchronous followers lag, so route a user's reads to the leader after their own write when read-your-writes matters. In quorum systems, R + W > N makes read and write sets overlap so a read sees the latest acknowledged write.
  3. Across services, avoid two-phase commit where you can, since a failed coordinator blocks participants. Use a saga with compensating actions (orchestrated or choreographed) and the transactional outbox pattern so a database change and its event are recorded atomically.
  4. Make consumers idempotent, because brokers deliver at least once: de-duplicate by event or message id, and use conditional writes or version checks to reject stale updates. Last-write-wins on wall-clock timestamps can lose updates under clock skew.
  5. For leader election, locks and configuration that must be linearizable, rely on a consensus system (Raft or Paxos, as in etcd or ZooKeeper) rather than building your own.

Follow-up

  • The payment succeeds but writing the order fails. How does your design recover?
  • A user updates their profile and the next page still shows the old value. Why, and how would you fix it?
  • How would you get effectively-once processing from a message broker that delivers at least once?

What factors do you consider when designing a microservices architecture?

Medium · System Design / Architecture

Approach

  1. Draw service boundaries around business capabilities (bounded contexts), give each service its own data store, and do not share a database between services. For a small team, a modular monolith is often the better starting point.
  2. Communication: synchronous REST or gRPC where the caller needs an answer now, asynchronous messaging (Kafka, RabbitMQ) for events. Avoid long synchronous call chains, and put an API gateway in front for routing, authentication and rate limiting.
  3. Resilience: timeouts on every remote call, retries with exponential backoff and jitter only for idempotent operations, circuit breakers and bulkheads (for example Resilience4j), and graceful degradation when a dependency fails.
  4. Data consistency: there are no ACID transactions across services, so use sagas, the outbox pattern and eventual consistency; for reads that join data from several services, use API composition or a read model built from events.
  5. Operations: containers and an orchestrator (Docker, Kubernetes), service discovery, an independent CI/CD pipeline per service, centralised logs, metrics and distributed tracing (OpenTelemetry), versioned APIs and contract tests. Name the cost too: network latency and operational overhead.

Follow-up

  • How would you split an existing monolith into services without a big-bang rewrite?
  • A downstream service becomes slow. How do you keep it from taking down its callers?
  • A page needs data owned by three different services. How do you serve it efficiently?

How would you approach debugging a complex software issue?

Medium · Problem-Solving / Case Studies

Approach

  1. Reproduce first: capture the exact input, environment, version and how often it happens, and turn it into a failing test or script if possible. Separate deterministic bugs from intermittent ones, which usually point at concurrency, timing or resource limits.
  2. Collect evidence before theorising: stack traces, logs joined by a request or correlation id, metrics around the first occurrence, and what changed then (deploy, config, dependency version, data shape).
  3. Narrow it down by halving the search space: git bisect between a known-good and a known-bad commit, disable components one at a time, shrink the input to a minimal reproduction, and use breakpoints or extra logging at module boundaries to check each assumption.
  4. Test one hypothesis at a time and write down what you expect to see. For Java services, take a thread dump (jstack) for hangs and deadlocks, a heap dump for memory growth or OutOfMemoryError, and read GC logs for latency spikes.
  5. If production is affected, mitigate first (roll back, flip a feature flag), then fix the root cause, add a regression test, confirm the fix in the environment where it failed, and record what happened.

Follow-up

  • The bug only happens in production and you cannot reproduce it locally. What do you do?
  • A test fails intermittently in CI. How do you find the cause?
  • How do you prove that your fix, not a coincidence, made the problem go away?

Suggested practice checklist

The plan follows the four reported rounds and their topics: Java and OOP, data structures and coding, SQL, design and debugging scenarios, then behavioral stories. Each day ends with something you can write down and check.

Day 1 — Map the loop and your CV

  • Write the four reported rounds in order and next to each one a sentence on what you still need to find out about its format
  • List every technology on your CV and mark the ones you could not discuss for several minutes
  • Compare your CV with the requirements candidates describe: Java or Python, web basics, databases, Git

Deliverable: A one-page loop map and a CV technology list with a defend, refresh or remove mark on each item.

Day 2 — Java and OOP fundamentals

  • Answer the polymorphism question aloud with a coded example showing overriding and overloading
  • Explain linked list versus array: memory layout, access cost, insertion cost and cache behaviour
  • Write a half-page note on garbage collection in Java covering reachability and generations, and an answer to stack versus queue

Deliverable: A one-page Java cheat sheet and two recorded spoken answers, one on polymorphism and one on linked list versus array.

Day 3 — Coding tasks in Java

  • Write reverse string and palindrome in Java without an IDE, then add case-insensitive and alphanumeric-only variants
  • Write largest element, duplicate detection (hash set, then sorting, then the in-place variant) and binary search
  • Implement a stack using two queues, then using one queue

Deliverable: Five working Java files plus a table of time and space complexity for each, with the edge cases you tested.

Day 4 — SQL and database fundamentals

  • Work through the two SQL practice drills, one on keyset paging and one on an owner filter that ignores an index
  • Write queries over a small schema using joins, grouping and subqueries, and check them with an EXPLAIN
  • Sketch a multi-user schema with keys, indexes and transaction boundaries, and explain the isolation level you would choose

Deliverable: Two solved SQL drills, a one-page schema sketch with its indexes and a short note on isolation and locking.

Day 5 — Web architecture and scenario questions

  • Draw the MVC request flow for an app you know and write what each part owns
  • Write the case for RESTful APIs and one case where REST is a poor fit
  • Rehearse a debugging sequence, a web-security checklist and an approach to a project with unclear requirements

Deliverable: An MVC diagram, a REST pros-and-cons note and spoken answers to the debugging, security and unclear-requirements questions.

Day 6 — System design practice

  • Design the scalable chat application: connections, message storage, delivery and ordering
  • Design the high-traffic e-commerce site: read and write paths, caching, inventory consistency and failure of a dependency
  • Answer the performance, distributed-consistency and microservices questions with named trade-offs

Deliverable: Two component diagrams with the first bottleneck marked, and a one-paragraph answer for each of the three remaining design questions.

Day 7 — Behavioral stories and a full run-through

  • Write the five behavioral stories so each states your decision, your alternatives and your result
  • Rehearse them aloud, then add the conflict and deadline-at-risk prompts
  • Do one mixed mock run: a coding task, a Java concept, a design question and two behavioral prompts

Deliverable: Five written stories using I, and one recorded mock run with a list of the answers you want to tighten.

Behavioral evaluations: engineering stories to prepare

Candidates describe the Behavioral Evaluations round as a check on interpersonal skills and fit. The reported prompts are short and general, so the work is in the stories behind them. Prepare engineering examples in which you made a decision, handled a disagreement or took feedback, and state your own part in each.

  1. Tell me about a time you had a conflict with a team member and how you resolved it.

Describe a time when you faced a significant challenge at work. How did you handle it?

Medium · Behavioral / Leadership

Approach

  1. Choose a technical challenge you personally owned, such as a production defect, a slow query, a failed release or an integration that kept breaking. Avoid a vague story about heavy workload.
  2. Set the scene in two sentences, then name the decision you made. Describe the options you considered and why you rejected the others, because the reasoning is the answer.
  3. Describe the actions in order, in the first person singular: what you investigated, what you changed, who you involved and when you asked for help.
  4. Close with a result you can state in concrete terms, such as errors dropped, a release shipped or a query's runtime fell, plus one lesson that changed how you work afterwards.
  5. The story that sinks this answer is one where the challenge belonged to someone else, the outcome is missing, or every action is described as what the team did.

Follow-up

  • What would you do differently if you faced the same problem again?
  • How did you know your fix worked rather than the problem going away by itself?
  • Who disagreed with your approach, and how did you resolve it?

How do you prioritize your tasks when working on multiple projects?

Medium · Behavioral / Leadership

Approach

  1. Give a repeatable method before the example: list everything with its deadline, who depends on it and the cost of delay, then estimate effort and order the work by impact against effort.
  2. Name the conversation, not only the list. When two projects collide, tell the stakeholders the trade-off, for example that one date moves, and ask which they would rather keep.
  3. Anchor it in a real case: two deliverables due in the same week, what you ranked first, what you postponed or cut and what you told people about it.
  4. Mention how you protect urgent interruptions, such as a production bug, by keeping slack in your plan, and how you re-check priorities when requirements change.
  5. Avoid answering with only a tool or a task list. The answer needs a decision you made and something you consciously gave up.

Follow-up

  • What do you do when two stakeholders each insist their project is the top priority?
  • Tell me about something you dropped or postponed and what it cost.
  • How do you handle a project deadline that is at risk partway through?

Can you give an example of how you worked effectively within a team?

Medium · Behavioral / Leadership

Approach

  1. Pick a story with a shared goal, such as a feature, a migration or a release, where your contribution is specific and checkable: you reviewed code, paired on a hard bug, defined an interface other people built against, or unblocked a teammate.
  2. Describe how the team coordinated in practice: pull requests and review through Git, short syncs, an agreed task split or written API contracts. This shows you understand how engineers work together.
  3. Include a moment of friction, such as a disagreement on a design or a missed handoff, and how you resolved it with evidence or a conversation instead of escalating.
  4. State the outcome for the team as well as for yourself, and what you changed afterwards in how you collaborate.
  5. Do not tell a hero story where you did everything alone, and do not hide inside the word we so that your own part cannot be identified.

Follow-up

  • Tell me about a time you had a conflict with a team member and how you resolved it.
  • How do you make sure your ideas are understood by the people building with you?
  • What did you do when a teammate was behind and the work was at risk?

What motivates you to perform your best at work?

Medium · Behavioral / Leadership

Approach

  1. Answer with a pattern drawn from real moments rather than a slogan. For instance, name the kind of work that pulled you in, such as tracing a hard bug to its cause or shipping a feature a user then used, and give one concrete episode.
  2. Connect the pattern to what a Software Engineer does day to day: building, testing, debugging and improving applications, and learning from teammates in code review. Do not claim knowledge of the employer's values beyond what you can verify.
  3. Show it influenced your behaviour, for example that you stayed to fix the root cause or took on a harder task because the work engaged you, and say what result followed.
  4. Be honest about what drains you as well, and how you keep quality up on routine work, so the answer sounds like a real person.
  5. Avoid answers that are only about salary or title, or a generic claim to love challenges with no example behind it.

Follow-up

  • Tell me about a time your motivation was low and what you did about it.
  • What kind of task or environment would reduce your motivation most?
  • How do you stay engaged when the work is routine maintenance rather than new building?

How do you handle feedback and criticism?

Medium · Behavioral / Leadership

Approach

  1. Use a specific piece of feedback you received, ideally from a code review or a retrospective, such as a pull request that was challenged for naming, test coverage or complexity. Show that it stung a little and that you considered it anyway.
  2. Show your sequence: you listened and asked a clarifying question, checked the claim against evidence, then decided what to change. Say what you changed in the code or your habits.
  3. Prove the change stuck: a later review went more smoothly, you added a checklist or tests, or you started giving the same kind of feedback to others.
  4. Cover the case where you disagreed with the feedback. Explain how you tested your view, presented your reasoning and accepted the outcome either way.
  5. The answer fails when it is a disguised strength such as I work too hard, when it turns defensive, or when it names no concrete behaviour change.

Follow-up

  • Tell me about feedback you disagreed with and what you did.
  • How do you give critical feedback to a peer, and how do they usually respond?
  • What is the most recent thing you changed because of feedback?