cswork / libraryOpen practice workspace

Interview guides · AIR

AIR Software Engineer Interview Guide

AIR Software Engineer interview guide: recruiter screen, technical dives and team fit, with answers on microservices, API design and a 7-day plan.

The 60-second brief

Candidates describe AIR as an aviation business, and one reported question asks how you feel about working for an airline company. As candidates relay it, the Software Engineer role is built around backend services, API design, cloud-based infrastructure and microservices. The work includes data-heavy applications and integration between many systems. It also carries ownership of reliability through on-call duties and code reviews, and it means working with product owners, architects and operations staff from requirements through to maintenance.

This guide is for backend-leaning software engineers interviewing at AIR. The requirements candidates describe ask for Java, Python or a similar backend language, API design, cloud technologies and microservices, with high-availability systems, CI/CD and aviation or logistics experience as extras. The guide covers the three reported stages and the thirteen reported questions: architecture, API design, mobile trade-offs, open problem-solving cases and motivation. It also covers the database querying topics candidates list (joins, GROUP BY, CTEs) and gives a seven-day plan built on all of them.

Candidates report three rounds over roughly three to five weeks: a Recruiter Screening, Technical Dives and a Team Fit Discussion. They describe the technical stage as discussion-heavy and driven by the CV, with design exercises and an occasional practical coding task somewhere in the process.

Focus areas

  • Microservices Architecture
  • Programming Problem Solving
  • API Design

Overview

Most of the questions candidates report for this loop are discussion questions about architecture and experience, not algorithm puzzles. Five are technical and domain questions: using microservices for a Silverstripe app, explaining microservice patterns and standards, comparing native iOS/Android with Flutter and React Native, describing your home lab, and your approach to API design and code review. Three are open problem-solving cases: designing an email app API, a stakeholder email situation, and walking through how you tackle a technical challenge. The other five are about motivation and background. Candidates also list database querying (joins, GROUP BY, CTEs) and programming problem solving among the tested topics, so you still need hands-on practice.

Candidates report that the technical discussion uses the CV as its map, asks why each technical choice was made, and goes deep on a technology the candidate presents as an area of expertise. So don't spread your preparation thinly across many topics. Choose the technologies you will stand behind. For each one, be ready with how it works internally, an alternative you rejected, a failure you debugged and what you would change now. The home lab question shows that personal projects can come up as well.

Two reported questions fall outside a typical Java or Python backend. Silverstripe is a PHP CMS framework, and the mobile question is about client frameworks. You do not need to have used either one, but you do need a method. For Silverstripe, find the boundaries, data ownership and deployment pain before you split anything. For mobile, compare the options on performance, platform access, team skills and maintenance, then commit to a recommendation for a case you state.

The requirements candidates describe are backend development in Java, Python or similar, API design, cloud and microservices. High-availability systems, CI/CD and aviation or logistics knowledge count as extras, and the role as candidates relay it includes on-call duties. Give your motivation answers specifics about airline software, such as integration with many systems, reliability and the load peaks that come with operational disruption. Back each point with an example from your own work.

The AIR interview process

Candidates report three stages in this order. Little is reported about the format inside each stage, so the preparation below comes from the stage names, what candidates say about the technical discussion, and the reported questions.

Recruiter Screening

Candidates describe the Recruiter Screening as a first conversation about their background and fit for the role. This is where your story gets set. Candidates report that the later technical discussion is steered by the CV, so the technologies you stress here should be ones you can defend in depth. Make your reasons for choosing AIR and airline work specific enough to hold up under a follow-up question. Use the call to confirm the remaining stages, whether your loop includes a coding task or a design exercise, and which language you may use.

What to demonstrate

  • Whether your background fits the backend, API, cloud and microservices requirements candidates describe
  • How clearly and briefly you summarise your experience and your motivation for the role

How to prepare

  • Write a spoken walk-through of your CV that names, for each job, the system you owned and the technology you are willing to be questioned on in depth.
  • Prepare a specific answer on why AIR and why airline software, tied to reliability, integration or operations work you have done yourself.
  • Ask the recruiter which language you may use, whether the technical stage includes live coding, a design exercise or both, and who you will meet.

Technical Dives

Candidates describe Technical Dives as in-depth technical discussions rather than a fixed question set. They report that the conversation follows the CV, asks why each technical choice was made, and goes deep on a technology where the candidate claims expertise. Across the process candidates also mention design exercises and, less often, practical coding tasks. The reported architecture, API and problem-solving questions are the material to practise for a discussion like this. Treat every answer as a trade-off argument: state the requirement, name two options, choose one, then say what it costs and how you would notice it failing.

What to demonstrate

  • Depth in the technologies on your CV, which candidates report the discussion follows
  • The reasoning and trade-offs behind your past technical decisions
  • Technical competence in the areas the role requires: backend development, API design, microservices and cloud

How to prepare

  • Pick your strongest technology and write out how it works internally, two production failure modes and one decision you would reverse.
  • Answer the Silverstripe microservices question and the patterns-and-standards question aloud. Cover decomposition, database per service, sagas and the outbox pattern, circuit breakers, tracing and an OpenAPI contract.
  • Outline the email app API from start to finish: resources, endpoints, cursor pagination, idempotent send, attachments, delta sync and storage.
  • Write three SQL queries over a users/messages schema (a join, a GROUP BY with HAVING, a CTE) and one small backend exercise in your main language.

Team Fit Discussion

Candidates describe the final stage as a discussion of how well they would fit with the team. Across the process, the behavioural themes candidates list are handling disagreements with stakeholders, an operational mindset around on-call and reliability, explaining technical ideas to non-technical colleagues, and motivation for the aviation sector. Answer with specific stories in STAR form. Each story should end with a result you can state and a lesson you applied later. Since this is the last conversation, have questions ready about the team's on-call rotation, its release process and how it works with product owners and operations staff.

What to demonstrate

  • How you work within a team: collaboration, communication and handling disagreement
  • Your motivation for this team and for working on airline software

How to prepare

  • Prepare four STAR stories: a stakeholder disagreement you resolved with evidence, an on-call incident you handled, a time you explained a technical trade-off to a non-technical person, and the biggest challenge you solved.
  • Rehearse the reported motivation questions (why AIR, thoughts on working for an airline, how you stay current) with specific answers, not general enthusiasm.
  • Write three questions for the team about on-call, deployment and how requirements reach engineers from product owners.

Where candidates lose points

Listing a technology on your CV that you cannot explain beyond the basics.

Candidates report that the technical dive uses the CV as its map and goes deep into a technology you present as your expertise. Before the loop, remove or play down anything you only touched. For each item that stays, prepare why you chose it, an alternative you rejected, a failure you debugged and how it behaves under load.

Reciting microservice pattern names without covering data ownership or failure handling.

In the Silverstripe and patterns questions, tie every pattern to the problem it solves: database per service for independent deploys, the outbox for consistent events, sagas for workflows across services, timeouts and circuit breakers for failing dependencies. Also say when a well-cached monolith is the better answer.

Designing the email app API as a bare list of CRUD endpoints.

Cover idempotent send, cursor pagination, delta sync across devices, attachment uploads through pre-signed URLs, asynchronous search indexing, the outbound SMTP queue and threading by message headers. Rehearse the outline aloud until you can go through resources, data flow and edge cases in order.

Motivation answers that could be given to any employer.

Both the why-AIR question and the airline question need specifics: what about airline software interests you (integration, reliability, peaks during disruption, operations) and evidence from your own work. Say anything about the company only if it comes from material you have actually read.

Skipping SQL and hands-on coding because most reported questions are discussions.

Candidates list database querying with joins, GROUP BY and CTEs among the tested topics, and they report occasional practical coding tasks. Before the loop, write real queries and a small backend exercise in your main language. Don't count on design talk alone.

Questions & practice

Find overlapping job attempts and peak concurrency from lease records

Medium · sweep line · intervals · leases

A day of job_run history yields about 50,000,000 attempt records: (job_run_id, job_type, attempt, started_at, finished_at which is NULL when the worker died, lease_expires_at). Leases expire on a clock, so a job that outran its lease ran twice. Produce (a) every job_run_id whose attempts overlapped in wall-clock time and (b) the peak number of simultaneously running attempts per job_type with the minute it occurred. Target O(n log n). State how you treat a NULL finished_at and what clock skew does to your answer.

Approach

  1. Define the interval before sorting anything: an attempt occupies [started_at, COALESCE(finished_at, lease_expires_at)). finished_at is observed and lease_expires_at is only a promise, so every attempt without a finish contributes an estimate and the whole result is a lower bound on overlap rather than an exact count.
  2. For peak concurrency, sweep: emit 2n endpoints, sort by (timestamp, kind) with ends ordered before starts at equal timestamps, then walk the sequence maintaining a counter per job_type and record each type's maximum with its timestamp. O(n log n) dominated by the sort, O(n) space, or O(1) extra if the sort is external and the walk streams.
  3. For overlap detection, do not compare attempts pairwise. A single global sort by (job_run_id, started_at) gives both the grouping and the order; within a group, keep the maximum end seen so far and report an overlap exactly when the next start is less than that running maximum, which is one linear pass after the sort.
  4. Half-open intervals matter and are easy to get wrong: with closed intervals an attempt ending at the same millisecond another begins reads as concurrency two, and across 50,000,000 records that artefact swamps the real signal.

Follow-up

  • A handler is not idempotent and you have found 400 overlapping jobs. Which of them actually caused damage, and what would you query to find out?
  • Peak concurrency for one job_type is 4 against a configured cap of 4. Is the cap working, or is the data hiding attempts that never started?

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

  1. 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.
  2. 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.
  3. 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.
  4. 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?

Archive a resource graph without breaking live references or recursing

Medium · graph traversal · topological order · tenant isolation

Resources reference other resources within a tenant; for the largest tenant the reference table holds up to 2,000,000 nodes and 8,000,000 edges. Archiving a resource must archive everything reachable from it that nothing outside the set still references, refuse when a live external referrer exists, and terminate when references form cycles, which they legitimately do. Produce the archive order and the refusal list, targeting O(V+E). Say what stops the traversal crossing a tenant boundary, and why recursion is the wrong control structure at this size.

Approach

  1. Load the subgraph with the tenant predicate on both endpoints of the edge, not only on the side you started from. Scoping the left table alone is the classic cross-tenant leak: one mis-entered edge then pulls another tenant's resources into the traversal and, worse, into the archive.
  2. Traverse iteratively with an explicit stack. A 2,000,000-node graph can hold a chain deep enough to exhaust a native stack in the low tens of thousands of frames, and that failure is a process crash rather than an error you can return.
  3. Treat cycles as data rather than corruption: compute strongly connected components with Tarjan in O(V+E) using its own explicit stack, then condense. The condensation is a DAG, so a topological order over it gives the archive order, and every member of a component archives in one transaction because no order within a cycle is valid.
  4. Decide refusals with reverse edges. A candidate is archivable only if every in-edge originates inside the candidate set, so build the transpose or count in-degrees restricted to the visited set, and emit each blocked resource with the id of the external referrer, which is the only part of the answer an operator can act on.

Follow-up

  • The graph is read in one query and the archive writes a minute later. What can change in between, and how do you make the write safe?
  • The candidate set is 400,000 resources. Is that one transaction, and if not, what does a half-finished archive look like to a reader?

Stop tag and share joins from fanning out a page

Medium · join fan-out · semi-joins · many-to-many

resource_tag is (resource_id, tag_id) with PK (resource_id, tag_id); resource_share is (resource_id, shared_with_user_id, permission). The tagged-and-shared listing inner-joins resource to both, filters tenant_id, tag_id = ANY($2) and shared_with_user_id = $3, orders by updated_at DESC and takes 50. Pages come back with fewer than 50 distinct resources and the total in the header is far too high. Explain the row multiplication, rewrite both the page query and the count query so each is correct, and name the index each one needs. PostgreSQL 16.

Approach

  1. Do the arithmetic against the predicates that are actually there. An inner join emits one row per matching child row, and both joins are filtered: tag_id = ANY($2) admits only the requested tags, shared_with_user_id = $3 admits one user's share rows. So a resource holding three of the requested tags and shared with $3 once yields three rows, not one — the multiplier is its count of matching tags times its share rows for that single user, and that second factor is 1 unless the table admits duplicate (resource_id, shared_with_user_id) pairs. LIMIT 50 then limits rows rather than resources, and COUNT(*) counts pairs — the header is the product, not the population.
  2. Reject DISTINCT as the fix. It deduplicates after the product has been built, so the planner must materialise and sort the fanned-out set before the LIMIT can apply, and it leaves any SUM or AVG in the same select list wrong.
  3. Rewrite both filters as semi-joins, keeping resource as the only row source: AND EXISTS (SELECT 1 FROM resource_tag rt WHERE rt.resource_id = r.resource_id AND rt.tag_id = ANY($2)) and the same shape against resource_share. A semi-join stops at the first match per resource and preserves the driving index order, so ORDER BY updated_at DESC, resource_id DESC LIMIT 50 still stops after 50 rows.
  4. Count with the same predicates and no join at all: SELECT count(*) FROM resource r WHERE r.tenant_id = $1 AND r.status = 'active' AND EXISTS (...) AND EXISTS (...). Nothing multiplies a resource, so the number is the population.

Follow-up

  • The filter changes from 'any of these tags' to 'all of these tags'. Rewrite it and state what it costs relative to the ANY form.
  • A resource can be shared with the same user twice under different permissions. Does your count change, and should it?

Find version gaps and relay lag with window functions

Medium · window functions · event tables · frame semantics

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

Approach

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

Follow-up

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

How will you use microservices for a Silverstripe app?

Medium · Technical and Domain Knowledge

Approach

  1. Start by finding out what the Silverstripe app does today. Silverstripe is a PHP CMS and framework with its own ORM, so a typical install is a monolith where content editing, page rendering and custom business logic share one codebase and one database. Ask which part causes trouble: coupled deploys, one slow feature, scaling public traffic, or a team boundary.
  2. Suggest a strangler-fig migration instead of a rewrite. Keep Silverstripe as the content authoring system and put a gateway or reverse proxy in front of it. Then extract capabilities one at a time, choosing those with a clear boundary and different scaling needs, such as search, media processing, notifications or form processing.
  3. Give each extracted service its own datastore. Expose CMS content through an API (REST or Silverstripe's GraphQL module) or publish content-change events, so that no service reads the CMS tables directly. Use a message queue for slow work like image resizing or sending email.
  4. Be honest about the cost: network calls, distributed failure, more pipelines and more observability work. Add timeouts, retries with backoff, circuit breakers, correlation IDs and tracing.
  5. Say when you would not split at all. A small site run by one team is often better served by caching, static publishing and a CDN in front of the monolith.

Follow-up

  • Which capability would you extract first, and how would you show the extraction was worth it?
  • How do you keep a search service consistent with the CMS content it indexes?
  • How would you roll back if the new service misbehaves in production?

Pros and cons of native Android/iOS vs. frameworks like Flutter and React Native?

Medium · Technical and Domain Knowledge

Approach

  1. Frame the answer as a decision with criteria: performance and animation needs, how deeply you use platform APIs (camera, Bluetooth, background tasks, widgets, wallet passes), team skills, release cadence, app size and long-term maintenance.
  2. Native (Swift/SwiftUI on iOS, Kotlin/Jetpack Compose on Android) gives full, immediate access to new OS features, the best performance, platform look and feel, and mature debugging tools. The cost is two codebases, two skill sets and features drifting apart between platforms.
  3. Flutter uses one Dart codebase with its own rendering engine, so the UI looks the same on both platforms and animation performance is strong. The costs: a larger binary, platform features reached through platform channels or plugins, and a UI that does not follow native conventions on its own.
  4. React Native uses JavaScript or TypeScript over native components, and it shares skills, and sometimes logic, with a web team. Its newer architecture (JSI, Fabric, TurboModules) reduces the old bridge overhead. Heavy native integrations still need native modules, though, and dependency upgrades can be painful.
  5. End with a recommendation for a concrete case. Cross-platform suits a content- and form-heavy app built by a small team. Native suits apps that depend on device hardware, heavy background work or day-one OS features. A hybrid of shared screens plus native modules is common.

Follow-up

  • How would you share business logic between platforms without a cross-platform UI framework?
  • What would you measure to decide that a React Native screen is too slow?
  • How do offline support and push notifications change your recommendation?

Explain the architecture of microservice patterns along with standards.

Medium · Technical and Domain Knowledge

Approach

  1. Organise the answer in layers instead of listing pattern names: decomposition, data, communication, resilience, operations, and the standards that tie them together. Decompose by business capability or bounded context. Give each service its own data (database per service) so that teams can deploy independently.
  2. For communication, use synchronous REST or gRPC behind an API gateway, or a backend-for-frontend per client, for queries. Use asynchronous events over a broker such as Kafka or RabbitMQ for state changes. When a workflow spans several services, use a saga (choreographed events or an orchestrator) with compensating actions, plus a transactional outbox so a database write and its event cannot diverge.
  3. For resilience, put timeouts on every call. Retry with exponential backoff and jitter, but only for idempotent operations. Add circuit breakers, bulkheads and idempotency keys on writes. Reads that cross services can use CQRS-style materialised views instead of chains of calls.
  4. For standards, give each service an OpenAPI or protobuf contract and make backward-compatible changes by default. Use one error format (for example RFC 7807 problem details), OAuth2/JWT or mTLS between services, and health and readiness endpoints. Add structured logs with correlation IDs, metrics, OpenTelemetry tracing, twelve-factor configuration and a CI/CD pipeline per service.
  5. Name the trade-off: you gain independent deployment and scaling, and you pay with distributed failure, eventual consistency and operational overhead. Mention the strangler fig for migrations. Call out the anti-patterns: a shared database, chatty synchronous chains, and a distributed monolith whose services must deploy together.

Follow-up

  • How would you handle an order that must reserve inventory in one service and take payment in another?
  • How do you version an event schema that several consumers read?
  • When would you merge two services back into one?

Describe your home lab and how it is set up.

Medium · Technical and Domain Knowledge

Approach

  1. Describe the lab as a small production system. Cover the hardware (a mini PC, NAS or old server), the virtualisation or orchestration layer (for example Proxmox, Docker Compose or a k3s cluster), the network (VLANs, firewall, a reverse proxy with TLS, internal DNS) and the services it runs.
  2. Explain your operating practices, because they map to the role's backend and cloud requirements: configuration as code (Ansible, Terraform or Compose files in Git), a pipeline that builds and deploys, monitoring and alerting (Prometheus and Grafana, uptime checks), 3-2-1 backups with a restore you have tested, and remote access over a VPN such as WireGuard instead of open ports.
  3. Choose one problem you hit and solved, such as a failing disk, an expired certificate or a container running out of memory. Tell it as an incident: the symptom, how you diagnosed it, the fix, and the alert you added afterwards.
  4. Be honest about scale and gaps. If you have no home lab, describe the side project or cloud environment where you try out technologies, and don't invent one. Any component you name can turn into a deep dive.

Follow-up

  • Why did you choose that hypervisor or orchestrator over the alternatives?
  • How would you find out if your backups were silently failing?
  • What would you change if the lab had to serve real users?

Design an email app API.

Medium · Problem-Solving and Case Studies

Approach

  1. Clarify the scope first. This is a client API for a mail app (web and mobile) with send, receive, list, read, search, labels or folders, attachments and threads. Ask about scale, and whether the system delivers over SMTP itself or sits on a provider. State the non-functional needs: fast inbox listing, no duplicate sends, sync across devices.
  2. Endpoints: POST /v1/messages to send, with an Idempotency-Key header; GET /v1/threads?label=inbox&cursor=..&limit=..; GET /v1/threads/{id}; GET /v1/messages/{id}; PATCH /v1/messages/{id} for read, starred and labels; DELETE to move to trash; POST /v1/attachments returning a pre-signed upload URL; GET /v1/search?q=..; plus label CRUD. Add cursor pagination, ETags, OAuth2 scopes and rate limits.
  3. For sync, give each mailbox a change id that only increases. Clients call GET /v1/changes?since=<id> to fetch deltas, and a WebSocket or mobile push acts only as a hint to sync. If the id is too old, the API tells the client to do a full resync.
  4. For storage, keep message metadata in a store partitioned by user id, so an inbox listing is one range query per user. Put bodies and attachments in object storage and update a search index (Elasticsearch or OpenSearch) asynchronously. Outbound mail goes on a queue to SMTP workers that handle retries, bounces and DKIM signing. Build threads from the Message-ID, In-Reply-To and References headers.
  5. Cover the edge cases: large attachments and virus scanning, a client retrying a send, a message carrying several labels, archive versus delete, and autosaving a message that is being written but not yet sent, which needs its own unsent state.

Follow-up

  • How do you make sure a message is never sent twice when the client retries?
  • How does the inbox stay fast for a user with millions of messages?
  • How would you add spam filtering without slowing inbound delivery?

Provide a situation about a company with emails involving stakeholders; discuss the technical skills needed to

Medium · Problem-Solving and Case Studies

Provide a situation about a company with emails involving stakeholders; discuss the technical skills needed to solve the problem.

Approach

  1. The prompt is open, so turn it into a concrete case before you solve it. For example: a company sends operational updates to stakeholders by email, and messages get missed, duplicated or sent to the wrong people. Ask who the stakeholders are, what triggers an email, and what a failure costs.
  2. Define success in measurable terms: delivery rate, time from event to notification, complaints, manual follow-ups. Size the problem with data: join events, recipients and delivery logs in SQL, GROUP BY template or domain to find failure rates, and use a CTE to stage the steps.
  3. Outline the solution and the technical skills it needs: an event-driven notification service behind an API, templates, recipient and preference management, a queue with retries and deduplication, SPF, DKIM and DMARC for deliverability, bounce handling, audit logs, and integration with the source systems.
  4. Name the non-technical skills too: gathering requirements from each stakeholder group, agreeing on who owns what, explaining trade-offs to non-technical people, and rolling out in stages while collecting feedback.

Follow-up

  • How would you prioritise if two stakeholder groups want conflicting things?
  • How would you show that the change worked?
  • Which parts would you build and which would you buy?

Walk me through your problem-solving approach for a technical challenge.

Medium · Problem-Solving and Case Studies

Approach

  1. Give a sequence you repeat every time, then prove it with a real example: understand and reproduce the problem, define what done means, gather evidence (logs, metrics, traces, recent deploys), rank hypotheses, test the cheapest high-information one first, fix, verify, and prevent it from happening again.
  2. Show the techniques you actually use: bisecting commits or configuration, minimal reproductions, temporary instrumentation, comparing a healthy instance with a failing one, and rolling back to stop the impact before you hunt for the root cause.
  3. For design problems the same method becomes: clarify requirements and constraints, sketch two options, compare their trade-offs and choose one with reasons.
  4. Tell your example in the first person with numbers (error rate, latency, time to resolve), and finish with the guardrail you added afterwards: a test, an alert or a runbook entry.

Follow-up

  • What do you do when your first three hypotheses turn out to be wrong?
  • When do you ask for help, and how do you ask?
  • How do you choose between a quick fix and a proper fix?

One log partition stops advancing while the others drain

Easy · poison message · head-of-line blocking · consumer lag

Search results for a subset of tenants are hours stale; the rest are current. The projection consumer reports lag of zero on 15 of 16 partitions and 400,000 on one. Its error rate is flat and its CPU is idle. outbox_event has no pending rows older than a second, so the relay has published everything it holds. Identify the mechanism, give the ordered checks, and state what you do in the first ten minutes versus what you change permanently.

Approach

  1. Read the lag distribution first. A slow consumer lags everywhere; zero on fifteen partitions and 400,000 on one is not throughput. Idle CPU on the stuck partition means the consumer is not advancing its offset at all, which points at one message it cannot get past rather than at a rate problem.
  2. Exonerate the producer before touching the consumer. No pending outbox rows older than a second means the relay published, so the event exists in the log. This separates never sent from sent and never applied, which are different code paths and usually different owners.
  3. Read the message at the stuck offset and the handler's log lines for its event_id. A flat error rate with no progress has two explanations and you must distinguish them: the handler is throwing and the retry loop is swallowing it, or the handler is blocking on something and never returning. Idle CPU with no error lines favours the second.
  4. Mitigate before diagnosing further. Move the offending event to a dead-letter store and commit the offset past it. Adding consumers does nothing here, because a partition is consumed by exactly one member of the group, and the blast radius is every aggregate hashed to that partition, not only the aggregate that produced the bad event.

Follow-up

  • The dead-lettered event carried aggregate_version 7 and the projection had applied 6. What must the replay do differently if 8 and 9 landed in the meantime?
  • How do you show staleness to the user while the partition is behind, given the API already returns the projection's watermark?

Suggested practice checklist

Each day covers one part of the reported loop: the CV deep dive, microservices, API design, database querying, coding and problem-solving method, the mobile and stakeholder cases, and finally motivation and team fit. Every day ends with something written or recorded that you can review before the interviews.

Day 1 — Turn your CV into deep-dive material

  • List every technology on your CV. For each one, write why you chose it, one alternative, one failure you debugged and one thing you would change, then cut anything you cannot defend.
  • Write and rehearse your self-introduction in present, past, future order, naming only technologies from that list.
  • Outline your biggest-challenge story in STAR form, and describe your home lab (or side-project environment) as a small production system with one incident.

Deliverable: A sheet of technologies you can defend, a recorded self-introduction, a STAR outline of your biggest challenge and a written home lab description with one incident.

Day 2 — Microservice patterns and the Silverstripe case

  • Write a one-page pattern sheet organised by decomposition, data, communication, resilience, operations and standards, noting the problem each pattern solves.
  • Sketch a strangler-fig plan for splitting a Silverstripe monolith: the first capability to extract, its datastore, the API or events it relies on, and how you would roll it back.
  • Solve the practice problem on tracking a rolling failure rate per destination, and explain how that rate drives a circuit breaker's decision to open.

Deliverable: A pattern sheet, a Silverstripe migration diagram with rollback notes, and working code for the rolling failure-rate tracker.

Day 3 — API design and code review

  • Outline the email app API (resources, endpoints, pagination, idempotent send, attachments, delta sync, storage) and present it aloud from start to finish.
  • Write the OpenAPI definition for sending a message and listing threads, including error responses and the Idempotency-Key header.
  • Write your code review checklist and one first-person story of a review that caught a real problem.

Deliverable: An email API outline with a recorded walkthrough, an OpenAPI file for two endpoints, and a review checklist with one story.

Day 4 — Database querying: joins, GROUP BY, CTEs

  • Build a small schema (users, threads, messages, labels) and write queries that use inner and left joins, GROUP BY with HAVING, and a CTE that stages a calculation in several steps.
  • Work the practice problem on stopping tag and share joins from fanning out a page, and explain why the duplicate rows appear.
  • Work the practice problem on version gaps and relay lag with window functions.

Deliverable: A query file with at least five commented queries, plus solutions to both SQL practice problems.

Day 5 — Coding and problem-solving method

  • Solve the overlapping job attempts and peak concurrency problem in your main backend language, stating its complexity and edge cases.
  • Solve the resource graph archiving problem iteratively, without recursion.
  • Work the stalled log partition debugging problem, then use it as the worked example in your answer on how you approach a technical challenge.

Deliverable: Two tested solutions with complexity notes, a written debugging sequence and a recorded problem-solving answer.

Day 6 — Mobile trade-offs and the stakeholder email case

  • Build a decision table comparing native iOS/Android, Flutter and React Native on performance, platform access, team skills, binary size and maintenance, and make a recommendation for two different app scenarios.
  • Recast the stakeholder email question as a concrete case: define success metrics, outline the notification service, and list the technical and communication skills it needs.
  • Answer both questions aloud and note every point where you hesitated.

Deliverable: A mobile decision table with two recommendations, a one-page stakeholder email case, and recordings of both answers with your hesitation notes.

Day 7 — Motivation, team fit and a full run-through

  • Write specific answers to why AIR, what you think about working for an airline and how you stay up to date, each backed by evidence from your own work.
  • Prepare STAR stories on a stakeholder disagreement, an on-call incident and a time you explained a trade-off to a non-technical colleague.
  • Run a mock that covers a screening conversation, one design question and one behavioural question, then rework your weakest answer.

Deliverable: Three motivation answers, three STAR stories, and a mock-loop recording with notes on what you changed.

Behavioural preparation

Candidates report a final Team Fit Discussion about how they would work with the team. Across the process, the behavioural themes they list are handling disagreements with stakeholders, owning reliability and on-call, explaining technical ideas to non-technical colleagues, and motivation for aviation work. Rehearse each prompt with a specific STAR story told with 'I', a result you can measure and what you learned.

  1. Tell me about a disagreement with a stakeholder over a technical decision and how it was resolved.

Can you explain your approach to API design and code review?

Medium · Technical and Domain Knowledge

Approach

  1. For API design, start from the consumers and their use cases. Model the resources and how they relate, then pick a style: REST for resource operations, gRPC for high-throughput internal calls, events for notifications. Write the contract first in OpenAPI and get it reviewed before you implement.
  2. Name the conventions you follow: correct HTTP methods and status codes, cursor pagination for large lists, filter and sort parameters, idempotency keys on POSTs with side effects, one error format, scoped tokens and rate limits. Make additive changes the default and add a new version only for breaking changes.
  3. For code review, keep pull requests small and focused. Let CI handle formatting, linting and tests, so that human review goes to correctness, edge cases, contract and schema changes, security (input validation, authorisation, secrets), observability and readability. Mark each comment as blocking or optional, and phrase comments as questions with a reason.
  4. Support it with one first-person example, such as: I caught a breaking change to a response field in review, raised it, and added a contract test so it could not happen again.

Follow-up

  • How do you deprecate an endpoint that external clients still call?
  • What do you do when reviewer and author disagree and both have a point?
  • How do you handle a pull request that is too large to review well?

Why do you want to work at AIR?

Medium · Behavioral and Leadership

Approach

  1. Use three parts: what draws you to the domain, how the role matches your skills, and what you want to learn there. Keep every part concrete.
  2. For the domain, explain what interests you as an engineer in airline software: operations that cannot pause, many integrated systems, data-heavy workloads, and disruption days when load and complexity spike. Read AIR's own public material beforehand and mention only what you have actually read.
  3. For the role, map your experience onto the requirements candidates describe: backend work in Java, Python or similar, API design, cloud and microservices, and on-call duties. Give one piece of evidence for each point, such as a service you built, an API you designed or an incident you handled.
  4. What sinks this answer: reasons that fit any employer (size, stability, travel perks), or claims about the company you cannot support.

Follow-up

  • What do you see as the hard parts of building software for aviation?
  • Which part of this role would stretch you most?
  • Why are you leaving your current role?

Tell me about yourself and your past experiences.

Medium · Behavioral and Leadership

Approach

  1. Use present, past, future: what I do now and the system I own; two or three earlier experiences that built the skills this role lists; why this role is the logical next step. Keep it short enough to leave room for questions.
  2. Choose the technologies you mention on purpose. Candidates report that the CV serves as the map for the technical deep dive, so anything you highlight should be something you can explain down to internals, trade-offs and failure modes.
  3. Give one result with a number for each job (lower latency, fewer incidents, a finished migration) and state your own part in it with 'I'.
  4. What sinks it: reading the CV out in date order with nothing connecting it to backend, API and microservices work.

Follow-up

  • Which of those projects are you proudest of, and why?
  • What exactly was your role in the microservices work you mentioned?
  • What would you do differently in your last job?

Could you describe your biggest challenge and how you solved it?

Medium · Behavioral and Leadership

Approach

  1. Pick a technical challenge with real stakes where you made the key decisions: a migration, a scaling limit, a production incident, or a design you had to defend. Ideally it also shows the microservices, API or reliability experience the role asks for.
  2. Use STAR. Keep Situation and Task brief and spend most of the answer on Action: the options I weighed, why I chose one, what I did when part of it went wrong, and whom I had to persuade.
  3. Close with a Result you can measure, the trade-off you accepted and what it cost, and a lesson you applied on a later project.
  4. What sinks the story: a team 'we' all the way through, which hides your contribution, or a challenge that someone else actually solved.

Follow-up

  • What would you do differently now?
  • How did you convince others that your approach was right?
  • How did you confirm the problem was really fixed?

How do you stay up to date with current trends and technologies?

Medium · Behavioral and Leadership

Approach

  1. Name specific sources tied to your stack: release notes for your language and frameworks, RFCs and specifications, engineering blogs and published postmortems from other companies, conference talks, and one or two newsletters. Specific names sound more credible than 'I read a lot'.
  2. Show how you filter. Explain how you decide what is worth trying (a problem you actually have, maturity, community, operating cost) and how you try it, for example with a spike in a home lab or side project and a short write-up.
  3. Give one example of a technology you adopted at work after evaluating it, with the outcome, and one you decided against, with the reason. That shows judgement, not trend-chasing.
  4. Tie it to the role by saying how you keep up with microservices, API and cloud practice, for example OpenTelemetry, contract testing or managed cloud services.

Follow-up

  • What did you learn recently that changed how you work?
  • How do you persuade a team to adopt something new?
  • Which current trend do you think is overrated, and why?

What are your thoughts on working for an airline company?

Medium · Behavioral and Leadership

Approach

  1. Show that you have thought about what airline software involves: operations that run around the clock, many systems that must integrate (often including older ones), safety and regulatory requirements, and sudden peaks when weather or disruption forces mass rebooking and notifications.
  2. Turn that into how you work: careful change management, testing and staged rollouts, observability, ownership of on-call, and designs that degrade gracefully when a dependency fails. The role as candidates relay it includes on-call, so say how you have handled on-call before.
  3. Be honest about the trade-offs. Change can move more slowly where reliability matters this much, so explain why that suits you or how you keep delivery moving anyway.
  4. Mention an interest in operations or logistics problems only if it is real, and say what sparked it.

Follow-up

  • How would you handle a production incident on a peak operational day?
  • How do you balance shipping speed against reliability?
  • What kinds of systems do you think an airline depends on?