Interview guides · American Airlines
American Airlines Software Engineer Interview Guide
American Airlines Software Engineer interview guide: the three reported rounds, OOP, Java runtime, coding and Azure design questions, and a 7-day plan.
The 60-second brief
American Airlines is an airline, and the Software Engineer role candidates describe covers the software around it: customer-facing mobile apps and booking engines, plus backend systems for flight operations, crew scheduling and baggage routing. Reports describe teams moving older on-premise applications onto service-oriented, cloud-hosted designs, with Microsoft Azure named most often and AWS also mentioned. The languages listed for the role are Java, C#, JavaScript, TypeScript and Python, with PostgreSQL or SQL Server as the relational databases. Day to day, candidates describe building and testing features, migrating legacy systems, maintaining CI/CD pipelines, setting up monitoring and alerting, joining production incident troubleshooting, and writing design and API documentation. Work runs in Agile sprints alongside product managers, UX designers and other engineering teams, and code review and pair programming are mentioned as regular practice.
This guide is for candidates preparing for the American Airlines Software Engineer loop. It covers the three reported rounds, all 20 reported questions (object-oriented and runtime fundamentals, string and array coding, service design and integration, and behavioral prompts), the stack candidates list for the role, and a seven-day plan. It does not cover other American Airlines job families, and it treats the reports as patterns rather than a fixed question list.
Candidates report three stages over roughly three to five weeks: an Initial Screening, Technical Assessments, and a Comprehensive Panel Interview that covers technical competence and fit.
Focus areas
- System Design
- Coding in General (Programming/Live Coding)
- Data Structures & Algorithms (DSA)
Overview
The loop candidates describe has three stages, and the 20 reported questions fall into four groups of five: object-oriented programming and system fundamentals, coding and algorithms, system design and integration, and behavioral scenarios. The reports do not say which question belongs to which stage, so the sensible plan is to be ready for the whole set rather than to guess a mapping. The topic mix behind this guide comes from a small number of reported loops, so use it as a map of likely areas, not a guarantee.
The technical side rewards accuracy more than cleverness. The reported coding questions are string and array problems (reverse each word, find leaders, check a palindrome, find the first non-repeating item, build a jagged list), so the work is stating the input, choosing a single-pass approach where one exists, covering empty and negative inputs, and writing tests next to the code. The fundamentals questions lean toward Java: heap versus stack, garbage collection, thread dumps and heap dumps. If you code in C#, JavaScript or Python, prepare the equivalent runtime story for your language, such as the .NET collector or the JavaScript event loop.
The design questions are tied to a named stack: a REST wrapper in front of a legacy booking system with rate limiting and caching, a CI/CD pipeline on Azure DevOps, transactions and consistency across Spring Boot microservices on PostgreSQL, Redis eviction in a distributed cache, and service-to-service security in the cloud. Because the role itself involves replacing legacy systems, frame each answer around incremental replacement, partial failure and what happens when a dependency is slow or down. Reports also mention an occasional logic puzzle such as the water jug problem, and a warning that strong coding does not offset weak behavioral answers, so keep your STAR stories as polished as your code.
The American Airlines interview process
The three stages below are what candidates describe, not a published process, and the reports do not say which questions come up in which stage.
Initial Screening
Candidates describe the Initial Screening as a first conversation that checks basic qualifications and fit. Nothing specific is reported about its format, so treat it as a short test of whether your background lines up with the requirements candidates describe: one major language (Java, C#, JavaScript, TypeScript or Python), object-oriented fundamentals, a relational database such as PostgreSQL or SQL Server, REST API design and Agile experience. Go in with a tight summary of your experience and a specific answer to why you want to work in this domain, because that question is among the reported ones.
What to demonstrate
- Whether your experience matches the basic qualifications for a Software Engineer role
- Fit for the role, which is how candidates describe this stage
- How clearly you summarise your own projects
How to prepare
- Write a short walkthrough of your last two projects that names the language, the database and how the work was deployed
- Map your experience against the listed requirements (OOP, relational database, REST, Agile, cloud) and note the gaps you will address honestly
- Prepare your answer to why American Airlines and how your background connects to aviation, using a transferable project rather than claimed domain experience
Technical Assessments
Candidates describe the Technical Assessments as the stage that tests coding skill and technical knowledge. The reported coding set is string and array manipulation, and the reported fundamentals questions cover object-oriented programming, Java memory management and production troubleshooting. Candidates mention writing code in a language of their choice, and one reported tip is to write unit tests (Jest or JUnit are named) alongside the solution. The reports do not pin specific questions to this stage, so prepare the whole technical set and the way you explain it aloud.
What to demonstrate
- Working code in the language you choose, including how it handles empty and unusual inputs
- Technical knowledge of object-oriented design and the runtime you use
- Whether you can explain your reasoning while you write
How to prepare
- Solve the five reported coding questions in your own language, each with a short test file covering empty, single-element and negative-number inputs
- Practise the in-place word-order reversal and a small Jest or JUnit test for a function that formats flight schedule data, both reported as example scenarios
- Prepare spoken answers for heap versus stack, garbage collection, and when you would take a thread dump or a heap dump
- Rehearse the interface versus abstract class question with a concrete example from your own code
Comprehensive Panel Interview
Candidates describe the Comprehensive Panel Interview as the closing stage, assessing technical competence and cultural fit together. Reports note that onsite panels can stretch the timeline for experienced hires. Expect to move between design discussion and behavioral stories, so be ready to explain a technical decision to engineers and then to a non-technical audience. The reported design questions (legacy booking wrapper, Azure DevOps pipeline, microservice transactions, Redis eviction, service security) and the reported example scenarios (real-time flight status updates, monolith-to-microservices migration, zero-downtime schema changes) are the best material to rehearse.
What to demonstrate
- Technical competence across design, integration and cloud topics
- Cultural fit, which candidates report is assessed together with the technical side
- Clear communication of technical ideas to both engineers and business stakeholders
How to prepare
- Outline each reported design question on one page: components, failure handling, and the trade-off you chose
- Prepare a short account of a legacy-to-cloud migration step by step, including how you would change a database schema without downtime
- Write STAR stories for the five reported behavioral prompts and rehearse them aloud
- Practise explaining a design decision in plain language for a product manager or business stakeholder
Where candidates lose points
Reciting the four OOP pillars as definitions with no example from your own work
Prepare one class or module from a real project for each pillar, and be ready to explain where you chose composition over inheritance. The same applies to the interface versus abstract class question: name a case where you picked each and what that choice cost.
Answering heap versus stack with 'the stack is fast, the heap is big' and stopping before garbage collection
Cover per-thread stack frames, objects and references on the heap, reachability and generational collection, and why leaks still occur when a static map keeps references alive. Then say when a thread dump (stuck or deadlocked threads) fits and when a heap dump (growing memory) fits.
Coding the string and array questions without stating edge cases or adding tests
Before coding the leaders, palindrome, word-reversal and first-non-repeating questions, list empty input, a single element, negative numbers, repeated spaces and mixed case. After coding, write a few quick tests in Jest or JUnit style, since candidates report that tests alongside the solution are a recommended habit.
Naming tools in the design questions without trade-offs, such as 'use Redis' with no eviction policy or 'use a transaction' across services
For each design, state the failure case and the choice: LRU or TTL-based eviction and what staleness it allows; per-service local transactions with an outbox or saga instead of a cross-service transaction; idempotency keys on retries; mutual TLS or token-based auth between services.
Treating the behavioral stories as an afterthought or telling them as 'we' stories
Candidates report being turned down despite strong coding because they could not articulate past experience. Write each STAR story with your own decision and a measured result, and rehearse the why-American-Airlines answer so it links a specific project to the work.
Questions & practice
What is the difference between the heap and the stack in memory management, and how does garbage collection wo
Medium · Object-Oriented Programming & System Fun
What is the difference between the heap and the stack in memory management, and how does garbage collection work in Java?
Approach
- Each thread has its own stack of frames holding local primitives and references; objects and arrays live on the heap, which all threads share. A too-deep recursion gives StackOverflowError, an exhausted heap gives OutOfMemoryError.
- Java passes everything by value: for objects the value copied is the reference, so a method can mutate the caller's object but cannot make the caller's variable point at a new one.
- GC is based on reachability from GC roots (live thread stacks, static fields, JNI references), not reference counting, so unreachable cycles are collected.
- HotSpot heaps are generational: new objects go to Eden, minor collections copy survivors between survivor spaces and promote long-lived objects to the old generation, which is collected less often. G1 is the default collector since JDK 9; ZGC and Shenandoah target very short pauses, Parallel targets throughput.
- Mention that a leak is still possible: objects stay reachable through static maps, unremoved listeners or ThreadLocals in pooled threads. Class metadata lives in Metaspace (native memory) since Java 8.
Follow-up
- How can a Java application leak memory if the garbage collector exists?
- What is a stop-the-world pause, and how would you reduce long GC pauses in a service?
- What are weak and soft references, and when would you use one?
Write a function to reverse each word in a given sentence while maintaining the original word order and spacin
Medium · Coding & Algorithmic Problem Solving
Write a function to reverse each word in a given sentence while maintaining the original word order and spacing.
Approach
- Clarify what counts as a word (runs of non-space characters, punctuation included or not) and whether tabs and multiple spaces must survive exactly; the requirement says spacing is preserved, so assume yes.
- Walk the string once: when a run of non-space characters ends, reverse that run in place with two pointers, and copy spaces through untouched. That is O(n) time; in Java strings are immutable, so work on a char[] (O(n) extra), or in place if given a mutable array.
- Explain why naive splitting fails: Python's str.split() with no argument collapses whitespace, and Java's split(" ") drops trailing empty strings, so the output loses spaces. In Python, re.sub(r'\S+', lambda m: m.group()[::-1], s) keeps all whitespace.
- Write tests for the edge cases: empty string, only spaces, leading and trailing spaces, double spaces between words, a single character, and punctuation attached to a word ("hi," becomes ",ih").
- Note that reversing UTF-16 chars splits surrogate pairs such as emoji; reverse by code point if the input can contain them.
Follow-up
- Now reverse the order of the words instead, in place with O(1) extra space.
- How would your function handle emoji or accented characters built from combining marks?
- How would you process a sentence too large to hold in memory?
Find all the "leader" elements in an array. An element is a leader if it is greater than all the elements to i
Medium · Coding & Algorithmic Problem Solving
Find all the "leader" elements in an array. An element is a leader if it is greater than all the elements to its right.
Approach
- Brute force compares every element with everything to its right: O(n^2). State it, then improve.
- Scan from right to left keeping the maximum seen so far. The rightmost element is always a leader; any element strictly greater than the running maximum is a leader and becomes the new maximum. O(n) time, O(1) extra space besides the output.
- Leaders are collected right to left, so reverse the result (or fill from the back) if the caller expects original order.
- Settle duplicates from the definition: with strictly greater, [5, 5] has only the last 5 as a leader. Initialise the maximum from the last element, not from 0, or arrays of negative numbers give wrong answers.
- Write unit tests for an empty array, a single element, all-equal values, a strictly decreasing array (every element is a leader), a strictly increasing one (only the last) and all-negative input.
Follow-up
- Elements now arrive as a stream from left to right: how do you maintain the leaders? (A stack kept strictly decreasing, popping every value less than or equal to the new one, O(n) amortised.)
- How does the answer change if a leader only needs to be greater than or equal to everything on its right?
- Return the indices of the leaders instead of the values: what changes in your tests?
Write a program to generate a list of jagged numbers based on a specific input criteria.
Medium · Coding & Algorithmic Problem Solving
Approach
- The term is not standard, so define it before coding: the two usual readings are numbers whose digits alternate up and down (a zigzag such as 1 3 2 5) and numbers whose adjacent digits differ by exactly 1 (stepping numbers such as 121). Confirm the range or count to produce and whether single digits and 0 qualify.
- Baseline: test every number up to N with a digit check, O(N times the number of digits). It is correct and easy to test, so write it first if the range is small.
- Better: generate only valid numbers. Start from the digits 1-9 and extend each number by appending digits that keep the property, using BFS or DFS, stopping once the value exceeds N. Cost is proportional to the number of valid outputs, not to N.
- For the zigzag reading, carry the last digit and the direction the next step must take, and reject equal adjacent digits. BFS that appends digits in ascending order emits each length in increasing order.
- Test single digits, 0, two-digit boundaries, equal adjacent digits and an upper bound that is itself valid.
Follow-up
- How would you count the valid numbers up to N without generating them? (Digit DP over position, last digit, direction and a tight flag.)
- How do you return them in sorted order if you generated them with DFS?
- What changes if the input is a range [low, high] instead of an upper bound?
Write an algorithm to check if a given string is a palindrome, optimizing for both time and space complexity.
Medium · Coding & Algorithmic Problem Solving
Approach
- Clarify the rules first: case-sensitive or not, and whether spaces and punctuation are ignored ("A man, a plan..."). Empty and single-character strings are palindromes.
- Use two pointers from both ends moving inward, comparing characters and skipping non-alphanumerics if required (Character.isLetterOrDigit in Java). O(n) time and O(1) extra space.
- Contrast with comparing the string to its reverse: also O(n) time, but it allocates an O(n) copy, which is what the space requirement rules out.
- Lowercase per character (Character.toLowerCase) or with Locale.ROOT rather than the default locale, and note that Unicode input with surrogate pairs should be compared by code point.
- Test even and odd lengths, a string of only punctuation, mixed case, and a near-palindrome that differs in the middle character.
Follow-up
- Return true if the string can become a palindrome by deleting at most one character.
- Check whether a singly linked list is a palindrome in O(1) extra space.
- Find the longest palindromic substring, and state the complexity of your method.
Given a list of integers, write a function to find the first non-repeating character or number.
Medium · Coding & Algorithmic Problem Solving
Approach
- Clarify the input type, since the prompt mixes characters and numbers, and what to return when every element repeats (null, an Optional, or a sentinel).
- Brute force checks each element against all others: O(n^2). The standard answer is two passes: count occurrences in a hash map, then scan the original order and return the first element with count 1. O(n) time, O(k) space for k distinct values.
- A LinkedHashMap keeps insertion order, so the second pass can iterate the map instead of the input; for a fixed character set an int[26] or int[256] array replaces the map with O(1) space.
- In Java, compare boxed Integer counts with equals or intValue, not ==, because == on Integer compares references outside the cached range of -128 to 127.
- Test an empty list, a single element, all duplicates, the unique element at the last position, and negative numbers.
Follow-up
- The values arrive as a stream: return the first non-repeating value after each insertion in O(1). (A map to nodes of a doubly linked list of currently unique values.)
- How does your solution change if the list has a billion integers and does not fit in memory?
- Return the first element that appears exactly k times.
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?
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?
Explain the four pillars of object-oriented programming (OOP) and how you have applied them in your past proje
Medium · Object-Oriented Programming & System Fun
Explain the four pillars of object-oriented programming (OOP) and how you have applied them in your past projects.
Approach
- Name each pillar with one concrete example from a project: encapsulation (private fields, changes only through methods that enforce an invariant), abstraction (callers depend on a small interface, not the implementation), inheritance (subclass reuses and specialises a base type), polymorphism (one call site, behaviour chosen at runtime by the object's type).
- Show polymorphism removing a conditional: for example a Notifier interface with Email and Sms implementations, so adding a channel adds a class instead of another branch in a switch.
- Say where inheritance went wrong or where you chose composition instead: deep hierarchies couple subclasses to base-class internals, so for has-a relationships or swappable behaviour I hold a collaborator and delegate to it.
- Tie inheritance to the Liskov substitution principle: a subclass must be usable wherever the base type is expected without callers checking its type.
- Keep each example to what you built and why the design helped (easier tests, a feature added without touching existing classes), not textbook definitions.
Follow-up
- When did you choose composition over inheritance, and what would have broken with the hierarchy?
- What is the difference between method overloading and overriding, and which one is runtime polymorphism?
- How does encapsulation help when several threads use the same object?
Given a specific scenario, such as designing a real-time flight tracking queue, which data structure would you
Medium · Object-Oriented Programming & System Fun
Given a specific scenario, such as designing a real-time flight tracking queue, which data structure would you choose and why?
Approach
- Pin down the operations first: is it FIFO processing of incoming position updates, ordering flights by next event time, or fast lookup of each flight's latest state? The answer picks the structure.
- For ordering by time, a binary-heap priority queue gives O(log n) insert and poll and O(1) peek; because a delayed flight changes its key, use an indexed heap or lazy deletion, or a balanced tree (Java TreeMap) that supports O(log n) remove and reinsert plus ordered range scans.
- Pair it with a hash map from flight id to current state for O(1) lookup, and drop out-of-order updates by comparing a timestamp or sequence number so a stale message cannot overwrite a newer one.
- For the ingest side, use a bounded blocking queue or ring buffer between producers and consumers so a burst applies backpressure instead of exhausting memory; ArrayBlockingQueue or ConcurrentLinkedQueue in Java, depending on whether you want blocking and a bound.
- At larger scale, partition updates by flight id so each flight's events stay in order on one consumer, and say what you lose: global ordering across flights.
Follow-up
- A flight's departure time changes while it sits in your priority queue: how do you update it efficiently?
- What happens to your design when updates arrive faster than consumers can process them?
- How would you keep only the latest position per flight without unbounded memory growth?
Explain the difference between an interface and an abstract class, and describe when you would choose one over
Medium · Object-Oriented Programming & System Fun
Explain the difference between an interface and an abstract class, and describe when you would choose one over the other.
Approach
- In Java a class extends at most one class but can implement many interfaces. Interfaces carry no instance state (fields are implicitly public static final); since Java 8 they can have default and static methods, and since Java 9 private methods. An abstract class can have constructors, instance fields, protected members and non-public methods.
- Choose an interface for a capability or contract that unrelated types share (Comparable, a PaymentGateway), when a type plays several roles, or when you want to mock the dependency in a unit test.
- Choose an abstract class when closely related types share state and a fixed skeleton, for example a template method that calls abstract hooks in a set order.
- Mention evolution: adding an abstract method to a published interface breaks every implementor, which is why default methods exist; adding a concrete method to an abstract class does not break subclasses.
- If C# is your language, give the matching facts: single class inheritance, multiple interfaces, and default interface members since C# 8.
Follow-up
- Two interfaces define the same default method and a class implements both: what does Java require?
- Would you make a repository type an interface or an abstract class, and how does that affect testing?
- What do sealed interfaces in Java 17 add?
Design a REST API wrapper for a legacy flight-booking system. How would you handle rate limiting and caching?
Medium · System Design & Integration
Approach
- Put a facade service in front of the legacy system that exposes resources (GET /flights?origin=&destination=&date=, POST /bookings, GET /bookings/{id}) and translates them into legacy calls, mapping legacy codes and errors to HTTP statuses so clients never see the old formats.
- Rate limiting: a token bucket per client key (bursts up to the bucket size, refill at a fixed rate), with counters held in Redis and updated atomically by a Lua script; return 429 with Retry-After. Separately cap concurrent outbound calls and add a circuit breaker so the legacy system is protected even when every client is within its limit.
- Caching by data type: reference data such as airports and schedules with long TTLs, availability and fares with short TTLs because they go stale, and booking writes never cached. Use cache-aside with stampede protection, and ETag or Cache-Control for clients.
- Make POST /bookings safe to retry: require an Idempotency-Key, store key to result, and return the stored result on a repeat, so a client retry after a timeout cannot book twice. If the legacy call is slow, return 202 with a status resource.
- Name the failure cases: legacy timeout, a fare cached as available but already sold (return 409 and re-quote), and partial failure between hold and payment.
Follow-up
- A client retries a booking request after a timeout: walk through what your wrapper does.
- The legacy system goes down for ten minutes: what do callers see for reads and for writes?
- How would you version this API once mobile clients depend on it?
Describe how you would set up a continuous integration and continuous deployment (CI/CD) pipeline using Azure
Medium · System Design & Integration
Describe how you would set up a continuous integration and continuous deployment (CI/CD) pipeline using Azure DevOps.
Approach
- Keep the pipeline as YAML (azure-pipelines.yml) in the repository, triggered by pull requests to main, with a branch policy that requires the build-validation run and review before merge.
- Build stage: restore dependencies, compile, run unit tests, publish test results and coverage, run dependency and static analysis scans, then produce one versioned artifact or container image and push it to a registry.
- Build once, promote the same artifact through dev, test and prod deployment stages; use Azure DevOps environments with approvals and checks on prod, and deployment jobs with a runOnce, rolling or canary strategy.
- Keep credentials out of the YAML: service connections for access to Azure, variable groups linked to Azure Key Vault for secrets.
- Plan rollback and schema changes: redeploy the previous artifact or swap App Service deployment slots back, and run backward-compatible database migrations (expand, migrate, contract) so old and new code run against the same schema during a rollout.
Follow-up
- How do you ship a schema change that renames a column without downtime?
- A deployment to prod passes all checks but error rates rise: how does the pipeline let you roll back?
- How do you handle flaky tests that block merges?
How do you manage database transactions and consistency when designing microservices with Spring Boot and Post
Medium · System Design & Integration
How do you manage database transactions and consistency when designing microservices with Spring Boot and PostgreSQL?
Approach
- Inside one service, wrap each business operation in a local transaction with @Transactional on a public service method. Two Spring details to name: calls from inside the same class bypass the proxy so the annotation is not applied, and by default only unchecked exceptions trigger rollback (use rollbackFor for checked ones).
- Handle concurrency explicitly: PostgreSQL's default isolation is READ COMMITTED, so prevent lost updates with optimistic locking (a JPA @Version column) or SELECT ... FOR UPDATE; SERIALIZABLE works but raises serialization failures (SQLSTATE 40001) that the caller must retry.
- Across services, give each service its own database and avoid distributed two-phase commit; model the workflow as a saga (orchestrated or event choreography) where each step commits locally and failures run compensating actions, with states such as PENDING and CONFIRMED.
- Use a transactional outbox so a state change and its event cannot diverge: write the business row and an outbox row in the same transaction, and have a relay publish from the outbox. Delivery is then at least once, so consumers must be idempotent (dedupe on an event id).
- State the trade-off: the system is eventually consistent, so define what users see while a saga is in progress and how long that window can last.
Follow-up
- A compensating action itself fails: what does your saga do?
- How do you make an event consumer idempotent when the same message arrives twice?
- When, if ever, would you accept two-phase commit?
Explain the role of Redis in a high-throughput, distributed system and how you would design a cache eviction p
Medium · System Design & Integration
Explain the role of Redis in a high-throughput, distributed system and how you would design a cache eviction policy.
Approach
- Describe what Redis is: an in-memory data-structure store where commands run on a single thread, so each command is atomic. Common roles: cache-aside in front of a database, session storage, rate-limit counters (INCR with EXPIRE), simple locks (SET key value NX PX), sorted sets for ranked data, pub/sub and streams.
- Eviction is set by maxmemory plus maxmemory-policy. The default, noeviction, rejects writes once memory is full; allkeys-lru and allkeys-lfu evict any key; the volatile-* variants evict only keys with a TTL; volatile-ttl evicts the keys closest to expiry. Redis approximates LRU and LFU by sampling keys (maxmemory-samples).
- Pick by access pattern: allkeys-lfu when a small set of keys is hot over time, allkeys-lru when recency predicts reuse, volatile-* when cache keys and keys that must persist share one instance (better: separate instances).
- Design the TTLs too: TTL per data type, random jitter so many keys do not expire at once, and stampede protection (a short lock or early recompute) for expensive keys. On writes, commit to the database first, then delete the cache key.
- Cover scale and failure: Redis Cluster shards across 16384 hash slots (use {hash tags} to keep related keys on one slot), replicas for read scaling and failover, and a fallback path with load shedding if the cache is unavailable.
Follow-up
- After a write, the cache and the database disagree: what ordering of operations caused it and how do you fix it?
- One key receives most of the traffic: how do you handle a hot key?
- Redis restarts empty during peak traffic: what happens to your database, and how do you protect it?
How would you secure microservices communicating with each other in a cloud environment?
Medium · System Design & Integration
Approach
- Authenticate both ends of every call: mutual TLS, where each service presents a certificate, often handled by a service mesh sidecar that issues and rotates certificates automatically. Treat the network as untrusted even inside a private VNet or VPC.
- Authorise each call with short-lived tokens: the OAuth 2.0 client credentials grant gives a service a JWT, and the receiver validates signature, issuer, audience and expiry, then checks scopes per endpoint (least privilege).
- Keep secrets out of code and config: use managed identities (Azure) or IAM roles (AWS) to reach resources, a secret store such as Key Vault or Secrets Manager for what remains, and scheduled rotation.
- Restrict reachability: private subnets, network policies or security groups that allow only the expected caller-to-callee paths, and a gateway at the edge as the only public entry point.
- When a request carries an end user's identity through several services, pass it in a signed token (or exchange it for a narrower one), never in a plain header that any internal caller could set; log the service identity and user on each call for audit.
Follow-up
- How do you rotate certificates or signing keys without downtime?
- JWTs cannot be revoked easily: how do short lifetimes and key rotation address that?
- An internal service is compromised: what limits how far an attacker can move?
What are thread dumps and heap dumps? In what scenarios would you analyze them to troubleshoot a production is
Medium · Object-Oriented Programming & System Fun
What are thread dumps and heap dumps? In what scenarios would you analyze them to troubleshoot a production issue?
Approach
- A thread dump is a snapshot of every thread's stack trace and state (RUNNABLE, BLOCKED, WAITING, TIMED_WAITING) with the monitors and locks each holds or waits on. Capture it with jcmd <pid> Thread.print, jstack <pid>, or kill -3 (output goes to the JVM's stdout).
- Use thread dumps for hung requests, deadlocks (the JVM reports Java-level deadlocks it finds in the dump), exhausted thread pools and high CPU: map the hot OS thread id from top -H to hex and find the matching nid in the dump.
- Take three or more thread dumps a few seconds apart; a thread stuck in the same frame across all of them is the signal, a single dump is just a moment.
- A heap dump is a snapshot of all objects on the heap (.hprof): jcmd <pid> GC.heap_dump or jmap -dump:live,format=b,file=heap.hprof <pid>, and -XX:+HeapDumpOnOutOfMemoryError to capture the failure automatically. Analyse it in Eclipse MAT or VisualVM: dominator tree, retained size, path to GC roots.
- State the costs: a heap dump pauses the JVM and writes a file roughly the size of the live heap, and it contains user data, so take it from an instance pulled out of the load balancer and handle the file as sensitive.
Follow-up
- Heap usage climbs steadily after a deploy until OutOfMemoryError: what is your sequence from alert to root cause?
- CPU is at 100% on one instance but the others are fine: how do you find the thread responsible?
- How do you tell a memory leak from a heap that is simply sized too small for the load?
Suggested practice checklist
The plan starts with the loop map and OOP fundamentals, moves through runtime questions and the two coding sets, then covers the five design questions and ends with a behavioral rehearsal. Each day targets reported questions from this guide.
Day 1 — Map the loop and choose your language
- Write out the three reported stages (Initial Screening, Technical Assessments, Comprehensive Panel Interview) and sort the 20 reported questions into fundamentals, coding, design and behavioral groups.
- Pick the one language you will code in (Java, C#, JavaScript, TypeScript or Python) and list what you need to review about its runtime.
- Write a short walkthrough of your last two projects that you could use in a screening conversation.
Deliverable: A one-page loop map with the question groups, your chosen language with its review list, and a written project walkthrough.
Day 2 — OOP pillars, interfaces and class design
- For each pillar, pick a class or module from your own work and write two sentences on how it shows that pillar, including one case of composition over inheritance.
- Write a comparison of interface versus abstract class for your language (state, constructors, multiple inheritance, default methods) with one decision rule.
- Sketch the classes and interfaces for a parking lot management system, a reported example scenario, and note where Singleton, Factory, Builder or Observer would fit.
- Say each of the answers aloud once without notes.
Deliverable: A pillars sheet with project examples, an interface versus abstract class comparison, and a parking lot class sketch.
Day 3 — Runtime, memory and production troubleshooting
- Explain stack versus heap and garbage collection aloud for your language, including why a static collection can leak.
- Write a small program that leaks memory and one that deadlocks, and capture a heap dump and a thread dump from each with your runtime's tools.
- Write a triage checklist for high memory use and long garbage-collection pauses, plus how you would make a shared resource thread-safe.
- Choose and justify a data structure for a real-time flight tracking queue, covering ordering, concurrency and bounded size.
Deliverable: Spoken answers for the memory and dump questions, a captured heap dump and thread dump with notes, a one-page triage checklist, and a written data-structure choice.
Day 4 — Coding set one with tests
- Solve the reverse-each-word question, keeping word order and original spacing, and test it with repeated spaces, leading spaces and an empty string.
- Solve the leaders question in one right-to-left pass and compare it with the quadratic version; test empty, negative and all-equal arrays.
- Decide what the jagged numbers question could mean, write down your assumptions, and implement one clear reading with tests.
- State the time and space complexity of each solution aloud.
Deliverable: Three working solutions with test files, a note of the assumptions behind the jagged numbers solution, and spoken complexity statements.
Day 5 — Coding set two and testing habits
- Solve the palindrome question with two pointers and decide how to treat case, punctuation and an empty string.
- Solve the first non-repeating item question with a counting map and a second pass that preserves order; discuss the one-pass alternative.
- Reverse the order of words in a string in place and write a Jest or JUnit style test for a function that formats flight schedule data.
- Run one full problem timed while talking through your reasoning aloud.
Deliverable: Two solutions plus the in-place reversal and the formatting function, each with tests, and one recorded timed run.
Day 6 — Service design on Azure, Spring Boot, PostgreSQL and Redis
- Outline the REST wrapper for a legacy flight-booking system, with rate limiting, a caching layer, idempotent retries and an error taxonomy, and outline an Azure DevOps CI/CD pipeline with build, test, deploy and rollback stages.
- Write how you would keep data consistent across Spring Boot microservices on PostgreSQL: local transactions, an outbox or saga, and idempotent consumers.
- Design Redis caching and an eviction policy for a high-read workload, then list how you would secure service-to-service traffic.
- Add a note for each design on what fails first at ten times the traffic and how a schema change ships without downtime.
Deliverable: Four one-page design outlines (REST wrapper and pipeline, transactions, Redis eviction, service security), each with a failure-case note.
Day 7 — Behavioral rehearsal and full mock
- Write a STAR story for each of the five reported behavioral prompts, naming your own decisions and one measured result.
- Rehearse the why-American-Airlines answer so it links one project to the work candidates describe for the role.
- Run a mixed mock: one coding question with tests, one design question and two stories, all spoken aloud.
- List the three weakest answers from the mock and fix them.
Deliverable: Five written STAR stories, a rehearsed motivation answer, and a list of three weak answers with fixes.
STAR stories for the American Airlines loop
Candidates report that the behavioral questions cover teamwork, communication and adaptability and are expected in STAR form (situation, task, action, result). For this role, build stories around the work candidates describe: Agile delivery with product and UX partners, explaining technical decisions to non-technical stakeholders, and troubleshooting production problems. Keep each story to your own decisions and a measured result.
- Tell me about a time you explained a technical decision to a non-technical stakeholder.
Describe a time when you had to work with a difficult stakeholder or team member. How did you resolve the conf
Medium · Behavioral & Situational Scenarios
Describe a time when you had to work with a difficult stakeholder or team member. How did you resolve the conflict?
Approach
- Choose a conflict about something concrete, such as scope, a release date, an API contract or a review standard, where you owned part of the resolution. Skip any story that boils down to one person being unreasonable.
- Set the scene in two sentences: who the stakeholder was, what each side wanted, and why both positions had merit. Spend most of the answer on actions: a one-to-one conversation to hear their constraint, a written summary of the options with costs, and a decision rule both sides accepted.
- Show that you translated between technical and business terms, for example turning 'this needs a schema migration' into the effect on booking flows and delivery dates that a product manager or business stakeholder cares about.
- Close with the result and the relationship afterwards: what shipped, what each side gave up, and what you changed in how you work together, such as a shared checklist or a standing sync.
- The mistake that sinks this answer is blaming the other person or claiming the conflict ended because you were right. A story resolved with evidence and a compromise is stronger than a won argument.
Follow-up
- What would you have done if the stakeholder still disagreed after that conversation?
- At what point would you have escalated, and to whom?
- What did you learn about their priorities that you did not know at the start?
Tell me about a project where you faced a significant technical hurdle. What was the issue, and how did you ov
Medium · Behavioral & Situational Scenarios
Tell me about a project where you faced a significant technical hurdle. What was the issue, and how did you overcome it?
Approach
- Pick a hurdle you diagnosed yourself: a memory leak, a slow query, a flaky integration with a legacy service or a concurrency bug. State the symptom in one sentence with a measurement from your own project, such as latency, error rate or heap growth.
- Walk through the diagnosis in order: what you checked first, which hypotheses you ruled out, and the evidence that narrowed it down, for example logs, a profiler, thread or heap dumps, a query plan or a minimal reproduction.
- Say what the fix was and why you chose it over the alternatives, including a trade-off you accepted, such as a cache with some staleness instead of a schema change.
- Prove the fix with the same measurement you started with, then name what you added to stop a repeat: a regression test, an alert, a runbook entry or a pipeline check.
- The mistake that sinks this answer is describing the hurdle as 'a hard bug' with no detail, or crediting the team throughout so your own actions disappear. Use 'I' for what you did and name teammates where they helped.
Follow-up
- What was your first wrong hypothesis, and what showed it was wrong?
- How did you confirm the fix addressed the root cause and not just the symptom?
- What would you instrument differently from the first day of that project?
How do you estimate tasks and handle changing requirements in an Agile development environment?
Medium · Behavioral & Situational Scenarios
Approach
- Answer in two halves, your estimation method and your response to change, and give a short real example for each. Staying abstract is the common failure here.
- For estimation, break the work into tasks small enough to reason about, size them relatively (story points) against similar past work, include testing, review, deployment and integration with older systems, and give a range with the assumptions behind it rather than a single date.
- Name the unknowns and handle them explicitly: schedule a time-boxed spike for the riskiest one, such as an undocumented legacy API, then re-estimate. Compare estimates with actuals each sprint so your sizing calibrates against your real velocity.
- For changing requirements, ask what the change replaces, re-rank the backlog with the product owner, make the cost in scope or date visible, keep mid-sprint scope stable unless something of equal size leaves, and use feature flags or thin slices so partial work can still ship safely.
- The mistake that sinks this answer is saying you simply 'adapt' or that estimates are impossible. Show a case where an estimate was wrong, what you told people and when.
Follow-up
- Your estimate is off by half partway through the sprint. What do you do, and who do you tell?
- A stakeholder adds a must-have feature mid-sprint. Walk through your response.
- How do you estimate work in a legacy codebase you have never opened?
Why do you want to work for American Airlines, and how does your background align with the aviation industry?
Medium · Behavioral & Situational Scenarios
Approach
- Build the answer from three parts: what draws you to this problem space, what in your background transfers, and what you want to learn. Candidates report that aviation experience is not required, so a transferable story is enough; do not claim domain experience you lack.
- Be concrete about the work as candidates describe it: customer-facing apps and booking engines, flight operations, crew scheduling and baggage routing behind them, and the move from legacy systems to cloud services. Pick one and say why the engineering challenge interests you, such as availability, integration with older systems or real-time updates.
- Tie your background to it with a specific project: a migration you ran, a high-availability service you operated, or an integration with a legacy system, including one outcome. Match it to the stack you are interviewing for (Java, C#, JavaScript, Python, Azure or AWS).
- Research the company's technology initiatives from public sources beforehand and mention only what you actually read. Reported tips recommend showing real interest in the industry, and specifics are what make that credible.
- The mistake that sinks this answer is generic praise that fits any large employer, or a reason based on the brand or travel perks with no link to the work.
Follow-up
- Why this company rather than another employer with similar scale?
- Which part of airline software would you find hardest to work on, and why?
- What have you read or used about American Airlines' technology so far?
Describe a situation where you had to deliver a project on a tight deadline. What trade-offs did you have to m
Medium · Behavioral & Situational Scenarios
Describe a situation where you had to deliver a project on a tight deadline. What trade-offs did you have to make?
Approach
- Choose a deadline that forced real choices and open with the constraint: the date, what was at stake, and what the full scope would have been. Then list the trade-offs explicitly rather than describing effort.
- Show a triage: what you cut or deferred (secondary features, polish, rare edge paths), what you refused to cut (correctness of the core flow, tests on the risky path, a rollback plan, security), and why the line sat where it did.
- Show that you negotiated it: you told the stakeholder early what would not fit, offered options with their costs, and got agreement instead of quietly shipping less. Mention thin vertical slices or feature flags if you used them.
- Report the result honestly: what shipped on time, what was deferred, the technical debt you recorded as a ticket with an owner, and what happened to it afterwards.
- The mistake that sinks this answer is a heroics story of late nights with no trade-offs, or one where tests were dropped silently and the cost surfaced later.
Follow-up
- Which corner would you refuse to cut even under more pressure, and why?
- How did you make sure the deferred work actually got done?
- Looking back, was there a point where you should have pushed back on the deadline itself?