Interview guides · Aurecon
Aurecon Software Engineer Interview Guide
Aurecon Software Engineer interview guide: the four reported rounds, behavioral and technical question guidance, and a seven-day prep plan.
The 60-second brief
Aurecon is described as a global engineering and advisory firm that applies technology to designing, delivering and managing infrastructure projects. Software engineers build the digital tools, automated workflows and data-driven solutions that engineering teams use. The examples candidates see named are software for structural analysis and platforms for project lifecycle management. The topic areas reported alongside the role are ports and marine engineering, structural engineering for ports, marine and coastal work, and renewable energy engineering, so the code you write is meant to serve engineers in those disciplines.
This guide is for a candidate applying for a Software Engineer role at Aurecon. It covers the four reported stages (Initial Screening, Technical Evaluation, Behavioral Evaluation, Team Involvement), the engineering-practice and behavioral questions candidates report, the skills the role lists (core programming languages, Git, testing methodology, with cloud platforms, data visualization and engineering software APIs as extras), and a plan for rehearsing all of it. It does not cover other Aurecon roles or the engineering disciplines themselves.
Candidates report four stages over roughly 3-5 weeks: Initial Screening, Technical Evaluation, Behavioral Evaluation and Team Involvement. The reported questions lean toward engineering judgement and personal stories rather than algorithm puzzles.
Focus areas
- Software Engineering
- Engineering Domain Knowledge (Multi-discipline)
- Ports & Marine Engineering
Overview
The role sits between software and engineering practice. As candidates describe it, you write, test and maintain code that supports structural, civil or electrical engineers, for instance by automating data processing or improving the digital tools they use in the field, and you take part in sprint planning, code reviews and cross-functional meetings. For preparation, that means your examples should show software built for colleagues who are not software engineers, and your explanations should work for them too.
The reported technical questions test engineering judgement more than puzzle skill: how you keep code maintainable and scalable, how you choose a language or framework, why automated testing matters in your workflow, how you handle technical debt under a deadline, and how you debug a production issue. Candidates also mention scenario prompts such as designing a data pipeline for real-time structural monitoring, describing how you run code reviews, optimizing underperforming software and prioritizing features when stakeholders conflict. Prepare each as a short structure (context, options, decision, trade-off, result) that you can say aloud, and keep one concrete project behind each answer.
Behavioral material carries real weight in this loop. Two of the four stages are named Behavioral Evaluation and Team Involvement, half of the reported questions are filed under behavioral and collaborative skills, and two of the technical-foundations questions (the production bug and technical debt) are really story questions. Build a small set of stories with your own decisions in them, and rehearse them in the first person singular so the choices you made are audible.
The Aurecon interview process
These are the four stages candidates describe, in the order they report them; treat them as a typical shape rather than a published process.
Initial Screening
Candidates describe Initial Screening as a preliminary check of your qualifications and fit for the role. The requirements candidates describe give you the vocabulary to expect: proficiency in core programming languages, experience with Git or similar version control, and a solid grasp of testing, with cloud platforms, data visualization and engineering software APIs as extras. Treat it as the stage where your CV has to line up with that list and where you explain why an engineering and infrastructure setting appeals to you.
What to demonstrate
- How your experience matches the listed requirements: languages, version control, testing methodology
- Your reasons for applying to a role that supports engineering projects
- Your ability to describe past work and the decisions behind it
How to prepare
- Walk through your CV so each project names the language, the Git workflow and the tests you wrote, then mark the optional items (AWS or Azure, data visualization, engineering software APIs) where you have real experience.
- Write a short, honest answer to why you want software work that supports infrastructure and energy projects, referring to one specific project area you have read about.
- Prepare to explain one past technical decision as a why, not only a what, since candidates are told to explain the reasoning behind choices.
- Write down questions about the next stages so you can ask for the format of the technical evaluation.
Technical Evaluation
Candidates describe Technical Evaluation as deeper assessment of problem-solving and technical proficiency. Reports emphasise practical application over abstract puzzles: real-world scenarios, how you structure code and how you approach hard debugging. The areas listed for it are development standards (clean code, documentation), system architecture (how components interact), and, less commonly, cloud infrastructure, CI/CD pipelines, data integration and edge cases in distributed or data-heavy systems. A coding exercise is not described, so prepare to talk through design and practice rather than to memorize algorithms.
What to demonstrate
- Engineering practice: maintainable code, testing, code review and technical debt
- Problem-solving in realistic scenarios such as a data pipeline or underperforming software
- Your reasoning for technical choices such as language or framework selection
- Debugging approach on a complex issue
How to prepare
- Rehearse the questions on long-term maintainability and scalability, language or framework choice, and automated testing, each as a structure you can say aloud with one project example.
- Sketch a data pipeline for real-time structural monitoring: ingestion, validation, storage, alerting, and what happens when a sensor feed arrives late, duplicated or out of order.
- Write your code review process as a checklist (correctness, tests, readability, risk) and note how you give feedback.
- Pick a case where you made slow software faster and be ready to say what you measured before and after.
Behavioral Evaluation
Candidates describe Behavioral Evaluation as a discussion of cultural fit and alignment with team dynamics. The reported questions that fit this stage's theme include explaining a technical concept to a non-technical stakeholder, handling disagreements about technical direction, pivoting when requirements change, balancing ownership with collaboration and what motivates you in the infrastructure space. Candidates are advised to answer with the STAR method (Situation, Task, Action, Result). Use stories where your own decision is clear.
What to demonstrate
- How you communicate with colleagues outside software
- How you handle disagreement and changing requirements
- How you balance personal ownership with working in a team
- Your motivation for engineering work in this sector
How to prepare
- Write five stories in STAR form (a stakeholder explanation, a technical disagreement, a pivot, an ownership versus collaboration case, a production problem) and say each aloud until the Action part is specific.
- For every story, add one sentence on what you would do differently, because follow-up questions tend to start there.
- Replace 'we' with 'I' wherever you made the call, and keep 'we' for what the team achieved.
- Draw on at least one story involving a colleague from another discipline, such as an engineer who used your tool.
Team Involvement
Candidates describe Team Involvement as discussions in which key stakeholders and team leads take part to judge your fit within the engineering practice. The reported advice is to use the end of the conversation to ask about the team's current technical challenges and the longer-term direction of the project you would support. Expect a mix of the earlier technical and behavioral themes in front of people who would work with you, and prepare to move between a high-level technical discussion and a specific scenario.
What to demonstrate
- Fit with the engineering practice and the team you would join
- Your ability to move between technical depth and collaboration scenarios
- The quality of your questions about the team's work
How to prepare
- Prepare a short description of your strongest project that a team lead from a non-software discipline could follow.
- Rehearse the ownership versus collaboration and technical-disagreement stories, since these are the themes of working with a team.
- Write four questions about the team's current technical challenges, how code reaches the engineers who use it, and how sprint planning and code review work there.
- Revise the weakest technical answer from the second stage so you can restate it clearly if it comes up again.
Where candidates lose points
Naming favourite tools when asked how you choose a language or framework
Answer with criteria: the team's skills, available libraries (including engineering software APIs), deployment target, long-term maintenance and hiring. Make a recommendation for a scenario and say what would change it.
Telling the production-debugging story as a hero tale with no method
Structure it as impact, scope, stabilize, hypothesize, evidence, fix, prevention. Mention the regression test and the monitoring you added, and say how you confirmed the real cause.
Saying automated testing is good without saying what you test or how
Name the layers (unit, integration, end-to-end), what runs in CI and what you do for calculation or data-processing code, such as known-answer cases and tolerance checks. Give one bug a test caught.
Using 'we' throughout stories so your own decision never appears
Write each STAR story with the action in the first person. State what you decided, what you gave up and what happened, then say what the team did.
Giving a generic motivation answer that ignores the infrastructure and energy setting
Read about the sector areas candidates report (ports and marine, structural, renewable energy) and prepare one specific, honest connection between your work and the engineers' problems.
Questions & practice
Canonicalise a request body into a stable idempotency fingerprint
Medium · parsing · canonicalisation · hashing
idempotency_key.request_fingerprint is a SHA-256 over the method, path and canonicalised body, and a retry whose fingerprint differs must be rejected with 422 rather than served the stored response. Write the canonicaliser. Bodies are JSON up to 256 KB nested at most 32 levels; clients vary key order, whitespace and unicode escaping, and some send 64-bit ids as JSON numbers. Produce a deterministic byte string such that semantically identical bodies match and any semantic difference does not. State your complexity and name two normalisations you refuse to perform.
Approach
- Parse once into a tree, then re-serialise under fixed rules: object keys sorted, array order preserved, one escaping convention, no insignificant whitespace. Parsing is O(n) and sorting keys is O(k log k) per object, so O(n log n) overall with O(depth) stack, and the 32-level cap is enforced during parsing because hostile nesting is how a canonicaliser becomes a stack overflow.
- Sort keys by their UTF-8 bytes and say why the obvious implementation is wrong in some runtimes: a default string comparison that orders by UTF-16 code units places surrogate pairs, meaning code points from U+10000 up, below U+E000 to U+FFFF, which is not UTF-8 byte order, so two services written in different languages disagree on the same document.
- Do not re-encode numbers through a double. IEEE-754 binary64 represents integers exactly only up to 2^53, so normalising a 19-digit id through a float changes it, and 1 against 1.0 cannot be reconciled without deciding whether they are the same value. Preserve the literal token, and require ids as strings at the API boundary if you want them comparable.
- Reject duplicate keys rather than picking one. JSON permits them and parsers disagree, most keeping the last, so any choice you make ties the fingerprint to a parser detail that the code handling the request does not necessarily share.
Follow-up
- A client sends the same logical request with an extra field your API ignores. Same key, different fingerprint, so you return 422. Is that the right answer?
- Where does the fingerprint get computed relative to request decompression and the body-size limit?
Track a rolling failure rate per destination for circuit decisions
Easy · sliding window · ring buffer · circuit breaker
The egress service delivers about 1,500 webhooks per second across roughly 40,000 destinations, each call bounded by a 10 second timeout. Maintain, per destination, the failure rate over the trailing 60 seconds so a caller can ask before dispatch whether the circuit should open. Attempts arrive as (destination_id, finished_at_ms, outcome). Requirement: amortised O(1) per attempt, with total memory bounded by the destination count rather than by traffic. Give the structure, its exact memory, and the rule that stops a destination with three attempts from opening a circuit.
Approach
- Name the exact-deque version and then reject it as the default. Holding timestamps and advancing a tail pointer past anything older than now minus 60 seconds is a correct two-pointer window at amortised O(1) per attempt, but its memory tracks in-window traffic, so one destination in a retry storm holds hundreds of thousands of entries while thousands of quiet destinations hold none.
- Use a ring of 60 one-second buckets per destination, each bucket a pair of counters for attempts and failures. On an attempt, advance the ring by the elapsed whole seconds, zeroing at most min(elapsed, 60) buckets, then increment the head. That is amortised O(1) with a fixed footprint per destination.
- State the footprint: 60 buckets times two 4-byte counters is 480 bytes of payload per destination, so 40,000 destinations is roughly 20 to 25 MB with per-entry overhead, bounded by the catalogue rather than by the rate. The cost is granularity, since the oldest bucket ages out in whole seconds, which is far tighter than the decision needs.
- Require a minimum sample before the circuit may open. A destination with three attempts and three failures reads as 100 percent and is not evidence; a floor of roughly 20 attempts in the window makes the ratio meaningful, and below that floor use a run of consecutive failures as the trigger instead.
Follow-up
- The fleet is 30 instances and each sees roughly a thirtieth of a destination's traffic. Where does the rate actually live, and what does a per-instance answer get wrong?
- A destination answers in 9.5 seconds and succeeds. It is not failing but it is consuming your per-destination concurrency. What signal should open the circuit here?
Merge partitioned event streams into one ordered feed with bounded lateness
Hard · k-way merge · watermarks · out-of-order streams
The read-model service consumes 64 log partitions carrying about 4,000 events per second in total. Each partition is ordered within itself, but partitions drift by up to 30 seconds, and the activity feed must present a tenant's events in occurred_at order. Produce the merge. State its complexity, the buffer it requires in events and in bytes, what happens when one partition is idle, and what you do with an event that arrives after you have already emitted its position. Payloads average 1 KB.
Approach
- Merge with a min-heap over the 64 partition heads keyed on (occurred_at, event_id): O(log P) per event and O(n log P) overall. The tie-break on event_id is what makes the output deterministic when two partitions carry the same millisecond, which matters because the feed is paginated and a non-deterministic order reorders pages under the reader.
- Emitting the heap head is only correct once every partition has produced everything up to that timestamp, so the emit condition is a watermark: the minimum across partitions of the highest occurred_at seen, less the allowed lateness. Events are held until the watermark passes them, which is what turns individually ordered streams into a jointly ordered one.
- Size the buffer from the lateness rather than guessing: 4,000 events per second times 30 seconds is 120,000 buffered events, and at 1 KB each about 120 MB of heap. That number is the real price of the ordering guarantee and belongs in front of whoever asked for it.
- Handle the idle partition explicitly, because it fails the feed rather than corrupting it: a partition with no traffic never advances its own maximum, so the watermark freezes and output stops entirely. Either every partition emits a periodic idle marker carrying the broker's current time, or the watermark falls back to wall clock for a partition silent beyond a threshold.
Follow-up
- The lateness budget is raised to five minutes. What is the new buffer, and what besides memory changes?
- The consumer restarts. Where does it resume from, and what does the feed look like for the first 30 seconds?
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
- 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.
- 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.
- 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.
- 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?
Write the update path that detects a concurrent edit
Medium · optimistic concurrency · transactional outbox · audit history
resource carries version INT NOT NULL DEFAULT 1. resource_revision holds revision_id, resource_id, version, actor_user_id, change_kind, patch JSONB, request_id, created_at with UNIQUE (resource_id, version). outbox_event holds aggregate_type, aggregate_id, aggregate_version, event_type, payload, status. A PUT carries the version the client read. Write the exact statements for the single transaction that applies the edit, records the revision and enqueues 'resource.updated', and give the handler's branch on zero affected rows. Then say what PostgreSQL 16 does under READ COMMITTED when two of these updates hit one row at once.
Approach
- One transaction, three writes, no network call inside it: UPDATE resource SET title = $3, version = version + 1, updated_at = now() WHERE resource_id = $1 AND tenant_id = $4 AND version = $2; then INSERT the resource_revision row at version $2 + 1; then INSERT the outbox_event row at the same aggregate_version. The event goes to a table rather than a broker because no transaction spans both.
- Branch on the affected-row count before doing anything else. Zero has three causes — stale version, wrong tenant, row gone — so re-read once and map to 409 carrying the current version, or 404 for an id outside the caller's tenant, which also stops the endpoint confirming that another tenant's id exists.
- State the engine behaviour instead of assuming it. Under READ COMMITTED the second UPDATE blocks on the row lock, and when the first commits PostgreSQL re-evaluates the WHERE clause against the newly committed row, so the version predicate now fails and the statement reports zero rows. Under REPEATABLE READ the identical collision raises SQLSTATE 40001 instead, so the handler must fold both shapes into one conflict response.
- Keep UNIQUE (resource_id, version) even though the predicate already serialises writers. It is what makes a lost update unwritable if any other path ever reaches the revision table, and it converts a logic bug into 23505 rather than into a silently missing history row.
Follow-up
- A client sends the version it read ten minutes ago and the resource has moved three versions. What is in your 409 so it can resolve the conflict without a full re-fetch?
- Two editors, two disjoint fields, no overlap. Does your answer still refuse the second write, and should it?
How do you ensure your code remains maintainable and scalable over the long term?
Medium · Technical Foundations
Approach
- Split the question in two. Maintainability is the cost of the next change: can someone else read, test and modify the code safely? Scalability is how it behaves as users, data volume or model size grow. Give one concrete example of each from your own work.
- For maintainability, describe module boundaries: keep calculation or business logic in pure functions with no I/O, and put file formats, databases and external APIs behind small adapter interfaces. That makes the core unit-testable and lets you replace an integration without touching the logic.
- Name how you enforce it, not just what you believe: a formatter and linter plus type checks in CI, tests that must pass before merge, code review against agreed conventions, and short decision records that explain why a design was chosen.
- For scalability, measure before optimising. Profile the hot path and know its complexity: a pairwise loop over n elements is O(n^2) and will hurt as datasets grow, so look for indexing, hashing or vectorised operations. Keep services stateless so they scale horizontally, and move long-running jobs onto a queue.
- State the trade-off: abstraction has a cost, so I avoid generalising until a pattern repeats (the rule of three) and refactor in small, test-covered steps rather than building for scale I cannot yet see.
Follow-up
- A batch job that took ten minutes now takes three hours after the input data grew. Where do you look first?
- How would you safely refactor a large module that has no tests and that nobody wants to touch?
- What signals tell you a codebase is becoming harder to maintain before it causes an outage?
What is your approach to choosing the right programming language or framework for a new project?
Medium · Technical Foundations
Approach
- Start from the constraints, not from preference: what the software must do (numerical computation, a web front end, a data pipeline, a plug-in for another application), where it will run, and what it must integrate with. If it has to call a host application's SDK, the languages that SDK supports narrow the choice immediately.
- Weigh the people and the lifetime: what the current team already knows, who will maintain it after you leave, the existing codebase and organisational standards, and how easy it is to hire for. A slightly better tool that only one person can maintain is usually the worse choice.
- Check ecosystem and operational fit: maturity of the libraries you need (for example NumPy and SciPy for numerical work), licence terms, release and long-term-support cadence, security patching, and support on the deployment target or cloud platform.
- Match non-functional needs to the runtime: CPU-bound numeric code versus I/O-bound services, the concurrency model (in standard CPython the GIL prevents threads from running Python bytecode in parallel, so CPU-bound work uses processes or native-extension libraries), memory footprint and static typing.
- Describe the process: shortlist two or three options, run a time-boxed spike against the hardest requirement, score them in a simple weighted matrix, and record the decision and its reversibility in a decision record so the reasoning survives.
Follow-up
- Tell me about a technology choice that turned out to be wrong. What did it cost to change course?
- The team knows Python but the computation is too slow. Do you rewrite it in another language or do something else?
- How do you stop every team in an organisation picking a different framework for similar problems?
Explain the importance of automated testing in your development workflow.
Medium · Technical Foundations
Approach
- Lead with what automated tests buy: fast feedback on every change, protection against regressions so refactoring is safe, and an executable description of intended behaviour. A defect found by a test before merge is far cheaper than one found by a user or in a client deliverable.
- Explain the shape of the suite with the test pyramid: many fast unit tests on pure logic, fewer integration tests for databases, file I/O and service boundaries, and a small number of end-to-end tests. The trade-off is speed and stability against fidelity, and end-to-end tests are where flakiness tends to come from.
- For calculation-heavy code, test against hand-worked or reference results, compare floating-point values with a tolerance (pytest.approx or assertAlmostEqual) rather than exact equality, cover boundary and invalid inputs and unit conversions, and consider property-based tests (Hypothesis) for invariants such as symmetry or conservation.
- Show where it sits in your workflow: tests run in CI on every pull request and failures block the merge; for a bug fix, write the failing test that reproduces it first, then fix it; treat coverage as a way to find untested paths, not as a target to game.
- Keep the suite trustworthy: make tests deterministic (fixed random seeds, controlled clocks, no shared mutable state, no order dependence), quarantine and fix flaky tests quickly, and keep the unit tier fast enough that people run it locally.
Follow-up
- How do you test code that depends on an external service or a third-party application API you cannot run in CI?
- You must change a legacy module with no tests and a tight deadline. What do you write first?
- Is 100% line coverage worth pursuing? What can a fully covered codebase still get wrong?
p99 jumped on one listing filter while p50 stayed flat
Medium · query planning · composite index · percentiles
After a release that added an owner_user_id filter to the resource listing, p99 rose from 90 ms to 1.9 s while p50 stayed at 40 ms. Traffic and row counts are unchanged. resource carries the index (tenant_id, status, updated_at DESC, resource_id DESC). The new query filters tenant_id and owner_user_id, orders by updated_at DESC, resource_id DESC, and takes 20 rows. On PostgreSQL, explain the shape of the regression, prove it from a query plan, and give the index you would add.
Approach
- Start from the shape. A flat p50 with a moved p99 means a subset of requests changed cost, not all of them, so the first job is naming the subset. Bucket the endpoint's latency by the tenant's row count; the natural hypothesis is that large tenants are a small share of requests and all of the tail.
- Get the plan for the new query on a large tenant with EXPLAIN (ANALYZE, BUFFERS). Expect an index scan over the tenant's range, a filter discarding most of it, then a Sort feeding the Limit, possibly reporting Sort Method: external merge Disk. Read actual rows on the scan node, not estimated.
- Explain why the existing index cannot serve it. A composite B-tree is seekable only as a left prefix, and with no equality predicate on status the scan cannot treat updated_at as an ordering, because rows in the tenant's range are ordered by status first. Everything matching must be read and sorted before LIMIT 20 can apply, so a tenant with 400,000 rows pays 400,000 rows to return 20.
- Add (tenant_id, owner_user_id, updated_at DESC, resource_id DESC). Equality on the first two columns leaves the index ordered by updated_at within that pair, so the plan becomes an index scan that stops after 20 rows with no Sort node. PostgreSQL can scan a B-tree backwards, so the DESC markers matter only if the two sort columns ever disagree in direction; keeping them explicit documents the order the keyset cursor depends on.
Follow-up
- The endpoint paginates with OFFSET. What does page 500 cost with your index, and what does the keyset version cost?
- How would you have caught this before release, given that a 10,000-row seed database produces the same plan shape at an unnoticeable cost?
Suggested practice checklist
The plan follows the four reported stages: day one maps the loop and your skills, days two to four prepare the technical judgement answers and debugging stories, days five and six prepare the behavioral and team stories, and day seven runs everything together.
Day 1 — Map the loop and your skills
- List the four reported stages and, beside each, the question types this guide associates with it.
- Make a checklist of the requirements candidates describe (core languages, Git, testing, and optionally AWS or Azure, data visualization, engineering software APIs) and rate each with a project you can cite.
- Read about the sector areas reported for the role (ports and marine, structural, renewable energy) and note three project types you could mention.
Deliverable: A one-page stage map and a skills checklist with a cited project beside each item.
Day 2 — Maintainability and automated testing
- Write and say aloud your answer on keeping code maintainable and scalable over time, with one project as evidence.
- Write your answer on why automated testing matters, covering test layers, CI and how you test calculation-style code.
- Pick a project and list the tests you would add to it first, and why.
Deliverable: Two spoken answers (maintainability, automated testing) and a prioritized test list for one project.
Day 3 — Technology choice and the monitoring pipeline
- Write a decision list for choosing a language or framework, and apply it to two different scenarios.
- Sketch a data pipeline for real-time structural monitoring: ingestion, validation, storage, alerting and late or duplicated readings.
Deliverable: A criteria list applied to two scenarios, a pipeline diagram with failure cases and one solved practice problem.
Day 4 — Debugging and performance stories
- Write the production-debugging story using the sequence impact, scope, stabilize, evidence, fix, prevention.
- Write a story about optimizing underperforming software, including the before-and-after measurements.
Deliverable: One debugging story, one optimization story and a solved debugging practice problem.
Day 5 — Debt, change and priorities
- Write the technical-debt answer with a decision rule, a negotiation with the product owner and a limit you would not cross.
- Write the pivot story: the original plan, what changed, what you kept and discarded, and how you told stakeholders.
- Prepare a short answer on prioritizing features when stakeholders disagree, and say it aloud.
Deliverable: Two STAR stories (technical debt, requirements pivot) and a prioritization answer.
Day 6 — Working with people
- Write the story about explaining a technical concept to a non-technical stakeholder and say how you checked understanding.
- Write the technical-disagreement story with evidence, a decision and what you learned.
- Prepare the ownership versus collaboration answer and a specific, honest motivation answer for the infrastructure setting.
Deliverable: Four rehearsed answers (stakeholder explanation, disagreement, ownership versus collaboration, motivation).
Day 7 — Full dry run and questions to ask
- Run a spoken mock that moves from technical questions (maintainability, testing, debugging) to behavioral stories, ideally with another person.
- Revise the two answers that felt weakest, and check that every story uses 'I' for your decisions.
- Write four questions about the team's technical challenges and how its code reaches the engineers who use it.
Deliverable: A completed mock, revised weakest answers and a list of four questions to ask.
Stories for the behavioral and team stages
Candidates report a Behavioral Evaluation and a Team Involvement stage, and half of the reported questions concern working with others. For this role the stories should show decisions made while working alongside engineers outside software, through disagreement, changing requirements and shared code. Use the STAR method (Situation, Task, Action, Result) and put your own decisions in the Action.
Can you describe a time you had to debug a complex issue in a production environment?
Medium · Technical Foundations
Approach
- Pick an incident where you owned the diagnosis. Open with impact in one sentence (what was wrong, who noticed, what was at stake), then follow the debugging sequence: confirm and scope the problem, stabilize first (rollback, feature flag, disabling a job), then find the cause.
- Name the evidence you used: logs, metrics, traces, a diff of recent deploys, a minimal reproduction or a bisect through commits. Say which hypotheses you ruled out and how, so the story shows a method rather than luck.
- If your software produces numbers other people rely on, say how you checked the output was correct rather than merely running, for example by comparing it with a known-good result.
- Close with the fix, a regression test that fails without it, any monitoring or alert you added, and a blameless review. The common mistake is a hero story with no prevention.
Follow-up
- How did you know you had found the root cause and not a symptom?
- What would you have done if you could not reproduce it?
- What changed in testing or monitoring afterwards?
How do you handle technical debt while meeting tight project deadlines?
Medium · Technical Foundations
Approach
- Show you treat debt as a trade-off with a price. Describe the specific shortcut or old code, what it cost (slow changes, repeated bugs, onboarding friction) and what the deadline demanded, rather than speaking in generalities.
- Describe your decision rule: ship the deadline-critical path, keep the shortcut isolated behind a clear interface, record it in the backlog with an owner and a trigger for repayment, and pay down debt in the files you are already touching.
- Show how you negotiated: you explained the cost to the product owner in schedule terms (future rework, risk of defects) and agreed on scope, so the decision was shared.
- Give the result and a limit. State when you would refuse to take on a shortcut, for example one that skips tests on code other people depend on. Mistakes to avoid are claiming debt never arises or claiming you always refactor first.
Follow-up
- How do you decide which debt is worth paying down first?
- What do you do if the deadline never relaxes and the debt keeps growing?
- How did you make sure the tracked item was actually done?
Describe a situation where you had to explain a highly technical concept to a non-technical stakeholder.
Medium · Behavioral and Collaborative Skills
Approach
- Choose a real case, ideally with an engineer, client or project manager, where the listener had to make a decision that depended on a technical fact (a trade-off, a risk, a limit of a tool). Start with what they needed to decide, not with the mechanism.
- Say how you adapted: stated the conclusion first, replaced jargon with a comparison from their own field, used one number or one picture, and cut everything that did not affect their decision.
- Describe how you checked understanding, such as asking them to say it back or what they would do next, and how you followed up in writing.
- Report the result in terms of their decision and what changed. The mistake is a story where you simply explained slowly or the listener agreed politely, with no evidence it landed.
Follow-up
- How did you know they understood?
- What happened when they disagreed or pushed back?
- Which analogy failed, and what did you use instead?
How do you handle disagreements within a project team regarding technical direction?
Medium · Behavioral and Collaborative Skills
Approach
- Pick a disagreement about direction (architecture, library, approach) where both options had merit. Show that you stated the other person's position fairly before presenting yours.
- Show how you moved from opinion to evidence: agree on the criteria first (correctness, delivery, maintenance cost, team skills), then use a small prototype, a benchmark or a written comparison.
- Show how it was settled: a decision by the owner, a short decision record, and a clear commitment from everyone, including you if you lost. Willingness to change your own mind is a strength worth displaying.
- End with what the relationship and the code looked like afterward. Sinking stories either make the other person wrong or hide the conflict entirely.
Follow-up
- What if the evidence had come out against your view?
- What do you do when a more senior engineer overrules you?
- How do you keep the disagreement from becoming personal in code review?
Tell us about a time you had to pivot your strategy based on changing project requirements.
Medium · Behavioral and Collaborative Skills
Approach
- Describe the original plan and the specific change that broke it (a client decision, a new constraint, a changed input format) and say how you found out. Show you noticed early and did not hold on to the plan.
- Explain your re-planning: what you kept, what you discarded, how you handled sunk cost, and what you re-estimated. Name the concrete choices, such as splitting the work or using interfaces that limit rework.
- Show communication: you told stakeholders what the change meant for scope and timing before it became a surprise, and agreed on what moved.
- Close with the outcome and the lesson, such as asking about likely changes at kickoff or keeping volatile parts easy to replace. Avoid blaming the requester.
Follow-up
- How did you decide what to throw away?
- How did you tell stakeholders about the schedule impact?
- What do you do differently now to make change cheaper?
How do you balance individual task ownership with team-wide collaboration?
Medium · Behavioral and Collaborative Skills
Approach
- Give your definition: owning an outcome means following a task through to working, tested, merged and documented, and also means asking for help or review early instead of hiding the problem.
- Use a story in which both sides appear: you owned a piece of work, kept others informed with brief updates and flagged a risk before it hit the timeline, and also reviewed someone else's code or unblocked a teammate.
- Include a moment when you chose to collaborate, such as opening a pull request early or pairing on an unclear part, and one when you decided alone to keep things moving.
- Name the failure modes you avoid: working in silence until the end, and diluting responsibility so that nobody owns the result.
Follow-up
- Tell me about a time you asked for help and what you did before asking.
- How do you handle a teammate who is falling behind on a shared piece of work?
- How do you split a task so that ownership stays clear?
What motivates you to solve complex engineering problems in the infrastructure space?
Medium · Behavioral and Collaborative Skills
Approach
- Answer with a specific reason rather than a general love of hard problems. Connect something you have built or enjoyed to the setting: software that helps engineers analyse structures, manage project data or handle large engineering datasets.
- Show that you have read about the sector, for example the ports and marine, structural or renewable energy areas, and name one kind of project or problem that interests you and why software matters there.
- Link motivation to behavior: give an example of staying with a hard problem, learning a domain from colleagues or automating a tedious technical process.
- Stay honest and concrete. A rehearsed passion statement with no examples sounds hollow, and an answer about the pay or brand does not address the question.
Follow-up
- Which kind of infrastructure or energy project would you most like to support, and why?
- What would you want to learn from the engineers you worked with?
- What part of this work would you find least motivating, and how would you deal with it?