cswork / libraryOpen practice workspace

Interview guides · Armor Defense

Armor Defense Software Engineer Interview Guide

Armor Defense Software Engineer interview guide: three reported rounds, coding and Python questions, behavioral prompts and a 7-day plan.

The 60-second brief

Armor Defense builds security products, and candidates describe the Software Engineer role as work on the software behind them: new features, bug fixes, performance improvements and changes driven by customer feedback. The role sits next to product management, operations and other engineering teams, so day-to-day work includes turning user requirements into technical specifications, reviewing teammates' code and following shared coding standards.

This guide is for Software Engineer candidates preparing for the Armor Defense loop. Candidates describe the requirements as Python, familiarity with databases, solid algorithms and data structures, version control, agile working and roughly two to five years of experience, with AI/ML, cloud platforms and DevOps listed as nice-to-have. The guide covers the three reported rounds, the reported coding, Python, troubleshooting and behavioral questions, and a seven-day plan.

Candidates report three rounds over about three to five weeks: Initial Screening, Technical Assessment and Behavioral Interview. The stages are what candidates describe, not a published process.

Focus areas

  • DSA (Data Structures & Algorithms)
  • Python
  • Problem Solving

Overview

The reported question list splits into four groups. Technical and domain questions cover Python 2 versus Python 3, error handling, testing, common data structures and AI/ML experience. Problem-solving questions cover optimizing a sorting algorithm, choosing how to store a data set, a hard bug, designing a feature for an existing product and a troubleshooting story. Coding questions are reversing a linked list, binary search and finding two numbers that add up to a target, plus explaining complexity and writing a test case. Behavioral questions cover a difficult teammate, deadlines, leading an initiative, motivation and feedback.

Candidates also report the topics Data Structures and Algorithms, Python, Problem Solving, Networking Fundamentals and Performance Troubleshooting. The first three match the question list. The last two do not have a named question, so prepare them as short explanations you can give aloud: what happens between a client request and a server response, and how you would narrow down a slow service. Treat them as preparation for the Technical Assessment's problem-solving scenarios, not as predicted questions.

Because the product area is security software and the work includes bug fixing and code review, the stories that matter most are the ones where you found a root cause, wrote the test that pins it and explained the change to a reviewer. Write your coding answers in Python, say the time and space complexity every time, and finish each solution by naming the test cases you would add. Keep three or four project stories ready that can be bent to fit a bug, a deadline, a conflict or a feedback question.

The Armor Defense interview process

Candidates describe three stages, from a background screen to coding and problem-solving work, then a behavioral conversation. Use each stage below to decide which of the guide's questions to rehearse.

Initial Screening

Candidates describe the first stage as a preliminary evaluation of background and qualifications. Since the requirements candidates describe center on Python, databases, algorithms and data structures, version control and agile working, the useful preparation is a clear account of your own experience measured against that list, plus an honest answer on AI/ML, which appears both as a reported question and as a nice-to-have skill.

What to demonstrate

  • How your background lines up with the requirements candidates describe: Python, databases, version control, agile working
  • Whether your experience level fits the two to five years candidates describe as typical
  • How clearly you summarize past projects and your own part in them

How to prepare

  • Write a short walk through your last two or three roles that names the Python, database and version control work in each, and what you personally owned.
  • Prepare an honest AI/ML answer: a real project, or the nearest adjacent work, and where your experience stops.
  • Write down questions about the next two rounds and the timeline, since candidates report three to five weeks end to end.

Technical Assessment

Candidates report coding exercises and problem-solving scenarios in this stage, with a live coding environment mentioned for the coding questions. Reported topics are Data Structures and Algorithms, Python, Problem Solving, Networking Fundamentals and Performance Troubleshooting. Practise coding in Python while talking, state complexity for every solution, and finish with the tests you would write.

What to demonstrate

  • Working code for data-structure and algorithm problems in Python
  • Explaining time and space complexity of a chosen approach
  • Structured problem solving and troubleshooting on open-ended scenarios
  • Testing habits: what you would check and how you would write it

How to prepare

  • Solve the linked-list reversal, binary search and two-sum questions from a blank file in Python, then write the tests for each.
  • Prepare a table of common data structures with lookup, insert and ordering costs, and a decision rule for choosing among them.
  • Rehearse a troubleshooting sequence for a slow or failing service: reproduce, measure, narrow, fix, add a regression test.
  • Review basic networking: DNS lookup, TCP connection, HTTP request and response, and where latency can hide.

Behavioral Interview

Candidates describe the last stage as a conversation about interpersonal skills and cultural fit. The reported questions here are stories: a difficult teammate, tight deadlines, leading an initiative, motivation, and giving and receiving feedback. Build each as a short account of a situation, your decision, your action and a result, told in the first person.

What to demonstrate

  • Collaboration with teammates and cross-functional partners
  • Communication when giving and receiving feedback
  • Ownership shown through a specific decision you made

How to prepare

  • Write four project stories with a clear role for you in each, then map each to at least two of the reported behavioral questions.
  • Practise the difficult-teammate and feedback stories out loud until neither casts anyone as a villain.
  • Prepare one story where a deadline forced you to cut scope, naming what you cut and what you protected.
  • Prepare questions for the interviewers about how product management, operations and engineering work together.

Where candidates lose points

Binary search or linked-list reversal that loses a node or loops forever

Name your invariant before writing code: for reversal, keep prev, current and next saved before you rewire; for binary search, decide whether the range is closed or half-open and keep every update consistent with it. Test an empty input, one element, two elements and a missing target.

Solving two-sum only with nested loops, or reusing the same element twice

State the O(n squared) approach, then give the one-pass hash map approach: check whether target minus the current value is already stored before inserting the current one. Cover duplicates such as 3 and 3 with target 6, no valid pair, and whether you return values or indices. Mention the sort-plus-two-pointers option and its cost.

Describing testing as running the program and checking it works

Give a concrete scheme: unit tests for small functions, tests for boundaries and failure inputs, integration tests for the database or service edge, and a regression test for every bug. Write at least three pytest cases for the function you just coded, including one that should fail loudly.

Telling a bug or troubleshooting story with no method and no root cause

Structure it as symptom, how you reproduced it, what you measured, the hypotheses you ruled out, the root cause, the fix, and the test or monitoring you added. Have a separate performance example ready where you measured before changing anything.

Behavioral answers told as 'we' stories, or as stories where a colleague is the villain

Use 'I' for your decisions and actions, keep the situation brief, and spend most of the answer on what you chose and what happened. For conflict and feedback, show what you changed in your own behavior.

Questions & practice

How would you optimize a sorting algorithm?

Medium · Problem-Solving / Case Studies

Approach

  1. Clarify what to optimise and for what input: size, key type, nearly sorted or random data, many duplicates, whether stability is needed, and whether the data fits in memory. Comparison sorts cannot beat Ω(n log n) comparisons in the worst case.
  2. For quicksort: choose a random or median-of-three pivot so sorted input does not trigger O(n²), and use three-way partitioning when keys repeat. Switch to insertion sort below a small cutoff, and recurse into the smaller side first to keep the stack at O(log n).
  3. Bound the worst case like introsort: fall back to heapsort when recursion depth passes about 2·log₂ n, which guarantees O(n log n). Mergesort is stable with an O(n log n) worst case but needs O(n) extra memory. You can skip a merge when the left half's last element is ≤ the right half's first.
  4. Exploit structure in the data. Timsort, used by Python's sorted and list.sort, detects existing runs and is O(n) on already sorted input. For integer keys in a bounded range, counting sort is O(n + k) and radix sort is O(d·(n + b)).
  5. In Python, pass key= rather than a comparison function, because the key is computed once per element. For data larger than memory, sort chunks that fit, write them to disk, then k-way merge them with a heap.

Follow-up

  • How would you sort 100 GB of log lines on a machine with 8 GB of RAM?
  • Why does a stable sort matter when you sort by several keys in turn?
  • What input drives a naive first-element-pivot quicksort to quadratic time?

Write a function to reverse a linked list.

Medium · Coding / Algorithms

Approach

  1. Confirm the node shape (val, next), whether the list is singly linked, and that I return the new head. The edge cases are an empty list, a single node and two nodes.
  2. Iterative: prev = None, curr = head; while curr: nxt = curr.next; curr.next = prev; prev = curr; curr = nxt; return prev. Save next before overwriting it, or the rest of the list is lost.
  3. Complexity: O(n) time and O(1) extra space, because each node's pointer is rewritten once.
  4. Recursive: reverse the rest of the list, then set head.next.next = head and head.next = None. It is also O(n) time but uses O(n) stack, and in Python it hits the default recursion limit (about 1000) on long lists.
  5. Test it on the empty list, one node, two nodes and a longer list, checking the values in order and that the old head's next is None.

Follow-up

  • Reverse only the nodes between positions m and n.
  • Reverse the list in groups of k nodes.
  • How would you check whether a linked list is a palindrome in O(1) extra space?

Implement a binary search algorithm.

Medium · Coding / Algorithms

Approach

  1. State the precondition: the input is sorted. Clarify what to return when the target is missing (-1 or the insertion point) and which index to return when values repeat.
  2. Closed interval: lo, hi = 0, len(a) - 1; while lo <= hi: mid = lo + (hi - lo) // 2; return mid on a match, otherwise move lo = mid + 1 or hi = mid - 1; return -1 after the loop. The lo + (hi - lo) // 2 form avoids overflow in fixed-width languages.
  3. For the leftmost match or the insertion point, use the half-open form [lo, hi) with while lo < hi and hi = mid when a[mid] >= target. That is what bisect.bisect_left computes.
  4. Complexity: O(log n) time. O(1) space iteratively, O(log n) stack if written recursively.
  5. Edge cases: an empty array, one element, a target below the minimum or above the maximum, and all elements equal. Most bugs here are infinite loops from mixing the closed and half-open forms.

Follow-up

  • Search for a target in a sorted array that has been rotated at an unknown point.
  • Find the minimum ship capacity that delivers all packages within D days.
  • How would you search a sorted collection whose length you cannot query?

Given a list of integers, find two numbers that add up to a specific target.

Medium · Coding / Algorithms

Approach

  1. Clarify: return indices or values, whether exactly one answer exists, whether the same element may be used twice, and whether there can be duplicates and negative numbers.
  2. Brute force checks every pair in O(n²) time and O(1) space.
  3. One pass with a hash map from value to index: for i, x in enumerate(nums): if target - x in seen, return (seen[target - x], i); otherwise seen[x] = i. This is O(n) time and O(n) space. Checking before inserting stops an element from pairing with itself.
  4. Alternative: sort and move two pointers inward, which is O(n log n) time. Sort (value, index) pairs if the original indices are needed, and it uses O(1) extra space when values alone are enough and sorting in place is allowed.
  5. Tests: a pair that includes negatives, duplicates such as [3, 3] with target 6, a single element equal to target / 2 that must not match itself, and no valid pair.

Follow-up

  • Return all unique pairs instead of one.
  • Extend it to three numbers summing to a target. What complexity can you reach?
  • The integers arrive as a stream too large to store. What changes?

Explain the time complexity of your solution.

Medium · Coding / Algorithms

Approach

  1. Count how the dominant operations grow with input size, give best, average and worst cases where they differ, and give space complexity separately, including recursion stack.
  2. Apply it to the reported coding problems: list reversal is O(n) time and O(1) space, binary search is O(log n), and hash-map two-sum is O(n) time and O(n) space against O(n²) for brute force.
  3. Name amortised and average-case costs exactly. list.append is amortised O(1). dict and set lookups are O(1) on average and O(n) in the worst case. Sorting is O(n log n).
  4. Point out hidden Python costs: x in list is O(n), slicing copies O(k) elements, list.pop(0) is O(n) while deque.popleft() is O(1), and building a string with repeated + can be quadratic, so use ''.join.
  5. For divide and conquer, write the recurrence. T(n) = 2T(n/2) + O(n) solves to O(n log n), and T(n) = T(n/2) + O(1) solves to O(log n).

Follow-up

  • Your solution is O(n log n). Could it be O(n), and what would that cost in memory?
  • Why is a hash map lookup O(1) only on average?
  • What is the space complexity of your recursive solution, and could it fail on large inputs?

How would you write a test case for your code?

Medium · Coding / Algorithms

Approach

  1. Structure each test as arrange, act, assert, and give it a name that says the behaviour under test, such as test_returns_minus_one_when_target_missing. Each test checks one behaviour.
  2. Cover cases by class: normal input, boundaries (empty, one element, first and last position, maximum size), duplicates and negatives, and invalid input. Use pytest.raises for expected exceptions.
  3. Use pytest.mark.parametrize to run one test body over a table of (input, expected) cases. Adding an edge case then takes one line.
  4. For algorithm code, add a property-based test with Hypothesis that compares the fast solution with a brute-force oracle on random inputs, plus a check that the input was not mutated if it should not be.
  5. Keep tests deterministic: no real network, clock or randomness without a fixed seed. Fakes or mocks stand in at those boundaries, and the suite runs in CI on every change.

Follow-up

  • How would you test a function that calls an external API?
  • Your tests pass but a bug reached production. What do you change?
  • How do you test code that depends on the current time?

Keep soft-deleted accounts from blocking re-registration

Easy · soft delete · unique constraints · engine differences

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

Approach

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

Follow-up

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

Hold a per-tenant active cap against concurrent creates

Hard · write skew · isolation levels · constraints

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

Approach

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

Follow-up

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

Explain the differences between Python 2 and Python 3.

Medium · Technical / Domain Questions

Approach

  1. Lead with the changes that break code: print became a function, and / on two ints is true division in Python 3 (3/2 == 1.5) where Python 2 floored it to 1. // floors in both.
  2. Explain text handling: Python 3 str is Unicode and bytes is a separate type, so mixing them raises TypeError instead of failing silently. Decode at the input boundary and encode at the output boundary.
  3. List the lazy-by-default changes: range, map, filter and zip return iterators or lazy objects, and dict.keys()/items()/values() return views. xrange, iteritems and the cmp argument to sort are gone. int and long are one type.
  4. Cover syntax and semantics: except E as e replaces except E, e; raise X from Y chains exceptions; comparing unorderable types such as 1 < 'a' raises TypeError; round() uses banker's rounding, so round(2.5) is 2.
  5. Close with migration: Python 2 reached end of life in January 2020. I would port with 2to3 or futurize, add from future imports, and run the test suite under both interpreters while the port is in progress.

Follow-up

  • A Python 2 service reads bytes from a socket and concatenates them with str. What breaks under Python 3, and where would you put the decode?
  • How would you migrate a large codebase incrementally without a freeze?
  • Which Python 3-only features would you adopt first after the port, and why?

Describe the process you use for testing your software.

Medium · Technical / Domain Questions

Approach

  1. Describe layers that match the risk. Fast unit tests in pytest cover pure logic. Integration tests run against a real database or service in a container. A few end-to-end tests cover the paths users depend on most.
  2. Explain how I pick cases: the happy path, boundaries (empty, one item, maximum size), invalid and hostile input, and error paths. For security-sensitive code I add negative tests showing that bad input is rejected, not just that good input passes.
  3. Mock only at the system boundary (network, clock, third-party APIs) with unittest.mock or a fake. Mocking internal functions ties the tests to the implementation.
  4. Make it automatic: every pull request runs the suite in CI, and every bug fix ships with a regression test that fails before the fix. I treat coverage as a way to find untested branches, not as a target.
  5. Mention what comes after merge: staged rollout or a feature flag, and monitoring that catches what tests cannot, such as performance regressions and real traffic patterns.

Follow-up

  • How do you deal with a flaky test that fails one run in twenty?
  • What would you test in a function that parses untrusted input?
  • When is an end-to-end test worth its maintenance cost?

What are some common data structures, and when would you use them?

Medium · Technical / Domain Questions

Approach

  1. Organise the answer by operation cost. A Python list is a dynamic array: O(1) index access, amortised O(1) append, O(n) insert or delete in the middle and O(n) membership test.
  2. Hash-based dict and set give average O(1) lookup, insert and delete (O(n) worst case under heavy collisions). Use them for membership, counting and deduplication. dict keeps insertion order from Python 3.7.
  3. collections.deque gives O(1) append and pop at both ends, which suits queues and BFS. list.pop(0) is O(n). heapq gives O(log n) push and pop with O(1) access to the minimum, which suits priority queues, scheduling and top-k in O(n log k).
  4. Use linked lists for O(1) splice when you already hold the node (LRU caches pair one with a hash map). Use balanced trees or a sorted list with bisect when you need ordered iteration or range queries. Tries handle prefix lookups, and graphs are stored as adjacency lists when sparse or as a matrix when dense.
  5. Finish with a decision rule: start from the operations the code performs most often and their required complexity, then account for memory overhead and whether order matters.

Follow-up

  • Design an LRU cache with O(1) get and put. Which two structures do you combine?
  • Why can a hash map lookup degrade to O(n), and how do languages defend against that?
  • You need the median of a stream. Which structure would you use?

Given a set of data, how would you determine the best way to store it?

Medium · Problem-Solving / Case Studies

Approach

  1. Ask before choosing: what the data looks like (fixed fields, nested documents, time series, large blobs), how it is read (point lookups, range scans, aggregates, full-text), the read/write ratio, volume and growth, and the consistency and retention requirements.
  2. Use a relational database such as PostgreSQL when the data has relations and needs transactions and constraints. Design the indexes from the actual WHERE and ORDER BY clauses, and remember that each index slows writes.
  3. Use other stores when the access pattern calls for them: a key-value store with TTLs for caches and sessions, a document store for schemas that vary, a columnar warehouse for analytical scans over a few columns of many rows, and object storage for large files with only their metadata in the database.
  4. Inside a program, the same reasoning picks the data structure: a dict for keyed lookup, a sorted structure for range queries, an array for dense numeric data.
  5. Cover sensitive data and operations: encryption at rest and in transit, access control and an audit trail for sensitive fields, plus backups and how the schema will evolve. Name the trade-off you accept, such as weaker consistency in exchange for write throughput.

Follow-up

  • Reads are fast but writes slow down as the table grows. What do you check first?
  • When would you denormalise, and what does it cost you?
  • How would you store event data that is written constantly and queried by time range?

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

Medium · Problem-Solving / Case Studies

Approach

  1. Pick a bug with a real root cause, such as a race condition, an off-by-one, a timezone or encoding mismatch, a memory or connection leak, or a cache serving stale data. Choose one where I did the diagnosis myself.
  2. Tell it in order: the symptom and who it affected, how I reproduced it, the hypotheses I ruled out and the evidence for each, then the root cause.
  3. Name the concrete tools: targeted logging, a debugger or pdb, git bisect to find the commit that introduced it, a minimal reproduction, and profilers or tracing for performance bugs.
  4. Finish with the fix, the regression test that failed before the fix and passes after it, and the prevention step, such as a lint rule, a test or a monitoring alert. Explain why the bug got past existing tests.
  5. Avoid two mistakes: a story where the fix appears with no reasoning, and blaming a teammate or a library without showing evidence.

Follow-up

  • How did you confirm the fix addressed the cause and not just the symptom?
  • If you could not reproduce it locally, what would you have done?
  • What changed in your process afterwards?

How would you approach designing a new feature for an existing product?

Medium · Problem-Solving / Case Studies

Approach

  1. Start with the problem: which user it serves, what it should change, and the metric that shows success. Then pin down scope and what is explicitly out of scope.
  2. Map it onto the existing system: which services, data model and APIs it touches, and what has to stay backward compatible. Prefer additive schema changes and new optional API fields to changing ones that already exist.
  3. Outline the components: API changes, a schema migration with a backfill plan, business logic, the UI, and permissions or input validation for anything that accepts user input.
  4. Plan the release: put it behind a feature flag, roll out in stages, add metrics and logs that show whether it works, and keep a rollback path. Write tests at the layers that change.
  5. State the trade-offs you weighed, such as extending an existing service versus adding a new one, or shipping a smaller first version, and how you would agree on them with product and the engineers who own the affected code.

Follow-up

  • The feature needs a new column on a large, busy table. How do you migrate it safely?
  • How would you decide whether the feature worked after launch?
  • What would make you choose a separate service over extending the existing one?

Walk us through a recent project where you had to troubleshoot a significant issue.

Medium · Problem-Solving / Case Studies

Approach

  1. Set the scene in two sentences: the system, the symptom (errors, latency, data mismatch), and its impact. Then say what changed and when (a deploy, config, traffic, a dependency) before offering any theory.
  2. Show the narrowing sequence: check that dashboards and logs report correctly, then use metrics, logs and traces to locate the failing layer. For latency, compare p95/p99 to the median, profile with cProfile or py-spy, and run EXPLAIN ANALYZE on slow queries.
  3. For network-shaped symptoms, check them in order: DNS resolution, connection and TLS handshake, timeouts and retries, then connection-pool exhaustion. Intermittent timeouts under load often come from the pool or retry storms rather than the network.
  4. Separate mitigation from fix: rollback or a flag first to stop the impact, then the root cause, the code fix, a regression test, and an alert that would catch it earlier next time.
  5. Quantify the result, for example error rate or latency before and after, and say what you would do faster next time.

Follow-up

  • How did you tell the cause apart from something that only happened at the same time?
  • What would you have done if rolling back was not possible?
  • Which alert or dashboard would have caught it sooner?

Suggested practice checklist

The plan follows the three reported rounds: background first, then data structures, Python, coding and troubleshooting for the Technical Assessment, then behavioral stories. Each day ends with something you can reread before the loop.

Day 1 — Background and the AI/ML answer

  • Write a walk through your recent roles, marking the Python, database and version control work, and what you owned.
  • Match your experience against the requirements candidates describe and note the gaps.
  • Write and say aloud your answer on AI/ML experience, covering a real project or the nearest adjacent work.

Deliverable: A one-page work summary, a requirements-versus-experience checklist, and a written AI/ML answer.

Day 2 — Data structures and sorting

  • Build a table of lists, dictionaries, sets, stacks, queues, heaps and trees with lookup, insert and ordering costs.
  • Write a decision rule for each structure, using a concrete use case from your own work.
  • Describe sorting options in Python: built-in sort, nearly sorted input, stability, memory, and when heapq or a counting approach beats a comparison sort.

Deliverable: A data-structure table with a use case per structure, and a short sorting-optimization answer.

Day 3 — Coding questions in Python

  • Reverse a singly linked list iteratively and recursively, stating complexity for both.
  • Implement binary search both for an exact match and for the first position at or after the target.
  • Solve two-sum with a one-pass hash map and say why the nested-loop version is slower.

Deliverable: Three working Python solutions, each with a one-line complexity statement and a list of edge cases.

Day 4 — Python fundamentals and testing

  • Write a comparison of Python 2 and Python 3 covering print, integer division, strings and bytes, and unicode.
  • Write an error-handling policy with examples of specific exceptions, cleanup and retries.
  • Write pytest cases for yesterday's three functions, including empty input, one element and no-answer cases.

Deliverable: A Python 2 versus 3 sheet, an error-handling policy with two examples, and a pytest file for the three functions.

Day 5 — Troubleshooting, performance and networking

  • Write two troubleshooting stories from your own work using the sequence symptom, reproduction, evidence, cause, fix and regression test.
  • Write a short checklist for a slow service: measure, profile, check the database, check the network, change one thing at a time.
  • Explain aloud what happens from DNS lookup to an HTTP response, and note where latency can occur.

Deliverable: Two written troubleshooting stories, a performance checklist and a spoken networking walkthrough.

Day 6 — Storage and feature design

  • Answer how you would choose how to store a given data set: access patterns, size, consistency, and relational versus key-value.
  • Outline how you would design a feature for an existing product, from requirements and edge cases to rollout and tests.

Deliverable: A storage decision checklist, a feature design outline and two completed SQL practice solutions.

Day 7 — Behavioral stories out loud

  • Write the situation, decision, action and result for the difficult-teammate, deadline and led-initiative stories.
  • Write the feedback story in both directions and a motivation answer tied to the work in this role.
  • Say every story aloud, once as written and once shortened, and remove each 'we' that hides your own action.

Deliverable: Five written story outlines, each practised aloud, with your own actions and results named.

Behavioral stories for the Armor Defense loop

Candidates describe the Behavioral Interview as the stage on interpersonal skills and cultural fit. For this role, prepare stories about working with teammates, product management and operations, meeting deadlines, reviewing code and receiving feedback. A few reported questions that sound technical, such as error handling and AI/ML experience, are also answered best with a specific personal example.

How do you handle errors and exceptions in your code?

Medium · Technical / Domain Questions

Approach

  1. Answer as a policy backed by one real case. State the rule you follow: catch specific exceptions you can handle, let programmer errors surface, and never write a bare except or an empty except block that hides failures.
  2. Separate failure types. Retry transient ones (timeouts, dropped connections) with backoff and a cap, and only when the operation is idempotent. Fail fast on invalid input or broken invariants and return a clear error to the caller.
  3. Describe what you do on the way out: use with blocks or finally for cleanup, raise a new exception from the original to keep the cause, and log with context and the traceback (logging.exception) instead of printing.
  4. Handle errors at boundaries. Convert internal exceptions into stable error responses at the API edge, and keep stack traces and internal paths out of what a user sees, which matters for a security product.
  5. Close with one concrete example: the bug a swallowed exception hid or the retry that saved a job, and the test you added for that error path.

Follow-up

  • When is it acceptable to catch the broad Exception class, and what do you do inside that handler?
  • How do you make a retried operation safe if the first attempt partly succeeded?
  • How do you test error paths such as a timeout or malformed input?

Discuss your experience with AI/ML, if applicable.

Medium · Technical / Domain Questions

Approach

  1. Start with a direct statement of what you have done, then name one concrete piece of work: the problem, the data, the model or library, and your own part, with the baseline you compared against and the metric you used.
  2. Cover the engineering around the model: how the data was cleaned and split, how you avoided leakage, how the model was served or called from a service, and how you noticed when its performance drifted.
  3. If your work was detection or classification, mention class imbalance and the different costs of a false positive and a false negative, and why you picked your threshold.
  4. If you have no direct experience, say so and offer the nearest real work: calling a model API from a service, testing nondeterministic output, or a course project you can explain end to end. Bluffing sinks this answer faster than a gap does.
  5. Be able to say when ML was the wrong tool and a rule or query would have done better.

Follow-up

  • How did you evaluate the model against a simple baseline, and what number convinced you?
  • What went wrong in production, or what would have, and how would you monitor for it?
  • Why was ML needed here rather than rules or a database query?

Describe a time when you had to work with a difficult team member.

Medium · Behavioral / Leadership

Approach

  1. Choose a real disagreement with a colleague over how work was done, not a personality clash you could not touch. The story must show what you did, not only what they did wrong.
  2. Set the situation in a few sentences: the shared goal, what the friction was and what it cost the team (missed reviews, rework, slipped dates).
  3. Describe your steps in order: a private conversation to understand their constraints, agreeing on a specific working rule (review turnaround, interface contract, who decides), and involving your manager only after a direct attempt.
  4. End with the observable result and what you changed in your own approach. The mistake that sinks this answer is casting the other person as a villain or ending with nothing resolved.
  5. Keep the language neutral and specific: 'I asked what was blocking him' rather than adjectives about the person.

Follow-up

  • What would you have done if the direct conversation had not changed anything?
  • How did your working relationship look afterward?
  • When would you escalate to a manager, and how would you present it?

How do you prioritize tasks when facing tight deadlines?

Medium · Behavioral / Leadership

Approach

  1. Give your method before the story: list everything due, mark what is blocking others, estimate impact against effort, and separate hard external deadlines from soft ones.
  2. Show the communication step. Tell product management or operations what you will deliver, what you will defer and what the risk is, and get agreement rather than silently dropping work.
  3. Cut scope, not safety. Name the corners you refused to cut (tests on the changed path, a security check, a rollback plan) and the ones you did cut (secondary features, polish).
  4. Use one concrete deadline story with the real numbers: what was due, what shipped, what moved, and what the outcome was.
  5. Mention what you did afterward, such as logging the deferred items so they did not vanish.

Follow-up

  • Two stakeholders each say their task is the urgent one. How do you decide?
  • What do you do when you realize midway that your estimate was wrong?
  • Which corner would you never cut under pressure, and why?

Can you share an experience where you led a project or initiative?

Medium · Behavioral / Leadership

Approach

  1. Pick an initiative where you owned the outcome, even if you had no formal title: a migration, a new service, a testing push or a release. Define its goal and who it served.
  2. Show how you organized it: breaking work into pieces, assigning or volunteering for each, setting up a way to track progress, and keeping stakeholders such as product or operations informed.
  3. Include a decision you made that others could have disputed, and how you reached it, with the alternatives you rejected.
  4. Describe a problem during the project (a blocker, a person falling behind, a scope change) and exactly what you did.
  5. State the result in checkable terms and one thing you would do differently. The sinking mistake is describing a team's achievement with 'we' and never saying what you decided.

Follow-up

  • How did you handle a teammate who fell behind or disagreed with your plan?
  • What did you decide not to do, and how did you decide?
  • How did you report progress to people outside engineering?

What motivates you to do your best work?

Medium · Behavioral / Leadership

Approach

  1. Give a specific, honest answer and prove it with a moment. For an engineer, believable drivers include solving a hard problem, owning something to completion, or seeing users benefit from a fix, each tied to something you did.
  2. Link the driver to the work the role involves: bug fixing, performance work, code review, and building features with product and operations. Show you would find that day-to-day work engaging.
  3. Describe a time when that driver produced your best work and what you did differently because of it.
  4. Name what drains you without sounding negative, and how you manage it, such as asking for a smaller scoped task or pairing with someone.
  5. Avoid generic lines about passion or money. Skip claims about the company's mission unless you have read about it and can say something specific.

Follow-up

  • Tell me about a time your motivation dropped. What did you do?
  • How does your answer apply to maintenance and bug-fix work rather than new features?
  • What kind of work would you not do well in?

How do you handle feedback, both giving and receiving?

Medium · Behavioral / Leadership

Approach

  1. Cover both directions with one example each. For receiving, use real feedback you first disagreed with or found hard, such as a code review comment, and say what you changed in code and in habit.
  2. For giving, show a method: be specific and timely, comment on the code or behavior rather than the person, explain the reason, and suggest an alternative. A code review where you caught a defect works well.
  3. Show how you check understanding: asking questions before defending your work, and confirming the next step.
  4. Include a case where you disagreed with the feedback, how you tested whether it was right, and how you responded respectfully either way.
  5. Avoid claiming you have never received negative feedback, or an example where the 'feedback' was a compliment in disguise.

Follow-up

  • Tell me about feedback you disagreed with. What did you do?
  • Describe giving feedback that landed badly. What did you learn?
  • How does your approach change when you review a senior colleague's code?