cswork / libraryOpen practice workspace

Interview guides · Arrive Logistics

Arrive Logistics Software Engineer Interview Guide

Arrive Logistics Software Engineer interview guide: four reported rounds, .Net or Node.js/React prep, system design, testing and behavioral questions.

The 60-second brief

Arrive Logistics is a freight brokerage operating in North America. Its software engineers build technology used by internal operations staff and by external customers. Candidates describe the role as covering a feature's whole lifecycle, from development and testing through deployment and monitoring, in close contact with product managers and design teams. Reports also mention contributing to engineering standards discussions and internal guild talks as independence grows.

This guide is for engineers with a few years of professional experience (candidates describe 3+ years as a requirement) preparing for the Software Engineer loop. It covers the stack candidates mention (.Net or Node.js depending on location, with React as a plus), the four reported rounds, how to answer each reported question, behavioral preparation and a seven-day plan.

Candidates report four rounds spread over roughly three to five weeks: Recruiter Screening, Technical Discussions, Behavioral Discussions, and Code and Systems Reviews.

Focus areas

  • Node.js
  • React
  • System Design

Overview

The work described is full-lifecycle ownership: you build a feature, test it, ship it and watch it in production. That is why the reported questions cluster around engineering practice rather than puzzles. Expect to explain how you debug a production incident, how you keep test coverage meaningful, how you document work that several teams depend on, and how you keep a growing codebase changeable. Each is easiest to answer with a real project, so list your own pull requests, incidents and design decisions before you start practising.

The reported design questions test judgement more than diagramming: how to take in high-volume data from many sources, how to choose a framework for a new feature, how to keep code maintainable as complexity grows, and how to deliver a solution that crosses departments. Candidates also mention monolith versus microservices, high availability, monitoring and alerting, and refactoring a legacy system. Prepare each as a short chain: requirements, options, the trade-off you accepted, and how you would know it worked.

The stack candidates list is .Net or Node.js (depending on location) with React as a nice-to-have, plus computer science fundamentals. Pick one primary stack and be ready to defend your choices in it against alternatives. Logistics experience is described as a plus, not a requirement; if you lack it, prepare an adjacent example and a few domain facts, such as shipment status events arriving late or out of order. Because candidates say the process moves quickly after the recruiter screen, keep recent project examples ready from day one.

The Arrive Logistics interview process

Candidates report four rounds over about three to five weeks, with the final stage described as the deepest technical assessment. The descriptions below are what candidates report, not a published schedule.

Recruiter Screening

Candidates describe a first conversation with a recruiter about your background and how it fits the role. The process is reported to move quickly once this screen is cleared, so treat it as the point where your story, stack and motivation must be ready. Be able to say which of .Net or Node.js you work in, what you have shipped, and why this company.

What to demonstrate

  • How your background lines up with the role and its stack
  • How clearly you summarize your experience and motivation

How to prepare

  • Write a short spoken career summary that names your primary stack (.Net or Node.js, with React if relevant) and two recent projects with outcomes.
  • Prepare a specific answer to why you want to join Arrive Logistics, built from the job posting and the company's own site.
  • Check the 3+ years of professional experience requirement against your history and have the dates and scope of each role ready.

Technical Discussions

Candidates describe Technical Discussions with engineering leadership focused on technical skills and problem solving. The reported technical and domain questions are the natural material here: a hard problem you solved, debugging production, test coverage, logistics-informed architecture and documentation. Anchor every answer in a project you personally drove and explain why you chose your approach over alternatives.

What to demonstrate

  • Technical skills in your primary stack
  • Problem solving, shown through how you structure a past challenge
  • Whether you can justify design and testing choices, not only describe them

How to prepare

  • Rehearse the complex-challenge story with a stated constraint, the options you weighed, one setback and a measured result.
  • Write a debugging sequence you can recite: assess impact, check recent changes, mitigate, localize, confirm, follow up.
  • Prepare your test strategy in terms of the pyramid, diff coverage and regression tests, with one real bug as the example.

Behavioral Discussions

Candidates describe Behavioral Discussions with potential peers, centered on team fit and collaborative style. This is the stage where questions on working in a fast-paced team, influencing a standard, handling code review feedback and delivering across departments are practised. Use specific stories in which you made a decision, someone disagreed, and something measurable changed.

What to demonstrate

  • Team fit and collaborative style
  • How you work with product, design and other engineers
  • How you take and give feedback

How to prepare

  • Outline four stories: fast-paced delivery, influencing a standard, a cross-department project, and a code review disagreement.
  • For each story, write the decision you personally made, the objection you heard and the result with a number.
  • Prepare two or three questions for peers about how the team ships, reviews and documents work.

Code and Systems Reviews

Candidates describe Code and Systems Reviews as in-depth technical assessments covering coding skills and system design. The format is not specified beyond that, so prepare both for writing working code in your primary stack and for reasoning through a design aloud. A coding stage is where coding practice shows; a systems stage is where ingestion, availability, monitoring and monolith-versus-services trade-offs come up.

What to demonstrate

  • Working code in your primary stack
  • System design that is scalable, available and easy to monitor
  • Quality habits such as testing and maintainable structure

How to prepare

  • Practise the high-volume multi-source ingestion design end to end: durable log, adapters, idempotent writes, dead-letter handling, replay.
  • Prepare a legacy refactor story: how you added tests first, what you changed in steps, and how you protected production.

Where candidates lose points

Answering the test coverage question with a percentage target and nothing else

Say coverage shows what ran, not what is asserted. Describe the pyramid, diff-coverage gates in CI, regression tests written before bug fixes, and mutation testing or branch coverage as quality checks.

Debugging answers that jump straight to root cause and never mention impact or mitigation

Open with scope and what changed recently, restore service first (rollback, flag, failover), then localize with metrics and traces by version and host, and finish with a postmortem and a new alert or test.

Designing the high-volume ingestion system as receivers writing directly to one database

Put a durable log between receivers and consumers, make writes idempotent on source ID plus event ID, handle late and out-of-order events, route bad records to a dead-letter queue and plan replay.

Choosing a framework by preference or hype, with no link to the existing .Net or Node.js stack

Start from requirements and the team's current tooling, weigh ramp-up, maturity and on-call cost, run a short spike on the riskiest part, and record rejected options in a decision record.

Behavioral stories told entirely in the plural with no personal decision, or a why-Arrive answer that fits any employer

State what you decided and the result in numbers. For the company question, cite facts you verified from primary sources and connect them to the work you want to do next.

Questions & practice

How do you ensure your code remains maintainable as a project grows in complexity?

Medium · System Design and Architecture

Approach

  1. Define maintainability concretely: how cheaply and safely the next engineer can change the code. Every practice you list should reduce the cost or risk of change; say that up front instead of reciting principles.
  2. Draw module boundaries around the domain: separate business logic from I/O (ports and adapters), keep dependencies pointing inward, and give each module a clear owner. Cross-module calls go through explicit interfaces so one change does not ripple across the codebase.
  3. Keep units small and readable: functions that do one thing, names from the domain, no clever tricks, and duplication tolerated until a pattern clearly repeats. The wrong abstraction usually costs more than duplication, because it couples code paths that later diverge and is harder to undo.
  4. Make change safe through automation: a fast test suite that checks behavior, static type checks, linters and formatters in CI, and scheduled dependency updates. Refactoring is only affordable when tests catch regressions.
  5. Manage debt deliberately: track it as tickets tied to the pain it causes, budget time for it each sprint, and refactor in small steps alongside feature work rather than waiting for a rewrite. Big rewrites tend to fail by relearning old edge cases.
  6. Watch the signals: hotspots (files with both high churn and high complexity), slow onboarding, bugs clustering in one area, and PRs that touch many modules. Give one example where acting on a hotspot cut change time or defects.

Follow-up

  • How do you decide between refactoring and shipping? Refactor code you are about to change when it makes that change easier or safer; leave stable, untouched code alone even if it is ugly.
  • When would you split a monolith into services? When team ownership or scaling needs diverge, and only after module boundaries are clean inside it; splitting tangled code yields a distributed monolith.
  • How do you keep a growing team consistent? Automate style with formatters and linters, record conventions in ADRs, and spend code review on design rather than formatting nitpicks.

Identify the heaviest tenants in a five-minute window under memory pressure

Medium · top-k · heavy hitters · streaming

The edge service handles about 3,000 requests per second across roughly 50,000 tenants, peaking near 9,000. Expose the 50 heaviest tenants by request count over the trailing five minutes so limits can be tightened before one tenant's backfill starves the fleet. You may not retain five minutes of raw records. Give the exact solution and its memory, then the bounded-memory approximation with its error stated as a formula, and say which you would ship and at what tenant cardinality that choice changes.

Approach

  1. Do the exact version first, because it is affordable at this cardinality: a ring of 300 one-second counters per tenant, advanced lazily, is 1,200 bytes of counters per tenant and roughly 60 to 90 MB for 50,000 tenants with overhead. Carry a running total and subtract the bucket you overwrite so a window read is O(1) rather than 300 adds.
  2. Extract the top 50 with a size-k min-heap over the tenant sums: O(d log k) for d tenants, against O(d log d) to sort them all. Maintaining the heap continuously instead of on query requires a tenant-to-heap-index map, because incrementing a count already inside the heap means sifting from a known position, and without that map you rebuild the heap on every request.
  3. State the approximation precisely rather than gesturing at sketches. Misra-Gries with m counters retains every item whose true count exceeds N/(m+1), and each retained count underestimates the truth by at most N/(m+1). With m = 1,000 and N = 900,000 requests in the window the error is roughly 900 requests, which is fine for spotting a tenant sending 50,000 and useless for ranking two tenants 200 apart.
  4. Say what breaks when the window slides: Misra-Gries and Space-Saving are insert-only and cannot be decremented as records age out. The workable construction is one summary per sub-window, say ten seconds, with 30 summaries merged at query time, and the merged error is the sum of the per-summary errors, so the bound degrades linearly in the number of sub-windows.

Follow-up

  • The heaviest tenant is heavy because of one export job rather than user traffic. Should the limiter treat those as the same tenant?
  • Two tenants sit tied at the boundary of the top 50. Does your answer flap, and does the flapping matter?

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

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

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?

Denormalise tenant onto revisions and backfill it live

Hard · denormalisation · online migration · backfill

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

Approach

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

Follow-up

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

What are your preferred methods for ensuring high test coverage in your code?

Easy · Technical and Domain Expertise

Approach

  1. Treat coverage as a signal, not the goal: line coverage shows which code ran, not whether any assertion would catch a bug. Say you aim for meaningful coverage of behavior and risk, and use the percentage to find untested code rather than to prove quality.
  2. Build on the test pyramid: many fast unit tests for pure logic and edge cases, fewer integration tests at database, queue, and HTTP boundaries (e.g. with Testcontainers), and a thin layer of end-to-end tests for critical user flows.
  3. Write tests with the change, not after it. For bug fixes, first write a failing test that reproduces the bug so the regression cannot return. Cover boundaries (empty input, nulls, max sizes, time zones) and error paths, where untested code usually hides.
  4. Enforce it in CI: run tests on every pull request, report coverage on the diff rather than only the global number, and block merges when new code falls below a threshold. Diff coverage raises the bar on new work without demanding a rewrite of legacy code.
  5. Check test quality too: branch coverage flags an if with no else that only ever ran true, which line coverage counts as covered; mutation testing (PIT, mutmut, Stryker) alters the code and checks that some test fails; property-based tests (Hypothesis) explore inputs you would not list.
  6. Name the misconception: chasing 100% produces brittle tests of getters and mock calls that assert implementation details. Test through public interfaces, mock only at process boundaries, and delete tests that break on every refactor without ever catching a bug.

Follow-up

  • How would you add tests to a legacy module with none? Start with characterization tests that pin current behavior at the module boundary, then refactor under that net and add unit tests as you extract seams.
  • What coverage threshold would you set? A diff-coverage gate around 80% of changed lines is a pragmatic default paired with review judgment; a hard global number invites assertion-free tests written to game it.
  • How do you keep a large suite fast? Run tests in parallel, keep most tests in memory, quarantine and fix flaky ones, and run slow end-to-end suites on merge or nightly instead of on every commit.

Explain how you handle technical documentation when working on a project with multiple teams.

Medium · Technical and Domain Expertise

Approach

  1. Split documentation by purpose, because one wiki page cannot serve every reader: design docs or RFCs for decisions before building, API contracts for integrators, runbooks for on-call, and READMEs for onboarding. Each has a different audience and a different update trigger.
  2. Make interfaces the source of truth: publish machine-readable contracts (OpenAPI for REST, protobuf or AsyncAPI for events) and generate docs and clients from them. A hand-written spec still drifts silently; only a CI check against the code (spec generated from code, or contract tests) catches it.
  3. Record decisions as Architecture Decision Records: short numbered files with context, decision, alternatives, and consequences, stored next to the code. Another team can see why a choice was made a year later without tracking down the person who made it.
  4. Keep docs as code: in the repo, reviewed in the same pull request as the change, with a PR-template checkbox for doc updates. Send cross-team RFCs to a named reviewer from each consuming team with a comment deadline, so silence is not mistaken for agreement.
  5. Assign ownership and freshness: every doc has an owning team and a last-reviewed date, stale pages get flagged, and one index page links each team's docs. The failure to avoid is five contradictory pages that nobody owns.
  6. Show how you know it works: fewer repeated questions in shared channels, faster onboarding for a newly integrating team, or an incident where a runbook shortened recovery. Use one example from your own work if you have it.

Follow-up

  • How do you roll out a breaking API change that affects other teams? Version the contract, publish a migration guide and deprecation date, and track consumers until traffic to the old version reaches zero.
  • What belongs in a good runbook? The alert it answers, how to confirm impact, step-by-step mitigation commands, escalation contacts, and dashboard links, written for someone paged at 3 a.m.
  • How would you get a newly integrating team productive on your service? Have them follow the README and API contract to a first working call, and fix every gap they hit in the docs rather than answering it in chat.

How would you design a system to handle high-volume data inputs from multiple sources?

Medium · System Design and Architecture

Approach

  1. Pin down requirements: source types (webhooks, polled APIs, file drops, streams), what "high volume" means, latency needs (seconds or hourly batch), and whether loss or duplicates are tolerable. Assume, e.g., 50 sources, 5k events/sec on average with 10x bursts, and at-least-once delivery.
  2. Front each source type with a thin ingestion layer over a durable log: stateless HTTP receivers authenticate, assign an ID, append the raw payload to Kafka or Kinesis, and return 202 fast; pollers and file loaders write to the same log. Archive raw payloads in S3 for replay.
  3. Normalize in consumers, not at the edge: per-source adapters parse and validate into one canonical schema, versioned in a schema registry, and publish to a clean topic. Invalid records go to a dead-letter queue with the error, so one malformed source never blocks the others.
  4. Name the sinks: consumers upsert events into an operational store such as PostgreSQL keyed on source ID + source event ID, so redelivery and replay are safe, and change an entity's current state only if the event is not older than the stored one. A separate consumer feeds a warehouse for analytics.
  5. Partition the clean topic on the entity key for per-entity order, and size partitions for peak up front: adding partitions later remaps keys and breaks that order. Consumers autoscale on lag up to the partition count; per-source quotas or topics stop a noisy source starving the rest.
  6. Plan the failure modes: a downstream database outage (consumers pause, the log retains data for replay), a source changing its schema (validation alerts, DLQ grows), and a source going silent (alert when its volume drops below baseline). Monitor lag, DLQ depth, and end-to-end freshness.

Follow-up

  • How would you reprocess a day of data after fixing a parsing bug? Reset the consumer group's offsets or replay raw payloads from object storage; idempotent upserts make the replay safe.
  • What if a consumer needs exactly-once? It rarely holds end to end across systems; use idempotency keys backed by a unique constraint, or Kafka transactions for read-process-write that stays within Kafka.
  • Why not have receivers write straight to the database? It ties ingestion availability to database capacity, so a burst or outage drops data; a log buffers it and lets several consumers read independently.

What factors do you consider when choosing between different development frameworks for a new feature?

Medium · System Design and Architecture

Approach

  1. Start from the feature's requirements, not the framework's popularity: latency and throughput, real-time push versus request/response, data shape, and how long the feature must live. A framework is a long-term dependency, so the choice has to outlast the novelty.
  2. Weigh fit with the existing stack heavily: if the codebase, CI, observability, and deploy tooling already support one framework, adding a second one adds operational and hiring cost. Default to what the team runs unless the feature needs something the current stack cannot do.
  3. Assess the team: who already knows it, how long ramp-up takes, and who will be on call for it. A technically better framework that nobody can debug during an outage is the worse choice.
  4. Check maturity and risk: release cadence, maintainer activity, license, security-advisory history, long-term support, and ecosystem (auth, testing, database libraries). A framework maintained by one person or an abandoned vendor is a future migration.
  5. Decide with evidence: build a time-boxed spike of the riskiest part, benchmark it if performance matters, and compare two or three options in a short weighted matrix. Record the outcome and rejected options in an ADR.
  6. Avoid choosing by benchmark alone: for most business features, developer productivity, maintainability, and operational simplicity matter more than raw requests per second.

Follow-up

  • When is introducing a new framework justified? When the feature needs something the current stack cannot reasonably provide, such as real-time push or heavy numeric work, and the team commits to owning it long term.
  • What if the chosen framework turns out to be wrong? Keep it behind an interface from day one, then use the strangler-fig pattern to move functionality to the replacement incrementally.
  • How do you settle a team disagreement over the choice? Agree on weighted criteria before debating options, run the spike, let the evidence decide, and disagree-and-commit once the ADR is written.

How do you approach debugging a production issue in a large-scale system?

Medium · Technical and Domain Expertise

Approach

  1. Stabilize before diagnosing: size the impact (which users, which endpoints, error rate against baseline), declare an incident if it crosses your threshold, and split roles so one person debugs while another handles communication.
  2. Check what changed first, because most incidents follow a change: recent deploys, config or feature-flag flips, schema migrations, dependency upgrades, traffic spikes, and upstream provider status. Line up when the symptom started against that timeline.
  3. Mitigate before root-causing: roll back the suspect deploy, turn off the flag, shed load, scale out, or fail over. Restoring service in minutes beats a perfect diagnosis in hours; capture evidence (logs, heap or thread dumps) before restarting anything.
  4. Localize with the golden signals (latency, traffic, errors, saturation) sliced by host, region, version, and customer. If one shard or one version is bad, you have narrowed it; then follow a single failing request through distributed traces and logs joined by request ID.
  5. Rank causes and test each with a cheap check: bad deploy (compare versions), exhausted resource (connection pool, threads, disk, memory), slow dependency (trace spans), data-specific bug (replay the failing payload). Hold one hypothesis at a time and try to disprove it.
  6. Close the loop with a blameless postmortem: timeline, root cause, why detection took as long as it did, and owned action items such as a new alert, a regression test, or a safer rollout step.

Follow-up

  • What if you cannot reproduce it locally? Pull the failing inputs from logs or traces, reproduce in staging with production-like data, or add targeted logging behind a flag and wait for the next occurrence.
  • How do you debug something that fails 1% of requests? Compare failed and successful traces for what they share (host, payload size, tenant, time); suspect races, timeouts, and a single bad node.
  • How do you avoid making the incident worse while debugging? Change one thing at a time, prefer reversible actions like flags and rollbacks, and announce every production change in the incident channel.

Suggested practice checklist

The plan follows the four reported rounds and the stack candidates list: map and stack refresh first, then testing, debugging, design and architecture, and finally behavioral stories with a full spoken run-through.

Day 1 — Map the loop and choose your primary stack

  • List the four reported rounds and write which question types each covers: technical and domain, system design, behavioral.
  • Decide whether .Net or Node.js is your primary stack and write five projects you can discuss, each with problem, your role and outcome.

Deliverable: A one-page loop map and a five-project inventory tagged by stack.

Day 2 — Stack fundamentals: Node.js or .Net, and React

  • Build a small endpoint in your primary stack that accepts a shipment status update, validates it, returns quickly, and has unit and integration tests.
  • Build a React table of shipments with loading, error and empty states, and test it with a component testing library.

Deliverable: A working tested endpoint and a tested React component you can explain line by line.

Day 3 — Testing, maintainability and documentation

  • Answer aloud the test coverage question using the pyramid, diff coverage and regression-test habits.
  • Answer aloud the question on keeping code maintainable as complexity grows, naming module boundaries and debt tracking.
  • Write a one-page decision record for a choice you made and outline how you document work shared across teams.

Deliverable: Two spoken answers plus a decision record and a documentation outline.

Day 4 — Production debugging and your hardest challenge

  • Answer aloud the production debugging question using impact, recent changes, mitigation, localization and postmortem.
  • Rehearse the complex technical challenge story with constraint, options, setback and measured result.
  • Outline a legacy-system refactor story: tests first, small steps, rollout safety.

Deliverable: Two spoken answers and a written refactor outline.

Day 5 — System design: high-volume multi-source ingestion

  • Sketch the ingestion design: sources, receivers, durable log, adapters, canonical schema, idempotent upserts, dead-letter queue, replay and monitoring.
  • Write a short list of failure modes and the alert for each.

Deliverable: One annotated architecture sketch, two completed drills and a failure-mode list.

Day 6 — Architecture judgement and logistics domain

  • Answer aloud the framework choice question with requirements, stack fit, team ramp-up and a spike.
  • Answer aloud how your logistics or adjacent experience shapes architecture, using shipment state, late events and unit and time zone traps.
  • Prepare a monolith versus microservices argument for one system you know.

Deliverable: Two spoken answers and a one-paragraph monolith-versus-services position.

Day 7 — Behavioral stories and a full run-through

  • Outline stories for fast-paced collaboration, influencing a standard, code review feedback and a cross-department project.
  • Write your why-Arrive answer from primary sources and three questions to ask the team.
  • Run all spoken answers back to back and note every place you credited the team when you should have said what you decided.

Deliverable: Four story outlines, a why-Arrive answer, three team questions and notes from a full run.

Behavioural preparation

Candidates describe the Behavioral Discussions as conversations with potential peers about team fit and collaborative style. For a full-lifecycle engineering role, prepare stories about shipping fast with quality, giving and receiving code review feedback, influencing a standard, and working across departments, each with your own decision and a measurable result.

Can you walk me through a complex technical challenge you solved in a previous role?

Medium · Technical and Domain Expertise

Approach

  1. This tests technical depth and ownership together: can you explain a hard problem to another engineer, show why it was hard, and defend the calls you made. Pick a challenge where you personally made the key decisions, not one where you watched someone senior solve it.
  2. Open with two or three sentences of context (the system, its scale, the symptom or goal), then name the constraint that made it hard, e.g. "migrate 40M rows with zero downtime." Without a stated constraint the story sounds like routine work.
  3. Spend most of your time on the reasoning: the two or three options you considered, what you measured to choose between them, and the tradeoff you accepted. Expect to be asked to sketch the architecture or walk the failing code path, so rehearse that level of detail.
  4. Include one thing that went wrong or surprised you and how you adapted, e.g. a first fix that only moved the bottleneck. A story where everything worked on the first try reads as either trivial or polished after the fact.
  5. Close with the result measured against the constraint you named, e.g. p99 latency cut from 2 s to 200 ms or a migration finished with zero downtime, plus one lesson you still apply. Say "I" for decisions you made and "we" for team work.
  6. Avoid challenges that were hard only for organizational reasons, or that need ten minutes of proprietary context. Aim for about three minutes of story before follow-up questions.

Follow-up

  • What would you do differently if you solved it again today? Name one concrete change, such as instrumenting earlier or choosing a simpler design, and say why it would have helped.
  • How did you verify the fix worked in production? Cite the metric, dashboard, or test that confirmed it and how long you watched it before calling it done.
  • Which alternatives did you reject, and why? Give at least one option with its specific drawback, such as cost, migration risk, or operational burden.

How does your experience in the logistics industry inform your approach to software architecture?

Medium · Technical and Domain Expertise

Approach

  1. Show how domain constraints shape your architecture, not just that you held a logistics job. If you have no logistics background, say so plainly, then answer from an adjacent domain (e.g. e-commerce fulfillment or payments) plus what you know about logistics.
  2. Tie domain realities to design choices. Logistics data comes from many outside parties with uneven quality, e.g. tracking updates that arrive late, duplicated, or out of order; that argues for idempotent ingestion, separate event and receipt timestamps, and a state machine for shipments.
  3. Show integration literacy: much of the industry still exchanges EDI (e.g. X12 204 load tenders, 214 status messages, 210 freight invoices) alongside REST APIs and emailed spreadsheets. That pushes toward an anti-corruption layer mapping each partner format into one internal model.
  4. Mention the correctness traps the domain creates: time zones across pickup and delivery locations, units and currency, rates that change between quote and booking, and money stored as decimals rather than floats. Each is a concrete case of domain knowledge changing the code.
  5. Anchor it in one real project: the domain problem, the architecture decision it drove, and the result, quantified as partner onboarding time, data error rate, or manual work removed. Never claim industry experience you do not have; follow-up questions expose it quickly.

Follow-up

  • How would you model a shipment's lifecycle? As a state machine (tendered, booked, picked up, in transit, delivered, invoiced) with an append-only event history; store late events in the history but only move current state forward.
  • How do you handle a partner that sends bad data? Validate at the boundary, quarantine rejected records with the reason, alert the owner, and never let one partner's failures block other partners' data.
  • How would you store rates that change between quote and booking? Save each quote as an immutable record with its expiry, and have the booking reference the accepted quote so invoices can be audited against it.

Describe a time you had to build a solution that spanned multiple departments.

Medium · System Design and Architecture

Approach

  1. This tests whether you can deliver when requirements, priorities, and data are owned by different groups, e.g. operations, finance, and sales. Choose a project where you gathered each group's requirements yourself; a finished spec handed down by a PM shows none of this.
  2. Set up the tension: what each department needed and why it conflicted, e.g. one wanted fast data entry while another needed strict validation for billing. A story with no competing needs does not show cross-functional skill.
  3. Show how you found the real requirements: shadowing users, mapping the end-to-end workflow across departments, and finding where handoffs broke. Name the shared source of truth you established, such as one data model or an agreed API.
  4. Explain how you kept it moving: one accountable decision-maker, regular demos to each group, and a pilot with one department before rolling out to all. Describe one disagreement and how data or a compromise resolved it.
  5. Quantify the result for each side (manual steps removed, cycle time, rework or error rate, adoption) and end with what you would change, such as involving a department earlier.
  6. Avoid stories that blame another department or that succeeded only by escalating to leadership; they suggest you cannot build trust with peers.

Follow-up

  • How did you handle conflicting priorities between departments? Make the tradeoff explicit, quantify the impact of each option, and have the shared decision-maker choose, then write the decision down.
  • How did you get people to adopt the new system? Involve them in design, pilot with a champion group, retire the old workflow on a set date, and fix their top complaints fast.
  • What if one department stopped responding? Follow up directly with a specific ask and deadline and find who owns the decision there; escalate only if that fails, and meanwhile proceed on documented assumptions they can correct.

Describe your experience working in a fast-paced, collaborative environment.

Easy · Behavioral and Team Fit

Approach

  1. Answer with a specific stretch of work that shows how you balanced speed with quality and coordinated when priorities shifted; "I thrive in fast-paced environments" without an example is a weak answer.
  2. Pick one period with real pressure, e.g. a launch deadline, shifting requirements, or a small team shipping weekly, and make the pace concrete: release frequency, team size, how often priorities changed.
  3. Show the habits that let you move fast without breaking things: small pull requests, feature flags, automated tests, and short written status updates. Describe one moment where you cut scope rather than quality and how you negotiated it.
  4. Make the collaboration explicit: pairing, unblocking a teammate, clean handoffs, or agreeing with product on what to drop. Speed that depends on heroics or working alone reads as a warning sign.
  5. End with what the pace produced and what it cost, e.g. a feature shipped every week with the incident rate held flat, plus one habit you now use to avoid rework or burnout when the pace stays high.

Follow-up

  • How do you handle a priority change mid-sprint? Clarify the reason and the new deadline, say what gets dropped or delayed, and get agreement before switching rather than silently juggling both.
  • How do you tell when the pace has become unsustainable? Point to signals such as rising rework, incidents, or missed estimates, and describe raising them with your lead with that data.
  • When did the pace cause a mistake? Own it, describe the fix, and name the process change that prevented a repeat.

Tell me about a time you had to influence a team's direction or advocate for a specific technical standard.

Medium · Behavioral and Team Fit

Approach

  1. Influence without authority is the core: show that you changed what a team does through evidence and trust rather than rank. Choose a story where people disagreed at first; a proposal everyone liked immediately shows no influence.
  2. State the standard and the problem it solved in measurable terms, e.g. adopting structured logging or an API versioning policy because inconsistent practice caused repeated incidents or slow reviews.
  3. Show how you built the case: data from incidents or metrics, a small proof of concept on your own code, and a written proposal (RFC or ADR) with alternatives and costs. A clear migration path matters as much as the end state.
  4. Describe how you handled resistance: hear the objections, adjust the proposal (e.g. apply it to new code only, add an escape hatch), recruit an early ally, and make adoption cheap with tooling or CI checks.
  5. Report the outcome and adoption: how many teams or repos took it up, which metric moved, and whether it stuck. A story where you lost the argument can also work if you show you committed to the decision and what you learned.

Follow-up

  • What if leadership rejected your proposal? Ask what evidence would change their minds, commit to the decision, and revisit it when new data appears rather than working around it.
  • How did you make sure the standard stuck? Enforce it automatically in CI or project templates, document it, and make the compliant path the easiest one.
  • How would you retire a standard that no longer fits? Show evidence that the original problem is gone or the cost has grown, propose the replacement through the same RFC process, and give teams a migration window.

How do you handle feedback from other developers during a code review?

Easy · Behavioral and Team Fit

Approach

  1. Show that you treat review as improving the code rather than defending it: describe your actual process and one concrete example, not a claim that you "love feedback."
  2. Describe your first move: read each comment for its intent, assume good faith, and ask a clarifying question when the reasoning is unclear. Separate blocking issues (correctness, security, design) from preferences and nits.
  3. Explain how you respond: fix and acknowledge when the reviewer is right; when you disagree, reply with evidence (a benchmark, a test, a documented convention) and switch to a call if the thread goes past two rounds. Turn recurring debates into a team convention.
  4. Show that you reduce friction up front: small PRs, a description with context and testing notes, and a self-review before requesting others. That cuts review cycles and makes the feedback you get more useful.
  5. Give one example where feedback changed your code or your habits, e.g. a reviewer caught a race condition and you now write concurrency tests for that pattern. A story where you were right every time backfires.

Follow-up

  • What if you and the reviewer cannot agree? Timebox the thread, talk it through live, and if still stuck defer to the code owner or team convention and move on.
  • How do you give feedback on someone else's PR? Be specific, explain why, mark nits as optional, and call out good decisions, so the author knows exactly what must change.
  • What if feedback arrives after the code has merged? Treat it the same way: open a follow-up ticket or PR if it matters, and add the lesson to the team's review checklist.

Why are you interested in joining the team at Arrive Logistics specifically?

Easy · Behavioral and Team Fit

Approach

  1. This asks for researched, genuine motivation; the word "specifically" rules out an answer that would fit any company. Prepare it like a technical question, not an afterthought.
  2. Research from primary sources before the interview: the job posting, the company's own website, any engineering posts or talks it has published, and anything your interviewers told you earlier. Cite only facts you verified yourself; a wrong claim about the company is worse than a general one.
  3. Structure the answer in three beats: the problem space that interests you and why, what in the role matches the work you want to do next, and what you bring to it. Tie each beat to your own experience.
  4. Connect it to your trajectory, e.g. "I've been building front-end features and want to own services end to end," then point to the part of the posting that offers that. Be honest about what you want to learn, not only what you offer.
  5. Avoid answers built on compensation, location alone, or flattery with no specifics. Finish with a question that shows depth, such as how the team measures the impact of what it ships.

Follow-up

  • What do you know about what we do? Summarize what you verified from primary sources in two or three sentences, and ask a question where your research ran out instead of guessing.
  • What other opportunities are you considering? Answer in general terms (industry, role type) without naming offers, and explain what makes this role a strong fit among them.
  • Where do you see yourself in a few years? Describe the skills and scope you want to grow into and how this role builds toward them, rather than naming a title.