cswork / libraryOpen practice workspace

Interview guides · Blue Canyon Technologies

Blue Canyon Technologies Software Engineer Interview Guide

Blue Canyon Technologies Software Engineer interview guide: coding and satellite-diagnosis questions, behavioral stories, and a 7-day prep plan.

The 60-second brief

Blue Canyon Technologies is an aerospace company, and candidates describe the Software Engineer role as software for satellite systems and small spacecraft. The work they list spans data processing, control systems and user interfaces, done alongside hardware engineers, systems engineers and product managers. Day to day it covers writing code, testing and validating it, taking part in code reviews and documenting specifications and designs.

This guide is for candidates interviewing for a Software Engineer position at Blue Canyon Technologies. It covers the three reported rounds (Phone Screen, Technical Interview, Behavioral Assessment), the reported questions on languages, version control, code quality, algorithms, data structures and scenario-style problems, and the behavioral prompts, with a seven-day plan that ties them together.

Candidates report three rounds over roughly three to five weeks: a Phone Screen with a recruiter, a Technical Interview built around coding and problem solving, and a Behavioral Assessment. Teams can vary the format slightly.

Focus areas

  • GD&T (Geometric Dimensioning and Tolerancing)
  • Technical Interviewing
  • Whiteboard Coding/Reasoning

Overview

The requirements candidates describe for this role name C++, Python or Java, Agile methods, a solid grasp of algorithms and data structures, and Git. Nice-to-have items include aerospace experience, software testing frameworks, simulation tools and DevOps practices. That mix points to a loop where fundamentals come first: pick one of the listed languages and be fluent in it on a whiteboard, with no editor to catch a missing pointer update or an off-by-one error.

The reported questions fall into four groups. Engineering-practice questions ask about the languages you use, how you work through a development life cycle, what version control does in your process and how you keep code maintainable. Scenario questions ask you to diagnose a hypothetical satellite system failure, design a feature for a satellite control application's user interface, reason about a data compression algorithm, tune a data processing pipeline and handle a project with unclear requirements. Coding questions cover reversing a linked list, optimising a sort for large datasets, searching a set of data points, comparing data structures and writing something like Fibonacci. Behavioral questions cover a difficult teammate, prioritising, adapting to change, motivation and criticism.

Because the role sits next to hardware and systems engineers, scenario answers gain from a visible method: state the symptom, list what changed, say which evidence you would gather first, then narrow down. You do not need spacecraft knowledge to do that. Some candidates also mention topics such as ADCS (Attitude Determination and Control System), star trackers, GD&T and automated testing in connection with this company. Treat them as background: be able to say in a sentence what each term means, and ask the recruiter which of them the team actually touches.

Preparation should therefore split roughly three ways: whiteboard coding without tooling, a repeatable structure for open-ended technical scenarios, and a set of behavioral stories drawn from real work, ideally including one where you worked across a software and hardware boundary or a changing specification.

The Blue Canyon Technologies interview process

Candidates describe three stages, in this order: a recruiter Phone Screen, a Technical Interview and a Behavioral Assessment. Different teams may vary the format slightly.

Phone Screen

Candidates report this as a first call with a recruiter about your background and qualifications. Treat it as a short, spoken version of your CV: the languages you use, the projects you built with them and why you want a software role on spacecraft and satellite systems. The reported question about the languages you are most proficient in and how you applied them fits this conversation well, so have a concrete answer ready.

What to demonstrate

  • Your background and qualifications as you describe them in conversation
  • How clearly you connect your language and project experience to the role

How to prepare

  • Write a two-minute walk through your CV that names one project per language you list, and what you personally built in it.
  • Pick one of C++, Python or Java as the language you will use on the whiteboard and be ready to say why.
  • Ask the recruiter what the technical stage looks like (whiteboard or coding challenge) and which team the role sits on, since candidates report slight format differences between teams.

Technical Interview

Candidates describe this stage as coding and problem-solving interviews, often run on a whiteboard or as coding challenges. The reported questions on algorithms, data structures and scenario-style problems are the practice material for this format: the linked-list reversal, the sorting and search questions, the data structure comparison, the Fibonacci-style problem, and the scenarios about a satellite failure, a control application interface, compression and pipeline tuning. Talk through your reasoning while you write, and finish by testing your own code on a small and an empty input.

What to demonstrate

  • Working code for a standard algorithm or data structure problem, written without tooling
  • Problem-solving approach on open-ended technical scenarios
  • Testing and debugging habits, which the role listing names as part of the work

How to prepare

  • Write the linked-list reversal, a binary search and an iterative Fibonacci by hand in your chosen language, then dry-run each on an empty input and a one-element input.
  • Prepare a fixed diagnosis sequence for the satellite failure scenario: symptom, recent change, evidence to collect, hypothesis ranking, smallest test that separates hypotheses.
  • Be able to compare arrays, linked lists, hash tables, trees and heaps by access, insert and memory cost, and say when each wins.
  • Rehearse the reported engineering-practice answers on version control, code quality and a hard technical problem you solved.

Behavioral Assessment

Candidates report this stage as interviews about how you fit with the team and with the company. The reported behavioral questions are the practice material: a difficult team member, prioritising across projects, adapting to a significant change, what motivates you in a team and how you take constructive criticism. The role listing stresses collaboration with hardware engineers, systems engineers and product managers and participation in code reviews, so stories that show those interactions are the most relevant ones to prepare.

What to demonstrate

  • How you describe working with other people and handling disagreement
  • Examples from your own past work, as you present them
  • How you respond to feedback and to changing circumstances

How to prepare

  • Write four stories with a clear structure of situation, your decision, the result and what you changed afterwards: a conflict, a competing-priorities case, a change in scope or requirements, and a piece of feedback you acted on.
  • Make every story say what you personally did; replace 'the team decided' with the part you owned.
  • Prepare one story about a code review, as reviewer or author, since the role lists code reviews as part of the work.
  • Prepare two questions for the interviewers about how software and hardware engineers coordinate on this team.

Where candidates lose points

Answering the languages question with a list of everything on your CV

Pick the one language you will use on the whiteboard, and tie each language you mention to a project and to what you built in it. Candidates describe C++, Python and Java as the languages in the requirements, so be ready to go deep in whichever of them you claim.

Writing the linked-list reversal and losing the next pointer

Save the next node before you rewire the current one, keep previous, current and next as three named variables, and dry-run your code on an empty list and a one-node list before you say it is done.

Freezing on the satellite failure scenario because you lack spacecraft knowledge

Use a method that works for any system: define the symptom and when it started, list recent changes, say which logs or telemetry you would read first, rank hypotheses and describe the smallest test that separates them. Ask clarifying questions about the system instead of guessing.

Giving behavioral answers where the team did everything and your own decision is missing

For each story, write one sentence that begins 'I decided' and one sentence about the outcome. A story about a difficult teammate or a change in scope needs your action and a resolution, not a description of the conflict.

Presenting code without testing it or naming edge cases

Testing and validation are listed in the role's responsibilities, so finish every coding answer by stating test cases aloud: empty input, single element, duplicates and a large input, and say what you would automate.

Questions & practice

Walk us through your thought process in developing a new algorithm for data compression.

Medium · Problem-Solving / Case Studies

Approach

  1. Clarify the data and constraints: sensor samples, images or text; lossless or lossy allowed; CPU and memory budget of the encoder; and whether the link can corrupt or drop bits.
  2. Set a baseline: estimate the Shannon entropy of the symbols as a bound for a simple symbol-by-symbol coder, and benchmark existing options (run-length encoding, Huffman, LZ77-family such as DEFLATE, LZ4 when speed matters).
  3. Exploit the structure: for slowly varying sensor data, use delta or predictive coding so residuals cluster near zero, then a variable-length code such as Rice or Golomb coding (the approach used in the CCSDS lossless standard); for repeated byte patterns, a dictionary method.
  4. Trade-offs: compression ratio vs speed vs memory; adaptive models compress better but a single corrupted bit can break decoding of everything after it, so compress in independent blocks with a checksum per block.
  5. Validate with round-trip tests (decompress(compress(x)) == x) on empty input, constant data and random data; random data cannot shrink, so cap the overhead with a stored-uncompressed fallback.

Follow-up

  • Why can no lossless compressor shrink every possible input?
  • How would you limit the damage from a bit flip in the compressed stream?
  • When would you choose arithmetic coding over Huffman coding?

Write a function to reverse a linked list and explain your approach.

Medium · Coding / Algorithms

Approach

  1. Iterative three-pointer reversal: prev = None, curr = head; while curr: nxt = curr.next; curr.next = prev; prev = curr; curr = nxt; return prev. O(n) time, O(1) extra space.
  2. Edge cases: empty list (return None), a single node, two nodes; confirm the old head's next is now null so no cycle remains.
  3. Recursive alternative: reverse the rest, then head.next.next = head and head.next = None. Also O(n) time but O(n) call stack, so a long list can overflow the stack (CPython's default recursion limit is 1000).
  4. Dry-run 1 -> 2 -> 3 aloud, tracking prev, curr and nxt at each step, before claiming the code works.
  5. Note the doubly linked variant: swap each node's prev and next pointers, then the old tail becomes the head.

Follow-up

  • Reverse the nodes between positions m and n only.
  • Reverse the list in groups of k.
  • How would you detect a cycle before reversing (Floyd's tortoise and hare)?

How would you optimize a sorting algorithm for large datasets?

Medium · Coding / Algorithms

Approach

  1. Clarify the data: does it fit in memory, what are the key type and range, is it partly sorted already, and is a stable sort required?
  2. In memory, comparison sorts cannot beat O(n log n) comparisons: quicksort is O(n log n) on average but O(n^2) worst case (introsort, as in std::sort, falls back to heapsort); merge sort is stable with O(n) extra space; heapsort uses O(1) extra but is not stable; Timsort (Python's sorted, Java's object sort) runs in O(n) on already sorted input.
  3. For integer or fixed-width keys, non-comparison sorts win: counting sort O(n + k) for key range k, radix sort O(d(n + k)) for d digits.
  4. When data exceeds memory, use external merge sort: sort memory-sized chunks into runs on disk, then k-way merge them with a min-heap in O(N log k), using large sequential reads and as few passes as possible.
  5. Further gains: sort partitions in parallel (range-partition by sampled splitters so outputs just concatenate), and sort keys or indices rather than moving large records.

Follow-up

  • When does stability matter, and which of these sorts are stable?
  • With M records of memory and N records on disk, how many runs and merge passes does external sort need?
  • Which algorithm would you choose for nearly sorted data, and why?

Given a set of data points, how would you implement a search algorithm to find specific values?

Medium · Coding / Algorithms

Approach

  1. Clarify: one query or many, exact match, range or nearest value, is the data sorted, does it change, and how many dimensions?
  2. Unsorted data and a single query: linear scan, O(n). Many exact lookups: build a hash set or map once in O(n), then O(1) average per lookup.
  3. Sorted data: binary search in O(log n); compute mid as lo + (hi - lo) / 2 to avoid integer overflow in C++ or Java; use the lower-bound form (first index with value >= target) for duplicates and range queries; the library versions are bisect in Python and std::lower_bound in C++.
  4. Data with inserts plus ordered or range queries: a balanced tree (std::map, Java TreeMap) gives O(log n) insert and search; for nearest-neighbour search in a few dimensions, a k-d tree or grid bucketing.
  5. Edge cases: empty input, target absent, duplicates, and floating-point values compared with a tolerance rather than ==.

Follow-up

  • Return the first and last index of a target in a sorted array with duplicates.
  • Search a sorted array that has been rotated.
  • Given time-stamped samples, find the sample nearest to a query time.

Explain the differences between various data structures and when to use each.

Medium · Coding / Algorithms

Approach

  1. Array or dynamic array: contiguous, O(1) indexing, amortised O(1) append, O(n) insert in the middle; cache-friendly, so it is the default choice.
  2. Linked list: O(1) insert or delete at a known node but O(n) access and poor cache locality; worth it when paired with a hash map, as in an LRU cache.
  3. Hash table: O(1) average insert and lookup, O(n) worst case, no ordering; balanced BST or ordered map: O(log n) operations with sorted iteration and range queries.
  4. Stack (LIFO) for DFS, undo and parsing; queue (FIFO) for BFS and producer-consumer buffers; a fixed-size ring buffer for streaming samples without allocation; binary heap with O(log n) push and pop and O(1) peek for scheduling and top-k.
  5. Graphs: adjacency list for sparse graphs, adjacency matrix for dense ones; a trie for prefix lookups. Choose from the operations you need most and the memory you have.

Follow-up

  • Design an LRU cache with O(1) get and put.
  • Why does a vector often beat a linked list in practice even for middle insertions?
  • How does a hash table handle collisions and resizing?

Can you code a solution for a common algorithm problem, such as the Fibonacci sequence?

Medium · Coding / Algorithms

Approach

  1. Clarify the indexing (F(0) = 0, F(1) = 1), the range of n, how to handle negative input, and whether the exact value or a value modulo m is wanted.
  2. Naive recursion recomputes subproblems and takes exponential time (about phi^n calls); memoisation brings it to O(n) time and O(n) space; bottom-up with two variables is O(n) time and O(1) space.
  3. For very large n, use matrix exponentiation of [[1,1],[1,0]] or fast doubling (F(2k) = F(k)(2F(k+1) - F(k)), F(2k+1) = F(k)^2 + F(k+1)^2), both O(log n) multiplications.
  4. Overflow: F(92) is the largest value that fits a signed 64-bit integer, so a long in Java or int64_t in C++ overflows from F(93); use modulo arithmetic or big integers (Python ints are arbitrary precision).
  5. Test n = 0, 1, 2 and 10 (F(10) = 55) before calling it done.

Follow-up

  • Count the ways to climb n stairs taking 1 or 2 steps at a time.
  • Compute F(n) mod 1,000,000,007 for n = 10^18.
  • Write it as a generator that yields the sequence lazily.

Hold a per-tenant active cap against concurrent creates

Hard · write skew · isolation levels · constraints

A tenant on the standard plan may hold at most 50 resources with status='active'. The create handler runs SELECT count(*) FROM resource WHERE tenant_id = $1 AND status = 'active', compares to 50, then inserts. Two creates arrive 3 ms apart on different instances and the tenant lands at 51. Name the anomaly, say whether PostgreSQL 16 READ COMMITTED or REPEATABLE READ prevents it and why, then give an implementation that holds the cap at READ COMMITTED with the exact statements. Finally, say what changes when the cap is 'at most one running export per tenant' on job_run.

Approach

  1. Name it: write skew. The two transactions read an overlapping set and write disjoint rows, so there is no row-level conflict for the engine to detect and each commit is individually legal.
  2. Rule out the levels precisely. READ COMMITTED takes a fresh snapshot per statement and takes no lock on the counted rows, so both see 49. PostgreSQL's REPEATABLE READ is snapshot isolation: it removes non-repeatable reads and phantoms within the snapshot but still admits write skew, because the anomaly is not a re-read of a changed row, it is a read of a set that a concurrent transaction invalidates. Only SERIALIZABLE closes it, by tracking the read dependency and aborting one transaction with SQLSTATE 40001 — a guarantee that exists only if the application re-runs the whole transaction from the read.
  3. Convert the set predicate into a single-row conflict: keep tenant.active_resource_count and run UPDATE tenant SET active_resource_count = active_resource_count + 1 WHERE tenant_id = $1 AND active_resource_count < 50 in the same transaction as the INSERT. Zero affected rows is the cap, returned as 409. The row lock serialises the decision at any isolation level, and contention is bounded to one tenant's row — which is also the fair-scheduling unit, unlike a global counter that would convoy every tenant behind one row.
  4. State the cost you just took on: a counter is a second source of truth that can drift, so every path that changes status must adjust it inside the same transaction, and a periodic reconciliation has to exist, with resource_revision as the authority for what the count should have been.

Follow-up

  • A resource moves from archived back to active. Which statements change, and what breaks if the counter update and the status change land in different transactions?
  • The cap becomes plan-dependent and a plan can change mid-month. Where does the number 50 live, and who reads it?

Denormalise tenant onto revisions and backfill it live

Hard · denormalisation · online migration · backfill

resource_revision (revision_id, resource_id, version, actor_user_id, change_kind, patch, request_id, created_at) has 400M rows and no tenant column; tenant_id lives only on resource. Two reads need it: a tenant-scoped audit feed ordered by created_at DESC, and an offboarding purge. Both join back to resource today. Justify adding tenant_id to resource_revision against those two reads, name the anomaly the copy introduces and the constraint that prevents it, then give the ordered migration for a live table taking 1.2k writes/second — the lock each step takes, how the backfill is batched, and where each step stops being reversible. PostgreSQL 16.

Approach

  1. Justify from the access path rather than from taste. Without the column, the audit feed either scans resource_revision by created_at and discards other tenants' rows, or resolves the tenant's resource_ids first and probes with them — both proportional to the tenant's whole history rather than to one page. With (tenant_id, created_at DESC, revision_id DESC) it is a seek that stops at 50 rows, and the purge becomes a ranged delete instead of a join.
  2. Name the cost exactly: a second copy of a fact can disagree with the first. Make the disagreement unwritable rather than documented — add UNIQUE (resource_id, tenant_id) on resource so it can serve as a foreign-key target, then FOREIGN KEY (resource_id, tenant_id) REFERENCES resource (resource_id, tenant_id) on the revision table. A revision can then only ever carry its parent's tenant.
  3. Step one, expand: ALTER TABLE resource_revision ADD COLUMN tenant_id BIGINT NULL, with no default, so it is a catalogue change and no rewrite. It still needs ACCESS EXCLUSIVE for an instant, and that instant queues behind the longest open transaction on the table while every later query queues behind it — set lock_timeout to 2s and retry rather than wait.
  4. Step two, dual-write: deploy the writer that populates tenant_id on every new revision while reads still use the join. Reversible by redeploying the previous build, because nothing reads the column yet.

Follow-up

  • The backfill is half finished and a rollback is required. What state is the table in, and what does the previous build do with a half-populated column?
  • How do you verify the backfill actually finished, given rows are still being inserted while it runs?

What programming languages are you most proficient in, and how have you applied them in your projects?

Medium · Technical / Domain Questions

Approach

  1. Name one or two languages you can code live in today, ideally from the C++, Python or Java that candidates report in the role requirements, and keep 'proficient' separate from 'have used'.
  2. For each language, give one project: what you built, why that language fit it (C++ for control over memory and latency, Python for test tooling, scripting and data analysis, Java for large typed services), and one measurable result.
  3. Prove depth with specifics: in C++, RAII, std::unique_ptr vs std::shared_ptr ownership, const-correctness, avoiding heap allocation in hot loops; in Python, generators for streaming large files, numpy vectorisation, type hints checked by mypy, pytest fixtures.
  4. Name a trade-off you hit: compiled vs interpreted speed, garbage collection pauses vs manual lifetime management, or the cost of crossing a Python-to-C++ boundary.

Follow-up

  • In C++, when would you choose std::unique_ptr over std::shared_ptr, and what does shared_ptr cost?
  • How does CPython's GIL affect a CPU-bound multithreaded job, and what would you do instead?
  • What bug did that language let you write that a different language would have caught at compile time?

Describe a challenging technical problem you faced and how you solved it.

Medium · Technical / Domain Questions

Approach

  1. Pick a problem with a concrete symptom (crash, wrong output, missed deadline, memory growth) and say in one sentence what made it hard: intermittent, hardware-dependent, or not reproducible on your machine.
  2. Walk the diagnosis in order: reproduce, shrink to a minimal case, narrow with logs, a debugger or git bisect across commits, then state the hypothesis you tested and the evidence that confirmed it.
  3. Explain the fix and at least one alternative you rejected, with the reason (risk, performance, scope).
  4. Close with verification: the regression test you added, the before and after numbers, and what you changed so the same class of bug is caught earlier.
  5. Tell it in the first person singular: say which steps you did yourself, not what the team did.

Follow-up

  • How did you rule out the second most likely cause?
  • What test or monitor now catches this if it comes back?
  • What would you have done with half the time?

What role does version control play in your development process?

Medium · Technical / Domain Questions

Approach

  1. Describe your branching flow in Git: short-lived feature branches merged through pull requests with review and CI on a protected main branch; contrast trunk-based development with long-lived GitFlow branches and say when each fits.
  2. Tie version control to traceability: tag every release, embed the commit hash in the build artefact, and pin dependencies or submodules so any shipped version can be rebuilt exactly.
  3. Commit hygiene: small atomic commits whose message says why; rebase your own local branch for a clean history, never rebase a branch others have pulled.
  4. Use history as a debugging tool: git bisect finds the regression commit in about log2(n) test runs over n commits; git log -S and git blame show when and why a line changed.
  5. Recovery: git revert to undo a pushed commit without rewriting shared history; git reset only for local work; git reflog to recover a commit you thought you lost.

Follow-up

  • When do you merge and when do you rebase?
  • A bad commit is already on main and others have pulled it. How do you undo it?
  • How do you handle large binary files or generated artefacts in the repository?

How do you ensure code quality and maintainability?

Medium · Technical / Domain Questions

Approach

  1. Automate the mechanical checks so review time goes to logic: compiler warnings as errors, static analysis (clang-tidy or cppcheck for C++, mypy and a linter for Python), and a formatter (clang-format, black) enforced in CI.
  2. Testing layers: unit tests for pure logic, integration tests at module interfaces, and a regression test for every bug fixed; treat coverage as a signal of untested paths, not a target.
  3. Make hardware- or I/O-touching code testable by putting it behind an interface and injecting fakes or simulators.
  4. Review small pull requests with a short checklist: error handling, boundary values, resource ownership and cleanup, units of measure in names or types.
  5. Maintainability trade-off: clear module boundaries and documented interfaces, but no abstraction until there is a second or third real use.

Follow-up

  • How would you add tests to legacy code that has none (characterisation tests first)?
  • What is the first thing you check when reviewing someone else's pull request?
  • How do you test code that depends on hardware you cannot run in CI?

Given a hypothetical satellite system failure, how would you approach diagnosing the problem?

Medium · Problem-Solving / Case Studies

Approach

  1. Scope the symptom first: what was observed (loss of telemetry, unexpected reset, attitude or power anomaly), when, and whether the vehicle is in a safe, stable state; stabilising the system comes before root cause.
  2. Collect evidence around the event: the telemetry timeline against a nominal baseline, event and error logs, the last commands uplinked, recent software or configuration changes, and environmental context such as an eclipse transition or temperature swing.
  3. Build a ranked hypothesis list (fault tree) split by subsystem (power, communications, attitude control, flight software) and by cause type (hardware, software, operator command, radiation-induced bit flip), ordered by likelihood and how cheaply each can be tested.
  4. Reproduce on the ground: replay the command sequence and telemetry in a simulator or hardware-in-the-loop testbed, changing one variable at a time.
  5. Fix and verify: test the patch on the testbed, uplink in stages, monitor the affected telemetry, and write up root cause plus the telemetry or fault-protection change that would make the next failure faster to diagnose.

Follow-up

  • Downlink time is limited. Which data do you request first, and why?
  • How would you tell a single-event upset apart from a software bug?
  • What would you add to the flight software or telemetry so this failure is easier to diagnose next time?

How would you design a software feature to improve the user interface of a satellite control application?

Medium · Problem-Solving / Case Studies

Approach

  1. Start from the operator and the task: who uses the screen, during what activity, and what goes wrong today (missed alarms, slow or error-prone command entry); define a measurable goal such as time to acknowledge an alarm or command errors per pass.
  2. Pick one concrete feature and outline it, for example a limit-alarm panel: telemetry points grouped by subsystem with caution and warning thresholds, acknowledge state, and a staleness marker when a value has stopped updating.
  3. Build safety into commanding: validate parameters against the command database before sending, show a preview, require a second confirmation for hazardous commands, show which vehicle is targeted, and log every action.
  4. Architecture: keep telemetry ingest separate from rendering, push updates over a subscription such as WebSockets, and batch screen updates so high-rate data does not freeze the UI; label every timestamp with its time base (spacecraft time vs ground receipt, UTC).
  5. Validate with operators on simulator-fed telemetry, and do not rely on colour alone for alarm state.

Follow-up

  • Telemetry arrives faster than the screen can usefully redraw. What do you do?
  • In a multi-vehicle view, how do you stop a command going to the wrong spacecraft?
  • How would you measure whether the feature actually helped?

If you had to optimize a data processing pipeline, what considerations would you take into account?

Medium · Problem-Solving / Case Studies

Approach

  1. Measure before changing anything: per-stage throughput, latency and queue depth, then fix the stage that bounds the whole pipeline; state the target (throughput, end-to-end latency or cost).
  2. Classify the bottleneck: I/O-bound (batch reads and writes, columnar or binary formats, compression, avoiding many small files), CPU-bound (better algorithm, vectorisation, parallelism across independent partitions) or memory-bound (stream in chunks instead of loading everything).
  3. Reduce data movement: filter and project as early as possible, avoid repeated serialisation between stages, cache intermediates that are reused; Amdahl's law caps the speed-up from parallelising only part of the work.
  4. Keep it correct under failure: idempotent stages, checkpoints so a retry does not reprocess everything, backpressure between stages, and explicit handling of late, duplicated or out-of-order records.
  5. Verify the optimisation by diffing outputs on the same input before and after, and keep the benchmark so regressions show up.

Follow-up

  • One stage cannot be parallelised. What are your options?
  • Records start arriving out of order. What changes in the design?
  • Your optimised pipeline's floating-point totals differ slightly from the old one. Is that a bug?

Describe how you would approach a project with unclear requirements.

Medium · Problem-Solving / Case Studies

Approach

  1. Separate what is known from what is not: list the stakeholders, write down your understanding of the goal, and list open questions with an owner for each.
  2. Turn it into a short written spec with acceptance criteria and interface definitions, mark every assumption explicitly, and get it confirmed before building much.
  3. Reduce risk with a thin end-to-end prototype or vertical slice early, so stakeholders react to something working rather than a description.
  4. Isolate the uncertain parts behind interfaces or configuration so a changed requirement means a local change, and avoid irreversible decisions until they are needed.
  5. When a requirement changes, update the spec and tests together and state the schedule impact; the failure to avoid is building the full solution on guesses and discovering the gap at delivery.

Follow-up

  • The stakeholder who owns the requirement is unavailable. How do you proceed?
  • Two stakeholders give conflicting requirements. What do you do?
  • How do you decide you have enough clarity to start building?

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

The plan follows the three reported rounds: Day 1 maps the loop and your stories, Days 2-3 drill whiteboard coding and data structures, Days 4-5 cover engineering practice and scenario questions, Day 6 covers behavioral stories, and Day 7 is a full run-through.

Day 1 — Map the loop, choose a language, build a term list

  • Write the three reported rounds (Phone Screen, Technical Interview, Behavioral Assessment) on one page, with the question types you expect in each and your weakest area marked.
  • Choose C++, Python or Java for the whiteboard and write a two-minute CV walk-through that names one project per language you list.
  • Write a one-sentence definition for each term some candidates mention (ADCS, star trackers, GD&T, automated testing) so none of them stops you.

Deliverable: A one-page loop map, a two-minute CV script that answers the languages question, and a term list with one-sentence definitions.

Day 2 — Whiteboard coding: lists, search and recursion

  • Write the linked-list reversal both iteratively and recursively on paper, then dry-run both on an empty list and a three-node list.
  • Write binary search for sorted data points and a linear scan for unsorted ones, and state when each applies.
  • Write Fibonacci three ways (naive recursion, memoised, iterative), with the time and space cost of each.

Deliverable: Handwritten code for the three problems, each with a written dry run and a stated complexity.

Day 3 — Sorting, data structures and compression

  • Write a comparison of quicksort, mergesort, heapsort and counting sort covering worst case, stability, memory and when external sorting is needed for data larger than memory.
  • Fill a table of array, linked list, hash table, balanced tree and heap with cost of access, insert, delete and search, and one use case each.
  • Outline how you would approach a new compression algorithm: what redundancy exists in the data, a baseline such as run-length or Huffman coding, and how you would measure ratio and speed.

Deliverable: A sorting comparison sheet, a data-structure cost table and a short compression plan with its measurement criteria.

Day 4 — Engineering-practice answers out loud

  • Record answers on how you use version control (branching, review, commit hygiene, reverting a bad change) and on how you keep code maintainable (tests, review, naming, small functions).
  • Write the story of a hard technical problem you solved, with the symptom, your debugging steps, the fix and how you proved it worked.
  • Describe the software life cycle you used on a real project, and what you would change in it.

Deliverable: Three recorded answers (version control, code quality, hard problem) and a written life-cycle description, each checked against a real project.

Day 5 — Scenario questions: diagnosis, design and pipelines

  • Write your diagnosis sequence and apply it to a hypothetical satellite system failure, listing the evidence you would collect and the hypotheses you would rank.
  • Sketch the design of a feature for a satellite control application's interface: who uses it, what must be shown, what must never be ambiguous, and how you would test it.
  • List the checks for optimising a data processing pipeline (measure first, find the slowest stage, batch, parallelise, avoid repeated work) and how you would approach a project with unclear requirements.

Deliverable: A diagnosis outline, a one-page interface feature sketch and a pipeline optimisation checklist with a note on handling unclear requirements.

Day 6 — Behavioral stories

  • Write four stories (difficult teammate, competing priorities, significant change, feedback you acted on) each with the situation, your decision, the result and what you changed.
  • Answer the motivation question using one concrete example of a team outcome you improved, and tie it to working with hardware or systems engineers.
  • Say each story aloud and cut anything that describes the team rather than your own action.

Deliverable: Four written stories with a one-line 'I decided' statement each, and a spoken answer to the motivation question.

Day 7 — Full run-through of all three rounds

  • Do a mock recruiter call: your CV walk-through and the languages answer.
  • Write one coding problem and one scenario answer on a whiteboard or paper with no tools, talking through your reasoning throughout.
  • Run two behavioral answers aloud, then list the two questions you will ask the interviewers.

Deliverable: A completed run-through with notes on the weakest answer, and a final list of two questions for interviewers.

Behavioral stories for a hardware-adjacent team

Candidates describe the Behavioral Assessment as a stage about fit with the team and company. The role listing puts you next to hardware engineers, systems engineers and product managers, so prepare stories about disagreement, shifting priorities, changing requirements and feedback, each with your own decision and a result.

  1. Can you provide an example of a time you had to advocate for a solution you believed in?

Can you explain your experience with software development life cycles?

Medium · Technical / Domain Questions

Approach

  1. Answer from one real project, not from the textbook phases. Name the process the team used (Agile sprints, a more staged plan or a mix) and walk it in order: how requirements arrived, how work was broken down, how code was reviewed and tested, how it was released and what happened after release.
  2. Say which steps you personally owned, for example writing tickets, doing code reviews, adding tests or running releases, so the answer is about your experience and not the team's.
  3. Show you understand trade-offs. Iterative planning copes with changing requirements; more upfront specification suits work with interfaces fixed early, such as software tied to hardware. Give one example where the process helped and one where it got in the way.
  4. Close with one change you made or would make to the process, backed by an observable effect such as fewer regressions or shorter review turnaround.

Follow-up

  • When does an Agile process break down, and what did you do when it did?
  • How did you handle a requirement that changed in the middle of a sprint or stage?
  • What did your team's testing and review steps catch that you would otherwise have missed?

Tell me about a time you had to work with a difficult team member.

Medium · Behavioral / Leadership

Approach

  1. Pick a conflict about behaviour and work (missed reviews, dismissive comments, changing decisions), not about personality. State it in two sentences and spend the rest on what you did.
  2. Show you tried the direct route first: a private conversation where you described the specific behaviour and its effect on the work, and asked about their constraints before assuming bad faith.
  3. Name the agreement you reached, such as review turnaround, a written interface decision or a clearer split of ownership, and what changed afterwards.
  4. Escalate only if direct steps failed, and say how you did it: with facts, asking for help on the process rather than complaining about the person. End with what you learned about your own part in the friction.
  5. Avoid a story where the other person is simply wrong and you are simply right, or one with no resolution.

Follow-up

  • What if they had not changed after that conversation?
  • At what point did you involve your manager, and what did you bring?
  • What would you do differently with the same person today?

How do you prioritize tasks when working on multiple projects?

Medium · Behavioral / Leadership

Approach

  1. State your method before the story: list the work, find hard deadlines and dependencies (what blocks other people), estimate impact and effort, then rank. Say that you ask stakeholders to confirm the ranking instead of guessing.
  2. Use a real case with two competing deadlines, name what you did first and what you deliberately delayed, and say whom you told and when.
  3. Show how you made the trade-off visible: a short written list of what will ship and what will slip, shared with the people affected, so no one is surprised.
  4. Describe how you re-check priorities when something new arrives, such as an urgent bug, and how you protect time for review and testing instead of dropping them.
  5. Avoid answers that rely on working longer hours or that call everything top priority.

Follow-up

  • Two stakeholders each say their project is the top priority. What do you do?
  • An urgent bug lands halfway through a sprint. What gets dropped, and who decides?
  • What tools or habits do you use to track the work, and when did they fail you?

Describe a situation where you had to adapt to significant change in a project. How did you handle it?

Medium · Behavioral / Leadership

Approach

  1. Choose a change with real consequences, such as a changed requirement, a switch of tooling or language, a reduced scope or a new team. Give the context briefly and the before and after.
  2. Walk through your first steps: understand why the change happened, list what work is now wasted and what carries over, update the plan and ask what is fixed and what is negotiable.
  3. Show how you communicated: who needed the new plan, what you told them about cost and risk, and how you kept others aligned.
  4. Cover quality under change: what you tested or re-checked so the new direction did not introduce regressions, and what you cut on purpose.
  5. End with the outcome and a lesson, such as keeping interfaces isolated so a late change touches fewer files. Avoid a story where you only complained or simply waited for instructions.

Follow-up

  • What did you decide to drop, and who agreed to it?
  • How did you stop the change from damaging quality?
  • How do you plan differently now, knowing change is likely?

What motivates you to contribute to a team environment?

Medium · Behavioral / Leadership

Approach

  1. Answer with a concrete behaviour, not a slogan. 'I like people' says nothing; 'I like that a code review catches what I cannot see in my own code' is checkable.
  2. Back it with one short example in which a team outcome improved because of something you did, such as documenting a design, pairing on a hard bug, or helping a teammate unblock.
  3. Connect it to the role as candidates describe it: working with hardware engineers, systems engineers and product managers means your own results depend on how well others understand your software.
  4. Be honest about how you work alone as well, and describe how you move between individual focus and team work.
  5. Avoid generic praise of teamwork or an answer that suggests you only want to work on your own task.

Follow-up

  • Tell me about a time you put the team's goal ahead of your own task.
  • What do you do when the team loses momentum or morale drops?
  • How do you work with people who see the problem very differently from you?

How do you handle receiving constructive criticism?

Medium · Behavioral / Leadership

Approach

  1. Choose real feedback that stung a little, ideally from a code review or a design review, and state exactly what was said. A fake weakness such as 'I work too hard' sinks the answer.
  2. Describe your first reaction honestly, then what you did next: asked clarifying questions, checked whether the criticism was right, and separated the point from the delivery.
  3. Show the change: what you did differently, with something observable like fewer review comments of that type, a new checklist, or a test you now always write.
  4. Close the loop by saying you went back to the person who gave the feedback and showed the result, and what the relationship looked like after.
  5. Avoid defensiveness, blaming the reviewer or a story where nothing changed.

Follow-up

  • Tell me about feedback you disagreed with. What did you do?
  • What is the hardest feedback you have received, and how did you respond?
  • How do you give critical feedback to a colleague?