cswork / libraryOpen practice workspace

Interview guides · Bhi

Bhi Software Engineer Interview Guide

Bhi Software Engineer interview guide: the three reported rounds, coding and system design questions, behavioral prep and a 7-day plan.

The 60-second brief

Candidates describe Bhi as a company whose software supports physical work: large electrical projects, solar field operations, and aggregates and paving workflows. The users named in the role description are Electrical Project Engineers and Solar Field Engineers, who use the software to follow project milestones and watch physical assets. The engineering problems candidates mention are data streams from paving equipment, telemetry from remote solar fields in Utah, and connections that drop out in the field. A Software Engineer builds backend services and APIs that move data between field sites and the central office. The role also covers replacing older software and spreadsheets with a unified platform, plus code reviews, documentation and mentoring.

This guide is for candidates interviewing for a Software Engineer role at Bhi. It covers the three reported stages, the reported coding, system design and behavioral questions, and a seven-day plan. The behavioral questions have full answer guidance on this page. The coding and system design questions have their own cards, and the plan points at them by subject.

Candidates report three stages over roughly 3-5 weeks: a Recruiter Screen, a Technical Assessment (live coding or a take-home), and a Virtual or Onsite Loop with system design, deep-dive coding and behavioral sessions.

Focus areas

  • Project Engineering
  • Construction Engineering
  • Solar Field Engineering

Overview

The reported questions share a theme: software that sits between machines in the field and people in an office. The coding prompts wrap classic problems in that setting. Merging overlapping equipment usage intervals is the standard interval merge. A critical path over project dependencies is a longest-path problem on a directed acyclic graph. The LRU cache and the API rate limiter are standard data-structure and algorithm exercises, and the solar CSV question is a streaming aggregation with a top-three selection. Candidates also report scenarios such as filtering temperature spikes in a sliding window and scheduling paving equipment across sites, so practise the underlying patterns rather than memorising prompts.

The system design questions are not all the same kind. Two are about getting data from remote equipment into a central system (distributed logging for solar field monitors, a dashboard backend for construction-site metrics). One is about alerting people (a maintenance notification system for paving equipment). One is about unreliable mobile connectivity (uploading site photos and inspection reports). One is a migration of an on-premise legacy project management database to a cloud-native architecture. Candidates also report offline-first sync, IoT integration and edge computing as less common topics. Your preparation should cover the failure modes of remote producers: a sensor that goes quiet, duplicate delivery after a retry, out-of-order events and clock skew.

The requirements candidates describe list one modern language (Python, Java, C++ or Go are given as examples), relational databases such as PostgreSQL and MySQL, and API development. Cloud platforms, IoT or SCADA familiarity and offline-sync experience are listed as nice to have. Candidates also report advice to state a brute-force approach first, to ask about data scale before coding, and to prefer simple, maintainable designs over elaborate ones. The behavioral side leans on working with people outside software, so prepare stories where a field engineer, project manager or other non-software colleague changed what you built.

The Bhi interview process

Candidates describe three stages, with a Technical Assessment that is either live coding or a take-home and a final loop that mixes design, coding and behavioral sessions. The order below is the one they report.

Recruiter Screen

Candidates describe the first stage as a conversation with a recruiter about your background, where you want to work, and whether your skills fit the role. Candidates mention that many engineering and project roles are based in Utah, so be ready to discuss location. Treat it as a short pitch: your experience, the stack you are strongest in, and why this field-operations domain interests you.

What to demonstrate

  • Your background and relevant experience
  • Location preferences
  • Basic technical fit with the stack the role lists

How to prepare

  • Write a short account of your last two projects that names the language, the database and the API style you used, since the role lists a modern language, PostgreSQL or MySQL, and API development.
  • Decide your location answer in advance, including whether a hybrid arrangement works for you.
  • Prepare one specific reason this domain interests you, such as telemetry from remote equipment, offline field software or replacing spreadsheet workflows.

Technical Assessment

Candidates report either a live coding interview or a practical take-home assignment at this stage. The format is not fixed, so practise both: solving aloud in an editor, and delivering a small tested program. The reported coding questions (interval merging, critical path, rate limiter, LRU cache, top three days from a CSV) are the practice material for any coding stage, though the reports do not tie a particular question to this round. Candidates also report advice to explain a brute-force approach first and then improve it.

What to demonstrate

  • Working code
  • Algorithmic thinking and data structure choice
  • Handling of edge cases and errors

How to prepare

  • Implement the interval merge, the LRU cache and the top-three-days CSV script in your chosen language, each with its own tests, and run them without looking at a reference.
  • Build a longest-path routine over a dependency graph with cycle detection, so that bad input fails clearly instead of looping.
  • For a take-home, practise delivering a small program with a README, input validation, tests and clear error messages, since a reported scenario is a script that must handle errors in daily electrical project logs.

Virtual or Onsite Loop

Candidates describe a virtual or onsite loop made of several focused sessions covering system design, deep-dive coding and behavioral interviews. They report meeting fellow software engineers and also engineering managers or product leaders familiar with solar, electrical or paving operations. Prepare for design conversations where you explain choices to people who know the field better than the software, and for stories about working with non-software colleagues.

What to demonstrate

  • System design for field-to-cloud data flows
  • Deeper coding than the first technical stage
  • Behavioral stories and cross-functional communication

How to prepare

  • Practise the five reported design prompts aloud: the maintenance notification system, distributed logging for solar monitors, the construction-site metrics dashboard, uploads over poor connectivity, and the legacy database migration. For each, name the failure modes of remote devices and how the system recovers.
  • Be ready for a longer coding problem in the same family as the reported ones, such as the sliding-window spike filter or the equipment scheduling example candidates mention.
  • Write out five behavioral stories in STAR form, each ending with a result a non-software colleague would recognise.

Where candidates lose points

Presenting an optimised interval merge, critical path or top-three solution with no working baseline

Say the brute-force version first, get it correct on a small example, then improve it and state the complexity. Candidates report advice to explain the simple approach before the optimised one, and a working answer is better than an unfinished clever one.

Drawing a design where every sensor, phone and upload always reaches the server on the first try

In the logging, notification, dashboard and file-upload questions, list the failure modes before you draw: a device that goes offline, duplicate delivery after a retry, out-of-order events, clock skew and partial uploads. Then name the mechanism that handles each, such as local buffering, idempotency keys, per-device sequence numbers or resumable uploads.

Reaching for heavy infrastructure for a few hundred remote monitors

Start with the simplest design that works, such as a relational database with an ingest API and a queue, and say at what load it stops working and what you would add then. Candidates report advice to prefer simple, maintainable architectures over complex ones.

Skipping edge cases that are specific to these coding questions

Before coding, list them aloud: touching versus overlapping intervals and empty input in the merge; cycles and disconnected tasks in the critical path; malformed rows, missing days and ties in the CSV top three; capacity of one in the LRU cache; bursts and per-sensor keys in the rate limiter. Test each after you write the code.

Behavioral stories where you are not the decision-maker, or which end without a result

Use first-person verbs for your own actions, give the situation in two sentences and spend the rest on the decision, the cost and the result. Make at least two stories involve a non-software colleague, since the reported prompts ask for that.

Questions & practice

Write a function to merge overlapping time intervals representing equipment usage logs.

Medium · Coding and Algorithms

Approach

  1. Clarify the interval convention first: are the logs closed [start, end] or half-open [start, end)? That decides whether a log ending at 10:00 merges with one starting at 10:00. Also ask whether intervals from different machines are mixed; if so, group by equipment id before merging.
  2. Sort by start time, then sweep once: keep a current interval and, when the next start <= current end, extend with end = max(end, next.end). Using max is what handles nested intervals like [1,10] and [2,3]. Otherwise emit the current interval and start a new one.
  3. Complexity is O(n log n) for the sort plus an O(n) sweep, with O(n) space for the output. If the logs already arrive sorted by start, the sweep alone is O(n) time and needs O(1) extra space.
  4. Edge cases: empty input, a single log, identical duplicates, and malformed rows where start > end, which I reject or report instead of merging. Timestamps should be normalised to one timezone before comparing.

Follow-up

  • The logs are too large for memory but already sorted by start time. How does your solution change?
  • How would you insert one new usage interval into an already merged, sorted list?
  • Using the same logs, how would you find the peak number of machines in use at the same moment?

Given a list of project dependencies, write an algorithm to determine the critical path for an electrical inst

Medium · Coding and Algorithms

Given a list of project dependencies, write an algorithm to determine the critical path for an electrical installation.

Approach

  1. Model the project as a directed acyclic graph: tasks are nodes carrying durations, and an edge A -> B means B cannot start until A finishes. The critical path is the longest-duration path through this DAG. It is not a shortest path.
  2. Run a topological sort (Kahn's algorithm, using in-degree counts and a queue). In topological order, compute earliest finish(v) = duration(v) + max(earliest finish of its predecessors), and keep a pointer to the predecessor that gave the max. Then backtrack from the task with the largest finish time.
  3. Detect cycles: if Kahn's algorithm processes fewer nodes than exist, the dependencies are circular and I return an error naming the tasks left unprocessed. Total cost is O(V + E) time and space.
  4. A backward pass gives latest start times, and slack = latest start - earliest start. Tasks with zero slack are critical, which also surfaces the case of several critical paths. With multiple start or end tasks, I add a virtual source and sink of duration 0.
  5. Validate the input: dependencies that name unknown tasks, negative durations, and duplicate task ids.

Follow-up

  • One task's duration changes. What do you need to recompute, and can you avoid redoing the whole graph?
  • How would you report every critical path when there are ties?
  • Crews are limited and two tasks cannot use the same crew at once. Does your algorithm still apply?

Write a script to parse a large CSV file of solar energy output and return the top three highest-producing day

Medium · Coding and Algorithms

Write a script to parse a large CSV file of solar energy output and return the top three highest-producing days.

Approach

  1. Clarify the file shape: one row per day, or many readings per day (per inverter or per interval) that must be summed. Ask for the column names, the units (Wh or kWh) and which timezone defines a day. Daily totals should use local site time, not UTC.
  2. Stream the file with csv.reader or csv.DictReader instead of loading it all, and accumulate a dict from date to total. Memory is O(number of days), which stays small even when the file has millions of rows.
  3. Pick the top three with heapq.nlargest(3, totals.items(), key=lambda kv: kv[1]), which is O(D log 3), or keep a min-heap of size 3. If the file is already one row per day, I can maintain that heap while streaming and use O(1) extra memory.
  4. Handle bad data explicitly: the header row, blank or non-numeric values, negative readings, duplicate rows and unparseable timestamps. I count and log skipped rows instead of failing silently, and I agree a rule for ties at third place and for fewer than three days.
  5. In pandas, read_csv(chunksize=...) with a groupby on the date per chunk, then combining the partial sums, gives the same bounded-memory result.

Follow-up

  • The file is too big for one machine. How would you compute the same answer?
  • How would you return the top three days per site rather than overall?
  • How would you test this script with a small fixture file?

Explain why the owner filter ignores the listing index

Medium · composite index · query plans · sort elimination

The only index on resource is (tenant_id, status, updated_at DESC, resource_id DESC). A new endpoint returns one user's resources across all statuses, newest created first: WHERE tenant_id = $1 AND owner_user_id = $2 ORDER BY created_at DESC LIMIT 20. On a tenant with 2M rows it takes 900 ms and EXPLAIN shows a sort above a large scan. Explain precisely why the existing index cannot serve it, give the index that can, and state which of these the new index still will not help: owner_user_id alone across tenants; the same query ordered by updated_at. PostgreSQL 16.

Approach

  1. Separate the two jobs an index does. For filtering, a composite btree is seekable only on a left prefix, so with no predicate on status the scan can at best range over tenant_id and test owner_user_id per row; PostgreSQL 16 has no btree skip scan to jump the unconstrained column.
  2. For ordering, the index is sorted by (status, updated_at) within a tenant and not by created_at, so the LIMIT cannot stop early: every matching row is read and then sorted. That is the 'Sort Method: top-N heapsort' line, and it is why the plan reads 2M rows to answer with 20.
  3. Derive the replacement from the access path — equality, equality, then the ordering column: CREATE INDEX CONCURRENTLY ON resource (tenant_id, owner_user_id, created_at DESC). The scan seeks to the (tenant, owner) range and walks 20 entries in order, so the Sort node disappears along with the row-read.
  4. Treat INCLUDE (title, status) as conditional, not free. An index-only scan still visits the heap for any row whose page is not marked all-visible, so on a table taking 1.2k writes/second the win depends on autovacuum keeping the visibility map current, and the wider index costs more on every insert.

Follow-up

  • 90% of rows are status='active'. Would a partial index WHERE status = 'active' change your answer, and for which of the three queries?
  • A dashboard runs this for 40 owners in one page load. What changes about the design?

Hold a per-tenant active cap against concurrent creates

Hard · write skew · isolation levels · constraints

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

Approach

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

Follow-up

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

Implement a rate limiter for an API that receives telemetry data from field sensors.

Medium · Coding and Algorithms

Approach

  1. Clarify the limit key (per sensor id, per site or per API token), the allowed rate and burst, and what a sensor should do once it is rejected. Rejected calls should return HTTP 429 with a Retry-After header so the sensor buffers and retries rather than losing readings.
  2. Implement a token bucket per key that stores tokens and a last-refill time. On each request, set tokens = min(capacity, tokens + elapsed * rate). If tokens >= 1, decrement and allow; otherwise reject. This is O(1) per request and O(active keys) memory, and I read time from a monotonic clock.
  3. Compare the alternatives. A fixed-window counter is simplest but can admit up to twice the limit across a window boundary. A sliding-window log is exact but stores every timestamp. A sliding-window counter approximates the log with two counters.
  4. For thread safety on one server, lock per key or use atomic operations. Across several API servers, keep the state in a shared store such as Redis and do the read-refill-decrement in one atomic Lua script so concurrent requests cannot both spend the last token.
  5. Evict idle keys, for example with a TTL on each bucket. Size the burst capacity so a sensor reconnecting after an outage can flush a reasonable backlog, or give it a separate batch endpoint.

Follow-up

  • A sensor was offline for an hour and reconnects with a large backlog of readings. How do you keep that data without letting it swamp the API?
  • What happens to your limiter if the Redis instance becomes unavailable: do you fail open or fail closed?
  • How would you set different limits for different classes of sensor?

Design a class to manage an in-memory cache with an LRU (Least Recently Used) eviction policy.

Medium · Coding and Algorithms

Approach

  1. Combine a hash map from key to node with a doubly linked list ordered by recency. get looks up the node, moves it to the head and returns its value. put updates an existing node and moves it to the head, or inserts a new node at the head and evicts the tail node (and its map entry) when size exceeds capacity.
  2. Both operations are O(1) time, and space is O(capacity). Sentinel head and tail nodes remove the null checks for an empty list or a one-element list.
  3. Library shortcuts are worth naming once the hand-built version works. In Python, OrderedDict offers move_to_end(key) and popitem(last=False). In Java, LinkedHashMap built with accessOrder=true and an overridden removeEldestEntry does the same.
  4. Edge cases: capacity 0 or less, get on a missing key (return None or -1 as agreed), put on an existing key, which must update the value and refresh recency without changing size, and evicting while the cache holds a single entry.
  5. Thread safety: get also changes the list, so a read-write lock does not help. A single mutex around each operation is correct; striping into several independent LRU shards cuts contention at the cost of approximate global LRU order.

Follow-up

  • How would you add a per-entry time-to-live alongside LRU eviction?
  • Entries vary widely in size. How would you cap the cache by bytes instead of entry count?
  • When would LFU eviction beat LRU for this workload?

Design a notification system that alerts project engineers when a piece of paving equipment requires maintenan

Medium · System Design

Design a notification system that alerts project engineers when a piece of paving equipment requires maintenance.

Approach

  1. Scope the triggers: usage-based (engine hours or distance since last service), calendar-based (a service due date) and fault-based (error codes from telemetry or a manual report from the field). Also scope recipients: the engineer assigned to that equipment or site, with an escalation contact.
  2. Components: telemetry ingestion into a queue, then a rules evaluator that compares readings with maintenance rules per equipment type, then a maintenance-event table with states open, acknowledged and resolved, then a notification service fanning out to push, SMS and email.
  3. Prevent alert storms and duplicates by keeping at most one open alert per (equipment id, maintenance type). A repeat reading updates that alert instead of sending again. The sender uses an idempotency key per alert and channel, so a queue retry does not text the engineer twice.
  4. Delivery is at least once with retries and backoff. If an alert stays unacknowledged past a configured window, it escalates to the next contact. Keep an audit log of what was sent, to whom and when.
  5. Treat missing data as a signal too: equipment that stops reporting should raise a no-data alert, not look healthy.

Follow-up

  • The engineer is on a site with no data connection. How do they receive and acknowledge the alert?
  • A firmware bug makes every machine report the same fault code. How does your design limit the damage?
  • How would you let engineers tune maintenance thresholds per machine type without a deploy?

How would you design a distributed logging system for hundreds of remote solar field monitors?

Medium · System Design

Approach

  1. Size it before choosing tools. A few hundred devices producing structured logs is modest throughput, so I estimate events per device per second and bytes per event, and let that number decide between a managed log service and a self-run pipeline.
  2. On the device, an agent writes structured JSON logs (device id, site, level, sequence number, device timestamp) to a bounded on-disk buffer. It ships compressed batches when connectivity allows. When the buffer fills, it drops DEBUG before ERROR and records how much it dropped.
  3. Ingestion: an authenticated HTTPS or MQTT endpoint writes into a durable queue partitioned by device id, which preserves per-device order. Consumers dedupe on (device id, sequence number), because retries after a dropped connection resend batches.
  4. Storage: a searchable index (for example OpenSearch) for recent days and compressed files in object storage for long retention, with lifecycle rules deleting old data. Store both device time and server receive time, because device clocks drift and batches arrive late.
  5. Add per-device rate limits or sampling, so one malfunctioning monitor stuck in an error loop cannot flood ingestion. Alert on devices whose logs stop arriving.

Follow-up

  • A monitor is offline for three days and its buffer overflows. What is lost, and how do operators know?
  • How would someone find every error from one site over the last week, and what index or partition makes that fast?
  • How do you push a change to log verbosity to the devices remotely?

Architect a dashboard backend that aggregates real-time metrics from multiple active construction sites.

Medium · System Design

Approach

  1. Clarify the metrics (equipment status, material quantities, sensor readings), how fresh the dashboard must be, the number of sites and users, and per-site access control.
  2. Write path: site data goes to an ingestion API, then a queue, then a stream processor that writes raw events and also pre-aggregates them into time buckets (such as per-minute rollups per site and metric). Read path: the dashboard API reads rollups, not raw events, so a page load does not scan millions of rows.
  3. Store data in a time-series-friendly database, for example PostgreSQL with TimescaleDB hypertables and continuous aggregates, partitioned by time and indexed on (site id, metric, time). Keep the latest value per site and metric in a cache such as Redis for the live tiles.
  4. Push updates to open dashboards over WebSocket or server-sent events, falling back to polling. Show a last-updated time per site, so a site that stopped reporting appears stale instead of reading as zero.
  5. Handle late and out-of-order data by aggregating on event time and letting recent buckets be updated (recompute a trailing window), so a site that uploads a backlog corrects its totals.

Follow-up

  • A site goes offline for two hours, then uploads everything at once. What does the dashboard show during and after?
  • Leadership wants a new metric added across all sites. What changes in your pipeline?
  • How do you stop a user from seeing metrics for sites they are not assigned to?

Design a system to handle file uploads (like site photos and inspection reports) from areas with poor mobile c

Medium · System Design

Design a system to handle file uploads (like site photos and inspection reports) from areas with poor mobile connectivity.

Approach

  1. Make the client offline-first. Each photo or report is saved locally with its metadata (site, inspection, capture time, a client-generated UUID) and added to a persistent upload queue that survives app restarts and resumes when connectivity returns.
  2. Use resumable, chunked uploads straight to object storage: S3 multipart upload through presigned URLs (parts at least 5 MB except the last) or the tus protocol. Retrying a failed chunk then does not restart a large file. Each chunk is retried with exponential backoff and jitter.
  3. Make it idempotent. The client UUID is the file's identity, so a retry after a timeout does not create a duplicate record. Checksums per part and on completion catch corruption, and the server marks the record complete only after the object is verified.
  4. Keep metadata separate from bytes: create the inspection record immediately and attach files as their uploads finish, with visible states (queued, uploading, uploaded, failed) so the field user knows what has synced.
  5. Downstream work such as thumbnails and virus scanning runs asynchronously from a storage event. A lifecycle rule aborts multipart uploads left incomplete, so abandoned parts do not accumulate cost.

Follow-up

  • Two inspectors edit the same report offline on different devices. How do you resolve the conflict when both sync?
  • The device is running out of storage while its queue is still full. What does the app do?
  • Would you compress photos on the device, and what does that cost if an original is later needed as evidence?

Explain how you would migrate an on-premise legacy project management database to a cloud-native architecture.

Medium · System Design

Approach

  1. Start with an inventory: schema and data size, stored procedures and triggers, every application and report that reads or writes the database directly, and how much downtime the business can accept. Those answers pick the strategy.
  2. Move first, re-architect second. Rehost onto a managed relational service (for example, managed PostgreSQL), keeping the engine if possible. Changing the engine adds schema conversion work: data types, collations, procedural code.
  3. Migrate with a full snapshot load followed by change data capture (for example AWS DMS or Debezium) to keep the cloud copy in sync. Validate with per-table row counts and checksums, and run key reports against both databases and compare the results.
  4. Cut over with a short write freeze, a final CDC catch-up, and an application connection switch. Keep a rollback path, such as reverse replication or keeping the old database intact and read-only until the new one has proven itself.
  5. Afterwards, decouple consumers. Put an API in front of the data (the strangler pattern) so other systems stop querying tables directly, then split or modernise pieces behind it. Cover networking (private link or VPN), encryption, backups and access roles along the way.

Follow-up

  • The business cannot accept any write downtime. How does your cutover change?
  • After cutover, a project cost report differs from the legacy version. How do you track down why?
  • A desktop tool in the field writes directly to the legacy database and cannot be updated quickly. What do you do with it?

One log partition stops advancing while the others drain

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

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

Approach

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

Follow-up

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

Suggested practice checklist

The plan starts with the loop and the stack, then works through the reported coding questions, the design questions grouped by theme, and ends with behavioral stories. Days that practise specific questions are tagged with them.

Day 1 — Map the loop and set up your workspace

  • Write out the three reported stages (Recruiter Screen, Technical Assessment, Virtual or Onsite Loop) and note which formats you must prepare for: live coding and take-home both.
  • List the stack the role describes (a modern language, PostgreSQL or MySQL, API development, plus the nice-to-haves) and mark which you can discuss from real experience.
  • Create a practice project in your chosen language with a test runner so that every later coding task starts with a failing test.

Deliverable: A one-page loop map, a stack checklist with strengths and gaps marked, and a practice project with a working test runner.

Day 2 — Interval merging and the solar CSV script

  • Implement the equipment-usage interval merge by sorting on start time and sweeping, deciding explicitly whether touching intervals merge. State the complexity.
  • Write the CSV script so it reads row by row, sums output per day in a hash map, and returns the three highest days with a size-three heap or an n-largest call. Handle malformed rows and ties.
  • Write tests for empty input, nested intervals, a single row and a file with a bad line.

Deliverable: Two working solutions (interval merge and top-three-days script) with a test file covering the edge cases listed above.

Day 3 — Critical path and the LRU cache

  • Write the critical path as a longest-path computation: topological order with Kahn's algorithm, track earliest finish per task, and rebuild the path through predecessor links. Detect and report a cycle.
  • Implement the LRU cache with a hash map plus a doubly linked list so get and put are O(1). Write the version using an ordered dictionary only after the manual one works.
  • Write tests for a diamond-shaped dependency graph, a disconnected task, a cycle, capacity one and repeated updates to the same key.

Deliverable: A critical-path function with cycle detection and an LRU cache class, each with tests for the edge cases above.

Day 4 — Rate limiter and relational basics

  • Implement a per-sensor token bucket rate limiter. Decide what happens when a sensor exceeds its limit (reject, delay or drop), and how bursts and idle sensors are handled.
  • Explain aloud how you would run the limiter across several API servers, and what you give up if the counters are not shared.

Deliverable: A tested rate limiter, a short written note on the multi-server trade-off, and a note on what each SQL drill taught you.

Day 5 — Design from the field to the server

  • Design the distributed logging system for remote solar field monitors: ingest API, local buffering on the device, retry with deduplication, storage and how you query it.
  • Design the file upload system for poor mobile connectivity: resumable chunked uploads, a record of upload state and what the user sees while offline.

Deliverable: Two labelled design diagrams with a failure-mode list for each, plus a short debugging note from the drill.

Day 6 — Alerting, dashboards and migration

  • Design the maintenance notification system: event source, rule evaluation, delivery channel, deduplication so an engineer is not alerted repeatedly, and what happens when delivery fails.
  • Design the dashboard backend that aggregates real-time metrics from several construction sites: write path, pre-aggregation versus on-demand queries, and how stale data is shown.
  • Outline the legacy database migration to the cloud: inventory, schema and data copy, change replication, a cutover plan and a rollback path.

Deliverable: Three design write-ups, each with a stated simplest version and the load at which you would change it.

Day 7 — Behavioral stories and a full rehearsal

  • Write STAR outlines for the five reported behavioral prompts: pivoting on changed requirements, working with someone outside software, technical debt versus features, building a tool to fix a bottleneck, and disagreeing with a senior engineer.
  • Add a sixth story for a production failure and its post-mortem, since a reported prompt asks for it.
  • Rehearse the stories aloud and check that each has a decision you made, a cost, and a measurable result.

Deliverable: Six written STAR outlines and one recorded rehearsal with notes on where each story lost focus.

Stories for field-facing engineering

Candidates report that the final loop includes behavioral sessions, and that the reported prompts centre on changing requirements, working with non-software colleagues, prioritising technical debt, building tools and disagreeing with senior engineers. Prepare stories where you made a decision, explained a technical constraint to a non-engineer, and can state the result.

  1. Describe a situation where a system you built failed in a production environment. How did you handle the immediate fallout and the post-mortem?

Tell me about a time you had to pivot your technical approach because of a change in business requirements.

Medium · Behavioral and Leadership

Approach

  1. Choose a story where the requirement changed after you had built or designed something real, and where you made the call on how to adapt. For this company, a field-driven example fits well: a team that needed live updates instead of a daily report, or a workflow that had to work offline.
  2. Spend two sentences on the original plan and the change, then focus on the decision. Say what you kept, what you threw away, and why. A line like 'I kept the data model, because the change only affected delivery, and rewrote the sync layer' shows that you separated stable parts from volatile ones.
  3. State the cost of the pivot honestly: lost work, a slipped date, a risk you accepted. Then say how you communicated it and what you did to cheapen the next change, for example putting the volatile rule behind a config or an interface.
  4. End with the result in concrete terms (shipped, adopted, error rate, deadline met) and what you would change if the requirement moved again. The mistake that sinks this story is blaming the stakeholder for changing their mind, or choosing a change so small that no real decision was involved.

Follow-up

  • How did you decide which parts of the original work to salvage?
  • What could you have done up front to make the original design survive that change?
  • How did you tell the stakeholders what the change would cost?

Describe a project where you had to collaborate closely with someone outside of the software engineering team.

Medium · Behavioral and Leadership

Approach

  1. Pick a project where the other person's knowledge was essential and different from yours: a field engineer, project manager, finance or operations lead. Name their role and what they knew that you did not.
  2. Show how you learned their workflow. Sitting in on the process, reading the spreadsheet they used, or asking them to walk through a bad day gives you requirements that a ticket would not. State one thing you misunderstood at first and how it came out.
  3. Show translation in both directions: how you turned their operational need into a technical requirement, and how you explained a technical limit (latency, connectivity, data quality) in their terms, with an option and a trade-off.
  4. Close with a result they would describe in their own language, such as fewer manual entries or a faster report, and how you checked it with them afterwards. The mistake to avoid is a story where you simply built what a ticket said, or where the collaborator is a faceless requester.

Follow-up

  • What did you misunderstand about their work at first, and how did you find out?
  • How did you explain a technical limitation to them without jargon?
  • How did you confirm that what you shipped actually helped their daily work?

How do you prioritize technical debt versus building new features requested by project managers?

Medium · Behavioral and Leadership

Approach

  1. This is a how-do-you question, so give a short framework and then a real example. A workable framework: estimate the cost of each debt item (incidents it causes, time it adds to every change, risk if it fails) and estimate the value of each requested feature, then compare them in the same terms the product owner uses.
  2. Describe tactics you actually use: pairing a debt fix with a feature that touches the same code, reserving a standing share of each cycle for debt, and splitting a big cleanup into steps that each ship value. Say when you refuse to pay debt: code that is stable and rarely changed.
  3. Tell the PM-facing side: you bring numbers rather than preferences ('this sync bug caused repeated support tickets and slows every change in that module'), and you let them choose with the trade-off visible. If they decline a fix, you record the risk and a trigger for revisiting it.
  4. Give one concrete case with a result, including one where you chose the feature over the debt and why. The mistake that sinks the answer is an absolute: always features first, or always cleaning first.

Follow-up

  • What do you do when the product manager says no to a debt item you think is urgent?
  • How do you decide that a piece of debt is not worth paying?
  • Can you give an example where deferring debt cost you, and how you handled it?

Tell me about a time you identified a process bottleneck and built a tool to fix it.

Medium · Behavioral and Leadership

Approach

  1. Start with how you found the bottleneck and measured it: hours per week, error count, number of people blocked. A story that begins with a number gives the tool a reason to exist, whether the bottleneck was manual data entry, a report assembled by hand or a deploy step.
  2. Say who you talked to before building. Show that you watched the people who lived with the problem and checked that your target was the real bottleneck rather than a visible one.
  3. Describe the smallest tool that removed the problem (a script, a form, a scheduled job) and why you chose it over buying or building something larger. Mention how you handled failure cases, such as bad input, so that people trusted it.
  4. Finish with adoption and a before-and-after measurement, and who maintains the tool now. The mistake that sinks the story is a tool nobody asked for, or a result stated as 'people liked it' with no measurement.

Follow-up

  • How did you get people to switch from the old process to your tool?
  • Who maintains it now, and what happens when its inputs change?
  • Why did you build it instead of using an existing tool or changing the process?

Describe a situation where you disagreed with a senior engineer's architectural decision. How did you handle i

Medium · Behavioral and Leadership

Describe a situation where you disagreed with a senior engineer's architectural decision. How did you handle it?

Approach

  1. Pick a real disagreement where the senior engineer's choice was defensible, such as a technology, a data-store or a service boundary. Begin by stating their reasoning fairly. If you cannot explain why a smart person chose it, the story reads as arrogance.
  2. Describe how you raised the concern: privately first, with evidence rather than opinion. Evidence can be a small prototype, a benchmark, a failure scenario or a cost comparison, and you present an alternative together with its downside.
  3. Be clear about the outcome. If the decision stood, show that you committed and helped it succeed, and say what you learned. If it changed, show that you gave credit and shared the decision. Either ending works if you are honest about it.
  4. Explain what the episode taught you about disagreeing, for example agreeing on decision criteria before debating options. The mistake that sinks this story is a version where you were simply right, or where you went around the engineer to a manager without talking to them first.

Follow-up

  • What would you have done if the senior engineer had overruled you and the problem you predicted appeared?
  • How do you decide when a disagreement is worth escalating?
  • What did you learn about their thinking that changed how you propose designs?