Zycus Interview Questions and Answers
118 questions12 themesLast reviewed
This page turns a consolidated Zycus technical preparation guide into a study plan: more than a hundred prompts across twelve themes, each rewritten as an interview question with an original model answer you can say out loud. The list leans towards Java and Spring Boot, transactions and microservices, Kafka and Redis, system design, cloud basics and AI-native engineering, and it ends with live-coding and trap questions.
Work through one theme at a time: answer aloud first, then open the model answer and compare. The experience-style prompts (your project, a production incident, your role) have no single right answer, so those answers teach a structure for you to fill with your own work. For more depth on any topic, follow the links to the topic question banks and the free courses.
Project & Architecture (10)
1Walk me through the architecture of the system you currently work on, end to end.Intermediate
Go outside-in. Start with who uses the system and what it must do, then trace one real request through the clients, gateway, services, data stores, messaging and infrastructure, naming the technology at each hop and why it is there. Pick a single journey, such as placing an order, and stay on it.
Then add the cross-cutting parts: authentication, how data stays consistent, deployment and observability. Finish with one real figure you know (traffic, data volume, team size) and one thing you would change. Do not recite every service and library; stopping at the right depth and going deeper on request sounds senior.
Illustrative opening: "A parcel-tracking platform. Scanners post events to a gateway, a tracking service stores them in PostgreSQL and publishes to Kafka, and a notification service reacts."
What the interviewer is checking: Whether you actually understand the system you own, can pick the right level of detail and explain why each piece exists.
Likely follow-up: Which part of this architecture would you redesign first, and why?
2What was your own role and contribution on that project?Beginner
Separate "we" from "I". Cover four things: the scope you owned (which services or modules), the decisions you made rather than inherited, the work beyond writing code (design documents, reviews, on-call, mentoring), and one outcome with a result you can defend.
Use "I" for actions and "we" for team results. Every claim invites a follow-up, so only say what you can explain in detail: how it worked, what you rejected, what went wrong. Overstating a role is the quickest way to lose credibility. Structure each example as situation, your action, result, as in the STAR method guide.
What the interviewer is checking: Honest ownership: whether your claimed contribution survives detailed follow-up questions.
Likely follow-up: Which decision on that project would you now make differently?
3Describe the most challenging feature you built and how you approached it.Intermediate
Choose a feature that was hard, not merely long. Say why it was hard (ambiguous requirements, correctness under failure, scale, a tight deadline), then the options you compared, why you picked one, how you reduced risk (prototype, feature flag, load test, staged rollout), and what the outcome taught you.
Illustrative: a refund flow spanning payment and inventory services, where a half-finished refund must never pay out twice. Options were a distributed transaction or a saga with idempotency keys; the saga won because the payment provider could not join a transaction. Mention what you gave up and what you would test differently now.
What the interviewer is checking: Problem-solving depth: how you weigh options, manage risk and learn, rather than the feature's name.
Likely follow-up: What was the riskiest assumption in your design, and how did you check it?
4Tell me about a production incident you handled. What was your process?Intermediate
Tell it in the order that real incidents go: detection (alert or a customer), blast radius, mitigation, diagnosis, fix, prevention. Mitigation comes before root cause: rollback, disable a flag, add capacity or fail over first, then dig. Say what evidence you used: metrics, logs, a thread or heap dump.
Illustrative: requests hung after a downstream slowed; a thread dump showed every worker waiting on one HTTP call with no timeout. Rollback gave relief, the fix added timeouts and a bulkhead, and the follow-up was an alert on pool saturation plus a short blameless write-up.
Avoid blaming people, and avoid a story in which you only watched.
What the interviewer is checking: Calm prioritisation, evidence-based debugging and whether you close the loop with prevention.
Likely follow-up: How did you decide between rolling back and fixing forward?
5How would you migrate a monolith to microservices, and what can go wrong?Advanced
First ask why: independent deployment, scaling or team ownership. Without a concrete pain, do not. Then use the strangler approach: put a routing layer in front, carve out one bounded context at a time (start with a seam that has few data ties), give the new service its own data, and shift traffic gradually while the monolith keeps running.
The failure modes are a distributed monolith (shared database, chatty calls), splitting data that used to share transactions (use sagas or accept eventual consistency), and the operational cost of tracing, deployment pipelines and on-call. If you have not led a migration, say so and describe this plan. See the microservices course.
What the interviewer is checking: Pragmatism: incremental migration, data ownership and awareness that microservices have real costs.
Likely follow-up: How would you split a database that the monolith's modules currently share?
6What scalability problems have you met in a backend system, and how did you fix them?Advanced
Begin with measurement: find the actual bottleneck before choosing a fix. Then work by layer. Application tier: keep instances stateless so you can add more, set timeouts, move slow work off the request path. Data tier: indexes, caching, read replicas, then partitioning. Traffic spikes: queues, rate limits and back-pressure.
Make the key point explicit: scaling out moves the bottleneck to the next shared resource, usually the database. Illustrative: an appointment-booking API slowed at peak; profiling showed one availability query scanning a large table, so an index plus a short-lived cache fixed it before any new servers were needed. Quote your own before-and-after numbers.
What the interviewer is checking: Whether you diagnose before scaling and understand where bottlenecks move.
Likely follow-up: How would you know whether a slowdown is CPU, database or a downstream dependency?
7Which communication patterns do microservices use, and how do you choose between them?Intermediate
Synchronous request and response (REST, gRPC) fits when the caller needs the answer now, such as checking stock before accepting an order. Asynchronous messaging or events (Kafka, RabbitMQ, SQS) fit when work can be deferred or several services react to one fact, such as "order placed".
Each has its own discipline. Synchronous calls need timeouts, retries with backoff, idempotent operations and a circuit breaker. Asynchronous flows need idempotent consumers, a partition or ordering key, a dead-letter queue and schema versioning. Long chains of synchronous calls multiply failure probability, so keep them short. See Apache Kafka for the event side.
What the interviewer is checking: Whether you pick a pattern by requirements and know the failure handling each one needs.
Likely follow-up: How do you make a retried "create payment" call safe?
8How do you choose databases for a service, and how do you scale them?Intermediate
Choose by access pattern, not fashion. A relational database is the default for transactions and joins; a document store suits aggregates with varying shape; a key-value store or cache suits hot lookups; a search engine suits text queries. Each service should own its data store.
Scale in the cheapest order: fix queries and indexes, pool connections, add caching, add read replicas (accepting replication lag), and only then partition or shard, because cross-shard queries and rebalancing are expensive. Name the trade-off of every step. For the first one, see database indexing.
What the interviewer is checking: Reasoning from access patterns and knowing the ordered, escalating scaling options.
Likely follow-up: What breaks when a read replica lags behind the primary, and how do you cope?
9Give an example of a performance optimisation you made and how you proved it worked.Intermediate
Structure: baseline metric (p95 latency, throughput, CPU), profile to find the real hotspot, make one change, re-measure under the same load, then check nothing else regressed. The proof is the before and after on identical conditions, not the code change.
Illustrative: a booking list endpoint issued one query per row (the N+1 pattern). Fetching the rows in one joined or batched query cut the database calls from many to a few per request. Say which tool exposed it (query log, profiler, APM trace). Avoid claiming gains you did not measure.
What the interviewer is checking: A measure-first habit and honest, verifiable results.
Likely follow-up: How did you make sure the optimisation did not hurt correctness or another endpoint?
10Explain a significant design decision you made and the trade-offs you weighed.Advanced
Use a decision-record shape: context and constraints, two or three options, the criteria you judged them by, the choice, what you gave up, and what would make you revisit it. Every real decision has a cost; if you present none, it sounds rehearsed.
Illustrative: keeping a search index eventually consistent with the main database for scalability, accepting a few seconds of stale results, while checkout reads the source of truth. Name the signal that would reverse the decision, such as complaints about stale data or a latency target you could no longer meet.
What the interviewer is checking: Whether you reason with trade-offs, constraints and reversibility instead of declaring a best practice.
Likely follow-up: What would make you reverse that decision?
Core Java & JVM (16)
11Which Java 17 and Java 21 features have you used, and what did each replace?Intermediate
Name features by what they let you delete. By 17 (LTS) you have records, sealed classes, text blocks, switch expressions,
instanceofpatterns andStream.toList(). Java 21 (LTS) adds pattern matching inswitchwith guards, record patterns, virtual threads and sequenced collections such asgetFirst()andreversed().Only claim what you have used, and know your project's runtime version. A useful migration note: Java 17 strongly encapsulates JDK internals, so old libraries that reflect into them may need upgrading or
--add-opens.java import java.util.List; public class Modern { sealed interface Event permits Borrowed, Returned, Reserved {} record Borrowed(String isbn, int days) implements Event {} record Returned(String isbn, boolean damaged) implements Event {} record Reserved(String isbn) implements Event {} static String describe(Event e) { return switch (e) { case Borrowed b when b.days() > 14 -> "long loan of " + b.isbn(); case Borrowed b -> "loan of " + b.isbn(); case Returned(String isbn, boolean damaged) -> damaged ? "damaged " + isbn : "back " + isbn; case Reserved r -> "hold on " + r.isbn(); }; } public static void main(String[] args) { for (Event e : List.of(new Borrowed("A1", 21), new Borrowed("B2", 7), new Returned("C3", true), new Reserved("D4"))) System.out.println(describe(e)); } }Output
long loan of A1 loan of B2 damaged C3 hold on D4
What the interviewer is checking: Whether you have real, current Java experience and can say what each feature simplifies.
Likely follow-up: Why does the switch above need no default branch?
12What are virtual threads, and when would you use them?Intermediate
A virtual thread is a
Threadwhose stack lives on the heap and is scheduled by the JVM rather than the OS. When it blocks on I/O it parks and its carrier thread runs something else, so you can keep the simple one-thread-per-request style and still serve tens of thousands of waiting tasks.Use them for blocking I/O work: HTTP calls, JDBC, queues. They do not speed up CPU-bound code. Never pool them; create one per task. In Spring Boot 3.2 and later,
spring.threads.virtual.enabled=trueswitches the web server over. Cap pressure on the database with aSemaphore, and avoid long blocking insidesynchronizedon Java 21. More depth: Java interview questions.java import java.util.concurrent.*; import java.util.concurrent.atomic.AtomicInteger; public class Vt { public static void main(String[] args) throws Exception { AtomicInteger done = new AtomicInteger(); try (ExecutorService ex = Executors.newVirtualThreadPerTaskExecutor()) { for (int i = 0; i < 10_000; i++) { ex.submit(() -> { Thread.sleep(200); // stands in for a blocking status call done.incrementAndGet(); return null; }); } } // close() waits for every task System.out.println("finished: " + done.get()); } }Output
finished: 10000
What the interviewer is checking: Whether you know what problem they solve and where they do not help.
Likely follow-up: Why should virtual threads not be pooled?
13How does the Stream API work internally? Why is it lazy?Advanced
A stream is a pipeline description: a source (exposed as a
Spliterator), a chain of intermediate stages and exactly one terminal operation. Callingfilterormaponly appends a stage. The terminal call wraps the stages into a chain of sinks and pushes each element through it.Stateless stages (
filter,map) handle one element at a time; stateful ones (sorted,distinct) must buffer, acting as barriers, which the output below shows: every element reachessortedbefore anything leaves it. Short-circuit operations such aslimitstop the pull early. A parallel stream usestrySplitand the common fork-join pool, and flags like SIZED and ORDERED let the framework skip work.java import java.util.*; public class Lazy { public static void main(String[] args) { List.of(5, 3, 9, 1).stream() .peek(n -> System.out.println("filter sees " + n)) .filter(n -> n > 2) .sorted() .limit(2) .forEach(n -> System.out.println("out " + n)); } }Output
filter sees 5 filter sees 3 filter sees 9 filter sees 1 out 3 out 5
What the interviewer is checking: Understanding of pipelines, sinks, barriers and short-circuiting beyond "streams are lazy".
Likely follow-up: Why is a stateful lambda inside a parallel stream dangerous?
14What is the singleton pattern, and what are the ways to implement it in Java?Beginner
A singleton guarantees one instance of a class (strictly, per class loader) and gives global access to it. Options: an eager
static finalfield; a lazy holder class, where the instance lives in a nested class that loads on first use; a single-elementenum; asynchronizedaccessor, simple but it locks every call; and double-checked locking withvolatile.I would pick the enum or the holder idiom. In a Spring application, the container's default singleton scope is better still, because it keeps the class testable. State the downside: a hidden global makes unit tests order-dependent and hard to isolate.
What the interviewer is checking: Breadth of implementations plus the judgement to prefer simple, safe ones.
Likely follow-up: Why is a hand-written singleton harder to unit test than a Spring-managed bean?
15How can reflection and serialization break a singleton, and how do you stop them?Advanced
Reflection:
setAccessible(true)on a private constructor lets anyone create a second instance. A guard in the constructor that throws if the instance already exists blocks it for an eager singleton. Serialization: reading the object back builds a new instance without your accessor; addreadResolve()returning the real instance. Cloning is similar, so do not implementCloneable.A single-element
enumavoids all three: the JVM refuses to construct enums reflectively and deserialises them by name. Also remember separate class loaders each get their own "singleton".java import java.lang.reflect.Constructor; public class Ref2 { static class Registry { private static final Registry INSTANCE = new Registry(); private Registry() { } static Registry get() { return INSTANCE; } } static class Guarded { private static final Guarded INSTANCE = new Guarded(); private Guarded() { if (INSTANCE != null) throw new IllegalStateException("already created"); } } enum Safe { ONLY } public static void main(String[] args) throws Exception { Constructor<Registry> c = Registry.class.getDeclaredConstructor(); c.setAccessible(true); System.out.println("second instance: " + (c.newInstance() != Registry.get())); Constructor<Guarded> g = Guarded.class.getDeclaredConstructor(); g.setAccessible(true); try { g.newInstance(); } catch (java.lang.reflect.InvocationTargetException e) { System.out.println("guard: " + e.getCause().getMessage()); } Constructor<Safe> s = Safe.class.getDeclaredConstructor(String.class, int.class); s.setAccessible(true); try { s.newInstance("COPY", 1); } catch (IllegalArgumentException e) { System.out.println("enum: " + e.getMessage()); } } }Output
second instance: true guard: already created enum: Cannot reflectively create enum objects
What the interviewer is checking: Whether you know the attack paths and the defences, not just the pattern.
Likely follow-up: Why does the constructor guard not work for a lazily created singleton?
16Explain double-checked locking. Why is volatile required?Advanced
Three details are worth stating. Why check twice: the first, unlocked check keeps the fast path lock-free once initialised; the second, inside the lock, stops two racing threads from both creating the object. Why
volatile: without it, the reference can be published before the constructor's writes are visible, so another thread may see a half-built object. Why the local variable: it costs one volatile read on the fast path instead of two.Then say you would rather avoid it. The holder idiom, shown below, is lazy and thread-safe because the JVM guarantees class initialisation happens once.
java public class Dcl2 { static class Catalog { private static volatile Catalog instance; private Catalog() { } static Catalog get() { Catalog local = instance; // one volatile read on the fast path if (local == null) { synchronized (Catalog.class) { local = instance; if (local == null) instance = local = new Catalog(); } } return local; } } static class Lazy { private Lazy() { } private static class Holder { static final Lazy INSTANCE = new Lazy(); } static Lazy get() { return Holder.INSTANCE; } } public static void main(String[] args) { System.out.println(Catalog.get() == Catalog.get()); System.out.println(Lazy.get() == Lazy.get()); } }Output
true true
What the interviewer is checking: Memory-model awareness: safe publication, reordering and the simpler alternative.
Likely follow-up: What breaks if the field is not volatile?
17How does HashMap work internally? Cover capacity, load factor and treeification.Intermediate
Remember five numbers. The table is allocated on the first
putwith 16 buckets and doubles when entries exceed 0.75 times capacity. The bucket index is(n - 1) & (h ^ (h >>> 16)), wherehis the key's hash code; spreading the high bits protects against poor hash codes. Collisions form a chain; at 8 nodes a chain becomes a red-black tree, but only if the table has at least 64 buckets, otherwise the map resizes instead. It reverts to a list at 6.On resize, each bucket splits into a low and a high half without rehashing keys. If you know the size, presize it, for example with
HashMap.newHashMap(n)(Java 19). It is not thread-safe, and its iteration order is unspecified.What the interviewer is checking: Whether you can give precise mechanics: index calculation, resize and when treeification happens.
Likely follow-up: Why does a tree bin first compare hash codes, and what happens when keys are not Comparable?
18How does ConcurrentHashMap differ from HashMap, and why is it faster than a synchronized map?Intermediate
HashMaphas no synchronisation, so concurrent writers can lose updates, and its fail-fast iterators throw when the map is modified.ConcurrentHashMap(Java 8 and later) inserts into an empty bucket with a compare-and-swap and otherwise locks only the first node of that one bucket, so writers to different buckets do not contend; reads take no lock.It rejects null keys and values, because a null from
getwould be ambiguous with absent. Iterators are weakly consistent and never throw.size()is an estimate under concurrent updates. Compound updates must usemerge,computeorputIfAbsent; a separategetthenputis still a race.What the interviewer is checking: Understanding of fine-grained locking and the atomic compound operations, not just "it is thread-safe".
Likely follow-up: Why does ConcurrentHashMap forbid null values?
19What is the difference between equals() and hashCode(), and how do they work together?Beginner
equalsanswers "are these two logically the same?";hashCodeanswers "which bucket should I look in?". The contract: equal objects must have equal hash codes; the value must not change while the object is stored in a hash structure; unequal objects may share a hash code, at the cost of slower lookups.Override both from the same fields, or use a record, which generates them. Keep the
equalsparameter asObject, and be careful withgetClass()versusinstanceofin inheritance hierarchies, since symmetry can break. Avoid mutable fields, and for database entities do not rely on a generated id that is null before saving.TreeMapusescompareTo, not these methods.What the interviewer is checking: Whether you link the two methods to how hash collections work and know the practical pitfalls.
Likely follow-up: What happens if two equal objects return different hash codes?
20What are the differences between String, StringBuilder and StringBuffer?Beginner
Stringis immutable: every change creates a new object.StringBuilderis a mutable buffer with no synchronisation, fast and the right default.StringBufferis the same API with synchronised methods, a legacy choice from Java 1.0; sharing one builder between threads is rarely a sound design anyway.A
+inside a loop builds a fresh string every iteration, copying the growing text each time, which makes it quadratic. The compiler handles a single expression well, but not across iterations. Use aStringBuilder,String.joinorCollectors.joiningwhen assembling pieces.What the interviewer is checking: Mutability, thread-safety and the practical cost of concatenating in a loop.
Likely follow-up: Is the + operator on strings compiled to a StringBuilder?
21What is the difference between heap and stack memory in Java?Beginner
Each thread has its own stack of frames, one per method call, holding local primitives and references. Frames vanish when the method returns, the size is set by
-Xss, and running out givesStackOverflowError, usually from runaway recursion.The heap is one region shared by all threads and holds every object and array, managed by the garbage collector and sized with
-Xmsand-Xmx; exhaustion givesOutOfMemoryError. InParcel p = new Parcel();the referencepis on the stack and the object is on the heap. The JIT can sometimes avoid heap allocation for objects that never escape a method.What the interviewer is checking: A precise mental model of where data lives and the two different memory errors.
Likely follow-up: Which error would an infinite recursion produce, and which a growing static list?
22Explain the JVM memory model: runtime memory areas and the Java Memory Model.Advanced
The phrase covers two ideas, so give both. Runtime areas: the heap (young generation with eden and survivor spaces, plus old generation), a stack per thread, the program counter, metaspace (class metadata in native memory, replacing PermGen in Java 8), the JIT code cache, and direct or native memory.
The Java Memory Model is a different thing: the rules for when one thread's write must be visible to another. A write is only guaranteed visible across an happens-before edge: unlock then later lock of the same monitor, volatile write then later read,
Thread.startandjoin, and safe publication of final fields. Without such an edge, the compiler and CPU may reorder or cache. See Advanced Java.What the interviewer is checking: Whether you separate memory layout from visibility rules and can name concrete happens-before edges.
Likely follow-up: What does volatile guarantee, and what does it not?
23How does garbage collection work, and how would you pick a collector?Intermediate
The collector keeps anything reachable from GC roots (thread stacks, static fields, native references) and reclaims the rest. Most objects die young, so the heap is split: young collections are frequent and cheap, survivors are promoted to the old generation, which is collected less often.
Choose by goal. Serial suits tiny heaps; Parallel favours throughput; G1, the usual default on server machines, balances throughput against a pause-time target; ZGC aims for very short pauses on large heaps, with a generational mode available in Java 21. Before touching flags, read GC logs (
-Xlog:gc) and set the heap size. Leaks are objects that stay reachable but are no longer needed.What the interviewer is checking: Reachability thinking and a goal-driven, log-first approach to choosing and tuning collectors.
Likely follow-up: What would you look at first if a service shows long GC pauses?
24What is the difference between a final class and a final method?Beginner
A final class cannot be extended:
String, the wrapper types and records are examples. A final method can be inherited but not overridden; the class itself can still have subclasses. Making a class final therefore makes all its methods effectively non-overridable. Private and static methods cannot be overridden anyway.Use final methods to protect an invariant, such as the fixed sequence in a template method. Today it is not a performance trick, since the JIT inlines most calls regardless. One practical catch: Spring's proxies for features like
@Transactionalwork by subclassing, so a final class cannot be proxied and a final method is not intercepted.What the interviewer is checking: Whether you know where each applies and the real design and framework consequences.
Likely follow-up: How does the sealed keyword differ from final?
25Can a constructor be final in Java? Why or why not?Beginner
No. Constructors are not inherited, so they can never be overridden, which makes
finalmeaningless, and the compiler rejects it. The same applies tostatic,abstractandsynchronized. A constructor may carry only an access modifier.If the goal is to stop subclassing, mark the class
final, usesealed, or make the constructor private and expose a static factory method. If the goal is fixed state, declare the fieldsfinaland assign them in the constructor.java public class Fin { final Fin() { } }Output
Fin.java:2: error: modifier final not allowed here final Fin() { } ^ 1 errorWhat the interviewer is checking: Basic language rules and the correct alternatives for the underlying goal.
Likely follow-up: How do you stop a class being subclassed without marking it final?
26What is the difference between abstraction and encapsulation? Give an example.Beginner
Abstraction is about the outside view: expose what a caller needs and hide how it is done, through interfaces and abstract types. Encapsulation is about the inside: keep state private and change it only through methods that enforce the rules, so the object cannot be put into an invalid state.
Example: a parcel locker.
LockerBank.reserve(size)is the abstraction; callers never learn how a free compartment is found. Inside, the compartment list is private andreserverefuses to book an occupied slot, which is encapsulation. Generating a getter and setter for every field is not encapsulation; it just exposes the state indirectly.What the interviewer is checking: A clear, distinct definition of each with a concrete example rather than swapped terms.
Likely follow-up: Can you have encapsulation without abstraction, or the reverse?
Spring Boot & Internals (10)
27What is dependency injection, and what problem does it solve in Spring?Beginner
A class states what it needs, usually as constructor parameters, and the container supplies those objects instead of the class building them with
new. The class depends on an interface, and the wiring decision lives in one place.The payoff is easy substitution. A
ReminderServicethat needs aMessageSendercan get an SMS sender in production and a recording fake in a unit test, without any change to its own code. It also keeps object creation, configuration and lifetime out of business logic.In the interview, give that one concrete swap rather than a definition. Fuller treatment: Spring Boot course.
java @Service class ReminderService { private final MessageSender sender; // an interface ReminderService(MessageSender sender) { // Spring supplies it this.sender = sender; } }What the interviewer is checking: Whether you explain DI through a testability and decoupling benefit, not only by quoting a definition.
Likely follow-up: What is the difference between dependency injection and inversion of control?
28What does the IoC container do between startup and a ready application?Advanced
Startup is two phases. First the container collects BeanDefinition objects, which are recipes (class, scope, constructor arguments, init method) gathered from component scanning,
@Beanmethods and imports, and stores them in a registry inside aBeanFactory. Special post-processors such asConfigurationClassPostProcessorandBeanFactoryPostProcessorimplementations can add or alter definitions at this point, before any application bean exists.Second, the container instantiates the non-lazy singletons, resolving dependencies in order, and runs
BeanPostProcessors around initialisation.ApplicationContextis the richer layer on top ofBeanFactory: events, environment and properties, message resources.Key sentence: definitions first, objects second.
What the interviewer is checking: Whether you can separate bean definitions from bean instances and name where customisation hooks in.
Likely follow-up: What is the difference between a BeanFactoryPostProcessor and a BeanPostProcessor?
29Walk me through the lifecycle of a Spring bean from creation to destruction.Intermediate
Order of events for a singleton: instantiate (constructor or factory method), inject dependencies, run Aware callbacks such as
BeanNameAware, callBeanPostProcessorbefore-initialisation hooks (this is where@PostConstructruns), thenInitializingBean.afterPropertiesSetand any custom init method, then after-initialisation hooks, where proxies are usually created. The bean is now ready.On context shutdown:
@PreDestroy,DisposableBean.destroy, then a custom destroy method. Remember that Spring does not call destroy callbacks for prototype beans, because it hands them over and stops tracking them.Practical rule: do not use injected collaborators in the constructor body of a field-injected bean; do the setup in
@PostConstruct.java @Component class KioskCatalogue { @PostConstruct void warmUp() { /* load titles */ } @PreDestroy void flush() { /* persist counters */ } }What the interviewer is checking: That you know the order, where post-processors and proxies fit, and the prototype exception.
Likely follow-up: At which step is the AOP proxy created, and what does injection into other beans receive?
30What bean scopes does Spring offer, and how do you choose one?Beginner
singleton is the default: one instance per container. prototype creates a new instance on every lookup. In a web application there are also request, session, application and websocket scopes, each tied to that lifetime.
Choose singleton for stateless services and let mutable per-user data travel in method arguments, a request-scoped bean, or the database. A singleton shared by threads must be thread-safe, which usually means no mutable fields.
If a singleton needs a request-scoped collaborator, declare the narrower bean with a scoped proxy so the singleton holds a stand-in that resolves the real instance per call.
What the interviewer is checking: Whether you tie scope choice to thread safety and know the scoped-proxy answer for mixed lifetimes.
Likely follow-up: What breaks if you keep a customer's basket in a field of a singleton service?
31Trace a request through the controller, service and repository layers.Beginner
Take "renew a library book". The
DispatcherServletmaps the URL to a controller method. The controller binds and validates input, then calls the service. It does no business logic and returns a DTO.The service holds the rules (is the loan overdue, is there a hold on the title) and defines the transaction boundary. It calls the repository, which is a Spring Data interface that talks to the database. On the way back, message converters write the DTO as JSON.
Failures travel up as exceptions, and one
@RestControllerAdviceturns them into consistent error responses. Say why the layers exist: each can be tested and changed independently.What the interviewer is checking: A clear mental model of responsibilities per layer, including where transactions and error handling live.
Likely follow-up: Why should the transaction boundary usually sit on the service rather than the controller?
32Why is constructor injection preferred over field injection?Beginner
With a constructor, dependencies are mandatory and visible in the signature, fields can be
final, and the object is never half-built. A unit test just callsnew ReminderService(fakeSender)with no Spring and no reflection.Field injection hides how many collaborators a class has, so a class quietly grows to eight of them. It also needs reflection to test and permits an object in a state with null fields. Constructor cycles fail immediately at startup, which is a feature.
Since Spring 4.3 a class with a single constructor needs no
@Autowired. Use setter injection only for optional dependencies. Related set: Spring Boot interview questions.What the interviewer is checking: Whether your reasons go beyond "it is best practice": immutability, testability and fail-fast behaviour.
Likely follow-up: How do you handle a dependency that is genuinely optional?
33Explain how Spring actually creates a bean, step by step, internally.Advanced
A call to
getBean(or startup pre-instantiation) finds the mergedBeanDefinitioninDefaultListableBeanFactory, and the factory's create logic (AbstractAutowireCapableBeanFactory) takes over. It picks a constructor or a@Beanfactory method, resolves each argument by type and qualifier (recursively creating other beans first), and instantiates through reflection.Then it populates properties, where
@Autowiredfields and setters are filled by aBeanPostProcessor. Then initialisation: Aware callbacks, init hooks, and the after-initialisation post-processors, which may swap the object for a proxy. Finished singletons are kept in a cache, so later lookups return the same instance.Do not claim more detail than you remember; the order above is the part to get right.
What the interviewer is checking: Whether you can narrate definition lookup, instantiation, population and post-processing in the right order.
Likely follow-up: Why can the object another bean receives be a proxy rather than your own class instance?
34How does Spring Boot auto-configuration work, and how do you debug it?Intermediate
Boot ships many configuration classes inside its jars and the starters you add.
@EnableAutoConfigurationimports the candidates named in anAutoConfiguration.importsfile underMETA-INF/spring. Every candidate is guarded by conditions such as@ConditionalOnClass,@ConditionalOnPropertyand@ConditionalOnMissingBean, so only the relevant ones apply.The design rule is that auto-configuration yields to you: declare your own
DataSourcebean and the default one backs off.To debug, start with
--debug(ordebug=true) to print the conditions report, which lists what matched and why not. Writing your own starter uses the same pieces. Full walk-through: Spring Boot course.java @AutoConfiguration @ConditionalOnClass(KioskClient.class) class KioskAutoConfiguration { @Bean @ConditionalOnMissingBean KioskClient kioskClient() { return new KioskClient(); } }What the interviewer is checking: Whether you know the conditional mechanism and the debugging report, not just "it configures things automatically".
Likely follow-up: How would you exclude one auto-configuration class for a single deployment?
35How do @Component, @Service and @Repository differ in behaviour?Beginner
All three are meta-annotated with
@Component, so component scanning registers each one as a bean. For@Servicethat is the whole story: it carries intent only, and it is a handy target for a pointcut or an architecture test.@Repositoryhas real behaviour. Spring registers a post-processor that translates persistence exceptions, such as a JPA or JDBC error, into itsDataAccessExceptionhierarchy, so the service layer does not depend on a vendor exception type. Spring Data interfaces already get this.Web-layer stereotypes (
@Controller,@RestController) add request mapping support. Pick by role, because a reader learns the layering from the annotations.What the interviewer is checking: Whether you know that only @Repository changes behaviour and can name what it does.
Likely follow-up: Could you annotate every class with @Component? What would you lose?
36How does @Transactional work internally, and why does self-invocation break it?Advanced
Boot enables transaction management, which registers an advisor holding a
TransactionInterceptor. An auto-proxyBeanPostProcessorfinds beans with matching methods and, after initialisation, replaces them with a proxy (CGLIB by default in Boot). A call through the proxy asks thePlatformTransactionManagerto start or join a transaction, binds the connection orEntityManagerto the current thread, runs your method, then commits or rolls back.Consequences follow directly. A call inside the same class uses
this, skipping the proxy. Private or final methods are not advised. A new thread has no bound transaction. Fix self-invocation by moving the method to another bean or usingTransactionTemplate.What the interviewer is checking: Whether you can connect the annotation to a BeanPostProcessor-created proxy and thread-bound resources.
Likely follow-up: What happens to the transaction when the method runs on an @Async thread?
Transactions & Distributed Systems (12)
37Describe the lifecycle of a database transaction and what ACID guarantees.Beginner
A transaction begins, runs several statements as one unit, then ends in commit (changes become durable and visible) or rollback (all discarded). Locks or row versions are held until it ends, so keep it short and never include slow remote calls.
ACID: atomic (all or nothing), consistent (constraints still hold), isolated (concurrent work does not corrupt each other, to the degree the isolation level allows), durable (committed data survives a crash).
In Spring the proxy does the begin and commit for you; the mental model is the same. The conditional update below shows a safe borrow: the last copy cannot be taken twice. I ran it against SQLite.
python db.execute("BEGIN") n = db.execute("UPDATE copies SET available = available - 1 " "WHERE book_id = 7 AND available > 0").rowcount if n == 0: db.execute("ROLLBACK") # nothing left, undo else: db.execute("INSERT INTO loans VALUES (7, ?)", (member,)) db.execute("COMMIT")Output
borrowed none left [(7, 'asha')] [(7, 0)]
What the interviewer is checking: That you know the begin/commit/rollback flow and the practical cost of long transactions.
Likely follow-up: Which ACID property does a crash right after COMMIT test?
38Explain transaction propagation and isolation levels in Spring.Intermediate
Propagation answers "what if a transaction already exists?":
REQUIREDjoins or creates one,REQUIRES_NEWsuspends and starts a fresh one,NESTEDuses a savepoint,SUPPORTSandNOT_SUPPORTEDare tolerant,MANDATORYinsists one exists,NEVERforbids it.Isolation answers "what may I see from concurrent transactions?". Levels from weakest to strongest: read uncommitted, read committed, repeatable read, serializable. Stronger levels prevent more anomalies (dirty reads, non-repeatable reads, phantoms) at a cost in locking or retries.
DEFAULTuses the database's own level, for example read committed on PostgreSQL and repeatable read on InnoDB, so state which database you mean.What the interviewer is checking: Whether you can keep propagation (joining behaviour) and isolation (visibility) as separate ideas.
Likely follow-up: Which anomaly does read committed still allow?
39When would you pick REQUIRES_NEW over REQUIRED?Intermediate
REQUIREDmeans the callee shares the caller's fate: one commit, one rollback. ChooseREQUIRES_NEWwhen a piece of work must survive the caller's rollback, the classic case being an audit or failed-attempt record: the booking fails, but the log row that says so must persist.It only takes effect when called through another bean, because of the proxy. It also holds a second database connection while the first is suspended, so heavy use can exhaust a small pool, and it cannot see the caller's uncommitted rows.
Do not use it to dodge rollback-only errors; that hides a design problem.
java @Service class AuditWriter { @Transactional(propagation = Propagation.REQUIRES_NEW) void record(String event) { auditRepo.save(new AuditRow(event)); } }What the interviewer is checking: Whether you can give a justified use case and name the pool and visibility risks.
Likely follow-up: What happens if the outer transaction needs a row the inner one also locks?
40What exactly gets rolled back when a transactional method throws?Intermediate
Only work done through the transaction-bound resource: SQL changes on the enlisted connection. Not rolled back: in-memory object state, a file you wrote, an HTTP call, an email, a message already sent to a broker. That gap is the reason for outbox and saga patterns.
By default Spring rolls back on
RuntimeExceptionandError, and commits on checked exceptions unlessrollbackForsays otherwise. If you catch and swallow the exception, the proxy sees a normal return and commits. If a joined inner method already marked the transaction rollback-only, the outer commit fails with anUnexpectedRollbackException.What the interviewer is checking: Whether you understand the boundary of rollback, including side effects it cannot undo.
Likely follow-up: How would you send a confirmation email only if the transaction really commits?
41What is the Outbox pattern, and what problem does it solve?Advanced
The problem is the dual write: saving to the database and publishing an event are two systems, so a crash between them loses the event or publishes one for data that never committed. The fix: write the business row and an
outboxrow in the same local transaction. A separate relay (a poller, or change-data-capture) reads unsent rows, publishes them, then marks them sent.A crash after publishing but before marking means a repeat, so delivery is at-least-once and consumers must deduplicate on an event id. The sketch below ran in Python with SQLite.
Full background: microservices course.
python with db: # one local transaction db.execute("insert into parcel values (1, 'DISPATCHED')") db.execute("insert into outbox(payload) values ('parcel 1 dispatched')") relay(crash=True); relay() # publish, crash before marking, retry # consumer: skip ids already seenOutput
[(1, 'parcel 1 dispatched'), (1, 'parcel 1 dispatched')] handle 1 skip 1
What the interviewer is checking: Whether you can explain the dual-write failure and accept the duplicate-delivery consequence.
Likely follow-up: Polling relay or change-data-capture: how do you choose?
42What is the Saga pattern, and how does it replace a distributed transaction?Advanced
A saga splits a business operation across services into a chain of local transactions. If a later step fails, earlier steps are undone by compensating actions run in reverse order. No global lock is held, so services stay available, but the system is eventually consistent.
Trade-off to state: no isolation. Other requests can see the intermediate state, for example a held slot that is later released, so model it explicitly with statuses like PENDING and CONFIRMED.
Illustrative clinic booking: hold slot, charge card, send confirmation. When the charge fails, the hold is released. I ran a small simulation of that flow.
python run_saga([("hold slot", hold, release), ("charge card", charge, refund), ("send confirmation", notify, noop)])Output
ok hold slot FAIL charge card - card declined undo hold slot ABORTED
What the interviewer is checking: Whether you can describe local steps, compensations, and the isolation trade-off.
Likely follow-up: What if the compensation itself fails?
43Orchestration versus choreography for sagas: how do you choose?Intermediate
In orchestration one coordinator tells each service what to do next and tracks the state. In choreography there is no coordinator; each service reacts to events and emits its own.
Choreography is lightweight for short, linear flows of two or three services, but the overall process becomes invisible, and cyclic event dependencies can creep in. Orchestration gives a single place to see state, handle timeouts and branches, and test the flow, at the cost of a central component that must stay thin and not absorb business rules.
Rule of thumb: few steps and few branches, choreography; many steps, deadlines or approvals, orchestration. Either way, steps need to be idempotent.
What the interviewer is checking: Whether you decide from complexity and observability needs instead of fashion.
Likely follow-up: How would you find out where a stuck saga instance is?
44What is a compensating transaction, and what makes a good one?Intermediate
A compensating transaction is a new action that semantically reverses an earlier committed step. It is not a rollback: the original row stays, and a refund or release record is added. Releasing a held clinic slot or issuing a refund are examples.
A good compensation is idempotent (safe to run twice), retryable until it succeeds because it must not be abandoned halfway, and works from stored data, not memory. Some actions cannot be undone, such as an email already sent, so put those last, after the point of no return, or make the compensation a follow-up message.
Business rules may also require a fee or a partial refund, so compensation is domain logic, not a generic undo.
What the interviewer is checking: Whether you treat compensation as idempotent domain logic and know about non-reversible steps.
Likely follow-up: How do you order steps so the irreversible one comes last?
45What is CQRS, and when is it worth the complexity?Intermediate
Command Query Responsibility Segregation separates the model that changes state (commands) from the model that answers questions (queries). The read side is usually a denormalised view built for one screen, updated from events or change feeds, while the write side stays normalised and enforces rules.
Worth it when read and write shapes or load differ a lot, such as a parcel-tracking timeline read thousands of times per update. The price is eventual consistency between the two sides and more moving parts.
It is not the same as event sourcing; you can do CQRS with ordinary tables. For plain CRUD it is overkill, and saying so shows judgement.
What the interviewer is checking: Whether you can justify CQRS by a concrete read/write mismatch and name its consistency cost.
Likely follow-up: How does a user see their own write if the read model lags?
46Why are distributed transactions hard, and what is two-phase commit?Advanced
Two-phase commit (2PC, as in XA) has a coordinator ask every participant to prepare, and if all vote yes, tell all to commit. It gives atomicity across databases, but participants hold locks while waiting. If the coordinator dies after prepare, they are stuck until it recovers, so availability and latency suffer, and not every broker or SaaS API supports it.
Microservice systems therefore usually avoid it: they combine local transactions with the outbox, a saga for coordination, and idempotent consumers, and accept eventual consistency.
Mention the exception honestly: if two writes truly must be atomic, keep them in one service and one database.
What the interviewer is checking: That you understand 2PC's mechanism and its blocking cost, and know the usual alternatives.
Likely follow-up: Does a Kafka transaction give you atomicity with your own database?
47What is idempotency, and how do you implement it for retried requests?Intermediate
An idempotent operation has the same effect when repeated. Setting a status to SHIPPED is naturally idempotent; "add 500 to the balance" is not. Retries, timeouts and at-least-once messaging make duplicates unavoidable, so non-idempotent actions need protection.
Implementation: the caller sends a unique key; the server inserts it into a table with a unique constraint in the same transaction as the effect. A repeat hits the constraint and returns the stored result. Reject the same key arriving with a different body, and expire old keys. The sketch ran against SQLite.
Related: System design interview questions.
python try: with db: # key and effect commit together db.execute("insert into idem(key) values (?)", (key,)) rid = db.execute("insert into refunds(amount) values (?)", (amount,)).lastrowid except sqlite3.IntegrityError: pass # seen before: return the stored answerOutput
refund 1 refund 1 refund 2 2 refund rows
What the interviewer is checking: Whether you can make idempotency race-safe with a constraint, not a check-then-insert.
Likely follow-up: How long should you keep idempotency keys, and what happens after they expire?
48How do you keep a business operation atomic across microservices?Advanced
First challenge the requirement: does it truly need atomicity, or just a consistent end state? If two things must change together, the cleanest answer may be that they belong in one service and one database.
Otherwise, accept that each service is atomic only locally and design for convergence. Use the outbox so each service reliably publishes its change, a saga with compensations for the multi-step flow, and idempotent handlers so retries are safe. Add visible intermediate states, timeouts and a dead-letter path for steps that keep failing.
In the interview, name the trade-off: you give up instant global consistency for availability and independence. Starting point: Microservices interview and course material.
What the interviewer is checking: Whether you question the requirement first and then combine outbox, saga and idempotency coherently.
Likely follow-up: Which orders or payments would you refuse to split across services?
Kafka, Redis & Async (8)
49Describe Kafka's architecture in a few sentences.Intermediate
Kafka is a cluster of brokers that store topics as append-only logs. Each topic is split into partitions, and each partition is replicated: one replica is the leader that handles reads and writes, the others follow. Records stay for a retention period, not until consumed, so many readers can replay them.
Producers append records; consumers pull them and track their own position, the offset. Cluster metadata and leader election are handled by controllers; newer versions use the built-in KRaft mode instead of a separate ZooKeeper ensemble.
Say the design idea: a durable, partitioned, replayable log. Fuller treatment: Apache Kafka course.
What the interviewer is checking: Whether you can describe the log, partition and replication model without drifting into product marketing.
Likely follow-up: What happens to a partition when its leader broker dies?
50Describe the producer-to-consumer flow of a message in Kafka.Beginner
The producer serialises the record, picks a partition (hash of the key if there is one, otherwise spread across partitions), batches records and sends them to that partition's leader. The leader appends and, depending on
acks, waits for followers before acknowledging.The consumer in a group polls, receives records from its assigned partitions, processes them, and then commits the offset so it can resume after a restart. When you commit relative to processing decides your delivery guarantee.
In Spring that is
KafkaTemplateto send and@KafkaListenerto receive.java kafka.send("parcel-scans", parcelId, event); // key = parcelId @KafkaListener(topics = "parcel-scans", groupId = "tracking") void onScan(ScanEvent e) { /* update the timeline */ }What the interviewer is checking: That you can follow a record end to end, including partition choice and offset commit.
Likely follow-up: What does acks=all change in that flow?
51What are a broker, a topic and a partition in Kafka?Beginner
A broker is one Kafka server. A topic is a named stream, say the parcel-scan feed. A partition is one ordered lane of that topic: a topic with six partitions is six independent logs, spread over the brokers, each with its own offsets.
Partitions are the unit of both ordering and parallelism: order holds only inside a lane, and at most one consumer of a group reads a lane at a time. The replication factor says how many brokers hold a copy of each lane.
Partition count can be increased later but not reduced, and increasing it changes which partition a key maps to, so plan it with expected throughput in mind.
What the interviewer is checking: Whether you tie partitions to ordering and parallelism, not just storage.
Likely follow-up: How would you choose the number of partitions for a new topic?
52How do Kafka consumer groups work, and what is a rebalance?Intermediate
Consumers sharing a
group.idform a group, and Kafka divides the topic's partitions among them so each partition goes to exactly one member. This is how you scale reading: add consumers, up to the partition count. Extra consumers sit idle. A different group gets its own full copy of the stream, with its own offsets.A rebalance reassigns partitions when members join, leave, crash or time out. During it, processing can pause, and uncommitted work may be redelivered to another member, so handlers should be idempotent. Cooperative assignment and static membership reduce the disruption.
What the interviewer is checking: Whether you know the one-partition-one-consumer rule and the cost of rebalances.
Likely follow-up: You have 12 consumers and 8 partitions. What do you observe and what do you change?
53What ordering guarantees does Kafka give, and how do you preserve order?Intermediate
Order is guaranteed within a partition only, not across a topic. Records with the same key go to the same partition (while the partition count is unchanged), so use the entity id, for example the parcel id, as the key: all scans of one parcel stay in order, while different parcels run in parallel.
Two ways to lose order: producer retries can reorder in-flight batches unless the idempotent producer is enabled (the default in recent clients), and a consumer that hands records to a thread pool may finish them out of order. Process one partition's records sequentially, or partition work by key inside the app.
What the interviewer is checking: Whether you can say "per partition, keyed by entity" and name two real ways ordering gets broken.
Likely follow-up: What happens to per-key ordering if you add partitions to a live topic?
54How do you get reliable delivery in Kafka, and what do at-most, at-least and exactly-once mean?Advanced
Durability on the producer side: replication factor 3,
acks=all, a sensiblemin.insync.replicas, retries on, idempotent producer on. Consumer side: commit offsets only after processing succeeds.At-most-once: commit before processing, so a crash loses work. At-least-once: process then commit, so a crash repeats work; this is the practical default, paired with idempotent handlers. Exactly-once: Kafka transactions plus idempotent producers give it for read-process-write inside Kafka, but an outside side effect such as a database write or email needs its own deduplication.
Send poison messages to a dead-letter topic after bounded retries.
What the interviewer is checking: Whether you tie the three semantics to commit timing and know exactly-once stops at Kafka's boundary.
Likely follow-up: How would you handle one message that fails every time?
55How does asynchronous processing work in Spring with @Async?Intermediate
Add
@EnableAsync, then annotate a method with@Async. Like@Transactional, it works through a proxy, so the call must come from another bean, and the body runs on aTaskExecutorthread. Returnvoidor aCompletableFutureso the caller does not block.Gotchas: an exception from a
voidmethod vanishes unless you configure anAsyncUncaughtExceptionHandler; the transaction and the security context do not follow to the new thread; and an unbounded or default pool can hide overload, so define a bounded executor with a queue. Boot 3.2 and later can run on virtual threads through a property.If the work must survive a restart, use a queue instead.
java @Async public CompletableFuture<Void> sendReceipt(long loanId) { mailer.send(loanId); return CompletableFuture.completedFuture(null); }What the interviewer is checking: Whether you know @Async is proxy-based, loses thread-bound context, and is not durable.
Likely follow-up: When would you use Kafka instead of @Async for a background job?
56How do TTLs and caching strategies work in Redis?Intermediate
Set a TTL with
SET key value EX 600orEXPIRE. Redis removes expired keys lazily on access and with a background sampler. Choose TTL from how stale the data may be, and add random jitter so many keys written together do not expire together and stampede the database.Usual strategy is cache-aside: read the cache, on a miss load from the database and store it; on a write, update the database and delete the cached key. Also consider caching "not found" briefly, and set
maxmemorywith an eviction policy so memory is bounded.In Spring,
@Cacheablewith a cache manager configured withentryTtldoes this declaratively. More: Redis course.java RedisCacheConfiguration cfg = RedisCacheConfiguration.defaultCacheConfig() .entryTtl(Duration.ofMinutes(10));What the interviewer is checking: Whether you pair TTL with invalidation and name stampede and eviction as real production concerns.
Likely follow-up: One hot key expires and a thousand requests miss at once. What do you do?
REST APIs & Security (11)
57How do GET, POST, PUT and PATCH differ, and which are safe or idempotent?Beginner
Two properties organise the answer. Safe means the call does not change server state: GET (and HEAD) qualify. Idempotent means repeating it leaves the same final state: GET, PUT and DELETE qualify, POST does not, and PATCH is not guaranteed to be.
Use GET to read a library loan, POST to create one (the server picks the ID, so a retry can create a duplicate), PUT to replace the whole record with the body you send, and PATCH to change a few fields, such as only the due date. The trap: a PATCH like "extend by 7 days" is not idempotent, while "set due date to 3 March" is.
What the interviewer is checking: Whether you reason from safety and idempotency, not from memorised one-line definitions.
Likely follow-up: A client times out on a POST that creates an order. How do you make the retry safe?
58Which HTTP status codes do you return for success, client errors and server errors?Beginner
Group by first digit. 2xx: 200 for a normal read or update, 201 with a
Locationheader after creating something, 204 when there is nothing to return. 4xx means the caller must change something: 400 malformed input, 401 not authenticated, 403 authenticated but not allowed, 404 unknown resource, 409 conflicts with current state, 422 well-formed but semantically invalid, 429 too many requests.5xx means the fault is ours: 500 unexpected failure, 502/504 a bad or slow upstream, 503 temporarily unavailable. Never send 200 with an error inside the body; clients, caches and monitoring all rely on the code. Full discussion: REST API course.
What the interviewer is checking: Accurate, purposeful use of codes, especially 401 versus 403 and 400 versus 422.
Likely follow-up: A user tries to book a slot someone else just took. Which code, and what body?
59How do you validate request input and handle exceptions consistently in a Spring REST API?Intermediate
Validate at the edge: constraint annotations on the request type,
@Validon the parameter, so bad input is rejected before business code runs. Rules that need data (is the slot still free?) belong in the service and throw a domain exception.One
@RestControllerAdvicemaps each exception type to a status and a uniform error body (a problem-details style document with a message and a field map). Log server faults with a correlation ID, but never return stack traces or SQL text to callers.java public record BookSlot(@NotBlank String patronId, @Future Instant start) {} @PostMapping("/slots") ResponseEntity<Void> book(@Valid @RequestBody BookSlot req) { /* ... */ } @RestControllerAdvice class ApiErrors { @ExceptionHandler(MethodArgumentNotValidException.class) ProblemDetail invalid(MethodArgumentNotValidException ex) { ProblemDetail p = ProblemDetail.forStatusAndDetail(HttpStatus.BAD_REQUEST, "Validation failed"); p.setProperty("fields", ex.getBindingResult().getFieldErrors().stream() .collect(Collectors.toMap(FieldError::getField, FieldError::getDefaultMessage, (a, b) -> a))); return p; } }What the interviewer is checking: Layered validation, one central error handler, and not leaking internals.
Likely follow-up: Where do you validate a rule that needs a database lookup, and what status does it map to?
60How would you paginate a list endpoint, and when does offset pagination stop working well?Intermediate
Offset (
?page=40&size=20) is simple and supports jumping to a page, but the database still walks past every skipped row, and rows inserted meanwhile shift pages so items repeat or vanish. Keyset (cursor) pagination asks for rows after the last seen sort key; it stays fast on deep pages and is stable under inserts, but cannot jump to page 40.Return the cursor opaquely, cap
size, define a stable order with a unique tiebreaker (such asid), and include a next link. Choose offset for small admin tables, keyset for feeds and large datasets.python # db: a sqlite3 connection holding a loans(id, title) table def page(after_id, size=3): return db.execute( "SELECT id, title FROM loans WHERE id > ? ORDER BY id LIMIT ?", (after_id, size)).fetchall() cursor = 0 while rows := page(cursor): print([r[0] for r in rows], "next cursor =", rows[-1][0]) cursor = rows[-1][0]Output
[1, 2, 3] next cursor = 3 [4, 5, 6] next cursor = 6 [7] next cursor = 7
What the interviewer is checking: Understanding the cost of OFFSET and the stability argument for cursors.
Likely follow-up: How do you keyset-paginate when the sort column, such as price, is not unique?
61What are the ways to version a REST API, and how do you choose?Intermediate
Common options: a path segment (
/v2/loans), a header or media type (Accept: application/vnd.library.v2+json), or a query parameter. Path versions are the most visible and easiest to route, cache and debug; header versions keep URLs stable but are harder to test from a browser.The better question is how rarely you need a new version at all. Additive changes (new optional fields, new endpoints) are backward compatible, so clients must ignore unknown fields. Cut a new version only for breaking changes, run old and new side by side, publish a deprecation date, and measure remaining traffic on the old one before removal.
What the interviewer is checking: Judgement: prefer compatible evolution, and treat versioning as a retirement plan too.
Likely follow-up: Which changes are breaking: renaming a field, adding a required field, adding an optional one?
62What is the difference between authentication and authorization, and where is each enforced?Beginner
Authentication establishes identity ("this is patron 17") using a password, one-time code or token. Authorization decides what that identity may do to a specific resource. Say in the first sentence that the order is authenticate, then authorize.
Both are enforced on the server for every request: a gateway or filter handles authentication, while authorization is closest to the data, checking roles for the action and ownership for the object. The classic failure is logged-in user A reading user B's record by changing an ID. Return 401 when identity is missing or invalid, 403 when it is known but not permitted. More: Security interview questions.
What the interviewer is checking: Clear separation, server-side enforcement, and awareness of object-level checks.
Likely follow-up: Where in a Spring app would you put role checks versus ownership checks?
63Walk me through a JWT-based authentication flow, step by step.Intermediate
The client posts credentials to a login endpoint; the server verifies them and returns a signed token carrying claims such as
sub,iss,audandexp. The client sends it asAuthorization: Bearer <token>on later calls. Each service checks the signature with a fixed expected algorithm and key, then the expiry, issuer and audience, and only then trusts the claims.The payload is encoded, not encrypted, so keep secrets out of it. The run below signs a token with HMAC, then shows expiry and a tampered payload both being rejected. Deeper: JWT course.
python import base64, hashlib, hmac, json def b64(b): return base64.urlsafe_b64encode(b).rstrip(b"=").decode() def unb64(s): return base64.urlsafe_b64decode(s + "=" * (-len(s) % 4)) KEY = b"demo-only-secret" def sig(head, body): return b64(hmac.new(KEY, f"{head}.{body}".encode(), hashlib.sha256).digest()) def sign(claims): head = b64(json.dumps({"alg": "HS256"}).encode()) body = b64(json.dumps(claims).encode()) return f"{head}.{body}.{sig(head, body)}" def verify(token, now): head, body, s = token.split(".") if not hmac.compare_digest(s, sig(head, body)): return "reject: bad signature" claims = json.loads(unb64(body)) return "reject: expired" if claims["exp"] <= now else "ok: " + claims["sub"] t = sign({"sub": "patron-17", "exp": 1000}) print(verify(t, 900)) print(verify(t, 1001)) h, _, s = t.split(".") print(verify(f"{h}.{b64(json.dumps({'sub': 'admin', 'exp': 9999}).encode())}.{s}", 900))Output
ok: patron-17 reject: expired reject: bad signature
What the interviewer is checking: That you can narrate issue, send and verify, including which checks happen on every request.
Likely follow-up: Why must the server pin the expected algorithm rather than read it from the token header?
64When would you choose JWTs over server-side sessions, and when the reverse?Intermediate
A session stores state on the server and gives the browser an opaque ID. Logout and revocation are instant, but every instance needs the shared store. A JWT carries its own claims and is verified without a lookup, which suits many independent services or third-party clients, but it is valid until it expires.
My default for a single browser app with one backend: sessions in a cookie. For service-to-service or mobile APIs: short-lived JWTs. If you need instant revocation with JWTs you reintroduce state (a deny-list or token version), so say that cost out loud. Compare: Security interview questions.
What the interviewer is checking: A reasoned default and an honest account of revocation, rather than "JWT is stateless so it is better".
Likely follow-up: An employee is dismissed; how fast does access end under each approach?
65What are access tokens and refresh tokens, and why use both?Intermediate
The access token is short-lived (minutes) and sent with every API call, so a leak has a small window. The refresh token is long-lived, used only against the authorisation endpoint to obtain a new access token, so it travels rarely.
That split gives revocability without a lookup on every request: the server can refuse to refresh. Good practice: store refresh tokens hashed server-side, bind them to a device or session, rotate on each use, and treat a reused old refresh token as theft, revoking that whole session family. Keep the refresh token out of script-readable storage, for example an HttpOnly, Secure cookie scoped to the refresh path.
What the interviewer is checking: Understanding the lifetime trade-off plus rotation and reuse detection.
Likely follow-up: How do you log a user out of all devices if access tokens are stateless?
66What are CORS and CSRF, and how are they different?Intermediate
CORS is a browser mechanism by which a server says which other origins may read its responses from script. It relaxes the same-origin rule, and it is not authentication: curl ignores it. CSRF is an attack where another site makes the victim's browser send a state-changing request that carries the victim's cookies automatically.
Defences differ. For CORS: an explicit allow-list of origins, never reflecting the incoming Origin, and no wildcard with credentials. For CSRF: SameSite cookies, anti-forgery tokens on state-changing requests, no state changes on GET, and an Origin check. APIs authenticated with an Authorization header are largely immune to classic CSRF.
What the interviewer is checking: Whether you keep the two apart: one is a read relaxation, the other a request-forgery attack.
Likely follow-up: Does enabling CORS for one origin make CSRF easier?
67How would you secure a REST API end to end? Give me a checklist.Advanced
Work outside in. Transport: TLS only. Identity: strong authentication (OAuth 2.0/OIDC or sessions), MFA for people, short-lived tokens, per-client credentials for services. Authorisation: deny by default, object-level checks on every endpoint.
Input and output: schema validation, parameterised queries, size and type limits, and no internal details in errors. Abuse control: rate limits per client and stricter ones on login. Data: least-privilege database users, secrets in a manager, sensitive fields masked in logs. Operations: audit logs, dependency scanning, security headers, tested key rotation. Mention a threat-modelling pass for each new endpoint. More: OWASP Top 10 course.
What the interviewer is checking: A structured, layered view, with object-level authorisation named explicitly.
Likely follow-up: Which two items from your list would you implement first on a new API, and why?
Microservices & System Design (13)
68Why would a team choose microservices, and what do they cost?Beginner
The gains: independent deployment, scaling a hot part separately, team ownership aligned to business domains, and fault isolation. The costs are real: network latency and partial failure replace method calls, data is split so cross-service transactions disappear, and you now need contract versioning, tracing, and mature deployment automation.
Frame it as a trigger, not a fashion: many teams blocked on one release, or one component with very different load. Without that, a modular monolith is faster and cheaper. If you do split, cut along business boundaries and give each service its own data. Full discussion: microservices course.
What the interviewer is checking: Balanced reasoning with named costs, not enthusiasm for the pattern.
Likely follow-up: Which part of a clinic appointment system would you extract first, and why that one?
69What is service discovery, and how do clients find healthy instances?Intermediate
Instances start, stop and move, so callers cannot hard-code addresses. A registry keeps the live list: each instance registers (or the platform does it) and is removed when health checks fail.
Client-side discovery means the caller fetches the list and picks an instance, which saves a hop but puts logic in every client. Server-side discovery sends the call to a load balancer or proxy that does the lookup. In Kubernetes the platform covers this: a Service name resolves through DNS to healthy pods only. Mention health checks, caching of results with a short TTL, and what happens when the registry is unreachable (keep using the last known list).
What the interviewer is checking: That you know why it exists and can compare client-side with server-side models.
Likely follow-up: What happens to in-flight requests when an instance is deregistered?
70What does an API gateway do, and what should it not do?Intermediate
It is the single entry point for outside clients: routing to services, authentication and token validation, rate limiting, TLS termination, request logging, and sometimes response aggregation or protocol translation. It hides internal topology so services can be reshuffled without breaking clients.
What it should not hold is business logic, because it becomes a shared bottleneck that every team must edit. It is also a single point of failure, so run it redundantly and keep it thin. Distinguish it from a service mesh, which manages service-to-service traffic inside the cluster.
What the interviewer is checking: Knowing the legitimate cross-cutting jobs and the risk of a bloated gateway.
Likely follow-up: Would you put authorisation rules in the gateway, in each service, or both?
71What is a circuit breaker, and how does it differ from a retry or a timeout?Intermediate
A timeout bounds one call. A retry repeats a failed call. A circuit breaker tracks recent outcomes across calls: when the failure rate passes a threshold it opens and fails immediately for a cooling period, half-opens to allow a few probe calls, then closes again on success.
The point is protecting both sides: the caller stops tying up threads on a doomed dependency, and the struggling service gets quiet time to recover. Pair it with a fallback (cached value, reduced feature, clear error) and keep retries behind the breaker, otherwise retries make an outage worse. Libraries such as Resilience4j provide it.
What the interviewer is checking: Correct states and the interplay of the three patterns.
Likely follow-up: What fallback would you show when the price-lookup service is open-circuited?
72How would you implement rate limiting, and which algorithm would you pick?Intermediate
Decide the key (API key, user, IP), the limits, and the rejection response (429 with a retry hint). A token bucket is my default: a bucket of capacity C refills at R tokens per second, each request spends one, so short bursts pass but the long-run rate stays at R. A fixed window is simpler but lets a double burst straddle the boundary.
With several servers the state lives in a shared store such as Redis and the check-and-update must be atomic. Decide whether the limiter fails open or closed when that store is down. Fuller treatment: rate limiting course.
python class Bucket: def __init__(self, cap, rate): self.cap, self.rate, self.tokens, self.t = cap, rate, cap, 0.0 def allow(self, now): self.tokens = min(self.cap, self.tokens + (now - self.t) * self.rate) self.t = now if self.tokens >= 1: self.tokens -= 1 return True return False b = Bucket(cap=5, rate=2) print("burst of 8 at t=0:", [b.allow(0.0) for _ in range(8)]) print("one second later: ", [b.allow(1.0) for _ in range(3)])Output
burst of 8 at t=0: [True, True, True, True, True, False, False, False] one second later: [True, True, False]
What the interviewer is checking: Algorithm choice with the reason, plus the distributed and failure-mode concerns.
Likely follow-up: How do you apply different limits per customer plan without redeploying?
73What techniques do you use to scale a backend service?Intermediate
Find the bottleneck first, then pick the cheapest fix. Typical order: tune queries and add indexes; cache read-heavy data; scale the stateless tier horizontally behind a load balancer; add read replicas; move slow work behind a queue so requests return fast; and only then partition (shard) the data.
Each step has a price: caches go stale, replicas lag, queues make results asynchronous, shards complicate joins. State the metric that triggers the next step (CPU saturation, p99 latency, replica lag, queue depth) and load-test before and after. Scaling also means degrading gracefully, for example shedding low-priority work under overload.
What the interviewer is checking: A measured, ordered approach instead of listing buzzwords.
Likely follow-up: Your database CPU is at its limit but the app tier is idle. What do you try, in order?
74Design a notification system for email, SMS and push. Give me a compact outline.Advanced
Requirements: multiple channels, user preferences and opt-outs, priorities (a security code beats a promotion), no duplicates, delivery status. Components: a notification API, a preferences and template service, one queue per channel (so a slow SMS vendor cannot delay email), channel workers calling providers, and a status store.
Flow: accept the request and persist it, check preferences, render, enqueue with an idempotency key; a worker sends and records the outcome. Failure: retry with backoff, dead-letter after a limit, fail over to a backup provider. Trade-offs: at-least-once plus deduplication rather than exactly-once; asynchronous, so senders get "accepted", not "delivered". See system design interview questions.
What the interviewer is checking: A structured outline covering requirements, flow, failure handling and trade-offs within a few minutes.
Likely follow-up: What do you change if a marketing campaign targets 5 million users at once?
75How would you handle email, SMS and push differently inside that notification system?Advanced
Share the pipeline, isolate the channel adapters. Each adapter hides one provider behind a common interface, owns its rate limits and error mapping, and has its own queue and concurrency cap.
Channel differences matter: email is cheap and slow, needs bounce and complaint handling, and reputation depends on suppressing bad addresses. SMS is costly, length- and region-regulated, and often needs quiet hours. Push needs device tokens that expire, so a "token invalid" response must delete the token. Template per channel, honour per-channel opt-in, and fall back (push, then SMS) only for critical messages. Providers throttle, so respect their limits instead of retrying blindly.
What the interviewer is checking: Awareness of real channel differences and a clean adapter boundary.
Likely follow-up: How do you stop one broken provider from consuming all worker capacity?
76How do you track delivery status and handle retries for notifications?Advanced
Give every notification an ID and a state machine: queued, sending, sent, delivered, failed, dead-lettered. Providers report asynchronously through callbacks (webhooks), so accept those idempotently, verify their signatures, and update by ID; "sent" and "delivered" are different facts.
Retry only transient failures, with exponential backoff and random jitter, a maximum attempt count, then a dead-letter queue with an alert and a replay tool. Reuse one idempotency key for all attempts so a retry after a timeout cannot double-send. Show only a status summary to users, and keep raw attempts for support.
python import random random.seed(7) def jittered(attempt, base=1.0, cap=30.0): return round(random.uniform(0, min(cap, base * 2 ** attempt)), 2) print("ceilings:", [min(30.0, 1.0 * 2 ** i) for i in range(7)]) print("waits: ", [jittered(i) for i in range(7)])Output
ceilings: [1.0, 2.0, 4.0, 8.0, 16.0, 30.0, 30.0] waits: [0.32, 0.3, 2.6, 0.58, 8.57, 10.97, 1.74]
What the interviewer is checking: State tracking, idempotent callbacks, and bounded retries ending in a dead-letter path.
Likely follow-up: A provider webhook arrives twice, out of order. How does your status update stay correct?
77A service must handle over 1 million requests a day. What do you actually design for?Intermediate
Do the arithmetic first: a day has 86,400 seconds, so 1,000,000 requests is about 12 per second on average. That is small; one modest instance can often handle it. The design is driven by peaks, not the average: traffic clusters (a 4-hour working window, a campaign, a retry storm), so plan for several times the mean, then check the numbers below.
What matters is per-request cost and dependencies: slow queries, the database connection pool, downstream limits, and the tail latency. Run at least two instances for availability, set timeouts and rate limits, and load-test to the measured peak with headroom. Do not shard or add Kafka for 12 requests a second.
python per_day = 1_000_000 avg = per_day / 86_400 print(f"average: {avg:.1f} req/s") print(f"x10 peak: {avg * 10:.0f} req/s") print(f"60% of traffic in a 4h window: {0.6 * per_day / (4 * 3600):.1f} req/s") print(f"in flight at x10 peak, 200 ms each: {avg * 10 * 0.2:.0f}")Output
average: 11.6 req/s x10 peak: 116 req/s 60% of traffic in a 4h window: 41.7 req/s in flight at x10 peak, 200 ms each: 23
What the interviewer is checking: Honest back-of-envelope maths, the average-versus-peak insight, and resisting over-engineering.
Likely follow-up: What if the same 1 million requests arrive in a single minute after an email campaign?
78Design a system that ingests very large files uploaded by customers.Advanced
Requirements: files up to many GB, resumable on flaky networks, integrity guaranteed, processing must not block uploads. Flow: the client asks the API for an upload session; it uploads in chunks, directly to object storage via short-lived signed URLs so the API servers never proxy gigabytes. A chunk can be retried independently; the client resumes from the last confirmed chunk.
On completion the service verifies a checksum, stores metadata, and puts a job on a queue; workers stream-process the file in a staging area. Failure handling: idempotent jobs, retries, a dead-letter queue, expiry of abandoned sessions. Trade-offs: chunk size (more overhead versus cheaper retries) and virus scanning delay. Scan before exposing results.
What the interviewer is checking: Direct-to-storage upload, resumability, integrity checks, and decoupled processing.
Likely follow-up: How do you stop one customer's huge uploads from starving everyone else?
79How do you process a 2 GB to 10 GB file atomically, so partial results are never visible?Advanced
Separate doing the work from making it visible. Write everything to a staging location under a temporary name, verify the checksum, then publish with one atomic step: a same-filesystem rename, or a commit marker/manifest row that readers require. Readers never see a half-written file.
For the processing, stream in bounded chunks instead of loading the file, and make each unit idempotent (keyed by file ID plus chunk or row range) so a crash resumes instead of duplicating. Apply backpressure: bounded queues and worker pools, so a slow sink slows intake instead of exhausting memory. Clean up orphaned staging data on a schedule. Object stores lack cheap rename, so a manifest is the usual commit.
python import hashlib, os, tempfile def stage(data, chunk, part_path): h = hashlib.sha256() with open(part_path, "wb") as f: for i in range(0, len(data), chunk): piece = data[i:i + chunk] h.update(piece) f.write(piece) f.flush() os.fsync(f.fileno()) return h.hexdigest() def publish(part_path, got, expected, final_path): if got != expected: os.remove(part_path) return "rejected: checksum mismatch, nothing published" os.replace(part_path, final_path) # atomic on one filesystem return "published" data = os.urandom(10_000) want = hashlib.sha256(data).hexdigest() with tempfile.TemporaryDirectory() as d: part, final = os.path.join(d, "a.part"), os.path.join(d, "a.csv") got = stage(data, 4096, part) print("before publish, final exists:", os.path.exists(final)) print(publish(part, got, want, final)) print("after publish, final exists:", os.path.exists(final), "| leftover .part:", os.path.exists(part)) got = stage(data, 4096, part) print(publish(part, got, "0" * 64, final + ".bad"))Output
before publish, final exists: False published after publish, final exists: True | leftover .part: False rejected: checksum mismatch, nothing published
What the interviewer is checking: Staging then atomic publish, idempotent chunk processing, and backpressure.
Likely follow-up: The worker crashes at 80 percent. What state is the system in, and how does it recover?
80Which non-functional requirements would you clarify, and what failure scenarios would you plan for?Advanced
Ask for numbers: peak load and growth, p95/p99 latency, availability target, durability (can we lose data?), consistency needs, recovery targets (RPO/RTO), security and compliance, cost ceiling. A vague "fast and reliable" cannot be tested.
Then walk failures, each with a planned response: an instance dies (health checks, redundancy), a dependency is slow (timeouts, circuit breaker, fallback), a retry storm (jitter, budgets), a poison message (dead-letter queue), a bad deploy (rollback), a zone or database failure (replication, failover, restore drill), duplicate delivery (idempotency). End with monitoring and an alert for each. Method: system design prep guide.
What the interviewer is checking: Quantified requirements and a systematic failure walk-through, not a list of technologies.
Likely follow-up: Choose one failure above and describe exactly what the user sees while it happens.
Cloud, Docker & Deployment (6)
81What are AWS EC2, EKS, RDS and S3 used for, and how do you choose among them?Beginner
EC2 gives you virtual machines: you choose size, OS and patching, which suits custom or legacy workloads. EKS is managed Kubernetes: AWS runs the control plane, while you still design workloads and node capacity, which suits many containerised services. RDS is a managed relational database: backups, patching, replicas and failover are handled, but you do not get OS access. S3 stores objects (files) by key, durable and cheap per GB, but it is not a file system or a database.
A typical stack: services in containers on EKS or EC2, relational data in RDS, uploads and exports in S3. Details: AWS interview questions.
What the interviewer is checking: One-sentence clarity on each service and its boundary.
Likely follow-up: Why would you store uploads in S3 rather than on the application server's disk?
82What does a load balancer do, and how do health checks and algorithms matter?Beginner
It presents one address and spreads requests across several instances, so no instance is a single point of failure and capacity can grow by adding more. Health checks remove an instance from rotation when it stops answering, which is why the check endpoint should test real readiness, not just "process is up".
A layer 4 balancer routes by IP and port; layer 7 understands HTTP, so it can route by path or host and terminate TLS. Algorithms: round robin for even requests, least connections for uneven ones. Keep the app stateless, otherwise you need sticky sessions, which unbalance the load.
What the interviewer is checking: Basics plus the health-check subtlety and the statelessness link.
Likely follow-up: An instance passes its health check but returns errors. What do you change?
83How does auto scaling work, and what must be true for it to help?Intermediate
A group of identical instances grows or shrinks between a minimum and maximum, driven by a metric (CPU, request count per instance, queue depth) or a schedule. New instances come from a template or image, join the load balancer once healthy, and surplus ones are drained and removed.
It only helps if instances are stateless and quick to start: no local sessions or files, configuration injected, and a startup time shorter than the load spike. Set a sensible minimum for availability, a maximum to cap cost, a cooldown to avoid flapping, and prefer a metric that predicts load (queue depth) over one that lags. Scaling a service cannot help if the database is the bottleneck.
What the interviewer is checking: Prerequisites for effective scaling and awareness of downstream bottlenecks.
Likely follow-up: Traffic spikes in 30 seconds but new instances need 3 minutes. What are your options?
84What is Docker, and how are images and containers different?Beginner
Docker packages an application with its dependencies into an image: a read-only, layered template built from a Dockerfile. A container is a running instance of an image, isolated by operating-system features, sharing the host kernel, so it starts in moments and is lighter than a virtual machine.
The benefit is the same artefact running identically on a laptop, in CI and in production. Habits worth stating: small base images, copy the dependency file before the source so layer caching works, run as a non-root user, one main process per container, keep data in volumes, never bake secrets into an image. More: Docker course.
What the interviewer is checking: Accurate image/container distinction and practical Dockerfile hygiene.
Likely follow-up: Why does the order of lines in a Dockerfile change build time?
85What problems does Kubernetes solve, and what are its basic building blocks?Intermediate
It keeps containers running as declared: you state the desired state, and controllers continually reconcile reality towards it, restarting failed containers, rescheduling when nodes die, and scaling replicas.
Core objects: a Pod runs one or more containers; a Deployment keeps N replicas of a Pod template and performs rolling updates; a Service gives them a stable name and load-balances across ready pods; ConfigMaps and Secrets inject configuration; an Ingress routes external HTTP traffic. Add readiness probes so traffic only reaches pods that can serve, and resource requests so the scheduler places pods sensibly. Course: Kubernetes.
What the interviewer is checking: The declarative model and correct roles of the basic objects.
Likely follow-up: What is the difference between a liveness probe and a readiness probe?
86Compare deployment strategies: rolling, blue-green and canary. How do you roll back?Intermediate
Rolling replaces instances gradually: cheap and the default, but old and new versions run together briefly, so they must be compatible. Blue-green keeps a full second environment and switches traffic at once: instant rollback, at the cost of duplicate capacity. Canary sends a small share of traffic to the new version, watches error and latency metrics, then widens: lowest risk, needs good observability.
Rollback means keeping the previous artefact and switching back, but the database is the catch: use backward-compatible changes (add the column first, remove the old one in a later release) so both versions work against the same schema. Feature flags separate deploying from releasing.
What the interviewer is checking: Choosing a strategy from risk and cost, and handling schema changes during rollback.
Likely follow-up: A release adds a non-null column. How do you ship it without breaking the old version?
AI-Native Engineering & GenAI (16)
87How would you compare two AI coding assistants, such as Cursor and Copilot, for your team?Intermediate
Products in this space change every few months, so I would not argue from a feature list or declare a winner. I would run a small trial: pick two or three real tasks from the backlog (a bug fix, a test-writing chore, a multi-file refactor), give each tool to the same developers, and record time to a reviewed pull request, review comments caused by the tool's output, and how often suggestions were rejected.
Alongside that, compare the constraints that are not features: where code and prompts are sent and kept, admin and audit controls, language and editor fit, cost per seat against measured time saved, and how well the tool follows repository conventions. Decide on your own data, and repeat the trial when either product changes materially.
What the interviewer is checking: Whether you judge tools with evidence and team constraints rather than brand preference.
Likely follow-up: What would make you reject a tool outright, even if developers liked it?
88How would you decide between Claude and ChatGPT for engineering work?Intermediate
I would not name a winner, because models and plans are revised often and the right choice depends on the task. I would build a small evaluation set from work we really do: summarise a design doc, explain a stack trace, draft a SQL query, write a unit test, answer a question from a pasted specification. Run both assistants on identical prompts, hide which is which, and have two engineers score correctness, completeness and tone against a short rubric.
Then weigh the practical side: context size needed, response speed, how each behaves when unsure, data-handling terms, API availability if we will integrate it, and cost at our volume. A result from today is a snapshot, so re-test every few months.
What the interviewer is checking: A repeatable, blind evaluation method and awareness that vendor comparisons go stale.
Likely follow-up: How would you stop evaluators from favouring the longer answer?
89What does a disciplined AI-assisted development workflow look like day to day?Intermediate
Treat the assistant as a fast junior pair, not the author. Start by writing the intent yourself: the behaviour, the interfaces and the tests that should pass. Give tight context (the relevant files, the conventions, the constraint), ask for one small change, and read the whole diff before accepting it.
Then loop: run tests, lint and type checks, fix or re-prompt, and commit in small steps. Keep design decisions, security-sensitive code and anything you cannot explain in your own hands. You stay accountable at review time, so the pull request description should say what you verified rather than that a tool wrote it.
What the interviewer is checking: That you use AI to speed up work you still own, with checkpoints instead of blind acceptance.
Likely follow-up: Which tasks would you never delegate to an assistant, and why?
90How do you validate code that an AI tool generated?Intermediate
Assume it is wrong until shown otherwise. First read for intent: does it solve the stated problem, and does every package, method and flag it mentions actually exist? Compile and run it, then use tests you wrote before seeing its output, including empty input, nulls, large values and concurrent access.
Then check what models tend to miss: error handling, resource cleanup, SQL built by string concatenation, secrets in code, new dependencies of unknown origin, and speed on realistic data volumes. Run static analysis and a dependency scan. If you cannot explain a line, rewrite it or ask the tool to justify it and verify that justification independently.
What the interviewer is checking: A concrete verification checklist, not trust in confident-sounding output.
Likely follow-up: The tests the tool wrote all pass. Why is that not enough?
91What are the main limitations of AI coding and chat tools that you plan around?Beginner
Four limits matter in practice. Plausible but wrong output: a model can invent functions, options or citations with full confidence. Limited context: it only sees what you supply, so it can miss conventions or code in other modules. Stale knowledge: training stops at a cutoff, so newer library behaviour may be unknown. Variability: the same prompt can give different answers on different runs.
Add weak spots in exact arithmetic, long multi-step reasoning without checks, and having no accountability or business context of its own. I plan around them with tests, current documentation supplied in the prompt, small tasks, human review and clear rules on what data may be pasted.
What the interviewer is checking: Realistic awareness of failure modes and the habits that contain them.
Likely follow-up: How would you handle a library released after the model's training cutoff?
92What is an agentic workflow, and when is it better than a fixed pipeline?Advanced
An agentic workflow lets a model choose its next step: it plans, calls tools such as search or a database query, reads the result, and decides whether to continue. In a fixed pipeline the steps are decided in advance by code. Prefer the pipeline when the path is known, since it is cheaper, faster and easier to test; use an agent when the route depends on what is found along the way, for example tracing a lost parcel across several systems.
Guard an agent with a tool allow-list, step and spend limits, a log of every action, and human approval before anything irreversible. Full course: AI agents.
What the interviewer is checking: Judgement about when autonomy is worth its cost, and the controls that make it safe.
Likely follow-up: How would you test an agent whose route differs on every run?
93Describe the architecture of a RAG system and what each component is responsible for.Intermediate
Draw two lanes on the board. The ingestion lane runs ahead of time: parser, cleaner, chunker, embedding model, then a vector store holding each vector plus its source, access group and date. The query lane runs per request: embed the question, fetch the closest chunks with the caller's permission filter applied, rerank if needed, assemble a prompt from those chunks alone, call the model, and return the reply with source ids.
Three design points to name: chunk quality caps retrieval quality, the prompt must say what to do when the context is silent, and retrieval and generation get scored separately. More in the RAG course.
python def build_prompt(question, passages): ctx = "\n".join(f"[{p['id']}] {p['text']}" for p in passages) return ( "Answer using ONLY the numbered context. Cite ids like [d2]. " "If the context lacks the answer, say you do not know.\n\n" f"Context:\n{ctx}\n\nQuestion: {question}" ) passages = [ {"id": "d1", "text": "Library cards expire after 2 years."}, {"id": "d2", "text": "Renewals can be done at the kiosk or online."}, ] print(build_prompt("How do I renew my card?", passages))Output
Answer using ONLY the numbered context. Cite ids like [d2]. If the context lacks the answer, say you do not know. Context: [d1] Library cards expire after 2 years. [d2] Renewals can be done at the kiosk or online. Question: How do I renew my card?
What the interviewer is checking: That you can describe both the ingestion and query paths and where permissions and refusal fit.
Likely follow-up: Where would you enforce per-user document permissions, and why there?
94What are embeddings, and what rules must you follow when storing and comparing them?Beginner
An embedding model maps text to a fixed-length vector so that texts with similar meaning land close together. "Reset my kiosk pin" and "forgot my locker code" share almost no words yet end up near each other. Closeness is usually measured with cosine similarity or a dot product.
Rules to remember: embed documents and queries with the same model, store the model name beside every vector because vectors from different models are not comparable, and re-embed everything when you switch. Embeddings capture topic well but can blur exact identifiers and negation.
What the interviewer is checking: A correct mental model plus the operational rules that cause real bugs.
Likely follow-up: You upgrade the embedding model. What happens to your existing index?
95What is semantic search, and how does it differ from keyword search?Beginner
Keyword search matches the words typed, usually ranked with a scheme such as BM25, so it misses synonyms and rephrasings. Semantic search converts the query and the documents to embeddings and ranks by closeness of meaning, so "cheap flights" can find a page titled "budget airfares".
It is weaker on exact strings such as part numbers, error codes and names, which is why many systems run both and merge the lists. Judge quality with a set of real queries and the page that should come first for each, not by eyeballing a handful of examples.
What the interviewer is checking: Understanding the strengths and blind spots of each approach and how to measure them.
Likely follow-up: A user searches for the error code E-4021 and gets unrelated pages. What happened?
96How does vector search work, and what trade-offs come with approximate indexes?Intermediate
Vector search returns the stored vectors nearest to a query vector. The exact method compares the query with every vector, which is accurate but slow across millions of items. Approximate methods build an index, graph-based or cluster-based, so only a small slice of the data is visited, trading a little recall for a large speed gain.
Two practical points: measure recall against exact results on your own data, and be deliberate about metadata filters such as language or tenant, because filtering before or after the nearest-neighbour step can change both results and latency. The snippet is a brute-force version with a filter, and it was run.
python import math def unit(v): n = math.sqrt(sum(x * x for x in v)) return [x / n for x in v] docs = [ {"id": "a", "vec": unit([0.9, 0.1, 0.2]), "lang": "en", "year": 2024}, {"id": "b", "vec": unit([0.8, 0.3, 0.1]), "lang": "de", "year": 2024}, {"id": "c", "vec": unit([0.1, 0.9, 0.3]), "lang": "en", "year": 2022}, ] def search(q, k, where): q = unit(q) pool = [d for d in docs if all(d[key] == val for key, val in where.items())] scored = sorted(((sum(a * b for a, b in zip(q, d["vec"])), d["id"]) for d in pool), reverse=True) return [(i, round(s, 3)) for s, i in scored[:k]] print(search([1, 0.2, 0.1], 2, {})) print(search([1, 0.2, 0.1], 2, {"lang": "en"}))Output
[('a', 0.989), ('b', 0.987)] [('a', 0.989), ('c', 0.317)]What the interviewer is checking: Knowing exact versus approximate search and that filters interact with the index.
Likely follow-up: How would you measure the recall your approximate index gives up?
97What is ChromaDB, and how would you use it in a RAG prototype?Intermediate
ChromaDB is an open-source vector database. You create a collection, add documents together with their embeddings (produced by an embedding function you configure, or supplied by you) and optional metadata, then query with text or a vector to get the nearest items. Metadata filters narrow results, for example by source or tenant, and data can be kept in memory for experiments or persisted so it survives restarts.
It suits prototypes and small to medium workloads. For production I would still check scaling, backup, access control and operational fit against alternatives rather than assume it is enough.
What the interviewer is checking: A general, accurate picture of a vector store's role and a sober view of production readiness.
Likely follow-up: What goes wrong if the embedding function changes after data is already loaded?
98What does prompt engineering involve beyond writing a clever instruction?Beginner
It means specifying a task precisely enough that the output can be relied on, then testing it like code. A solid prompt states the context, the exact task, the input, the constraints and the output format; it adds one or two examples for tricky cases and says what to do when information is missing.
The engineering part is iteration with evidence: keep a set of test inputs, change one thing at a time, version the prompt, and compare results before shipping. Prefer structured outputs you can validate. Full course: prompt engineering.
What the interviewer is checking: Treating prompts as versioned, tested artefacts rather than folklore.
Likely follow-up: Your new prompt fixes three failing cases. How do you know it did not break others?
99What is fine-tuning, and what kinds of problems does it solve?Intermediate
Fine-tuning continues training a pre-trained model on your own examples so its weights shift towards a behaviour: a house writing style, a strict output schema, domain vocabulary, or a narrow classification skill. It needs a clean set of input and output pairs, an evaluation set kept apart from the training data, and a plan to retrain when requirements shift.
It is not a dependable way to store facts, and small or noisy data can leave the model worse or narrower. Try prompting and retrieval first; tune when you have measured a gap they cannot close. Budget for data preparation, training, hosting and re-testing.
What the interviewer is checking: Knowing fine-tuning targets behaviour, needs good data, and is not the first tool to reach for.
Likely follow-up: How would you prove the tuned model beats the prompted base model?
100What is QLoRA, and why is it cheaper than full fine-tuning?Advanced
QLoRA fine-tunes a model whose base weights are held in a quantised, low-precision form (commonly 4-bit) and kept frozen. Instead of updating every weight, it trains small low-rank adapter matrices attached to chosen layers, with gradients flowing through the quantised base into those adapters.
Memory drops sharply because the large base is stored compactly and only the small adapters carry gradients and optimiser state, so a model too big for full training can be tuned on far less hardware. The adapter can be saved and swapped separately. Quality is often reported to be close to ordinary LoRA, but you must still evaluate on your own task.
What the interviewer is checking: Precise understanding of quantised frozen base plus trainable low-rank adapters.
Likely follow-up: What do you lose compared with full fine-tuning?
101How do you reduce hallucinations in an LLM-powered feature?Intermediate
No single switch removes them, so layer the defences. Ground the answer: retrieve source text and instruct the model to use only that. Give it an exit: a retrieval-score floor and an explicit "not found" path. Require citations that you can check against the retrieved passages. Constrain output with schemas or fixed options, and use low sampling randomness for factual tasks.
Then verify and measure: automatic checks that quoted ids exist, human review of samples, and a test set with unanswerable questions so you can track how often it correctly refuses. Add a human step for high-stakes answers.
python def answer(question, hits, floor=0.75): # hits: list of (score, passage_id) from retrieval, best first if not hits or hits[0][0] < floor: return "I could not find this in the documents." return f"Answer drawn from {hits[0][1]}" print(answer("late fee?", [(0.88, "fees-3")])) print(answer("parking rules?", [(0.41, "fees-3")]))Output
Answer drawn from fees-3 I could not find this in the documents.
What the interviewer is checking: A layered mitigation plan with measurement, not a single trick.
Likely follow-up: How would you choose the score floor without guessing?
102A team asks whether to use RAG or fine-tuning for a product assistant. How do you decide?Intermediate
I ask three questions. Is the gap about knowledge or behaviour? Changing, private or citable facts point to RAG; style, format or a narrow skill point to tuning. How often does the data change, and who may see what? Retrieval handles updates and per-user filters at query time, while tuned weights cannot hide content from some users. What is the cost shape? RAG adds retrieval and longer prompts to every request; tuning adds upfront training and upkeep.
I start with prompting plus RAG and an evaluation set, and add tuning only for a measured behaviour gap. They can be combined. Deeper comparison: generative AI interview questions.
What the interviewer is checking: A decision framework built on the type of gap, data churn, access control and cost.
Likely follow-up: Give an example where you would use both together.
Behavioral & Thought Process (6)
103In a team project, how do you describe your own contribution without overclaiming?Beginner
Use "I" for what you personally did and "we" for the team's result. Structure it as one line of context (the system and its goal), your specific responsibility, the two or three actions that were yours (a design you proposed, a module you built, a defect you traced), and the outcome.
Be ready to go one level deeper on anything you mention, because interviewers probe details. Avoid listing everyone's work, and avoid vague verbs such as "helped with". If the result is not measurable, say what changed, such as fewer manual steps, without inventing numbers. See the STAR method guide.
What the interviewer is checking: Clear ownership, honest scope and the ability to defend details.
Likely follow-up: Which part of that project was hardest, and what exactly did you do about it?
104What lessons have you learned from a project that did not go as planned?Beginner
Pick a real, modest setback and tell it in four beats: what happened, which part was yours, what you changed afterwards, and where you have applied that change since. The last beat turns a confession into a lesson.
Good lessons are concrete and behavioural: "I now write the rollback plan before the deployment" beats "communication is important". Do not blame others, do not choose a failure caused by carelessness you would repeat, and do not offer a lesson with no later evidence. Keep it near two minutes.
What the interviewer is checking: Self-awareness, accountability and evidence that you changed your behaviour.
Likely follow-up: How would a teammate describe the same setback?
105Why did you choose that approach? How do you justify a technical decision?Intermediate
Answer in a decision-record shape: the problem and its constraints (deadline, team skills, data volume), the two or three options you genuinely considered, the criteria you weighted, why the chosen one won, and what you gave up. Mention how you validated it, such as a small spike or a benchmark.
"It is the industry standard" or "I knew it best" are inputs, not a full justification. Show that you would revisit the choice if a stated assumption changed, for example if traffic grew tenfold. Honest, constraint-driven reasoning beats a polished-sounding story.
What the interviewer is checking: Structured reasoning about alternatives and the willingness to revisit a decision.
Likely follow-up: What new fact would make you reverse that decision?
106What trade-offs did you consider in a design, and how do you talk about them?Intermediate
Name each tension as a pair: consistency against availability, delivery speed against test depth, one deployable against several services, cost against latency. For each, say what you picked, what it cost, and what would make you revisit it.
Illustrative: a parcel-tracking service might cache status for 30 seconds, accepting slightly stale data to relieve the database; the trigger to revisit would be customers needing live scan results. Tie every choice to a requirement and state the downside plainly. Claiming there were no trade-offs signals shallow analysis.
What the interviewer is checking: Whether you can articulate costs and revisit triggers, not only the benefits of your choice.
Likely follow-up: Which trade-off turned out wrong, and how did you find out?
107What would you consider before putting a service under heavy production load?Advanced
Go through it in order. Know the numbers: requests per second, peak against average, payload sizes. Find the bottleneck by measuring: database queries and indexes, connection and thread pools, downstream calls. Then protect the service with timeouts, retries with backoff, rate limits, caching, back-pressure and a degraded mode.
Prove it with a load test at a multiple of expected peak, and make it operable: dashboards for latency percentiles and error rates, alerts, spare capacity or autoscaling, and safe rollout with rollback. Say what you would measure first rather than reciting tools, and if you have not done this at scale, describe the test you would run.
What the interviewer is checking: A measure-first, protect-then-operate approach to scale.
Likely follow-up: Latency doubles at peak but CPU is low. Where do you look first?
108How do you think through failure scenarios, and how do you tell a production incident story?Advanced
For design questions, list what can fail (a dependency down, slow responses, duplicate messages, partial writes, a bad deploy) and state the behaviour you want for each: timeout, retry, fallback, idempotent handling, alert. For a real incident, follow this order: impact and detection, mitigation first, root cause, permanent fix, then the process or monitoring change.
Keep it blameless and be specific about your own role. Do not invent an outage; if you have none, describe a failure from testing or a near miss. Strong answers end with a prevention that is now in place, such as a runbook or an alert.
What the interviewer is checking: Systematic failure thinking and an honest, blameless incident narrative.
Likely follow-up: How did you decide to mitigate before finding the root cause?
Live Coding (4)
109You are asked to build a CRUD library management system live. How do you plan and start?Intermediate
Spend the first five minutes on scope, not code. Confirm the entities (Book, Member, Loan), the must-have operations (create, read, update and delete books; borrow and return), the storage (in memory or a database) and the language. Say the endpoints aloud: POST /books, GET /books/{id}, PUT /books/{id}, DELETE /books/{id}, then POST /loans and POST /loans/{id}/return.
Build one vertical slice first: model, service, endpoint, one test, running. Then add validation, 404 and 409 (no copies left) handling, and the loan rules. In Spring Boot 3.x that is an entity, a JpaRepository and a @RestController (a sketch, not run here); the Python service below, which was run, shows the shape.
python from dataclasses import dataclass from itertools import count @dataclass class Book: id: int title: str copies: int = 1 class LibraryService: def __init__(self): self._books, self._ids = {}, count(1) def create(self, title, copies=1): if not title.strip() or copies < 1: raise ValueError("title required, copies >= 1") b = Book(next(self._ids), title.strip(), copies) self._books[b.id] = b return b def get(self, book_id): try: return self._books[book_id] except KeyError: raise LookupError(f"book {book_id} not found") from None def update(self, book_id, **changes): b = self.get(book_id) for k, v in changes.items(): setattr(b, k, v) return b def delete(self, book_id): self.get(book_id) del self._books[book_id] svc = LibraryService() b = svc.create("Dune", 2) svc.update(b.id, copies=3) print(svc.get(b.id)) svc.delete(b.id) try: svc.get(b.id) except LookupError as e: print("404:", e)Output
Book(id=1, title='Dune', copies=3) 404: book 1 not found
What the interviewer is checking: Scoping, ordering of work, and a working slice early rather than a big-bang build.
Likely follow-up: Where would you put the rule that stops a book being borrowed when no copies remain?
110You are handed AI-generated code and asked to explain it line by line. How do you handle it?Intermediate
Read the whole thing silently first and state its purpose in one sentence. Then walk top-down in blocks: inputs, main flow, branches, outputs and side effects. Spend your time on lines that carry decisions: conditions, loops, error handling and library calls.
If you meet something unfamiliar, say so and reason from names and types, or settle it with a tiny experiment; do not bluff. Point out anything wrong, risky or missing, such as an unchecked null or an unbounded query, because spotting issues shows ownership. Finish by saying how you would test it.
What the interviewer is checking: Genuine comprehension, honesty about gaps and a reviewer's eye.
Likely follow-up: You spot a bug halfway through your explanation. What do you do?
111You are asked to add a feature to code you did not write. What is your approach?Intermediate
Read before you write: find the entry point, follow one request through the code, note the naming and error-handling conventions, and run the existing tests. Restate the new requirement and ask about edge cases before touching anything.
Make the smallest change that fits the existing structure: add a method or a field rather than reshaping the design, write a failing test first, make it pass, then re-run the old tests. Narrate trade-offs as you go, for example "I will extend rather than refactor because time is short", and mention cleanup you would do later but are not doing now.
What the interviewer is checking: Respect for existing code, test-first habits and communicated trade-offs.
Likely follow-up: The existing code has no tests. How does that change your plan?
112Midway through a live exercise the interviewer changes an API contract. How do you react?Advanced
Treat it as a normal requirement change, not a failure. Pause, restate the new contract in your own words and confirm what is affected: request shape, response shape, status codes or behaviour. Ask whether existing callers must keep working, because that decides between changing in place, versioning (/v2) or adding an optional field.
Then change it in layers, from the contract and tests outward to the handler and the service, rather than patching everywhere. Keep the old tests as a safety net and update only those that encode the old contract. Say aloud what the change costs and what you would document.
What the interviewer is checking: Composure, clarifying questions and a layered, test-backed response to change.
Likely follow-up: How would you roll out that change if real clients already use the old endpoint?
Common Trap Questions (6)
113What happens when a prototype-scoped bean is injected into a singleton bean?Advanced
The trap is expecting a fresh object on every use. The singleton is built once and its dependencies are injected once, so it keeps that single prototype instance for its whole life. Prototype scope only produces a new object when the container is asked, and injection asks exactly once.
Fixes: inject an ObjectProvider and call getObject() per use, use @Lookup method injection, or give the prototype a scoped proxy so each call is delegated to a new instance. If state is per-call, pass it as arguments instead. Spring also does not run destroy callbacks on prototype beans. More in the Spring Boot course.
java // Sketch only (Spring Boot 3.x), not run here @Component @Scope("prototype") class Ticket { final String id = UUID.randomUUID().toString(); } @Service class Desk { private final ObjectProvider<Ticket> tickets; Desk(ObjectProvider<Ticket> tickets) { this.tickets = tickets; } String issue() { return tickets.getObject().id; } // new Ticket each call }What the interviewer is checking: Knowing that scope applies at creation and injection time, plus the standard remedies.
Likely follow-up: What is the difference between ObjectProvider and a scoped proxy here?
114Can a constructor be final in Java?Beginner
No. The compiler rejects it with "modifier final not allowed here". The final modifier stops overriding, and constructors are never inherited or overridden, so it would mean nothing. The same applies to static, abstract and synchronized.
The trap is mixing it up with the goal you probably have. To forbid subclassing, make the class final. To stop a subclass changing one method, make that method final. For immutable state, mark the fields final and assign them inside the constructor. A private constructor blocks instantiation from outside the class.
java public class Bad { final Bad() { } }Output
Bad.java:2: error: modifier final not allowed here final Bad() { } ^ 1 errorWhat the interviewer is checking: Precision about modifiers and knowing the right tool for each intent.
Likely follow-up: Can a constructor be private, and what does that allow?
115If a database transaction fails and rolls back, will an email sent in that method also roll back?Advanced
No. A transaction undoes only what the database controls. An email is an external side effect: once the mail call returns, nothing can unsend it. The reverse also bites: if the mail goes out and the commit then fails, the customer holds a confirmation for an order that does not exist.
Fix: send only after a successful commit, with @TransactionalEventListener(phase = AFTER_COMMIT). For reliability use a transactional outbox: write a pending-message row in the same transaction, and let a separate worker send it, mark it done and retry. Delivery then becomes at-least-once, so keep the send idempotent.
java // Sketch only (Spring Boot 3.x), not run here @Transactional public void place(Order o) { orders.save(o); events.publishEvent(new OrderPlaced(o.id())); // not an email yet } @TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT) void onPlaced(OrderPlaced e) { mailer.sendConfirmation(e.orderId()); }What the interviewer is checking: Understanding transaction boundaries versus external side effects, and the after-commit and outbox fixes.
Likely follow-up: The after-commit mail call itself fails. What guarantees do you have, and what do you add?
116How exactly does Spring create a bean? Is it just calling new?Advanced
The trap is answering "it calls new". First the container reads definitions from component scanning, @Bean methods and configuration classes into metadata called bean definitions; nothing is built yet. When a bean is needed (singletons are normally created at startup), it resolves constructor arguments, instantiates through the constructor or a factory method, then injects remaining dependencies.
After that come Aware callbacks, BeanPostProcessors and initialisation hooks such as @PostConstruct. A post-processor may replace the object with a proxy, which is how @Transactional and AOP work, so the object you receive can be a wrapper rather than your own class. Singletons are cached by name.
What the interviewer is checking: Knowing the definition-then-instantiation lifecycle and where proxies appear.
Likely follow-up: Why can @Transactional fail when a method calls another method on the same object?
117What can break a Java Singleton, and how do you defend against each?Advanced
A hand-written singleton can be broken by anything that creates instances behind its back: reflection calling the private constructor, deserialization building a fresh object, cloning when the class is Cloneable, several class loaders each holding their own copy, and unsafe lazy initialisation racing on first use. In Spring, "singleton" means one per container, so two contexts give two.
Defences: a single-element enum, which resists both reflection and serialization; readResolve on a serializable class; a constructor that throws if an instance exists; and a holder class for thread-safe lazy loading. The snippet, which was run, shows the first two attacks succeeding.
java import java.io.*; import java.lang.reflect.Constructor; public class Registry implements Serializable { private static final Registry INSTANCE = new Registry(); private Registry() {} public static void main(String[] args) throws Exception { Constructor<Registry> c = Registry.class.getDeclaredConstructor(); c.setAccessible(true); System.out.println("reflection: " + (c.newInstance() != INSTANCE ? "second instance" : "same")); ByteArrayOutputStream bos = new ByteArrayOutputStream(); try (ObjectOutputStream out = new ObjectOutputStream(bos)) { out.writeObject(INSTANCE); } Object copy = new ObjectInputStream(new ByteArrayInputStream(bos.toByteArray())).readObject(); System.out.println("deserialization: " + (copy != INSTANCE ? "second instance" : "same")); } }Output
reflection: second instance deserialization: second instance
What the interviewer is checking: A complete list of singleton-breaking paths and a matching defence for each.
Likely follow-up: Why does a single-element enum resist reflection?
118Can AI replace conceptual understanding for an engineer?Intermediate
No, and the trap is equating speed with understanding. A model produces plausible code; it cannot know your system's constraints, and you cannot review what you do not understand. Without the concepts you will not notice that a generated singleton is not thread-safe, that a transaction does not cover an email, or that an index is missing.
The fix is to use AI to accelerate work you could explain and to explain things back to you, then verify with tests and primary documentation. Practise by predicting what code will do before running it. In a live round, be ready to justify every line you accepted.
What the interviewer is checking: Whether you see AI as an accelerator that still depends on your own judgement.
Likely follow-up: Give an example where a fluent AI answer would have misled someone lacking the basics.
Go deeper by topic
The topic question banks cover the same ground with more questions at every level.
Fill the gaps with a free course
- Java
- Advanced Java
- Spring Boot
- Microservices Architecture
- Apache Kafka
- Redis
- System Design
- Docker
- Kubernetes
- AWS Fundamentals
- Large Language Models
- Retrieval-Augmented Generation
Applying for roles like this? Browse open jobs or upload your resume to see which ones match your skills.