cswork / libraryOpen practice workspace

Interview guides · CareerXperts

CareerXperts Software Engineer Interview Guide

CareerXperts Software Engineer interview guide: reported rounds, schema, sync and testing questions, behavioral answer structures and a 7-day plan.

The 60-second brief

Candidates describe CareerXperts Software Engineers as people who build and maintain the software that supports engineering project operations: tools for civil site management and for MEP (Mechanical, Electrical, and Plumbing) work, used to follow progress, manage resources and keep job sites safe. The reports mention work on projects in places such as Khāvda as well as tools used across the organisation. Day to day, the role is described as working with QS MEP engineers and civil site engineers to find the pain points in their workflows, then shipping backend services and mobile-friendly front ends for them, from requirements and prototyping through deployment and monitoring after release.

This guide is for candidates interviewing for the Software Engineer role at CareerXperts. It covers the four reported rounds, the design, data and reliability questions candidates describe, the behavioral questions with worked answer structures, and a seven-day plan. It does not cover other CareerXperts roles, and it makes no claim about how any individual interview is run.

Candidates report four rounds over about 3-5 weeks: Initial Technical Screen, Collaborative Problem-Solving, Feedback at Each Stage, and Final Technical and Behavioral Evaluations. The names are what candidates describe, not a published process, and the order of individual questions across rounds is not reported.

Focus areas

  • MEP Engineering
  • QS (Quantity Surveying) for MEP
  • MEP Site Engineering

Overview

The role described to candidates is software for people who work on sites, not for people at desks. The users are QS MEP engineers and civil site engineers, the product areas named are progress tracking, resource management and safety, and the work spans backend services, mobile-friendly interfaces and the full lifecycle from gathering requirements to monitoring a release. The skills candidates describe for the role are a modern language (Python, Java or JavaScript are named), SQL and NoSQL databases, and RESTful API development, with cloud platforms (AWS, Azure or GCP), mobile development and CI/CD pipelines listed as extras.

The reported technical questions all circle the same problem: field data that must stay correct. They ask for a database schema that tracks real-time progress across a multi-phase construction project, a comparison of monolith and microservices for a field-reporting tool, a way to keep data intact when mobile field devices sync with a central server, and the testing strategy for software that has to be reliable. Candidates also describe system design areas such as database design and normalization, API design and protocols, cloud deployment, and data latency and synchronization, with scenarios like tracking equipment status across remote sites and absorbing a sudden surge of uploads from field tablets. Reports also mention intermittent connectivity as a condition to design for.

The behavioral questions are about working with people who are not engineers: explaining a technical issue to a project manager or site engineer, prioritising when different engineering departments have conflicting deadlines, catching a bug or process inefficiency early, and handling feedback from users who are not used to digital tools. A story about optimizing a slow query or data process is also on the reported list. Rehearse each as a structured story with a measurable result.

Preparation therefore splits in three. Build fluency in data modelling and offline-tolerant sync so you can reason aloud about conflicts, retries and duplicates. Keep your coding sharp in the language you will use, since the first stage is described as a coding and problem-solving screen. And learn enough construction vocabulary (what a phase, a bill of quantities, an MEP trade or a site report is) that your examples sound like they belong in this domain.

The CareerXperts interview process

Candidates describe four stages, from a technical screen to a final combined technical and behavioral evaluation. The stage names below are as reported; where little is said about a stage, the guidance sticks to what its name implies.

Initial Technical Screen

Candidates describe the Initial Technical Screen as the first stage, aimed at your coding skills and problem-solving ability. A coding and problem-solving stage means working code and clear reasoning out loud, so treat it as a conventional coding screen in the language you know best. The reports name Python, Java and JavaScript as languages for the role, so pick one and stay in it. Narrate your plan before typing, name the edge cases (empty input, duplicates, a single element, very large input), and state the time and space cost when you finish.

What to demonstrate

  • Working code in a language you choose
  • Problem decomposition and the ability to explain it as you go
  • Handling of edge cases and a correct complexity statement

How to prepare

  • Solve a few medium problems in your chosen language, finishing each with a quick test of empty and duplicate inputs.
  • Use the practice set on archiving a resource graph without recursion and on a rolling failure rate per destination, to get used to state-heavy problems rather than pure puzzles.
  • Rehearse a two-sentence opening for any problem: restate it, then say the first data structure you would reach for and why.

Collaborative Problem-Solving

Collaborative Problem-Solving is described as sessions that mirror how teams at CareerXperts work day to day, and candidates mention scenarios such as tracking equipment status across remote construction sites. Expect to build a design with someone rather than present a finished one. Start by asking who uses the system, what happens on a site with poor connectivity, and what a wrong record costs. Then split the problem into components (data model, API, sync, storage, deployment) and decide them one by one, saying why at each step.

What to demonstrate

  • Breaking an open-ended scenario into components
  • Working through a design in conversation and adjusting when new constraints appear
  • Data and API design choices with their reasons

How to prepare

  • Practise two designs aloud: a schema that tracks progress across the phases of a construction project, and a sync flow between mobile field devices and a central server, covering conflicts and duplicates.
  • Prepare a short answer on monolith versus microservices for a field-reporting tool, including when you would start with a single deployable unit.
  • Write a list of clarifying questions you would always ask (users, connectivity, volume, correctness requirements) and use it at the start of each practice design.

Feedback at Each Stage

Feedback at Each Stage is listed as a round of its own, and candidates describe it as the part of the process where you are told how you are progressing and how well you fit. The reports do not say what you are asked to do in it. Treat it as a checkpoint: use any feedback from the earlier stages to adjust your preparation, and be ready to talk through your technical choices again, since reliability and testing come up in the reported questions.

What to demonstrate

  • How you take in and respond to feedback on your earlier performance
  • Your progress and fit as shared with you at that point

How to prepare

  • After each stage, write down what went well and what you would change, and be ready to act on anything you are told.
  • Prepare your answer on testing strategy for software that must be reliable: unit tests on the core logic, integration tests against a real database, tests for sync conflicts, and checks in the deployment pipeline.
  • Have two or three questions ready about the team, the users and the projects the role supports.

Final Technical and Behavioral Evaluations

The Final Technical and Behavioral Evaluations combine technical skills and behavioral fit for the team. Candidates also say they meet engineers, project managers and potential team leads during the process. For the technical half, be ready to revisit schema design, sync, architecture trade-offs and a query or data process you have optimized. For the behavioral half, bring structured stories in situation, task, action, result form, each with a result you can measure.

What to demonstrate

  • Technical depth across the design, data and reliability topics
  • Behavioral fit, including how you work with non-engineers
  • Your ability to explain engineering choices in terms of business value

How to prepare

  • Write five stories matched to the five reported behavioral prompts, each with a number attached to the result.
  • Rehearse explaining one technical decision twice: once to an engineer and once to a project manager with no coding background.
  • Do a full mixed run: one design question, one coding problem and two behavioral stories back to back.

Where candidates lose points

Designing the progress schema as a single table of status flags

Model phases, tasks, locations and progress events separately, store progress as dated entries rather than overwriting a status, and say how you would answer 'what was the state last Tuesday' and 'what is still blocked' from it.

Answering the sync question with 'last write wins' and nothing else

Cover idempotent writes with client-generated ids, a version or sequence number per record, how conflicts are detected and resolved, retries after a dropped connection, and how you verify the two sides agree afterwards.

Treating monolith versus microservices as a matter of taste

Tie your choice to team size, deployment burden, data ownership and the need for offline-tolerant clients, and say what would make you split a service out later.

Telling behavioral stories in which 'we' did everything and the result is vague

Name your own decision, give the before and after numbers (query time, tickets, hours saved), and say what you would do differently.

Ignoring the people and the setting the software is for

Learn the basics of civil and MEP site work, and ask who uses the tool, on what device and under what connectivity before you propose anything.

Questions & practice

Archive a resource graph without breaking live references or recursing

Medium · graph traversal · topological order · tenant isolation

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

Approach

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

Follow-up

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

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

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

Track a rolling failure rate per destination for circuit decisions

Easy · sliding window · ring buffer · circuit breaker

The egress service delivers about 1,500 webhooks per second across roughly 40,000 destinations, each call bounded by a 10 second timeout. Maintain, per destination, the failure rate over the trailing 60 seconds so a caller can ask before dispatch whether the circuit should open. Attempts arrive as (destination_id, finished_at_ms, outcome). Requirement: amortised O(1) per attempt, with total memory bounded by the destination count rather than by traffic. Give the structure, its exact memory, and the rule that stops a destination with three attempts from opening a circuit.

Approach

  1. Name the exact-deque version and then reject it as the default. Holding timestamps and advancing a tail pointer past anything older than now minus 60 seconds is a correct two-pointer window at amortised O(1) per attempt, but its memory tracks in-window traffic, so one destination in a retry storm holds hundreds of thousands of entries while thousands of quiet destinations hold none.
  2. Use a ring of 60 one-second buckets per destination, each bucket a pair of counters for attempts and failures. On an attempt, advance the ring by the elapsed whole seconds, zeroing at most min(elapsed, 60) buckets, then increment the head. That is amortised O(1) with a fixed footprint per destination.
  3. State the footprint: 60 buckets times two 4-byte counters is 480 bytes of payload per destination, so 40,000 destinations is roughly 20 to 25 MB with per-entry overhead, bounded by the catalogue rather than by the rate. The cost is granularity, since the oldest bucket ages out in whole seconds, which is far tighter than the decision needs.
  4. Require a minimum sample before the circuit may open. A destination with three attempts and three failures reads as 100 percent and is not evidence; a floor of roughly 20 attempts in the window makes the ratio meaningful, and below that floor use a run of consecutive failures as the trigger instead.

Follow-up

  • The fleet is 30 instances and each sees roughly a thirtieth of a destination's traffic. Where does the rate actually live, and what does a per-instance answer get wrong?
  • A destination answers in 9.5 seconds and succeeds. It is not failing but it is consuming your per-destination concurrency. What signal should open the circuit here?

Keep soft-deleted accounts from blocking re-registration

Easy · soft delete · unique constraints · engine differences

app_user holds user_id, tenant_id, email CITEXT, password_hash (NULL for SSO principals), email_verified_at, auth_version, status ('invited','active','suspended','deactivated'), created_at, updated_at, deleted_at. Two live accounts for one address inside a tenant must be impossible, but an address freed by a soft delete must be reusable, and the same tenant may delete and re-register it repeatedly. Write the uniqueness DDL for PostgreSQL 16, then the equivalent for MySQL 8 where partial indexes do not exist, and say what each permits once three deleted rows already hold that address.

Approach

  1. Start from what is actually unique: not (tenant_id, email), but (tenant_id, email) among live rows. PostgreSQL says that directly — CREATE UNIQUE INDEX app_user_live_email ON app_user (tenant_id, email) WHERE deleted_at IS NULL. A full constraint over the same two columns burns the address permanently the first time someone deletes an account.
  2. Keep case-insensitivity in the type or the index, never in the application: CITEXT as given, or UNIQUE (tenant_id, lower(email)) as an expression index where the extension is unavailable. A case-sensitive unique column is exactly how two accounts for one human appear.
  3. For MySQL 8 the predicate has to move inside the key: add a discriminator column that is a constant 0 while the row is live and is set to user_id on delete, with UNIQUE (tenant_id, email, deleted_marker). Live rows share the constant and still collide; deleted rows differ from each other and stop colliding.
  4. State the NULL variant and its dependency: leaving the marker NULL for deleted rows also works, because a unique index treats NULLs as distinct — true in MySQL, and true in PostgreSQL only under the default NULLS DISTINCT, which PostgreSQL 15 lets you reverse. Check the polarity against the three existing deleted rows: constant-on-live is what preserves the collision you want, and reversing it silently admits duplicate live accounts.

Follow-up

  • A deleted account re-registers with the same address the next day. Do the old resource rows follow the new user_id, and how does the API keep the two principals apart?
  • How do you honour an erasure request while resource_revision.actor_user_id still references this table?

Find version gaps and relay lag with window functions

Medium · window functions · event tables · frame semantics

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

Approach

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

Follow-up

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

How would you design a database schema to track real-time progress for a multi-phase construction project?

Medium · Technical and Domain Proficiency

Approach

  1. Name the core tables first: project, phase (project_id, sequence, planned_start, planned_end, status), task (phase_id, planned_quantity, unit, weight), task_dependency (task_id, depends_on_task_id) and progress_entry (task_id, reported_by, reported_at, quantity_done, source_device_id, client_entry_id).
  2. Store progress as an append-only log, not as an overwritten percent column. That keeps the audit trail. Corrections become compensating entries instead of deletes, and percent complete is derived as the weighted sum of min(done / planned, 1) across tasks.
  3. Serve the live dashboard from a per-task and per-phase rollup that is updated in the same transaction as the insert, or by an async aggregator. The trade-off is write latency against staleness. Index progress_entry on (task_id, reported_at) for history queries.
  4. Add a UNIQUE (source_device_id, client_entry_id) constraint so a retried upload from a field device is idempotent, and store timestamps as UTC timestamptz so sites in different zones still order correctly.
  5. Cover the edge cases. Re-baselined plans need versioned planned quantities so old progress stays meaningful. Phases can overlap, units of measure can mix (metres against counts), and a task reported past 100% needs a rule.

Follow-up

  • The plan is re-baselined halfway through the project. How do you keep historical progress reports accurate?
  • Write the query for percent complete per phase. Which index or rollup makes it fast when the log has millions of rows?
  • Two engineers report progress on the same task while offline. What does the schema record, and what does the dashboard show?

Explain the trade-offs between a monolithic and microservices architecture in the context of a field-reporting

Medium · Technical and Domain Proficiency

Explain the trade-offs between a monolithic and microservices architecture in the context of a field-reporting tool.

Approach

  1. Start by splitting a field-reporting tool into its parts: a report capture and sync API for devices, attachment ingest if the tool accepts files, dashboards and exports for office users, notifications, and auth. Then ask which of these actually have different scaling or release needs.
  2. Monolith strengths: one deployable, in-process calls, and a single database transaction for a report and its line items. Local development, debugging and CI are also simpler. Weaknesses: you scale the whole app for one hot path, one bad deploy takes every feature down, and module coupling grows without enforced boundaries.
  3. Microservices strengths: independent scaling (a burst of device uploads does not starve dashboard reads), independent deploys and fault isolation. Costs: network failures between services, no cross-service ACID transaction (you need sagas or a transactional outbox), distributed tracing, more infrastructure, and API versioning between services.
  4. Give a reasoned default. A modular monolith with strict module boundaries suits a small team. Extract the ingest or sync path first, through the strangler-fig pattern, only once its load or release cadence clearly differs from the rest.
  5. Tie the choice to team size and deploy frequency. Mobile clients in the field run old app versions, so the device-facing API contract must stay backward compatible whichever architecture you pick.

Follow-up

  • Which component would you extract first, and how would you migrate it without downtime?
  • If reports and attachments live in separate services, how do you keep them consistent when one write fails?
  • How do you monitor and debug a single failed report submission across several services?

How do you ensure data integrity when syncing information between mobile field devices and a central server?

Medium · Technical and Domain Proficiency

Approach

  1. Make the device local-first. Writes go to an on-device store such as SQLite plus an outbox queue of operations. Each record carries a client-generated UUID, so the server can upsert on that key and a retried batch never creates duplicates.
  2. Never trust device clocks for ordering. The server assigns a monotonically increasing version or change sequence. Devices pull changes since their last cursor and push their outbox, and an item leaves the outbox only after the server acknowledges a committed write.
  3. Detect conflicts with optimistic concurrency. The client sends the base version it edited, and the server rejects a stale write (HTTP 409 or a conflict record). Then choose a resolution per data type: last-writer-wins only where losing an edit is acceptable, field-level merge for forms, append-only entries where possible so no conflict can arise, and manual review for values that matter.
  4. Validate on the server and commit each batch atomically, or make each item independently idempotent. Verify attachments with a checksum such as SHA-256 and use resumable uploads, so a dropped connection mid-file cannot leave a corrupt or partial record.
  5. Cover the edge cases. Deletes need tombstones so they propagate. Old app versions send old payload shapes, so version the sync API. Also handle connectivity that drops after the server commits but before the client receives the acknowledgement.

Follow-up

  • Two people edit the same record offline and both sync later. Walk through exactly what each of them sees.
  • How do deletes propagate to a device that has been offline for two weeks?
  • How would you detect, after the fact, that a device and the server have silently diverged?

What testing strategies do you employ to ensure high reliability for mission-critical software?

Medium · Technical and Domain Proficiency

Approach

  1. Lay out the layers. Fast unit tests cover pure logic such as quantity rollups and status transitions, including boundaries (zero, the exact limit, over-limit). Property-based tests, for example with Hypothesis in Python, check invariants like 'syncing the same batch twice changes nothing'.
  2. Run integration tests against a real database, not mocks, for queries, migrations and transaction behaviour; Testcontainers is one way to start a disposable instance. Add contract tests between the mobile client and the API so an old app version in the field keeps working after a server release.
  3. Inject faults deliberately. Drop the network mid-upload, deliver the same request twice, return a 500 after a commit, and skew the device clock. Load-test the upload path for a sudden burst from many devices. Keep end-to-end tests to a few core user flows, because they are slow and flaky.
  4. Gate every merge in CI and add a regression test for every production bug. Treat coverage as a signal on core modules, not a target, and quarantine and fix flaky tests instead of retrying them.
  5. Reliability continues after the tests pass: feature flags, canary or staged rollouts, monitoring and alerting on error rates and sync failures, and a rehearsed rollback, because no suite covers every device and network condition.

Follow-up

  • How would you test offline-sync behaviour deterministically in CI?
  • What would you deliberately not test, and how do you justify that trade-off?
  • A bug reached production despite the suite. Walk through what you change afterwards.

Exports duplicate a row range about once a week

Hard · leases · clock skew · idempotency

Roughly once a week an export writes a file containing a duplicated range of rows. The affected job_run rows show attempt = 1, status = succeeded, one started_at, and a lease_owner naming a different host from the one whose logs show the job starting. Leases last 30 seconds and are heartbeated every 10 from inside the handler; lease_expires_at is computed on the worker and compared against the database's now(). Find the mechanism, and give a fix that holds even if you cannot fix the clocks.

Approach

  1. Start from the fact that eliminates the obvious answer. attempt = 1 means no retry was recorded, so this is not a re-run after failure; two workers ran the same row concurrently and the takeover path never touched the counter. lease_owner naming a host other than the one that started the job is the same statement from the other side.
  2. Enumerate the mechanisms that cause a premature takeover, then find the signal that separates them. Either the lease genuinely expired because the heartbeat did not fire, which is what happens when the heartbeat runs on the handler's own thread and the handler makes a long blocking call, or it only appeared expired because two clocks disagree, since lease_expires_at is written from the worker's clock and evaluated against the database's. The discriminator is the distribution: incidents clustered on the longest exports indict the heartbeat, incidents clustered on one host indict skew. Measure both, and measure each host's offset against the database directly.
  3. Read the reclaim query precisely. In PostgreSQL now() is transaction start time, not statement time, so a reclaimer holding a long transaction compares against an older timestamp than expected; clock_timestamp() is the statement-time function. This is worth ruling in or out before you redesign anything, because it changes which rows look expired.
  4. Remove the second clock rather than trying to synchronise it. Issue and extend the lease in the database, with lease_expires_at = now() + interval '30 seconds' in both the claim and the heartbeat, so exactly one clock is ever compared and worker skew stops mattering to this predicate.

Follow-up

  • The displaced worker has already streamed half the file to object storage. What makes that side effect safe to repeat?
  • You now count takeovers. What alert fires on that counter, and at what threshold?

Suggested practice checklist

The plan moves from the loop map and domain vocabulary, through the reported design, sync and reliability questions, to coding practice and the behavioral stories, and ends with a mixed mock.

Day 1 — Map the loop and learn the domain vocabulary

  • List the four reported rounds and write one line on what you expect to do in each, marking the stage you feel least ready for.
  • Write a one-page glossary of the domain: MEP trades, quantity surveying, civil site work, project phases, site reports.
  • Write the user profile for a site engineer using a tablet: device, connectivity, the three tasks they do most.

Deliverable: A round map, a one-page glossary and a site-engineer user profile.

Day 2 — Schema for progress across project phases

  • Design the schema for tracking progress across a multi-phase construction project: phases, tasks, locations, progress entries.
  • Write three queries it must answer: percent complete per phase, tasks behind schedule, and history as of a past date.
  • Say out loud where you normalize and where you would deliberately denormalize for reads.

Deliverable: A schema diagram, three working SQL queries and a spoken two-minute explanation.

Day 3 — Sync and integrity between devices and the server

  • Design the sync protocol: client-generated ids, per-record versions, a change feed, retry rules and conflict handling.
  • Walk through a field tablet going offline, editing for a day and reconnecting, including a duplicate upload.
  • Answer the monolith-versus-microservices question for a field-reporting tool, with a rule for when you would split.

Deliverable: A sync sequence diagram, a conflict-handling table and a one-minute architecture trade-off answer.

Day 4 — Reliability testing and a query optimization story

  • List the test layers you would put around the sync and progress code, and one example case for each.
  • Work the practice items on soft-deleted accounts and on version gaps with window functions to sharpen SQL.
  • Write your slow-query story with the before and after measurements and the plan you read.

Deliverable: A test strategy list, two solved SQL practice items and a finished slow-query story.

Day 5 — Coding and debugging practice

  • Solve the practice items on archiving a resource graph without recursion and on merging partitioned event streams.
  • Solve the rolling failure rate item, stating complexity and edge cases for each.
  • Work the practice debugging item on exports that duplicate a row range, naming your first three checks before you open any code.

Deliverable: Three solved coding problems with notes on complexity, and a written debugging sequence.

Day 6 — Behavioral stories for non-engineer collaboration

  • Write the story of explaining a technical issue to a project manager or site engineer, with the analogy you used.
  • Write the prioritization story for conflicting deadlines, including who you told about the trade-off.
  • Write the story of catching a bug or process problem early, and the story about feedback from users new to digital tools, each with a measurable result.

Deliverable: Four stories in situation, task, action, result form, each under two minutes spoken.

Day 7 — Mixed mock and questions to ask

  • Run a mock in order: a short coding problem, a design question, then two behavioral stories.
  • Re-do the weakest answer from the mock and record it.
  • Write three questions about the projects, the users and the team to ask at the end.

Deliverable: A completed mock, a re-recorded weak answer and three questions to ask.

Stories for working with site engineers and project managers

The behavioral questions candidates report are about working with people who are not engineers, handling competing demands, spotting problems early and tuning slow data work. Prepare each as a concrete story with your own decision in it and a result you can measure, and keep a second example ready in case the first is not a good fit.

Describe a time you had to optimize a slow-running query or data process.

Medium · Technical and Domain Proficiency

Approach

  1. Choose a case where you made the call. Open with the symptom and a number: a report that took minutes, a nightly job that overran, an endpoint with a high p95.
  2. Describe how you found the cause: read the query plan (in PostgreSQL, EXPLAIN ANALYZE with buffers), looked for sequential scans, N+1 patterns, sorts spilling to disk or row counts far off the estimate.
  3. Name the fix and why it fit: a composite index matching the filter and sort, a rewrite to remove a correlated subquery, batching, keyset pagination in place of large offsets, or pre-aggregating a summary table.
  4. Give the cost of the fix as well as the gain: index maintenance on writes, extra storage, build time and locking on a live table, and how you rolled it out.
  5. Close with before and after measurements on realistic data, plus a check that the results were identical.

Follow-up

  • How did you confirm the improvement came from your change and not from caching or lower load?
  • What would have gone wrong if the table were ten times larger?
  • Did the new index slow down any writes, and how did you check?

Describe a time you had to explain a complex technical issue to a project manager or site engineer.

Medium · Behavioral and Problem-Solving

Approach

  1. Pick an issue whose consequence the other person cares about, such as a delayed sync that left site records out of date, and open with what it meant for their work, not the mechanism.
  2. Show how you adapted the explanation: a plain analogy, a simple diagram or a concrete example from their own site or schedule, with no jargon.
  3. Present options with cost, time and risk, then give a recommendation and ask for the decision you needed from them.
  4. Check understanding by asking them to restate the plan or the impact, then follow up in writing.
  5. State the result: the decision made, the action taken and what changed afterwards.

Follow-up

  • What did you leave out on purpose, and why?
  • What if they had disagreed with your recommendation?
  • How did you know they had understood, not just nodded?

How do you prioritize tasks when faced with conflicting deadlines from different engineering departments?

Medium · Behavioral and Problem-Solving

Approach

  1. Lay out your method before the story: collect the facts for each request (deadline, who is affected, what slips if it waits, dependencies, whether it can be split), then rank by impact and reversibility.
  2. Make the trade-off visible: share the competing asks with all requesters or with the person who owns the priorities, instead of deciding in private.
  3. Negotiate scope as well as dates: deliver a smaller first slice to one team, and agree what is dropped or moved for the other.
  4. Use one concrete example with the actual deadlines and the order you chose, and say what you told each team.
  5. Finish with the outcome and a lesson, such as agreeing a priority rule in advance or recording estimates so the next conflict is faster to resolve.

Follow-up

  • What if two managers both insisted theirs was the top priority?
  • Describe a time your ordering turned out to be wrong, and how you recovered.
  • How did you handle the team whose work you delayed?

Tell me about a time you identified a bug or process inefficiency before it became a major problem.

Medium · Behavioral and Problem-Solving

Approach

  1. Start with the signal that made you look: an odd metric, a failing edge-case test, a code review comment, a data reconciliation mismatch or an alert nobody else had read.
  2. Show how you sized the problem: how many records or users would have been affected, how soon, and what would have been expensive to fix later.
  3. Describe the fix and the guard against recurrence: a regression test, a database constraint, validation on input, an alert or a changed process, not only the patch.
  4. Say how you brought others in: who you told, the evidence you showed and any pushback you got.
  5. Quantify what was avoided or saved, and be honest about what you were able to confirm.

Follow-up

  • How did you decide it was a real problem and not noise?
  • What did you add so it would be caught automatically next time?
  • Was there a cost to acting early, such as time taken from planned work?

How do you handle feedback from users who are not accustomed to digital tools?

Medium · Behavioral and Problem-Solving

Approach

  1. Choose a real case where users were hesitant or struggled with a tool, ideally a mobile or field setting, and describe who they were and what they were trying to do.
  2. Say how you gathered feedback: watch them perform a task, ask them to talk through it and note where they hesitate, rather than relying only on what they say is wrong.
  3. Separate the symptom from the cause. 'The app is confusing' might mean too many steps, small tap targets, unclear labels or a failed save they never noticed.
  4. Turn feedback into specific changes, such as fewer steps, plainer wording, a visible saved or pending status or a short walkthrough, and say how you checked with the same users afterwards.
  5. Show respect: avoid blaming users, and explain how you balanced their requests against other users and constraints.

Follow-up

  • What did you do when two users gave opposite feedback?
  • How did you measure whether the change helped?
  • Tell me about a request you declined and how you explained it.