cswork / libraryOpen practice workspace

Interview guides · Armis

Armis Software Engineer Interview Guide

Armis Software Engineer interview guide: phone screening and onsite rounds, reported coding, design and behavioral questions, and a 7-day prep plan.

The 60-second brief

Armis builds a security platform that gives enterprises visibility into, and control over, the devices connected in their environment. Software Engineers on that platform design, implement and maintain the software systems behind it, and candidates describe day-to-day work alongside product management, quality assurance and operations. Python, Java and Go appear as example languages in the requirements candidates describe, and cloud platforms (AWS, Azure), Docker, Kubernetes and CI/CD pipelines appear as nice-to-have experience. Security principles are listed as a must-have, so shape your engineering answers around building for a security product.

This guide is for engineers preparing for the Armis Software Engineer loop. It covers the two reported rounds, the twenty-five reported questions grouped by type (technical and domain, system design, problem-solving cases, coding and algorithms, behavioral) and a seven-day plan. Candidates say emphasis varies by team, so treat the question list as a map of question types, not a fixed script.

Candidates report two rounds over roughly 2-4 weeks: a phone screening with HR, then an onsite interview made up of discussions with team leaders and technical assessments.

Focus areas

  • Problem Solving
  • Coding Exercise Execution
  • Interview Preparation (Technical Interviewing)

Overview

The work described for this role is broad: building features, maintaining existing systems, troubleshooting, reviewing code and contributing to the design of new services, on a platform that deals with connected devices and security. The reported questions mirror that breadth. They run from a REST versus SOAP comparison and a secure-coding question, through a real-time data processing design for connected devices, to reversing a linked list and a dynamic programming problem. Security principles are a listed must-have, so every technical answer you give is stronger when it names the security consequence of the choice you are making: authentication on an API, validation of device-supplied input, secrets handling in a deployment.

Plan around five question types. Technical and domain questions are short and conceptual (REST versus SOAP, secure code, unit testing, cloud deployment, a hard bug), so you need a crisp, structured answer for each. System design questions cover real-time device data, schema design, scaling, microservices and high availability. Problem-solving cases ask for a programmatic approach to a use case, debugging an intermittent failure, recovering a late project and a build-versus-buy call. Coding questions cover linked lists, searching a sorted array, dynamic programming, complexity analysis and data structure choice. Behavioral questions cover conflict, prioritization, mentoring, change, setbacks and decisions under uncertainty.

Because the loop is only two rounds, each stage has to carry a lot. The phone screening with HR is about your background and fit, so your CV story needs to be tight before anything technical. The onsite mixes technical assessments with discussions with team leaders, which means the same day can require writing correct code, defending a design with trade-offs and telling a credible team story. Candidates also report no take-home, so ask the recruiter to confirm the format. Rehearse out loud: the reported guidance stresses explaining your thought process, and that skill only improves by speaking.

The Armis interview process

Candidates report two stages, in this order: a phone screening with HR and an onsite interview. Format details beyond that vary by team, so confirm them with your recruiter.

Phone Screening

Candidates report the first stage as a phone screening with HR that covers your background and how it fits the Software Engineer role. No coding or design task is reported for it, so preparation here is narrative: a short, consistent account of what you have built, the languages and cloud tooling you used, and why a company building security software for connected devices interests you. Read the public description of the Armis platform beforehand so your reason is specific.

What to demonstrate

  • How your past roles map onto a Software Engineer position
  • Role fit and motivation for working on a security product
  • Clear, concise spoken communication

How to prepare

  • Write and rehearse a CV walkthrough that states, for each role, what you built, in which language, and what changed because of it.
  • List the languages and tools you can discuss in depth (Python, Java and Go are the example languages candidates mention) and the cloud, Docker, Kubernetes or CI/CD experience you can back with a real project.
  • Prepare one concrete example of security work from your history: input validation, authentication, secrets handling or a vulnerability you fixed.
  • Have your working-method answer ready, since Agile and Scrum experience is a listed must-have.

Onsite Interview

Candidates report an onsite interview that combines discussions with team leaders and technical assessments. The reported question pool behind it spans technical and domain questions, system design, problem-solving cases, coding and algorithms, and behavioral prompts, so prepare all five types rather than guessing which will come up. A coding assessment is where the linked list, sorted array search, dynamic programming and complexity questions are practised; a design discussion is where the connected-devices, scaling, microservices and availability questions are practised. Work in the language you code fastest in and say your reasoning aloud.

What to demonstrate

  • Working code for list, search and dynamic programming problems, with complexity stated correctly
  • Design reasoning: scalability, high availability, microservices trade-offs and schema choices
  • Debugging and decomposition of an unfamiliar problem
  • Collaboration and leadership stories told with a clear personal contribution

How to prepare

  • Write reverse-a-linked-list and sorted-array search from memory in your main language, with empty, single-element and duplicate cases tested.
  • Solve two dynamic programming problems end to end: brute-force recursion, memoization, tabulation, then complexity.
  • Sketch the real-time device data design on paper: ingestion, buffering, processing, storage, and what happens when a stage falls behind.
  • Prepare a tight answer for each secure-coding and unit-testing question, and a bank of stories covering conflict, mentoring, change and setbacks.

Where candidates lose points

Answering the secure-code question with a list of buzzwords

Give a structure you can apply to a real service: validate and encode input, authenticate and authorize every call, keep secrets out of source, patch dependencies, log without leaking data. Attach each item to something you actually did.

Reversing a linked list or searching a sorted array and failing the edge cases

Dry-run empty, one-element and two-element lists, and for the search include duplicates, a missing target and an off-by-one around the middle. Save the next pointer before you overwrite it, and state O(n) time with O(1) space aloud.

Naming tools in the connected-devices design before pinning down the problem

Ask about the number of devices, message rate, delay tolerance and what happens to a message that cannot be processed. Then draw ingestion, buffering, processing and storage stages and say what you do when a stage falls behind.

Presenting microservices and high availability as only benefits

State the costs next to each benefit: network failures, distributed data consistency and operational overhead for microservices; redundancy, health checks, failover and replication lag for availability. Say when a single service is the better choice.

Telling team stories without your own role or result

For conflict, mentoring, change and setback stories, state your decision and action in the first person, give the outcome, and name what you would change. Prepare each story once and map it to several prompts.

Questions & practice

Write a function to reverse a linked list.

Medium · Coding / Algorithms

Approach

  1. Iterative solution with three pointers: prev = null, curr = head. On each step save next = curr.next, set curr.next = prev, then advance prev = curr and curr = next. Return prev. That is O(n) time and O(1) extra space.
  2. Recursive alternative: reverse the rest of the list, then set head.next.next = head and head.next = null. It is also O(n) time, but it uses O(n) call stack, which can overflow on long lists (CPython's default recursion limit is 1000).
  3. Edge cases: empty list, single node and two nodes. Make sure the old head's next ends up null, or the result contains a cycle.
  4. Test by walking the returned list and comparing it against the reversed input values. For a doubly linked list, swap each node's prev and next pointers and return the old tail.

Follow-up

  • Reverse only the nodes between positions m and n.
  • Reverse the list in groups of k nodes.
  • How would you detect a cycle before reversing, and in how much space?

How would you implement a search algorithm for a sorted array?

Medium · Coding / Algorithms

Approach

  1. Binary search: keep lo and hi, compute mid = lo + (hi - lo) / 2 (this avoids integer overflow in Java or C++), compare and discard half. O(log n) time and O(1) space when iterative.
  2. Pick one invariant and keep it: closed [lo, hi] with while lo <= hi, or half-open [lo, hi) with while lo < hi. Mixing the two causes the classic off-by-one and infinite-loop bugs.
  3. With duplicates, write a lower bound (first index with a[i] >= target) and an upper bound. The library equivalents are Python's bisect_left and bisect_right and C++'s std::lower_bound. Java's Arrays.binarySearch returns -(insertion point) - 1 when the key is missing and makes no promise about which duplicate it finds.
  4. Edge cases: empty array, one element, target below the minimum or above the maximum, and all elements equal.
  5. Related variants: a rotated sorted array (decide which half is sorted at each step), unknown length (exponential search, O(log i) for the target's index i), and interpolation search on evenly spread values (O(log log n) on average, O(n) worst case).

Follow-up

  • Return the first and last positions of a target that appears several times.
  • Search a sorted array that has been rotated at an unknown pivot.
  • Use binary search on the answer, for example the minimum ship capacity to deliver all packages within D days.

Solve a problem involving dynamic programming, and explain your thought process.

Medium · Coding / Algorithms

Approach

  1. Spot the signs: optimal substructure plus overlapping subproblems. Pick a standard problem to reason through aloud, such as minimum-coin change, and start from the plain recursion so the repeated subproblems are visible (exponential time).
  2. Define the state and recurrence exactly: dp[a] is the fewest coins that make amount a, dp[0] = 0, and dp[a] = min over coins c <= a of dp[a - c] + 1, with infinity for unreachable amounts. Return -1 if dp[amount] stays infinite.
  3. Top-down memoisation and bottom-up tabulation give the same complexity, here O(amount x number of coins) time and O(amount) space. Bottom-up avoids recursion-depth limits and makes the fill order explicit.
  4. Explain why greedy fails: with coins {1, 3, 4} and amount 6, greedy takes 4+1+1 (three coins) while the optimum is 3+3 (two).
  5. Mention space reduction and reconstruction. A two-dimensional table such as LCS's O(m x n) can often shrink to two rows, but rebuilding the actual solution needs the full table or parent pointers.

Follow-up

  • Count the ways to make the amount instead. Why does putting coins in the outer loop count combinations, while amounts in the outer loop count ordered sequences?
  • Return the coins used, not just how many.
  • How would you solve longest common subsequence in O(min(m, n)) space?

Discuss the time and space complexities of your code.

Medium · Coding / Algorithms

Approach

  1. Define Big-O as growth with input size: count the dominant operations, drop constants and lower-order terms, and give best, average and worst cases when they differ (quicksort is O(n log n) on average and O(n^2) in the worst case).
  2. Space: count auxiliary memory including the recursion stack (recursive DFS on a skewed tree uses O(n) stack), and say whether the output counts.
  3. Amortised and average costs: appending to a dynamic array is O(1) amortised even though a resize copies O(n). Hash map operations are O(1) on average but O(n) in the worst case under heavy collisions.
  4. Point out hidden costs in your own code: slicing copies O(k) elements, a membership test on a list is O(n) against O(1) average for a set, sorting is O(n log n), and repeated string concatenation in a loop can total O(n^2) because strings are immutable (use a builder or join).
  5. Use separate variables for separate inputs, for example O(m + n) for two arrays or O(V + E) for BFS on a graph, instead of a single n.

Follow-up

  • What is the space complexity of your recursive solution once the call stack is included?
  • Can you trade memory for time here, and what would it cost?
  • Why does building a heap from n elements take O(n) rather than O(n log n)?

Provide an example of a data structure and explain its use cases.

Medium · Coding / Algorithms

Approach

  1. Pick one structure and go deep, for example a hash table: a bucket array plus a hash function, O(1) average insert, lookup and delete, O(n) worst case, and resizing once the load factor passes a threshold (0.75 by default in Java's HashMap), which keeps inserts amortised O(1).
  2. Explain the internals: collisions resolved by chaining or open addressing, the need for keys with stable hashes (do not mutate a key once inserted), and iteration order (Python dicts keep insertion order since 3.7; Java's HashMap guarantees none).
  3. Give concrete uses: deduplication, frequency counts, caches, indexing records by id (such as looking up a device record by its MAC address) and two-sum-style complement lookups.
  4. Contrast with alternatives: a balanced BST or TreeMap for ordered iteration and range queries at O(log n), a heap for top-k or priority scheduling, a trie for prefix lookups, and hash map plus doubly linked list for an LRU cache with O(1) get and put.
  5. Name the trade-offs: memory overhead from empty buckets, dependence on hash quality, and hash-flooding attacks. Python has randomised string hashing by default since 3.3 to counter them.

Follow-up

  • Implement an LRU cache with O(1) get and put.
  • When would a sorted map be a better choice than a hash map?
  • How does resizing work, and why is insertion still O(1) amortised?

What considerations do you take into account when designing a database schema?

Medium · System Design / Architecture

Approach

  1. Start from access patterns: the main queries, the read/write ratio, expected volume and growth. These decide what to normalise, what to denormalise and what to index.
  2. Normalise to roughly third normal form to avoid update anomalies. Denormalise only on purpose for hot read paths, and say how the copies stay consistent (trigger, application write, or an async job and how stale it can get).
  3. Keys and constraints: surrogate versus natural primary keys, foreign keys, UNIQUE, NOT NULL and CHECK constraints that enforce invariants in the database. Pick the right types: timestamps with time zone, and DECIMAL rather than float for money.
  4. Indexes: back the WHERE, JOIN and ORDER BY columns. A composite index on (a, b) serves filters on a, or on a and b, but generally not on b alone. Every index adds write cost and storage.
  5. Evolution and scale: backward-compatible migrations (expand, migrate, contract), soft deletes versus history tables, partitioning large time-ordered tables, a tenant_id strategy for multi-tenant data, and where personal data lives and who can read it.

Follow-up

  • When would you denormalise, and how do you keep the copies in sync?
  • How would you add a NOT NULL column to a large live table without downtime?
  • Given an index on (a, b), which of your queries can use it, and which cannot?

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?

Explain the differences between REST and SOAP APIs.

Medium · Technical / Domain Questions

Approach

  1. Frame the category difference first: REST is an architectural style over HTTP (resources addressed by URLs, standard verbs, stateless requests, usually JSON), while SOAP is a protocol whose XML envelope (header plus body) is normally POSTed to one endpoint, with the operation named inside the message.
  2. Contracts: SOAP services are described by WSDL and XML Schema, so tooling can generate typed clients. REST contracts (often OpenAPI) are optional and looser, and that makes it easier to evolve them by adding fields.
  3. HTTP semantics: in REST, GET is safe and cacheable, PUT and DELETE are idempotent, and status codes carry errors. SOAP sends everything through POST and reports errors as a SOAP Fault in the body, so it gets nothing from HTTP caches or verb semantics.
  4. Security and reliability: SOAP has WS-Security for message-level signing and encryption that survive intermediaries, plus WS-ReliableMessaging. REST relies on transport-level TLS plus OAuth 2.0 or JWT bearer tokens.
  5. When each fits: SOAP lingers in enterprise and legacy integrations that need a formal contract and message-level security. REST suits public, web and mobile APIs where lighter payloads matter. gRPC is worth naming as the typed alternative for internal service-to-service calls.

Follow-up

  • How would you make a POST that creates a resource safe to retry after a timeout?
  • Why is PUT idempotent while POST is not, and what does PATCH guarantee?
  • How would you version a REST API without breaking existing clients?

How do you ensure that your code is secure?

Medium · Technical / Domain Questions

Approach

  1. Validate at every trust boundary: allow-list input validation, bind parameters for every SQL query, context-aware output encoding against XSS, and no shell commands built from strings. Tie each control to the OWASP Top 10 category it addresses (injection, broken access control, and so on).
  2. Authorization on every request, checked server-side for the specific object, which prevents insecure direct object references. Give service accounts and tokens least privilege.
  3. Secrets and crypto: keep secrets out of source control and in a secrets manager with rotation. Hash passwords with bcrypt, scrypt or Argon2, use vetted crypto libraries instead of hand-rolled ones, and use TLS everywhere.
  4. Process and tooling: threat-model new features (STRIDE is a usable checklist), make security part of code review, run SAST in CI, scan dependencies for known CVEs with pinned lockfiles, and fuzz parsers that handle untrusted input.
  5. Close with one real example: the flaw, how it was found, the fix, and the test or CI check that keeps it from coming back.

Follow-up

  • How does a bind parameter prevent SQL injection, and where can it not help, for example with a dynamic column name?
  • A critical CVE lands in a transitive dependency: what do you do, in order?
  • How would you store and rotate an API key that a backend service uses?

Describe a challenging bug you faced and how you resolved it.

Medium · Technical / Domain Questions

Approach

  1. Choose a bug whose cause was not obvious, such as a race condition, a memory leak, a time zone or encoding error, or stale cache data. Open with the symptom and its impact in concrete terms: who saw it, how often, and what it broke.
  2. Walk the investigation as a series of hypotheses and the evidence that ruled each one out: logs, metrics, a minimal reproduction, git bisect, a debugger, extra instrumentation.
  3. State the root cause precisely at code level, and explain why the hypotheses you dropped looked plausible at the time.
  4. Describe the fix and its cost (for example, a lock that adds latency), then the prevention: a regression test that reproduces the original failure, plus an alert or check that would have caught it sooner.
  5. Avoid stories where someone else found the cause, or where the resolution is a vague 'changed the config'. Your own reasoning has to carry the answer.

Follow-up

  • How did you confirm the fix worked, rather than the bug just going quiet?
  • What would you instrument up front next time so the cause shows up faster?
  • What made it hard to reproduce, and how did you get around that?

What is the significance of unit testing in software development?

Medium · Technical / Domain Questions

Approach

  1. What unit tests buy you: fast, isolated checks of one unit's behaviour that catch regressions at commit time, make refactoring safe and document intended behaviour. A bug costs less to fix the earlier it is found.
  2. Place them in the test pyramid: many unit tests, fewer integration tests and few end-to-end tests. Unit tests cannot catch contract or wiring problems between components, so they do not replace the other layers.
  3. What a good unit test looks like: Arrange-Act-Assert, deterministic (inject the clock, randomness and network instead of calling them), asserting behaviour rather than implementation details, and covering empty input, boundaries and error paths.
  4. Test doubles: separate stubs, mocks and fakes. Heavy mocking ties tests to the implementation and breaks them on harmless refactors.
  5. Coverage: line coverage is a floor, not a goal. Mutation testing shows whether the tests actually detect changed logic. Run the suite in CI on every push, and mention TDD's red-green-refactor loop if you use it.

Follow-up

  • How would you unit test a function that reads the current time or calls an external API?
  • When is a fake or an integration test better than a mock?
  • Is 100% coverage worth chasing? Why or why not?

Design a system to handle real-time data processing for connected devices.

Medium · System Design / Architecture

Approach

  1. Pin down scope before drawing anything: number of devices, events per second, event size, latency target, what processing means here (enrichment, anomaly detection, alerting, device-state updates) and retention.
  2. Ingestion: devices or collectors send over MQTT or HTTPS to a gateway tier that authenticates them (mutual TLS or device certificates), validates the schema and writes to a durable partitioned log such as Kafka or Kinesis. Partitioning by device id keeps each device's events in order.
  3. Processing: consumer groups (Flink, Kafka Streams or stateless workers) handle enrichment and windowed aggregations, using event time and watermarks so late events land in the right window. Delivery is at-least-once, so sinks must be idempotent (upsert by device id plus event id).
  4. Storage and serving: a key-value store for each device's current state, a time-series or columnar store for history, object storage for the raw archive, a notification path for alerts and a query API on top.
  5. Failure and scale: watch consumer lag as the backpressure signal, scale consumers up to the partition count, rate-limit or sub-key a chatty device that creates a hot partition, send malformed events to a dead-letter queue, and replay from log offsets after fixing a processing bug. A schema registry lets payloads evolve safely.

Follow-up

  • A device was offline for hours and then uploads a backlog: how do out-of-order and late events get handled?
  • One device starts flooding the pipeline. What protects everyone else?
  • How would you reprocess a week of data after fixing a bug in the enrichment step?

How would you approach scaling an application to handle increased user demand?

Medium · System Design / Architecture

Approach

  1. Measure before changing anything: find the bottleneck from metrics (CPU, p99 latency, database connections, queue depth) and load-test to find the breaking point. Scaling the wrong tier wastes money.
  2. App tier: make it stateless (sessions in a shared store or tokens), put it behind a load balancer and autoscale horizontally. Vertical scaling is a quick first step with a hard ceiling.
  3. Caching: a CDN for static assets, HTTP cache headers, and an application cache such as Redis in cache-aside mode, with TTLs and an explicit invalidation rule.
  4. Database: connection pooling and query and index tuning first, then read replicas (accept replication lag, or route read-your-writes traffic to the primary), then partitioning or sharding by a key chosen from the dominant query.
  5. Asynchrony and protection: move slow work onto queues and workers, rate-limit and shed load at the edge, and degrade gracefully (serve stale data, turn off non-essential features) instead of failing outright.

Follow-up

  • A user writes and then immediately reads from a replica that has not caught up. How do you handle it?
  • Which shard key would you pick, and which query does it make expensive?
  • At ten times today's traffic, what breaks first, and how would you know before it does?

Describe how you would implement microservices architecture in a project.

Medium · System Design / Architecture

Approach

  1. Start by asking whether to split at all: a modular monolith is often the right first step. When splitting, follow business capabilities or bounded contexts, and give each service ownership of its own data (database per service).
  2. Communication: synchronous REST or gRPC for queries that need an immediate answer, asynchronous events through a broker for decoupling, and an API gateway for external clients. Avoid long chains of synchronous calls, because their latency and failure rates multiply.
  3. Consistency without distributed transactions: sagas (choreographed or orchestrated) with compensating actions, a transactional outbox so events are published only when the local write commits, and idempotent consumers.
  4. Resilience and operations: timeouts on every call, retries with exponential backoff and jitter, circuit breakers, service discovery, containers on an orchestrator such as Kubernetes, an independent CI/CD pipeline per service, and distributed tracing plus centralised logs and metrics.
  5. Migration and contracts: extract services gradually from an existing monolith with the strangler fig pattern, and protect service boundaries with consumer-driven contract tests and versioned APIs.

Follow-up

  • How would you keep an order and its payment consistent when they live in two services?
  • How would you change a service's API without breaking the services that call it?
  • What costs of microservices would you warn a small team about before it splits a monolith?

What patterns do you use to ensure high availability in your applications?

Medium · System Design / Architecture

Approach

  1. Set a target and find the weak points: an SLO with its downtime budget (99.9% is about 8.8 hours a year, 99.99% about 53 minutes), then list every single point of failure in the request path.
  2. Redundancy: several instances across availability zones behind health-checked load balancers, active-active or active-passive failover, and database replication with automatic failover. Asynchronous replication can lose the last writes on failover, so state the RPO.
  3. Failure isolation: timeouts, retries with backoff and jitter, circuit breakers, bulkheads (separate pools per dependency), load shedding, and graceful degradation such as serving cached data when a dependency is down.
  4. Change safety: rolling, blue-green or canary deploys with automated rollback, plus feature flags, because deploys and config changes are a frequent outage trigger.
  5. Verification: separate liveness and readiness probes, alerting on SLO burn rate, regular failover drills or chaos tests, and backups proven by actually restoring them.

Follow-up

  • What happens to in-flight writes when the primary database fails over?
  • How do you stop client retries from turning a partial outage into a full one?
  • What gets harder when you go active-active across regions?

Given a specific use case, outline how you would approach solving it programmatically.

Medium · Problem-Solving / Case Studies

Approach

  1. Clarify the inputs, outputs, constraints and scale, restate the problem in your own words, and write two or three concrete examples, at least one of them an edge case such as empty input, duplicates or invalid values.
  2. Model the data before writing logic: name the entities and pick structures from the access pattern (a hash map for O(1) average lookup by key, a heap for top-k, a queue for ordered or breadth-first processing, a sorted structure for range queries).
  3. Get a simple correct version working first and state its time and space complexity, then optimise the step that dominates and explain what the optimisation costs in memory or code complexity.
  4. Write small, well-named functions that handle invalid input explicitly, then trace your examples through the code out loud, edge cases included.
  5. Finish with what changes at larger scale or with streamed input, and which unit tests you would write first.

Follow-up

  • What changes if the input is a hundred times larger, or arrives as a stream?
  • Which part would you unit test first, and with which cases?
  • How would your code behave with malformed or hostile input?

If a project is behind schedule, what steps would you take to get it back on track?

Medium · Problem-Solving / Case Studies

Approach

  1. Diagnose before acting: how far behind, and why (scope growth, underestimated work, blocked dependencies, unplanned work, people pulled away). Re-estimate the remaining work as concrete tasks rather than trusting the old plan.
  2. Lay out the levers: cut or defer scope to the must-haves, move the date, remove blockers, reduce work in progress, or add people carefully. Brooks's law warns that new people on a late project cost onboarding time before they help.
  3. Tell stakeholders early, and bring options with their trade-offs rather than only the bad news. Agree a revised plan with explicit milestones.
  4. Track the new plan closely (milestones, burndown, blockers raised daily), and protect quality: record any deliberate shortcut as tech debt instead of silently skipping tests.
  5. Afterwards, run a retrospective on why the estimate slipped and change how you estimate: time-boxed spikes for unknowns and explicit buffers.

Follow-up

  • The stakeholder will neither cut scope nor move the date. What do you do?
  • When does adding an engineer help a late project rather than slow it down?
  • Which early signal would have shown the slip sooner?

How would you evaluate whether to build a feature in-house or use an existing third-party solution?

Medium · Problem-Solving / Case Studies

Approach

  1. Ask first whether the capability sets the product apart. Build what differentiates it, and buy or adopt commodity pieces such as authentication, payments, logging or feature flags.
  2. Compare total cost of ownership, not sticker price. Building costs engineering time plus maintenance, on-call and security patching for the life of the feature. Buying costs licence fees that grow with scale, plus integration and vendor management.
  3. Assess fit and risk: requirement coverage, extensibility, lock-in and an exit plan, the vendor's SLA and viability, data residency, a security review of what data the vendor touches, and the obligations of open-source licences (GPL versus MIT or Apache).
  4. Weigh time to market against team capability: a vendor ships the feature sooner, while building needs people who can own it long term.
  5. Decide with a weighted comparison and a time-boxed proof of concept, and put the vendor behind an internal interface so switching later stays cheap.

Follow-up

  • How would you reduce the risk of the vendor going away or raising prices sharply?
  • How does the analysis change for an open-source library versus a commercial vendor?
  • Give an example of a build-or-buy call you made. Did it hold up?

How do you approach debugging a system that is intermittently failing?

Medium · Problem-Solving / Case Studies

Approach

  1. Characterise the failure before theorising: how often, on which requests, hosts, regions or versions, and whether it lines up with deploys, cron jobs, traffic peaks, GC pauses or certificate and token expiry. Slice the failures by each dimension to see what they share.
  2. Collect evidence: structured logs with request or correlation ids, distributed traces, and metrics for latency percentiles, error rate and saturation (CPU, memory, file descriptors, connection and thread pools), plus the list of recent changes.
  3. Check the usual causes of intermittent failure: race conditions, pool exhaustion, timeouts on a slow dependency, a single bad host behind the load balancer, DNS or cache TTL effects, retry storms, clock skew and memory leaks.
  4. Make it reproducible: raise concurrency or load, replay captured traffic, pull the suspect host out of rotation, add targeted logging, and change one variable at a time. Bisect recent changes if the start of the failures can be dated.
  5. Mitigate first (roll back, drain the host), then fix the root cause, add a regression test and an alert, and confirm the fix by watching for clearly longer than the usual gap between failures.

Follow-up

  • The failures only happen on one host out of ten. What do you compare?
  • The failure occurs about once a day. How do you show your fix worked?
  • How would you track down a race condition you cannot reproduce locally?

Suggested practice checklist

Built from the two reported rounds and the reported question types: coding fundamentals first, then technical answers, design and case studies, with behavioral rehearsal and a full mock last.

Day 1 — Loop map, CV story and security basics

  • Write the two-round map (phone screening with HR, then onsite with team leaders and technical assessments) and mark the part you are weakest at.
  • Prepare a spoken CV walkthrough stating what you built in each role and the languages and cloud tools you used.
  • Read the public description of the Armis platform and write two sentences on why you want to build security software for connected devices.
  • List every project where you handled security (input validation, authentication, secrets) so you have real examples ready.

Deliverable: A one-page loop map, a rehearsed CV script, a written reason for Armis, and a list of security examples from your work.

Day 2 — Linked lists and sorted-array search

  • Write iterative and recursive linked-list reversal in your main language, then trace empty, one-node and two-node inputs.
  • Write binary search for a sorted array, then extend it to the first occurrence and the insertion point when the target is missing.
  • Write unit tests for both functions covering the edge cases, and say the time and space complexity aloud for each.

Deliverable: Two tested functions (list reversal and sorted-array search) with a spoken complexity statement for each.

Day 3 — Dynamic programming, complexity and data structures

  • Solve two dynamic programming problems, one one-dimensional (such as climbing stairs) and one two-dimensional (such as longest common subsequence). Write the brute force, then memoization, then tabulation.
  • For each solution, state the state definition, the transition and the time and space cost, and the way to reduce space.
  • Prepare a spoken example of a data structure (hash map, heap or trie) with two use cases and the operation costs.

Deliverable: Two dynamic programming solutions in three forms each, plus a spoken answer for the data structure example and complexity discussion.

Day 4 — Technical and domain answers

  • Write a comparison of REST and SOAP covering message format, contracts, statefulness, error handling and when you would choose each.
  • Write a secure-coding checklist you can say in under a minute, tied to a service you built.
  • Prepare an answer on the value of unit testing: what to test, test isolation and mocks, and what unit tests do not catch.
  • Write the challenging-bug story: symptom, how you narrowed it down, root cause, fix and the test you added.

Deliverable: A REST versus SOAP comparison, a secure-code checklist, a unit-testing answer and a written bug story.

Day 5 — System design: devices, schemas and scaling

  • Design the real-time data processing system for connected devices on paper: ingestion, buffering, processing, storage, and the behavior when a stage falls behind.
  • Design a database schema for the data you stored, listing keys, indexes, and the queries each index serves.
  • Write a scaling ladder for an application facing more demand: measure, cache, add instances, split reads from writes, partition.

Deliverable: A device-data design diagram, a schema with indexes and a scaling ladder, plus a solved index-reasoning practice question.

Day 6 — Architecture patterns and case studies

  • Write when you would adopt microservices and when you would not, including service boundaries, data ownership and failure handling.
  • List high-availability patterns (redundancy, health checks, failover, replication, graceful degradation) with the cost of each.
  • Write a debugging sequence for an intermittent failure: find what changed, check instrumentation, bisect, reproduce.
  • Practise the project-behind-schedule and build-versus-buy answers aloud, then outline a programmatic approach to a use case you invent.

Deliverable: Written microservices and availability answers, a debugging sequence, and spoken answers for the schedule recovery, build-versus-buy and use-case questions.

Day 7 — Behavioral stories and a full mock

  • Write six stories (conflict, prioritization, mentoring, change, setback, a decision with limited information) using situation, action, result and lesson, in the first person.
  • Write the cloud services and deployment story with the actual services, strategy and rollback.
  • Run a mock onsite: one coding problem, one design question and three behavioral prompts, spoken aloud with a timer you set.

Deliverable: Seven rehearsed stories and one full mock run with notes on where the answers lost structure.

Behavioural preparation

Candidates describe leadership and teamwork as part of the evaluation, and the role involves working with product management, quality assurance and operations. These prompts cover conflict, prioritization, mentoring, change, setbacks and decisions under uncertainty. Prepare stories where you made the decision, state the result, and say what you would do differently.

Discuss your experience with cloud services and deployment strategies.

Medium · Technical / Domain Questions

Approach

  1. Choose one system you personally deployed and name the actual services you used (for example compute, storage, a managed database, a queue), not a tour of every cloud product. If your experience is on AWS or Azure, say which and stay inside what you did.
  2. Walk through the deployment strategy as a decision: rolling update, blue/green or canary, and why that fit the risk. Say what signal triggered a rollback, such as error rate or failed health checks, and how fast you could revert.
  3. Cover the pipeline: build in CI, container image if you used Docker, automated tests before promotion, and how configuration and secrets were injected so they never sat in the repository.
  4. Address the awkward parts: database migrations that must work with old and new code during a rollout (add the column first, remove it later), and any state that made the deployment harder than a stateless service.
  5. Close with a measurable result or a lesson, such as fewer failed releases or faster rollback, and the one thing you would change.

Follow-up

  • How did you roll back, and how did you know the rollback itself worked?
  • How would you deploy a schema change that is not backward compatible?
  • What would you pick for a stateful service, and why would that differ from a stateless one?

Describe a time when you had to resolve a conflict within your team.

Medium · Behavioral / Leadership

Approach

  1. Pick a real disagreement about work, such as an API shape, a review dispute or an ownership boundary, where you were a participant and the outcome mattered. Describe it in two sentences, then spend the answer on what you did.
  2. Show that you understood the other person's position before arguing yours: say it back to them, and state what they were optimizing for (delivery speed, safety, simplicity).
  3. Move the conflict from opinion to evidence: a small prototype, a benchmark, a written comparison of options against criteria you both agreed on, or a decision from the person who owned the area.
  4. State the outcome honestly, including a compromise or a case where you were overruled and committed anyway, and what the working relationship looked like afterward.
  5. Avoid the story where the other person was simply wrong and you won; it shows no skill.

Follow-up

  • What would you have done if they still disagreed after the evidence?
  • How did you keep the relationship working with that person afterward?
  • Was there a point where you realized you were partly wrong?

How do you prioritize tasks when working on multiple projects?

Medium · Behavioral / Leadership

Approach

  1. Name the method you actually use: list the work, rank by impact and deadline, note dependencies and who is blocked, and weigh the cost of delay. Then show it on a real week when several projects collided.
  2. Give specifics: how many items were competing, which one you did first and why, which one you deliberately delayed or cut, and who you told. Priorities set in silence fail when the people affected find out later.
  3. Show cross-team handling, since the role involves product management, QA and operations: how you negotiated scope or dates with the owners of the work you pushed back.
  4. Describe how you re-checked priorities as new information arrived, for example an incident or a changed deadline, and what you stopped doing to make room.
  5. Avoid a generic answer about tools (task lists, calendars). The substance is the trade-off you made.

Follow-up

  • What did you drop, and who was unhappy about it?
  • How do you handle an urgent request from a senior person that conflicts with your plan?
  • How do you decide when to ask for help or more time instead of absorbing the load?

Can you give an example of how you have mentored a junior developer?

Medium · Behavioral / Leadership

Approach

  1. Choose one specific junior developer and state their starting point: what they could do alone and where they were stuck, such as writing tests, reading unfamiliar code or scoping a task.
  2. Describe the mechanics you used: pairing on the first change, code review comments that explain the reason behind each suggestion, tasks that grew in size, and having them present their own design. If it fits, show how you taught secure coding habits through review.
  3. Say what you did not do: you did not rewrite their code or take over when they struggled. Mentoring is shown by their independence increasing.
  4. Give evidence of progress: they shipped a feature alone, review rounds dropped, or they began mentoring someone else. State what you learned about giving feedback.
  5. Mention one thing that did not work at first and how you adjusted your approach to that person.

Follow-up

  • What did you do when they kept repeating the same mistake?
  • How do you give critical feedback in a code review without discouraging someone?
  • What did you learn from the experience that you apply to your own work?

Discuss a situation where you had to adapt to significant changes in a project.

Medium · Behavioral / Leadership

Approach

  1. Pick a change that was real: shifted requirements, a reorganized team, a cancelled approach or a technology migration. Say what had been planned and what was different, with its impact on your work.
  2. Describe your first reaction honestly, then the steps you took: re-scoping, identifying what work could be salvaged, updating the plan and tests, and telling the people depending on you what moved.
  3. Show that you learned what you needed quickly, whether a new codebase, a new tool or a new part of the system, and how you went about it instead of waiting to be told.
  4. Give the outcome and what was lost along the way, and if the change was a mistake or the direction later shifted again, say how you handled that.
  5. Avoid a story where the change was minor or where your only action was to complain and comply.

Follow-up

  • What was the hardest part of the change for you personally?
  • How did you help teammates who were struggling with the same change?
  • Would you have pushed back on the change, and what would you have said?

How do you handle failure or setbacks in your work?

Medium · Behavioral / Leadership

Approach

  1. Choose a setback with a real cost, such as a release that caused an incident, a missed deadline or a design that did not hold up. A fake failure that is secretly a strength ('I work too hard') is easy to recognize and weakens the answer.
  2. Own your part in one clear sentence, then describe the response in order: limit the damage first, communicate to the people affected, find the cause without blaming individuals, and then fix it.
  3. Show the lasting change: a test, an alert, a checklist item, a review rule or a different way you estimate. A concrete change shows the lesson was learned.
  4. Describe how you handled the emotional side without drama, such as staying methodical under pressure and asking for help at the right moment.
  5. End with how you behave differently today and, if possible, a later situation where that change paid off.

Follow-up

  • What was the exact moment you realized it was your mistake?
  • How did you rebuild trust with the people affected?
  • What would a teammate say about how you handled it?

Describe a time when you had to make a difficult decision based on limited information.

Medium · Problem-Solving / Case Studies

Approach

  1. Set up the decision in two sentences, then list what you knew, what you did not know, and what had a deadline. Making the gap explicit shows disciplined thinking.
  2. Explain how you bounded the risk: whether the decision could be reversed, the smallest experiment or spike you could run in the time available, and who could give you the missing fact fastest.
  3. State the criteria you chose and the assumptions you wrote down, so anyone could see why you picked that option, and the signal you would watch to decide whether to change course.
  4. Describe what happened, including if it turned out partly wrong, and how you corrected it. Do not claim hindsight certainty.
  5. Show that you communicated the decision and its uncertainty to the people affected instead of presenting it as settled fact.

Follow-up

  • What information would have changed your decision, and could you have gotten it?
  • How did you decide the decision was reversible or not?
  • What would you do differently with the same information today?