Interview guides · Cannon Construction
Cannon Construction Software Engineer Interview Guide
Cannon Construction Software Engineer interview guide: two reported rounds, reported questions with answer approaches, a 7-day plan and behavioral prep.
The 60-second brief
Cannon Construction is an infrastructure construction firm. Candidates describe its project work as running from telecommunications to power grid development, with field operations that include Ft Lewis and Milton. The Software Engineer role builds internal software for the business side of that work: tools for cost estimation, for government-facing operations and for engineering drawing accuracy. Candidates report that the engineer works with Infrastructure Construction Estimators and Government Operations leads, owns a tool from concept through deployment and ongoing support, and often works inside legacy systems while introducing newer workflows.
This guide is for engineers preparing for a Software Engineer interview at Cannon Construction. It covers the two reported stages, all twelve reported questions (design-style and behavioral), the database, integration and legacy-system scenarios candidates describe, and a seven-day plan. It assumes you can code and design a database; it spends its time on how to explain maintainability, data integrity, trade-offs and teamwork in answers tied to estimation and operations software. It does not cover pay.
Candidates report two stages over roughly 2-4 weeks: a Technical Background Screen, then Deeper-Dive Technical Rounds that may mix system design, coding challenges and behavioral assessments.
Focus areas
- Software Engineering
- Construction Estimation
- Infrastructure Domain Knowledge
Overview
The reported work is internal business software, not a consumer product. The tools serve estimators who price infrastructure jobs and operations leads who handle government-related work, and the engineer is described as owning the whole lifecycle: requirements, design, deployment and support. Candidates also report legacy systems sitting next to newer workflows. Preparation therefore leans on three things: designing data that stays correct, changing old code safely, and explaining decisions to people who are not engineers.
The reported technical scenarios are concrete. One asks for a database schema for an estimation tool that must handle multiple versions of a bid. Another asks how to speed up a slow query in a legacy system. The twelve reported questions add maintainability on long-lived projects, third-party API integration into estimation tools, data integrity for large project files, and weighing technical debt against new features. Candidates also report testing and QA philosophy, system architecture, data handling, and, as less common topics, cloud deployment and security for sensitive government project data.
The behavioral half of the question list is large: production troubleshooting, version control in a team, simplifying a process for an end-user, conflicting requirements from non-technical stakeholders, working with field engineers or project managers, handling code feedback, and keeping quality under pressure. Candidates also report that explaining the reason behind a technical decision, and its business effect, matters as much as the decision. Build each story around a decision you made and a result you can state in numbers or in a concrete before-and-after.
Candidates report that most roles, including those in Ft Lewis and Milton, are on-site, and that domain knowledge of construction and infrastructure is worth showing even when you are a strong coder. Spend some preparation time on how a cost estimate is assembled and revised, because the schema and data-integrity questions are far easier to answer when you can name real entities such as bids, versions and line items.
The Cannon Construction interview process
Candidates describe two stages in order: a technical background screen, then deeper technical rounds. No stage-by-stage question assignment is reported, so prepare every question type for both.
Technical Background Screen
Candidates report the first stage as a Technical Background Screen, an initial assessment of your technical background. Nothing reported fixes its format or its questions, so treat it as the stage where your past work has to be explained clearly. Candidates are advised to describe projects by outcome as well as by the stack used, so for each project be ready to say what the tool did for its users and what you personally decided.
What to demonstrate
- Your technical background as the stage name describes it
- How well you describe past projects by both stack and outcome, which candidates are advised to do
- Core fundamentals the role lists: a programming language, database design and software development lifecycle practice
How to prepare
- Write a one-page inventory of your three strongest projects: stack, your role, the hardest technical decision, and a measurable result
- Rehearse aloud the maintainability question and the production-troubleshooting question, since both draw on your past work
- Refresh database design basics: keys, normalization, indexes and how you would store changing data
- Prepare an honest answer for a technology you have not used, including how you would learn it
Deeper-Dive Technical Rounds
The second stage is reported as Deeper-Dive Technical Rounds, in-depth interviews that may include system design, coding challenges and behavioral assessments. Candidates describe the topics as system architecture, data handling for large estimation datasets, and testing and QA, with cloud deployment and security for sensitive government project data as less common. The reported scenarios are a database schema for an estimation tool with multiple versions of a bid and the optimization of a slow query in a legacy system. Prepare design answers that start from the data model and the failure cases, and behavioral stories that end in a result.
What to demonstrate
- System design ability, one of the formats candidates say this stage may include
- Coding challenges, which test working code under live conditions
- Behavioral assessments across teamwork, feedback and quality under pressure
- Data handling, testing and QA philosophy, as the reported evaluation areas describe
How to prepare
- Design the versioned-bid schema on paper: bids, versions, line items, who changed what and when, and how to read the state as of a given version
- Work through the third-party API integration and large-project-file integrity questions with retries, validation and reconciliation in mind
- Take one slow query, read its execution plan and write what you would change and how you would verify it
- Rehearse seven behavioral stories with a concrete result each, then run one mixed technical-and-behavioral mock
Where candidates lose points
Answering the maintainability and technical-debt questions with slogans such as write clean code and refactor later
Name mechanisms: tests around risky calculations before refactoring, small modules with clear interfaces, documented decisions, and a visible debt list ranked by user impact and change frequency. Give one real example where you paid down debt and what it cost.
Designing the versioned-bid schema as a single table you overwrite, so earlier versions and their history disappear
Model bids, immutable versions and line items separately, record who changed what and when, and explain how you would reconstruct the figures as of any version and keep totals consistent across versions.
Saying add an index when asked how to speed up a slow query in a legacy system
Describe the sequence: capture the query and its plan, find the expensive step, check statistics and row counts, change the query or index one thing at a time, measure before and after, and say how you would roll it back in an old system.
Telling behavioral stories in which the decision was the team's and no personal action is visible
For each of your stories, write the one decision you made and the reason. Use I for it, give the result with a number or a clear before-and-after, and state what you would change.
Describing technical choices without their effect on estimators, operations leads or project outcomes
Candidates report that the why behind a decision matters. End every answer with who benefits and how: fewer errors, faster bids, less manual rework, safer deployment.
Questions & practice
Collapse a redelivered event batch into per-aggregate high-water marks
Easy · hashing · at-least-once · aggregation
You drain a batch of up to 5,000,000 events, each (aggregate_id BIGINT, aggregate_version INT, event_type, payload). The log guarantees order within one aggregate only; the batch merges 64 partitions, and a relay failover has redelivered a range, so an older version for an aggregate can appear after a newer one. Given a map of last_applied_version per aggregate, produce the events worth applying, at most one per (aggregate_id, version), plus the count discarded. Target O(n) time. State the memory for 2,000,000 distinct aggregates and what you do when it does not fit.
Approach
- One pass, one hash map from aggregate_id to the highest version kept, and a discard counter. An event whose version is at or below last_applied_version for its aggregate is dropped without further work, which is the whole reason the event carries its version rather than a delta. O(n) expected time, O(d) space in distinct aggregates.
- Keep the maximum, never the last occurrence. The redelivered range means the final appearance of an aggregate in the batch can be an older version than one seen earlier in the same batch, so last-wins applies stale state over newer state and the projection regresses with no error anywhere.
- Cost the memory instead of calling it large: an 8-byte key plus a 4-byte version is 12 bytes of payload, and an open-addressed table held at a 0.7 load factor costs roughly 17 bytes per entry before per-slot metadata, so 2,000,000 aggregates is tens of megabytes in a native layout and several times that in a runtime that boxes both key and value.
- If the distinct set exceeds memory, partition on hash(aggregate_id) mod P and reduce each partition independently. Every event for one aggregate hashes to the same partition, so the per-partition result is exact and the merge is concatenation rather than a second reduction.
Follow-up
- The payload is a patch rather than a snapshot, so applying only the highest version loses the intermediate changes. What changes in your reduction?
- How do you detect that version 7 arrived while version 6 was never delivered, and what should the consumer do about the gap?
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?
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
- 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.
- 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.
- 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.
- 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?
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
- 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.
- 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.
- 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.
- 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?
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
- 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.
- 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.
- 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.
- 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?
How do you ensure your code remains maintainable when working on long-term infrastructure projects?
Medium · Technical and Domain Knowledge
Approach
- Separate the domain rules (quantity takeoffs, cost roll-ups, unit conversions) from I/O such as database access, file import and UI, so the rules are plain functions you can test without a database and change without touching the plumbing.
- Back the rules with tests built from hand-checked worked examples. Before changing legacy code that has no tests, write characterization tests that pin its current output, then refactor. Run the whole suite in CI on every merge.
- Keep the schema under version control: every change is a numbered migration (Alembic, Flyway or similar) checked into the repo, never a hand edit in production, so any environment can be rebuilt from history.
- Write down the why. A short decision record for each non-obvious choice, linting and formatting enforced in CI, and pinned dependencies with a lockfile plus scheduled upgrades keep a codebase readable after the original authors leave.
- Name the trade-off: abstraction has a cost. Generalise when a second real use case appears, not before, because a wrong abstraction is harder to remove than duplicated code.
Follow-up
- How would you start adding tests to a legacy module that has none and that nobody fully understands?
- A core library you depend on reaches end of life. How do you plan and sequence the upgrade?
- How would you tell whether a codebase is getting more or less maintainable over time?
What is your process for integrating third-party APIs into internal estimation tools?
Medium · Technical and Domain Knowledge
Approach
- Start with the contract: authentication, rate limits, pagination, error codes and how the vendor versions its API. Then wrap it in one adapter (an anti-corruption layer) that maps the vendor's shapes to your internal model, so a vendor change touches one module.
- Make every call resilient. Set an explicit timeout, retry only reads or requests carrying an idempotency key, use exponential backoff with jitter, honour Retry-After on HTTP 429, and add a circuit breaker so a dead vendor fails fast instead of tying up workers.
- Protect the estimate's reproducibility. If the API supplies prices or reference data, store the value used together with its source and fetch timestamp on the estimate, so an old bid recalculates the same way after the vendor's numbers change. Cache reference data with a clear expiry.
- Validate every response against a schema and normalise units and currency at the boundary. Quarantine bad payloads rather than letting them flow silently into totals.
- Keep credentials in a secrets manager with least privilege. Test against recorded fixtures or the vendor sandbox, and monitor error rate and latency per endpoint so you notice a change in the vendor's behaviour before users do.
Follow-up
- The vendor API is down the afternoon an estimate is due. What does the user see, and what can they still do?
- The vendor changes a response field without notice. How does your design catch it, and where does it fail?
- How do you test the integration in CI without hitting the live API or its rate limits?
How do you approach data integrity when dealing with large-scale construction project files?
Medium · Technical and Domain Knowledge
Approach
- Define integrity first: the file is complete, uncorrupted and the version the user meant. Compute a SHA-256 checksum on upload, store it with the file's metadata, and verify it after every transfer or restore.
- For large files, use chunked or multipart upload with a checksum per part, and make it resumable. Write to a staging location, verify the whole object, then commit the metadata row that points at it in one transaction, so readers never see a half-written file.
- Treat versions as immutable: never overwrite, always add a new version. Enforce this in the relational metadata with foreign keys and a unique constraint such as (project_id, file_name, version_no), and use optimistic concurrency (a version number or ETag checked on save) so two people editing the same file cannot silently lose each other's changes.
- Validate at ingest: file format, required fields, units and value ranges. Reject or quarantine bad records with a reason instead of coercing them, and keep an audit log of who changed what and when.
- Back up with object-store versioning and point-in-time recovery for the database, and test restores on a schedule. A backup that has never been restored is not proven.
Follow-up
- Two estimators open and save the same project file at the same time. Walk through exactly what happens in your design.
- How would you detect files that were corrupted silently in storage months after upload?
- How does your versioning scheme support several competing versions of the same bid at once?
How do you prioritize technical debt against the need for new feature delivery?
Medium · Problem-Solving and Logic
Approach
- Make the debt visible and costed. Keep a list where each item records what it costs to carry (incidents, hours lost per change, workarounds) and roughly what it costs to fix. Change frequency multiplied by complexity is a quick way to find the hotspots.
- Pay down debt where the roadmap is heading. Refactor the modules the next features will touch, and leave stable code that rarely changes alone, even if it is ugly.
- Let correctness and safety debt jump the queue: calculation errors, data-loss risks and dependencies with known security vulnerabilities are defects, not cleanup.
- Use mechanisms that fit delivery rather than compete with it: a standing share of each iteration for debt, refactoring folded into the feature that needs it, and small incremental steps behind tests instead of a big rewrite.
- Explain it to stakeholders in delivery terms, for example: this kind of change takes three days today and would take one after the cleanup. Give a concrete example where you chose to keep a piece of debt and why.
Follow-up
- A stakeholder says there is no time for any refactoring this quarter. What do you do?
- Tell me about debt you decided not to fix. How did that decision hold up?
- After a paydown, how do you show it actually made delivery faster or safer?
Describe a situation where you identified a bottleneck in a workflow and implemented a software-based solution
Medium · Problem-Solving and Logic
Describe a situation where you identified a bottleneck in a workflow and implemented a software-based solution.
Approach
- Pick a story with a measured before and after: time per job, items waiting in a queue, error or rework rate. Open with the baseline number, not the solution.
- Show how you found the bottleneck rather than guessed it: timing each step, logs or traces, profiling, or sitting with the users who do the work. Only the constraint step limits throughput, so speeding up any other step changes nothing.
- Name the root cause precisely. A manual one (re-keying data between spreadsheets) needs a different fix from a system one (a slow query diagnosed with EXPLAIN ANALYZE and fixed with an index or by rewriting the query).
- Justify the fix and the alternatives you rejected: build versus buy, the smallest change that removes the constraint, and how you rolled it out (a pilot group, running in parallel with the manual process and comparing outputs, a fallback).
- Close with the result in numbers, how many people adopted it, and where the bottleneck moved next, because removing one constraint exposes the next one.
Follow-up
- How did you confirm the improvement came from your change and not from something else that changed at the same time?
- What became the bottleneck after your fix, and did you address it?
- Did the users resist the new tool, and how did you handle that?
Edge instances grow 400 MB per hour until the nightly restart
Hard · memory leak · heap analysis · metric cardinality
Edge API instances start at 700 MB resident and grow about 400 MB/hour; a nightly rolling restart has hidden it for weeks. Growth continues unchanged when request rate halves overnight, p99 degrades in the last hours before an instance is recycled, and heap used immediately after a forced full GC rises monotonically. The service holds no product state. Name the discriminating measurement that separates the plausible causes, give the most likely cause, and give the fix and how you would verify it.
Approach
- Separate resident memory from live heap first, because they fail differently. Resident size can grow from fragmentation, native buffers or thread stacks while the heap is flat; heap used after a full GC rising monotonically is the measurement that says objects are reachable and not being released. You already have it, so this is retention, not fragmentation, and that closes off half the candidate list.
- Use the rate's independence from traffic as the discriminator. Growth that continues at half the request rate rules out per-request objects that are merely slow to collect and points at a structure that grows with distinct values observed rather than with call volume. Write the candidates that have that property: a metrics registry keyed on a high-cardinality label, an unevicted cache, an interner, a per-key lock map.
- Take two heap snapshots an hour apart and diff by retained size, reading the dominator tree, not by allocation count or instance count. Expect one root holding a map with millions of entries, then follow the reference chain to the code that inserts and never removes. Allocation profilers point at churn, which is the wrong signal here.
- The candidate that fits this service is an observability label carrying an identifier, such as a request path recorded before templating so that /v1/resources/48213 becomes its own metric series. That grows with distinct ids seen, is independent of rate, and explains the late p99 degradation, since GC cost rises with the size of the live set.
Follow-up
- Post-GC heap is now flat but resident size still creeps. What are you looking at, and does it matter?
- How would you have detected this before an OOM, given the nightly restart masked the trend?
Suggested practice checklist
Day 1 — Map the loop and the domain
- Write out the two reported stages and, beside each, the question types it may include: background discussion, then system design, coding and behavioral.
- Read about how a cost estimate is built and revised, and list ten nouns you will use in answers: bid, version, line item, project file and similar.
- Write your one-page project inventory with stack, role, decision and measurable result for three projects.
Deliverable: A one-page loop map, a ten-term domain glossary and a three-project inventory.
Day 2 — Maintainability and technical debt
- Write a spoken answer to the maintainability question naming tests, module boundaries, documentation and review habits, with one real example.
- Build a debt-versus-feature framework: cost of delay, risk, frequency of change and user impact, and write how you would present it to a non-technical stakeholder.
- Say both answers aloud and cut any sentence that is a slogan.
Deliverable: Two spoken answers, each with one concrete example and a stated trade-off.
Day 3 — Versioned data and data integrity
- Sketch the schema for an estimation tool that handles multiple versions of a bid: tables, keys, version rows, history and how you read the state at a version.
- List integrity safeguards for large project files: checksums, validation on import, constraints, transactions and a reconciliation report.
Deliverable: A schema diagram, an integrity checklist and one solved version-gap query.
Day 4 — Third-party API integration
- Outline an integration process: contract and error cases, authentication, retries with backoff, idempotency, timeouts, monitoring and a fallback when the provider is down.
Deliverable: A written integration checklist plus two solved coding exercises.
Day 5 — Bottlenecks and production failures
- Take one slow query, read its plan and write the changes you would try, in order, with how you would verify each.
- Prepare the workflow-bottleneck answer: what you measured, what software you built, and the before-and-after result.
Deliverable: A query-tuning note, one bottleneck story and one production-failure story in outline.
Day 6 — Collaboration stories
- Write the version control answer with branch strategy, review process, one conflict or revert incident and release practice.
- Outline the simplify-a-process story and the conflicting-stakeholders story, each with a measure or a before-and-after.
- Outline the cross-functional story involving field engineers or project managers, and say each aloud.
Deliverable: Four outlined stories, each with a personal decision and a result.
Day 7 — Feedback, pressure and a full rehearsal
- Write the code-feedback story and the high-pressure quality story, with what you cut and what you protected.
- Run a mixed mock: one design question, one coding exercise and two behavioral prompts, answered aloud.
- List three questions to ask about the team's tools, legacy systems and the people you would work with, and fix the weakest answer from the mock.
Deliverable: Two finished stories, a recorded mock and a list of three questions to ask.
Stories to rehearse for the field-and-office loop
Candidates report behavioral assessments inside the deeper technical rounds, and the reported prompts cover production failures, collaboration with non-engineers, feedback and quality under pressure. Prepare stories that show a decision you made, the trade-off, and a result you can state. Use the STAR structure of situation, task, action and result, but spend most of the time on the action.
Describe a time you had to troubleshoot a system failure in a production environment.
Medium · Technical and Domain Knowledge
Approach
- Choose an incident where you drove the diagnosis. Open with the symptom and who it hurt: a wrong total in an estimate, a job that stopped, an outage. Say how you detected it, whether by an alert, a user report or a log, and what the impact was.
- Show a diagnostic sequence rather than a hunch: stop the bleeding first (rollback, feature flag, restart), then ask what changed recently, read logs and metrics, reproduce in a safe environment, and narrow with one hypothesis at a time. State which hypotheses you ruled out and what evidence did it.
- Separate the mitigation from the root cause and from the prevention. Name the real cause in one sentence, then the fix, then what you added so it cannot recur silently: a regression test, an alert, a validation, a runbook note.
- Close with the result and a lesson. Give time to recovery or the number of affected records if you have them. The story sinks when it is a heroic all-night fix with no root cause, or when you blame another team without evidence.
Follow-up
- Why did you mitigate before you found the root cause?
- How did you confirm the cause rather than a correlation?
- What changed afterward so the same failure would be caught earlier?
Explain your experience with version control systems in a collaborative team environment.
Medium · Technical and Domain Knowledge
Approach
- Answer with specifics of how you used version control in a team: branch strategy (short-lived feature branches off a main branch, or trunk-based with flags), pull requests with review, and CI checks that must pass before merge. Say whichever system you used and how your team protected the main branch.
- Explain merge versus rebase in terms of consequences: rebase gives a linear history on your private branch, merge preserves a shared branch's history, and rewriting commits that others have pulled is the thing to avoid. Say which your team chose and why.
- Give one concrete incident: a hard merge conflict you resolved by talking to the other author, or a bad commit you removed from shared history with a revert instead of a force-push. Describe what you checked afterward.
- Add release hygiene: tags for releases, hotfix branches for production, small focused commits with readable messages so a bisect can find a regression. Tie it to long-lived tools where you must reproduce what shipped months ago.
Follow-up
- How would you undo a bad commit that is already on the shared main branch?
- How do you keep a long-running branch from drifting away from main?
- How do you decide between a squash merge and keeping the commit history?
Walk me through a time you had to simplify a complex process for an end-user.
Medium · Problem-Solving and Logic
Approach
- Name the user and the process in plain terms, such as an estimator filling in a multi-step form or a coordinator reconciling spreadsheets by hand. Show how you learned the real pain: sat with them, watched the steps, or counted the errors and support requests, rather than guessing.
- Describe what you removed or changed and why: fewer fields through sensible defaults, validation at entry, merging screens, hiding rarely used options, or automating a manual copy step. Say what you deliberately kept, because simplification that drops a needed control causes new errors.
- Prove it was simpler with a measure: steps before and after, time to complete, error rate, tickets or questions per week. If you lack numbers, give a clear before-and-after from the user's own words, and say how you rolled it out and trained people.
- State the trade-off. Power users may have lost a shortcut or an option, so say how you handled them. The story sinks when it only describes interface polish and never shows the user's problem or any evidence of improvement.
Follow-up
- How did you know the new process was actually simpler for the user?
- What did you cut that someone later asked you to restore?
- How did you roll the change out without disrupting people mid-task?
How do you handle conflicting requirements from non-technical stakeholders?
Medium · Problem-Solving and Logic
Approach
- Start by making the conflict explicit: write each stakeholder's requirement in concrete terms and check whether they truly conflict or only seem to. Ask what outcome each person needs, for example fast bid turnaround for estimators versus an audit trail for operations, since the underlying goals are often compatible.
- Quantify the cost and impact of each option in terms they care about: delay, risk, effort, error exposure. Present two or three options with trade-offs in plain language, avoiding jargon, and recommend one with your reasoning.
- If they still disagree, take it to the person who owns the priority and ask for a decision rather than choosing silently. Write down what was decided, by whom, and what was deferred, and share it with everyone involved.
- Show the outcome and how you kept both parties on side, including the one who lost. The story sinks when you quietly picked a side, built both and doubled the cost, or framed the stakeholders as unreasonable.
Follow-up
- What would you do if both stakeholders were equally senior and neither would yield?
- How did you tell the stakeholder whose request you did not build?
- What happened when the decision changed later?
Tell me about a time you had to work with a cross-functional team, such as field engineers or project managers
Medium · Behavioral and Cultural Alignment
Tell me about a time you had to work with a cross-functional team, such as field engineers or project managers.
Approach
- Set the scene with the roles involved: you as the engineer, plus field engineers or project managers, and what the shared goal was. Say how you built a shared vocabulary, for instance by walking through their real documents, attending a site or planning meeting, or having them show you a day of their work.
- Focus on how you gathered requirements and kept them engaged: a short feedback loop with demos, a shared list of open questions, and clear ownership of who decides what. Give one decision where a field or project constraint changed your design, and explain what you changed.
- Be specific about your own contribution, using I for your decisions and naming teammates for theirs. Describe a friction point, such as different priorities or timing, and how you resolved it.
- End with the result for the project or users and what you would do differently. The story sinks when it lists meetings without any decision, casts the other team as an obstacle, or hides your own role behind we.
Follow-up
- How did you learn the terms the field team used?
- Tell me about a time a field constraint made you change your design.
- How did you keep non-engineers informed without overwhelming them?
How do you handle feedback on your code or design choices?
Medium · Behavioral and Cultural Alignment
Approach
- Choose real feedback that stung or changed your work, not a trivial one. State the situation briefly, the specific comment, and your first reaction honestly, then focus on what you did: asked clarifying questions to understand the reasoning, and separated style preference from a correctness, safety or maintainability issue.
- Show that you tested the claim. Either you reproduced the issue the reviewer saw and changed the code or design, or you answered with evidence, such as a benchmark or a requirement, and reached an agreed outcome. Both are good; defensiveness and automatic agreement are not.
- Describe what changed afterward in your habits: smaller pull requests, a design note before large changes, a checklist, or a test you now always add. Mention also how you give feedback to others, because that shows you treat review as two-way.
- The story sinks when the feedback was minor, when you were simply right, or when the lesson is vague. Keep the result concrete.
Follow-up
- Tell me about feedback you disagreed with and how it ended.
- How do you give critical feedback to someone more senior than you?
- What did you change in how you submit code for review?
Describe a high-pressure situation and how you maintained your focus on quality.
Medium · Behavioral and Cultural Alignment
Approach
- Choose a situation with real stakes, such as a deadline on an estimation tool or a production issue, and say what made it high-pressure. Then state the quality bar explicitly: which parts could not be compromised (calculation accuracy, data integrity) and which could move (scope, polish, secondary features).
- Show the mechanics of how you protected quality under time pressure: cut scope instead of tests, kept review on the risky changes, added tests on the calculation paths, used a checklist or staged rollout, and communicated early about what would slip.
- Describe how you managed yourself and others: breaking the work into small verifiable steps, avoiding long unreviewed changes, and asking for help or a second pair of eyes at the right moment. Include a decision where you said no or renegotiated the timeline.
- Finish with the outcome, including anything that slipped and what you learned. The story sinks when it glorifies long hours, when quality was sacrificed without acknowledgement, or when nothing in it shows a decision of yours.
Follow-up
- What exactly did you cut, and who agreed to it?
- What if the deadline was fixed and you could not reduce scope?
- How did you check afterward that quality had held?