Interview guides · Auto & General Insurance
Auto & General Insurance Software Engineer Interview Guide
Auto & General Insurance Software Engineer interview guide: Java 8-11, Spring Boot, memory leak debugging, performance questions and a 7-day plan.
The 60-second brief
Auto & General Insurance sells a suite of insurance products, and candidates describe the Software Engineer role as building and maintaining the digital platforms through which customers deal with those products. The reported stack is Java 8-11 with Spring Boot on the backend, with frontend work in AngularJS listed as a plus. Day to day, engineers are described as covering the whole lifecycle of a feature, from clarifying requirements and design through writing, testing and debugging, and as working alongside IT Operations and Product colleagues. The work is described as project-based, with specific features and tasks assigned to an engineer.
This guide is for Software Engineer candidates preparing for the Auto & General Insurance loop. It covers the four reported stages (Initial Screening, Technical Assessment, Phone Screens, Video Interviews), the reported Java and Spring Boot questions, the performance and pseudo-code questions, the four reported background questions, and a seven-day plan that moves from fundamentals to spoken practice.
Candidates report four stages over roughly 3-5 weeks: Initial Screening, Technical Assessment, Phone Screens and Video Interviews. Some candidates say the stages were compressed into a few days.
Focus areas
- Java
- Spring Boot
- Performance Optimization
Overview
The role as candidates describe it is broader than writing Java. The work runs from clarifying requirements, through design, coding and testing, to debugging, with regular contact with IT Operations and Product colleagues. Backend work in Java and Spring Boot is the core, and some frontend work, with AngularJS named as a plus, is reported. In practice, have a story for each stage of that lifecycle, including one where you worked with an operations or product counterpart, and be ready to say which parts of the stack you have touched and which you would learn on the job.
The reported technical questions cluster around Java fundamentals and the reasoning behind them: how to debug a memory leak, why a team would adopt Spring Boot, what the transient keyword means, how equals and hashCode relate, and whether you are comfortable with Java 8-11 features. Two further questions are about performance: how you would minimise performance implications, and how you would explain an algorithm or write pseudo-code for a performance scenario. Do not settle for definitions. For each topic, prepare a small runnable example you can describe from memory, such as a HashMap that loses entries because a key's hashCode changed, or a heap dump that points at a cache that never evicts.
Communication is a stated part of the loop. Candidates report that explaining your thinking, using diagrams, trade-offs and pseudo-code before implementation, matters as much as the code, and that a technical task or project may be part of the Technical Assessment. Four background questions are also reported: your current day-to-day, why you are leaving, your most memorable achievement and the working environment you want. Treat them as one connected story and rehearse them aloud. Candidates also say the requirements favour experience that matches the listed stack, so make sure your CV shows Java 8-11, Spring Boot and any frontend work in terms a reader can verify.
The Auto & General Insurance interview process
Candidates describe four stages, usually quoted as 3-5 weeks end to end, though some report finishing within days. The descriptions below cover what each stage is reported to involve and how to prepare for it.
Initial Screening
Candidates describe the Initial Screening as the opening stage, where fit for the role is checked. Reports also say that a question about what you already know of the company is a common way for interviews to start. Treat it as your chance to present a short, accurate account of your Java and backend experience and to show you have read the role's requirements: Java 8-11, Spring Boot, backend architecture, and AngularJS or other frontend work as a plus. Prepare a concise career summary, a reason for choosing this role, and a few facts about the company drawn from its public website rather than guesses.
What to demonstrate
- Fit for the role as described in the requirements
- How clearly you summarise your background and recent work
- How well your stack experience lines up with Java 8-11 and Spring Boot
How to prepare
- Write a short career summary that names the Java version and Spring Boot projects you have shipped, and say what you owned in each.
- Read the company's public site and prepare two or three facts about its insurance products, plus one question about the team.
- Rehearse the four reported background questions (day-to-day, leaving, achievement, working environment) so your first answers are calm and consistent.
Technical Assessment
The Technical Assessment is reported as a more intensive stage that may include a technical task or project, described as a practical simulation of the work in the role. If a task is set, the code is part of what is judged, and so is how you explain it. Prepare by building something small in Java and Spring Boot from scratch (a REST endpoint with validation, a service layer, a couple of tests) so the structure is familiar, and by revising the Java fundamentals candidates report: transient, equals and hashCode, Java 8-11 features and memory leaks.
What to demonstrate
- Working, readable Java if a task or project is set
- Command of Java fundamentals and the reasoning behind them
- Ability to explain design choices and performance trade-offs
How to prepare
- Build a small Spring Boot service with a controller, a service class and unit tests, and be ready to say why each piece sits where it does.
- Practise the transient and equals/hashCode answers with a short program that demonstrates each behaviour.
- Write a one-page list of Java 8-11 features you have used, with a code line for each.
Phone Screens
Phone Screens are reported as a combination of calls with technical leads and support staff. A phone call means you cannot rely on a whiteboard, so practise describing structure in words: name the components, say how data flows between them, and state the complexity out loud. Because the conversation includes more than one kind of colleague, prepare both a technical version and a plain-language version of the same explanation, for example of what a memory leak is and how you would find it.
What to demonstrate
- Spoken explanation of technical ideas without visual aids
- Java and Spring Boot knowledge discussed in conversation
- Clarity when explaining the same idea to different colleagues
How to prepare
- Record yourself explaining how you would debug a Java memory leak, then replay it and cut any step you cannot justify.
- Prepare a two-level explanation of Spring Boot: a plain-language one and a technical one covering auto-configuration, starters and the embedded server.
- Have a short, honest answer ready for any tool you have not used, covering how you would learn it and which of your skills transfer.
Video Interviews
Video Interviews are reported to assess technical skills and company culture fit together. Reports say that explaining your approach with diagrams, trade-offs and pseudo-code before implementing is part of the technical conversation, and that the background questions about your day-to-day, your reasons for leaving, your best achievement and your preferred working environment belong to the wider loop. On video you can sketch: practise drawing a request path or a data flow while you talk, and have your behavioural stories ready in a structure you can deliver without notes.
What to demonstrate
- Technical skills, as stated for this stage
- Culture fit, as stated for this stage
- Use of diagrams and pseudo-code to explain a performance-related approach
How to prepare
- Practise sketching a performance scenario (where time or memory goes, what you would measure, what you would change) while speaking.
- Write the four background stories as short outlines: situation, your decision, the result, what you would change.
- Prepare questions about the team, its projects and how engineers work with IT Operations and Product.
Where candidates lose points
Defining transient or the equals/hashCode contract without showing what goes wrong when it is broken
For each, keep a two-line example ready. For transient, show a field that is null or zero after serialization and deserialization. For equals and hashCode, show an object with equals overridden but not hashCode being lost in a HashMap or HashSet, and state the contract: equal objects must have equal hash codes.
Answering the memory-leak question with a restart or a vague mention of profilers
Give a sequence: confirm the symptom through heap growth after full garbage collections, capture a heap dump, find the dominant retainer in a tool such as Eclipse MAT or VisualVM, and name the usual culprits (an unbounded static cache, listeners never removed, ThreadLocals on pooled threads). Finish by saying how you would verify the fix.
Explaining Spring Boot as popular, or as what the team already uses
Name what it removes or provides: starter dependencies, auto-configuration, an embedded server so the service runs as a plain jar, externalised configuration and production endpoints such as health checks. Be ready to say when a lighter option would be enough.
Saying you are comfortable with Java 8-11 features but being unable to name any
Keep a short list by version and use each item in code: lambdas, streams, Optional and java.time from 8; factory methods such as List.of from 9; var from 10; new String methods and the standard HTTP client from 11. State where you would not use streams.
Jumping to code on a performance question without saying where the time or memory goes
Start with the measurement: what you would profile or time, the suspected hotspot, the brute-force cost and the target cost. Sketch the data flow and write pseudo-code first, then fix and re-measure. Candidates report that explaining the reasoning is part of the exercise.
Questions & practice
Can you explain your algorithm or write pseudo-code for a performance-related scenario?
Medium · Problem-Solving & Architecture
Approach
- Restate the input before writing pseudo-code: its size, whether it is sorted, whether it fits in memory, and whether it is one batch or a stream. Then give the brute-force version and its cost, for example comparing every pair in O(n^2) to find duplicates or matching pairs.
- Choose the data structure from the access pattern. HashMap/HashSet give O(1) average lookups, so duplicate or pair problems become O(n) time with O(n) space. Sorting plus two pointers is O(n log n) with little extra memory. A size-k PriorityQueue gives top-k in O(n log k). A sliding window handles contiguous ranges. Binary search is O(log n) on sorted data.
- Write the pseudo-code as named steps, then trace a small example aloud. Cover the edge cases: empty input, a single element, duplicates, ties, and integer overflow (use long for running sums in Java).
- State the final time and space complexity and the trade-off you chose. Add Java-specific costs: boxing in HashMap<Integer,Integer> compared with primitive arrays, StringBuilder instead of string concatenation in a loop, and setting an initial capacity so a large HashMap does not rehash repeatedly.
- Say what changes at scale. If the data does not fit in memory, sort in chunks and merge (external sort), or stream it through a bounded heap or counter, so memory stays fixed regardless of input size.
Follow-up
- The input becomes a stream too large for memory. What changes in your algorithm?
- Can you cut the extra space to O(1), and what does that cost in time?
- Which test cases would you write to show the optimised version gives the same results as the brute-force one?
Track a rolling failure rate per destination for circuit decisions
Easy · sliding window · ring buffer · circuit breaker
The egress service delivers about 1,500 webhooks per second across roughly 40,000 destinations, each call bounded by a 10 second timeout. Maintain, per destination, the failure rate over the trailing 60 seconds so a caller can ask before dispatch whether the circuit should open. Attempts arrive as (destination_id, finished_at_ms, outcome). Requirement: amortised O(1) per attempt, with total memory bounded by the destination count rather than by traffic. Give the structure, its exact memory, and the rule that stops a destination with three attempts from opening a circuit.
Approach
- Name the exact-deque version and then reject it as the default. Holding timestamps and advancing a tail pointer past anything older than now minus 60 seconds is a correct two-pointer window at amortised O(1) per attempt, but its memory tracks in-window traffic, so one destination in a retry storm holds hundreds of thousands of entries while thousands of quiet destinations hold none.
- Use a ring of 60 one-second buckets per destination, each bucket a pair of counters for attempts and failures. On an attempt, advance the ring by the elapsed whole seconds, zeroing at most min(elapsed, 60) buckets, then increment the head. That is amortised O(1) with a fixed footprint per destination.
- State the footprint: 60 buckets times two 4-byte counters is 480 bytes of payload per destination, so 40,000 destinations is roughly 20 to 25 MB with per-entry overhead, bounded by the catalogue rather than by the rate. The cost is granularity, since the oldest bucket ages out in whole seconds, which is far tighter than the decision needs.
- Require a minimum sample before the circuit may open. A destination with three attempts and three failures reads as 100 percent and is not evidence; a floor of roughly 20 attempts in the window makes the ratio meaningful, and below that floor use a run of consecutive failures as the trigger instead.
Follow-up
- The fleet is 30 instances and each sees roughly a thirtieth of a destination's traffic. Where does the rate actually live, and what does a per-instance answer get wrong?
- A destination answers in 9.5 seconds and succeeds. It is not failing but it is consuming your per-destination concurrency. What signal should open the circuit here?
Canonicalise a request body into a stable idempotency fingerprint
Medium · parsing · canonicalisation · hashing
idempotency_key.request_fingerprint is a SHA-256 over the method, path and canonicalised body, and a retry whose fingerprint differs must be rejected with 422 rather than served the stored response. Write the canonicaliser. Bodies are JSON up to 256 KB nested at most 32 levels; clients vary key order, whitespace and unicode escaping, and some send 64-bit ids as JSON numbers. Produce a deterministic byte string such that semantically identical bodies match and any semantic difference does not. State your complexity and name two normalisations you refuse to perform.
Approach
- Parse once into a tree, then re-serialise under fixed rules: object keys sorted, array order preserved, one escaping convention, no insignificant whitespace. Parsing is O(n) and sorting keys is O(k log k) per object, so O(n log n) overall with O(depth) stack, and the 32-level cap is enforced during parsing because hostile nesting is how a canonicaliser becomes a stack overflow.
- Sort keys by their UTF-8 bytes and say why the obvious implementation is wrong in some runtimes: a default string comparison that orders by UTF-16 code units places surrogate pairs, meaning code points from U+10000 up, below U+E000 to U+FFFF, which is not UTF-8 byte order, so two services written in different languages disagree on the same document.
- Do not re-encode numbers through a double. IEEE-754 binary64 represents integers exactly only up to 2^53, so normalising a 19-digit id through a float changes it, and 1 against 1.0 cannot be reconciled without deciding whether they are the same value. Preserve the literal token, and require ids as strings at the API boundary if you want them comparable.
- Reject duplicate keys rather than picking one. JSON permits them and parsers disagree, most keeping the last, so any choice you make ties the fingerprint to a parser detail that the code handling the request does not necessarily share.
Follow-up
- A client sends the same logical request with an extra field your API ignores. Same key, different fingerprint, so you return 422. Is that the right answer?
- Where does the fingerprint get computed relative to request decompression and the body-size limit?
Explain why the owner filter ignores the listing index
Medium · composite index · query plans · sort elimination
The only index on resource is (tenant_id, status, updated_at DESC, resource_id DESC). A new endpoint returns one user's resources across all statuses, newest created first: WHERE tenant_id = $1 AND owner_user_id = $2 ORDER BY created_at DESC LIMIT 20. On a tenant with 2M rows it takes 900 ms and EXPLAIN shows a sort above a large scan. Explain precisely why the existing index cannot serve it, give the index that can, and state which of these the new index still will not help: owner_user_id alone across tenants; the same query ordered by updated_at. PostgreSQL 16.
Approach
- Separate the two jobs an index does. For filtering, a composite btree is seekable only on a left prefix, so with no predicate on status the scan can at best range over tenant_id and test owner_user_id per row; PostgreSQL 16 has no btree skip scan to jump the unconstrained column.
- For ordering, the index is sorted by (status, updated_at) within a tenant and not by created_at, so the LIMIT cannot stop early: every matching row is read and then sorted. That is the 'Sort Method: top-N heapsort' line, and it is why the plan reads 2M rows to answer with 20.
- Derive the replacement from the access path — equality, equality, then the ordering column: CREATE INDEX CONCURRENTLY ON resource (tenant_id, owner_user_id, created_at DESC). The scan seeks to the (tenant, owner) range and walks 20 entries in order, so the Sort node disappears along with the row-read.
- Treat INCLUDE (title, status) as conditional, not free. An index-only scan still visits the heap for any row whose page is not marked all-visible, so on a table taking 1.2k writes/second the win depends on autovacuum keeping the visibility map current, and the wider index costs more on every insert.
Follow-up
- 90% of rows are status='active'. Would a partial index WHERE status = 'active' change your answer, and for which of the three queries?
- A dashboard runs this for 40 owners in one page load. What changes about the design?
Replace offset paging on the resource feed with keyset
Easy · keyset pagination · composite index · sort order
resource holds resource_id, tenant_id, owner_user_id, title, body_ref, version, status ('draft','active','archived','deleted'), created_at, updated_at, deleted_at, with an index on (tenant_id, status, updated_at DESC, resource_id DESC). The listing endpoint returns active resources for one tenant, newest update first, 50 per page, today with LIMIT 50 OFFSET n. Tenants reach page 400 and rows are created while they read. Write the keyset query, define what the cursor carries and how it is encoded, and say which part of the index each predicate uses. Assume PostgreSQL 16.
Approach
- Name the two failures separately. OFFSET 20000 makes the server produce and discard 20,000 rows, so page cost grows with depth rather than with page size. Independently, any write that changes how many rows sort above the offset moves the window between two fetches, and the direction decides which anomaly you get: an insert lands at the head of updated_at DESC and pushes already-returned rows down past the boundary, so they are returned a second time; a delete above the offset, or a row whose updated_at is bumped above the cursor, pulls rows up and one is never returned at all. Nothing in the response reveals either.
- Write the seek: WHERE tenant_id = $1 AND status = 'active' AND (updated_at, resource_id) < ($2, $3) ORDER BY updated_at DESC, resource_id DESC LIMIT 50. The row-value comparison is one index range rather than a disjunction, and both columns are NOT NULL, which is what makes that comparison well defined.
- Map each predicate onto the index: tenant_id and status are equality on the leading columns, (updated_at, resource_id) is the range, and the ORDER BY matches the index order so no Sort node appears and the scan stops after 50 rows. The DESC in the definition only matters for mixed directions — a plain ascending btree on the same columns is read backwards for this query.
- Put both sort columns in the cursor and nothing the client can tamper with into another tenant: base64 of (updated_at, resource_id), validated server-side, with tenant_id taken from the principal.
Follow-up
- The client asks for 'jump to page 400'. What do you offer instead, and what does the honest version cost?
- Sort order becomes user-selectable across four columns. How many indexes is that, and which would you refuse to add?
Why do we need to use SpringBoot?
Medium · Technical Proficiency & Java Expertise
Approach
- Separate the two layers. Spring Framework supplies the IoC/dependency-injection container, Spring MVC and declarative transactions. Spring Boot is an opinionated layer on top that removes most of the wiring and setup work.
- Name what Boot actually adds. Auto-configuration creates beans based on conditions such as @ConditionalOnClass and @ConditionalOnMissingBean. Starters pull in dependency versions that are known to work together. An embedded server (Tomcat by default with spring-boot-starter-web) is packaged into an executable jar you run with java -jar.
- Cover operations. Externalised configuration (application.yml, profiles, environment-variable overrides, @ConfigurationProperties) lets one artifact run in every environment. Actuator exposes health, info and Micrometer metrics endpoints for monitoring.
- Give a concrete example. Adding spring-boot-starter-data-jpa plus spring.datasource.* properties gives you a configured DataSource, connection pool (HikariCP since Boot 2.0) and EntityManager without writing any of those beans yourself.
- State the trade-offs. Auto-configuration can hide what is wired: the conditions report (--debug, or Actuator's conditions endpoint) shows it. Defining your own bean makes Boot's default back off. Startup time and memory are heavier than with minimal frameworks.
Follow-up
- How does auto-configuration decide whether to create a bean, and where are auto-configuration classes registered (spring.factories before 2.7, AutoConfiguration.imports from 2.7)?
- How would you turn off one auto-configuration, for example DataSourceAutoConfiguration?
- Why prefer constructor injection over field injection in a Spring Boot service?
What is the meaning of the keyword transient?
Medium · Technical Proficiency & Java Expertise
Approach
- Define it precisely. transient marks an instance field to be skipped by default Java serialization (Serializable written through ObjectOutputStream). The field's value is not written to the byte stream.
- Explain what happens on deserialization. Constructors and field initialisers of the serializable class do not run (only the no-arg constructor of the first non-serializable superclass does), so a transient field comes back as its default: null, 0 or false.
- Give the use cases: values derived from other fields or cached, references that cannot be serialized (Logger, Thread, a DB connection), and secrets such as passwords that should never reach the stream.
- Show how to rebuild the field. In a private readObject(ObjectInputStream in), call in.defaultReadObject() and then recompute the transient value. For full control, implement Externalizable instead. Also mention declaring serialVersionUID.
- Cover the edge cases. static fields are never serialized, so transient adds nothing to them. A transient final field cannot be reassigned in readObject without reflection. Other frameworks differ: JPA treats a Java-transient field as not persistent, Gson skips transient fields by default, and Jackson can still output the value through a getter.
Follow-up
- What value does a transient int field hold after deserialization, and why does its initialiser not run?
- How would you serialize a class that holds a reference to a non-serializable object you still need afterwards?
- How does the transient keyword differ from JPA's @Transient annotation?
What is the relationship between equal and hashCode?
Medium · Technical Proficiency & Java Expertise
Approach
- State the contract. If a.equals(b) is true, then a.hashCode() == b.hashCode() must hold. The reverse is not required, because collisions are allowed. hashCode must also stay the same while the fields equals uses do not change. equals itself must be reflexive, symmetric, transitive, consistent, and return false for null.
- Explain why it matters through HashMap. A lookup hashes the key (h ^ (h >>> 16)) to pick a bucket, then compares the entries in that bucket with equals. If you override equals but not hashCode, two equal keys land in different buckets, so get() returns null and a HashSet keeps duplicates.
- Implementation: build both methods from the same fields, using Objects.equals and Objects.hash (accept the boxing cost or hand-roll for hot paths). Choose getClass() vs instanceof deliberately, since instanceof can break symmetry with subclasses that add state. Arrays need Arrays.equals and Arrays.hashCode.
- Pitfalls: changing a field used in hashCode after inserting the object as a key makes it unreachable, which is effectively a leak. A JPA entity with a generated id has a null id before persist. A constant hashCode is legal but puts every key in one bucket.
- Performance: with a good hash, get and put are O(1) on average. Since Java 8, a bucket holding 8 or more entries in a table of at least 64 buckets is turned into a red-black tree, which limits the worst case (best when keys are Comparable).
Follow-up
- What happens if you put two equal objects into a HashSet when only equals is overridden?
- Should a JPA entity's equals and hashCode use its database-generated id? What breaks if they do?
- Why should compareTo be consistent with equals when you use a TreeSet or TreeMap?
Are you comfortable answering questions regarding Java 8–11 features?
Medium · Technical Proficiency & Java Expertise
Approach
- Answer yes, then structure the answer by release. Java 8: lambdas, functional interfaces (Function, Predicate, Supplier, Consumer), method references, the Stream API (lazy intermediate operations, Collectors.groupingBy), Optional, default and static interface methods, java.time (immutable LocalDate, Instant, ZonedDateTime) and CompletableFuture.
- Java 9: the module system (module-info.java); List.of/Set.of/Map.of, which are immutable and reject nulls; private interface methods; jshell; Stream takeWhile/dropWhile; Optional.ifPresentOrElse, or and stream. G1 also became the default collector in Java 9.
- Java 10: var for local variables only (it needs an initialiser and cannot be used for fields or parameters), List.copyOf, Collectors.toUnmodifiableList and no-arg Optional.orElseThrow(). Java 11 (LTS): the standard java.net.http HttpClient, String isBlank/strip/lines/repeat, Files.readString/writeString, Predicate.not, Optional.isEmpty, var in lambda parameters, and running a single source file with java Foo.java.
- Give a production example for two or three of these, such as replacing a loop of map updates with groupingBy, or moving from Date/Calendar to java.time. Name the migration gotcha: Java 11 removed the Java EE and CORBA modules (JAXB, JAX-WS), so those must be added back as dependencies.
- Show you know the pitfalls: side effects inside stream lambdas, Optional used as a field or parameter type, and parallel streams running blocking I/O on the shared ForkJoinPool common pool.
Follow-up
- What is the difference between map and flatMap on a Stream, and on an Optional?
- Why can Optional.orElse(createDefault()) be costly where orElseGet(this::createDefault) is not?
- What broke, or what would you check, when moving a service from Java 8 to Java 11?
How would you solve a problem to minimize performance implications?
Medium · Problem-Solving & Architecture
Approach
- Pin down the target before changing anything: which metric matters (p95/p99 latency, throughput, memory, cost) and at what load. Reproduce the problem with a load test and profile with Java Flight Recorder or async-profiler instead of guessing. Use JMH only for isolated micro-benchmarks.
- Fix complexity and data access first. Replace nested-loop O(n^2) matching with a HashMap lookup (O(n)). Remove N+1 queries in JPA with a join fetch, @EntityGraph or batch fetching. Add an index that matches the WHERE and ORDER BY. Page through large result sets instead of loading them whole.
- Then cut repeated work: cache stable reads (Spring @Cacheable backed by Caffeine with a size limit and TTL), batch inserts and updates, and size the connection pool deliberately. State the cost: a cache trades memory and staleness for speed, and needs an invalidation rule.
- Take slow, non-essential work off the request path with a queue, or @Async/CompletableFuture on a bounded executor. Put timeouts on every downstream call so one slow dependency cannot use up all your threads.
- Verify with the same load test before and after, watch GC pauses and allocation rate, and keep the correctness tests green. In the interview, sketch the request path as a diagram and mark where each change applies.
Follow-up
- A single endpoint is slow only in production. How do you find the bottleneck without reproducing it locally?
- When does adding a cache make performance or correctness worse?
- How would you stop the improvement from regressing in later releases?
How to debug a Java memory leak?
Medium · Technical Proficiency & Java Expertise
Approach
- First confirm it really is a leak. Turn on GC logging (-XX:+PrintGCDetails on Java 8, -Xlog:gc* on 9+) and check whether old-gen occupancy after each full GC keeps rising. A heap that is too small plateaus. Read the OutOfMemoryError message too: 'Java heap space', 'Metaspace' and 'Direct buffer memory' each point somewhere different.
- Capture evidence: start with -XX:+HeapDumpOnOutOfMemoryError and -XX:HeapDumpPath, or take dumps on demand with jcmd <pid> GC.heap_dump or jmap -dump:live,format=b,file=heap.hprof <pid>. Take two dumps some time apart, or compare jmap -histo:live counts, to see which classes keep growing.
- Analyse the dump in Eclipse MAT. Use the dominator tree to find the largest retained sizes, then Path to GC Roots (excluding weak and soft references) to find what keeps the growing objects reachable. The bug is that reference chain, not the objects themselves.
- Name the usual culprits. A static Map or cache with no eviction. HashMap keys whose equals/hashCode are missing or use mutable fields. ThreadLocals in pooled threads that are never removed. Listeners or resources that are registered and never released. Classloader leaks after redeploys, which show up in Metaspace.
- Fix the root cause, for example a bounded Caffeine cache with maximumSize/expireAfterWrite or ThreadLocal.remove() in a finally block. Then run the same load again and check that post-GC heap stays flat, rather than just raising -Xmx.
Follow-up
- How do you tell a real leak from a heap that is simply sized too small for the workload?
- Taking a heap dump pauses a large production JVM. How would you collect evidence safely, for example by draining one instance or using Java Flight Recorder's old-object sampling?
- The process RSS keeps growing but the heap looks flat. Where do you look next (Native Memory Tracking, direct buffers, thread stacks)?
Suggested practice checklist
The plan starts with a map of the four reported rounds, then spends one day each on the reported Java topics, Spring Boot, memory-leak debugging and performance, and finishes with spoken rehearsal of the four background answers. Each day ends with something you can produce.
Day 1 — Map the loop and match your CV to the stack
- List the four reported rounds (Initial Screening, Technical Assessment, Phone Screens, Video Interviews) and write what you need ready for each, including a plain-language and a technical way to describe your work.
- Make a table of the requirements candidates describe (Java 8-11, Spring Boot, backend architecture, AngularJS and frontend as a plus) against a project or example from your own work for each.
- Mark the three cells with the weakest evidence; those set the order of the rest of the week.
Deliverable: A one-page loop map and a requirement-to-evidence table with the three weakest items marked.
Day 2 — transient and the equals/hashCode contract
- Write a Serializable class with a transient field, serialize it, read it back and note which values survive. Add a note on when transient is the right choice and what happens to static fields.
- Write a class with equals overridden but not hashCode, use it as a HashMap key, and show the lookup failing. Fix it with Objects.equals and Objects.hash, then mutate a key field after insertion and show why that also breaks lookups.
- Say each explanation aloud, covering the contract, the example and the consequence.
Deliverable: Two short runnable programs and a spoken answer for each of the transient and equals/hashCode questions.
Day 3 — Java 8-11 features you can use in code
- Build a sheet by version: lambdas, streams, Optional, default methods and java.time from 8; factory methods such as List.of and private interface methods from 9; var from 10; String methods such as isBlank and strip and the standard HTTP client from 11.
- Rewrite one loop-heavy method with streams, then write down a case where the loop stays because it is clearer or faster.
- Prepare a spoken answer to whether you are comfortable with Java 8-11 features, naming one feature you have used in production and why.
Deliverable: A version-by-version feature sheet with a code line for each item, plus one stream rewrite with a note on its limits.
Day 4 — Spring Boot: what it provides and why teams use it
- Build a small Spring Boot service with starter-web, a controller, a service class, a configuration property and a health endpoint, then run it as a plain jar.
- Write a short answer on why Spring Boot is used, covering starters, auto-configuration, the embedded server, externalised configuration and production endpoints, and one case where it would be more than you need.
- Add two unit tests and a test of the controller, and note what each one protects.
Deliverable: A running Spring Boot service with tests and a written answer on why teams adopt Spring Boot.
Day 5 — Debug a memory leak and reason about performance
- Create a deliberate leak: an unbounded static map, a listener never removed, or a ThreadLocal on a pooled thread. Watch heap use rise after garbage collections.
- Capture a heap dump (jcmd or jmap), open it in Eclipse MAT or VisualVM, and find the object retaining the memory.
- Write the sequence as a checklist you could say aloud: measure, profile, find the hotspot, change one thing, measure again, and apply it to the question about minimising performance implications.
Deliverable: A leak program, the heap-dump finding that identifies its retainer, and a spoken measure-profile-fix-verify checklist.
Day 6 — Algorithm and pseudo-code for a performance scenario
- Choose a scenario such as finding duplicate records in a very large list or paging through a big result set. Write the brute-force version, its complexity and the improved pseudo-code with the data structure chosen and why.
- Draw the data flow as a diagram and explain it aloud as you would on a phone call.
Deliverable: Brute-force and improved pseudo-code with complexities, one diagram, and two completed practice exercises.
Day 7 — Background answers and a full mock
- Write four outlines: current day-to-day, reason for leaving, most memorable achievement, and preferred working environment. Check that they tell one consistent story.
- Say each answer aloud and cut anything that is vague or that you could not back up with an example.
- Run a mock of the loop: one spoken technical answer from each earlier day, then the four background answers, then your questions for the team.
Deliverable: Four story outlines and one recorded mock covering a technical answer per day and the background answers.
Background and motivation answers
The reported background questions cover your current day-to-day, your reason for leaving, your most memorable achievement and the working environment you want. Candidates also report that the video interviews assess culture fit, so aim for answers that are specific, honest and consistent with each other.
- What do you know about Auto & General Insurance and why this role?
- Tell me about a time you explained a technical decision to a colleague who was not an engineer.
Describe what your day-to-day is like in your current position.
Medium · Behavioral & Background
Approach
- Open with one sentence of scope: your team, the system you work on and its stack, for example Java services behind a REST API, so the rest of the answer has context.
- Describe a typical week as a mix of activities: building features, reviewing code, debugging production problems, and talking to product or operations colleagues. Then pick one recent ticket and walk it from requirement to release, naming the decision you personally made.
- Cover the lifecycle stages the role is described as including: clarifying requirements, design, testing, debugging, and working with IT Operations and Product. If your current job covers fewer of them, say which ones you want more of.
- Use concrete nouns such as services, endpoints, queries and tools. Reciting your job title or a list of meetings, or claiming ownership of work you only reviewed, makes the answer vague or unverifiable.
- Close by connecting to the target role: Java backend work with some frontend, delivered as specific features. If your day-to-day differs, name the overlap instead of stretching the match.
Follow-up
- What is the most recent production issue you handled, and how did you find the cause?
- Which part of your current work do you enjoy least, and why?
- How do you decide what to work on first when several requests arrive?
Why did you decide to leave your current job?
Medium · Behavioral & Background
Approach
- Lead with what you are moving toward, not what you are leaving: for instance, more ownership of backend Java systems or closer contact with production. Say it only if it is true, since the follow-up questions will test it.
- Give one concrete, checkable reason (scope of work, stack, growth path, location or a change in the company) and one sentence on what you tried first, such as asking for a different project or moving teams.
- Never criticise named people or your employer. If the real cause was a conflict, describe it as a mismatch in working style and say what you learned from it.
- Keep this answer consistent with your achievement story and your preferred working environment, because the three should read as one coherent account of what you want.
- Tie the reason to this role: say which part of the Java, Spring Boot and backend work answers the motivation you just gave.
Follow-up
- Did you raise this with your manager before deciding, and what happened?
- What would make you leave the next job for the same reason?
- What would you want to be different in your next role?
What was the most memorable achievement you've done in your work life, and why was it impressive?
Medium · Behavioral & Background
Approach
- Choose an achievement you can describe at engineering level, with a measurable change: a memory leak you traced, a slow endpoint you sped up, a migration you completed. Use only something you really did.
- Use situation, task, action, result, but spend most of the time on the action: what options you weighed, what you rejected and why, and what you built or changed yourself.
- Quantify the result with the measure you actually used, such as latency before and after, heap usage, error counts or release time, and say how you confirmed your change caused the improvement.
- Explain why it was impressive by naming the constraint: a deadline, legacy code, unclear requirements or scale. Use I for your own contribution and name teammates for theirs, so your role is clear.
- The mistake that sinks this answer is a small win with no numbers, or a team result in which your own part is impossible to identify.
Follow-up
- What exactly did you do versus the rest of the team?
- What went wrong along the way, and how did you recover?
- How would you approach the same problem now?
What kind of working environment are you looking for?
Medium · Behavioral & Background
Approach
- Describe the environment in observable terms: how requirements reach you, how code review works, how often you release, how much you work with other functions, and how disagreements and feedback are handled.
- Back each preference with a past example, for instance: I do my best work when operations and product join the conversation before release, and on my last project involving them early removed a late rework.
- Name one trade-off you accept, such as a fast pace with less documentation. It shows a realistic view and keeps the answer from reading as a wish list no workplace could meet.
- Connect to what candidates report for this role: work alongside IT Operations and Product, and feature work delivered project by project. Mention only what you found in your own research, and do not claim knowledge of the culture you have not verified.
- Avoid generic answers such as good culture or great people. They give nothing to follow up on and could be said to any employer.
Follow-up
- Tell me about a time the environment did not suit you, and what you did about it.
- How do you work with colleagues in operations or product when their priorities differ from yours?
- What do you do when requirements are unclear?