Interview guides · Alloy Holdings
Alloy Holdings Software Engineer Interview Guide
Alloy Holdings Software Engineer interview guide: four reported rounds, JavaScript and API coding, banking system design, behavioral prep, 7-day plan.
The 60-second brief
Candidate reports place Alloy Holdings in financial technology and identity: its products support financial and identity decisioning, and its clients range from fintech startups to established banks. As candidates describe the role, a Software Engineer designs, builds and maintains the services and APIs behind that platform, writes tested code, takes part in code reviews, works with Product Managers on requirements and with Engineering Managers on scope, and presents technical demos to the team. Reported day-to-day tasks include debugging the transaction pipeline and tuning graph algorithms, and the services are described as subject to security and compliance requirements. Background candidates list as a plus: fintech, banking or identity verification experience, cloud platforms (AWS or GCP) and containers.
This guide is for candidates interviewing for the Software Engineer position at Alloy Holdings. It covers the four reported rounds, the reported coding, system design and behavioral questions, the JavaScript and API emphasis candidates describe, and a seven-day plan to rehearse all of it. It does not cover other roles at the company.
Candidates report four stages over roughly three to five weeks: Recruiter Screening, Hiring Manager Discussion, Technical Evaluation and an Onsite Interview Loop. The technical stage reportedly varies by team.
Focus areas
- String manipulation
- API design
- Programming language fluency: JavaScript
Overview
The work candidates describe is service and API engineering, with JavaScript or Node.js named as the main ecosystem. Candidates report writing functioning APIs in live coding rather than discussing them theoretically. The reported topics are string manipulation, API design, JavaScript, algorithmic problem solving and explaining your reasoning aloud. Prepare by writing real code in a plain Node project: a rule-driven string formatter, a data-cleaning script, a shortest-path search, and a small JSON endpoint with validation and correct status codes. Candidates also report multi-step problems that start with basic data manipulation and escalate, so after each solution add a second and third requirement and see whether your structure survives.
The reported design questions are a core banking ledger, real-time data ingestion, a distributed API rate limiter, a database schema for an identity verification product, and failure handling and retries across microservices. They share one theme: money and identity records must stay correct when requests are repeated, services fail and traffic spikes. Build your answers around integer amounts in minor units, append-only entries, idempotency keys, an audit trail, bounded retries with backoff, and a stated consistency level for every read and write path. Even without fintech experience, being able to talk about transaction processing and data security in these terms is what makes the designs concrete.
Candidates also describe conversations that are not coding: the recruiter and the Hiring Manager discuss the business model, your past work and your growth, some teams use a take-home that ends in a technical demo, and the onsite includes Product Managers, Engineering Managers and sometimes leadership. Prepare a small set of stories that you can reshape for the reported behavioral prompts (a demo or architecture plan, a disagreement with a Product Manager, speed versus quality, a mid-project pivot) and a list of questions for leadership. Rehearse the demo shape too: problem, architecture, trade-offs, and what you would change.
The Alloy Holdings interview process
Candidates report four stages over about three to five weeks. The technical stage differs by team, so the descriptions below say what each stage can contain rather than a fixed schedule.
Recruiter Screening
Candidates describe the first call as a recruiter conversation covering your work history, the company's business model and how well you fit its culture. Treat it as a content round: arrive able to connect your work to a company whose products support financial and identity decisioning for fintechs and banks, and use it to learn which technical format your team uses.
What to demonstrate
- How your background maps to the Software Engineer role
- Your understanding of the company's business model
- Cultural alignment, as candidates describe the conversation
How to prepare
- Write a short career summary framed around services, APIs and data you owned, ending with why identity and financial decisioning interests you.
- Read what the company sells and to whom, and prepare two questions about the business that a homepage cannot answer.
- Ask which technical format your team uses: a standardized assessment, a take-home with a demo, or live pair programming.
- Be ready to describe your JavaScript or Node.js experience concretely, since candidates report a strong JavaScript emphasis.
Hiring Manager Discussion
Candidates describe a deep-dive conversation with the Hiring Manager about your past experiences, how you can leverage them in the role and your career growth aspirations. Come with two projects you can explain end to end, including the decisions you owned and the trade-offs you accepted.
What to demonstrate
- Your past experiences, as you describe them
- How you can leverage that experience in the role
- Your career growth aspirations
How to prepare
- Pick two projects and write for each the problem, your decision, the alternatives you rejected, and the measurable result.
- Prepare one story about presenting a design or demo and one about changing technical direction mid-project.
- Write three questions about the team's work, how it partners with Product, and how engineers grow there.
- Prepare a direct answer to where you want your skills to be in a year or two, tied to backend and API work.
Technical Evaluation
Candidates report that this stage depends on the team: a standardized assessment (a Byteboard exam is mentioned), a take-home that ends in a technical demo, or a live online pair-programming session. The problems are described as multi-step and escalating, from basic data manipulation to harder algorithmic work. This is where the coding question types are practised: string transformation, data cleaning, graph search and complexity improvement.
What to demonstrate
- Working code on multi-step problems that get harder
- String and data manipulation followed by algorithmic problem solving
- Explaining your reasoning aloud while you code
- For a take-home, presenting your architectural choices in the demo
How to prepare
- Practise in a plain runnable JavaScript file with tests: the string-formatting, data-cleaning and shortest-path questions, adding a new requirement after each solution.
- Build a small endpoint from an empty folder: server, route, JSON validation, 400 and 422 responses, and a mocked body.
- If given a take-home, outline the demo first: problem, diagram, trade-offs, what you would do with more time.
- Narrate aloud while you type, since candidates say interviewers can be quiet during the coding.
Onsite Interview Loop
Candidates describe an onsite or virtual loop with peer engineers, Product Managers, Engineering Managers and sometimes leadership. The reported content is a blend of three formats: coding a working API, system design around banking infrastructure, and behavioral interviews. Prepare each format separately, then run a mixed rehearsal so switching between them feels normal.
What to demonstrate
- Hands-on coding, including a working API
- System design on banking-style systems: ledgers, data flow, secure storage
- Collaboration with Product and Engineering Managers
- Culture fit and how you think beyond your immediate task
How to prepare
- Rehearse aloud the five reported designs: ledger, real-time ingestion, rate limiter, identity verification schema, and retries across microservices.
- Practise the endpoint exercise again with idempotency and error handling added, in the language you will use on the day.
- Prepare the five reported behavioral prompts as stories and a list of questions for leadership.
- Prepare to explain a technical concept such as idempotency or consistency to a non-technical listener in plain words.
Where candidates lose points
Treating the recruiter and Hiring Manager calls as casual and arriving without a view on the business
Candidates report these calls cover the business model, your past work and your growth. Read what the company sells, prepare two project stories with your own decisions in them, and write questions about the team and its clients.
Writing pseudocode or a half-set-up solution when the stage expects a working endpoint
Candidates report building functioning APIs in a live coding environment. Practise from an empty folder until you can start a server, add a route, validate a JSON body, return 400 or 422 with a clear error shape, and exercise it with curl.
Going silent while coding in a pair-programming or assessment stage
Candidates say interviewers can be quiet while you work. Say what you are about to do, state the brute-force approach and its complexity first, test with a small case aloud, and explain each requirement you add as the problem escalates.
Designing the ledger with a mutable balance, floating-point amounts and no answer for duplicate requests
Store amounts as integers in minor units, record append-only entries in one database transaction, derive or reconcile balances from them, and attach an idempotency key to every write so a retry cannot apply twice. Name the consistency you need on reads.
Presenting a take-home or demo as a file-by-file tour with no stated decisions
Open with the problem, show the architecture, name the alternatives you rejected, and finish with what you would change. Rehearse it aloud so a mix of engineers and managers can follow the reasoning.
Questions & practice
Write a function to manipulate a given string into a specific desired output format based on dynamic rules.
Medium · Coding and Algorithms
Approach
- Pin the rules down before coding: are they fixed or supplied at runtime, do they apply in order, and can one rule's output feed the next? I model each rule as an object with a match test and a transform, kept in an ordered array, so adding a rule never touches the loop.
- If rules are independent, one left-to-right pass works: at each position try the rules in order, push the output piece into an array, and join once at the end. The cost is O(n x R x match cost) for R rules tried at each position, and each rule stays testable on its own. If one rule's output must feed the next, a single pass is wrong: run repeated passes, or a pipeline of transforms, and say which you chose.
- Name the JavaScript traps out loud. str.length and indexing count UTF-16 code units, so emoji and other astral characters split in two; I iterate with for...of or Array.from when characters matter. A regex with the g flag keeps lastIndex between .test() calls, and replaceAll with a regex throws a TypeError unless the g flag is set.
- Edge cases to cover with small tests: empty string, input no rule matches, two rules matching at the same position (the first in the list wins, and I state that), leading and trailing whitespace, and mixed case when matching is meant to ignore case.
Follow-up
- A new rule has to be added from a config file without redeploying. How do you validate it and stop it from breaking the existing rules?
- Two rules overlap on the same substring. How do you define precedence, and how would you test it?
- The input becomes a multi-gigabyte stream. What changes if a rule's match can span a chunk boundary?
Implement a graph traversal algorithm to find the shortest path between two nodes in a complex network.
Medium · Coding and Algorithms
Approach
- Ask whether edges are weighted. If not, BFS from the source finds the shortest path in O(V + E). I mark a node visited when it is enqueued, not when it is dequeued, so it is never queued twice, and I keep a parent map so I can rebuild the path by walking back from the target.
- With non-negative weights I use Dijkstra with a binary min-heap, O((V + E) log V). JavaScript has no built-in priority queue, so I write a small heap or push duplicate entries and skip stale ones on pop (lazy deletion). Negative weights rule Dijkstra out: Bellman-Ford handles them in O(V·E) and also reports a negative cycle.
- Build an adjacency list (a Map from node to an array of neighbours) rather than a matrix. A sparse network makes a V×V matrix waste memory and turns each neighbour scan into O(V).
- Edge cases: source equals target (a path of length zero), target unreachable (return null or an empty path, and say which), node ids missing from the graph, and cycles, which the visited set already handles.
- For a large graph where only one pair matters, bidirectional BFS searches from both ends and stops when the two frontiers meet, which usually expands far fewer nodes than a one-sided search.
Follow-up
- The network is a directed graph of transactions. How would you detect a cycle in it, and return the cycle itself?
- How does your solution change if edge weights can change while queries are running?
- What would you do if the graph were too large to fit in one machine's memory?
Given a raw dataset, write a script to clean, parse, and restructure the data efficiently.
Medium · Coding and Algorithms
Approach
- Write down the target shape first: every output field, its type, and the rule that fills it (trim, case, date format, default when missing). Then the parsing code has a fixed contract to meet.
- Stream instead of loading the whole file, and treat the formats separately. For line-delimited data such as JSONL, I read it with readline over fs.createReadStream, so memory follows the record size, not the file size. For CSV, I pipe the stream into a streaming parser such as csv-parse instead of splitting lines or on commas, because reading line by line would cut a quoted field that contains a line break in two.
- Normalise each value on its way in: dates to ISO 8601, and money to integer minor units (cents) instead of floats, since 0.1 + 0.2 !== 0.3 in IEEE 754 doubles. Restructure with a Map keyed by the grouping field, so grouping and de-duplication stay O(n) expected time.
- Never drop a bad row silently. Send it to a rejects output with the line number and the reason, and print rows read, rows written and rows rejected per reason, so the totals can be reconciled.
- Make a rerun safe by writing to a new output and swapping it in at the end, or by upserting on a natural key, so a crash halfway never leaves duplicated or half-written data.
Follow-up
- Two rows describe the same entity with conflicting values. Which one wins, and how do you make that rule visible?
- The file grows to 50 GB and the grouping no longer fits in memory. What do you change?
- How would you unit-test the cleaning rules separately from the file input and output?
How would you optimize a block of code that is currently running in O(n^2) time to run in O(n log n) time?
Medium · Coding and Algorithms
Approach
- Find out what the inner loop is doing for each element of the outer loop. Usually it is a search (a partner, a nearest value, a count of smaller elements), and that search is the part to make logarithmic.
- Sort first, in O(n log n), then replace the inner loop. Two pointers over the sorted array handle pair sums and difference windows in O(n). A binary search per element gives n × O(log n). A sweep over intervals sorted by start finds overlaps in one pass.
- For counting questions, such as how many earlier elements are smaller, use merge-sort inversion counting, or a Fenwick tree over coordinate-compressed values. Both are O(n log n).
- If only equality matters, say that a hash map gives O(n) expected time, which beats the target, and mention its worst case and memory cost.
- In JavaScript, call arr.sort((a, b) => a - b). The default sort compares elements as strings, so [10, 9, 1] sorts to [1, 10, 9]. Then check the fast version against the brute-force one on random inputs before trusting it.
Follow-up
- Can this particular problem be solved in O(n)? What would that cost in memory?
- Sorting destroys the original order. How do you report results in terms of the original indices?
- At what input size is the O(n^2) version actually fine, and how would you check that with measurements?
Walk me through how you would structure the database schema for a new identity verification product.
Medium · System Design and Architecture
Approach
- Start from the core entities: applicant (person data), verification_request (tenant id, applicant id, status, timestamps), check (one row per check run, with type, vendor, outcome and score), document (type plus a reference to an encrypted object in storage, not a blob in the row), and decision (outcome, reason codes, rule version).
- Model status as a state machine with an enum column, plus an append-only status-history or audit table. Then the question of who changed what, and when, is a query, not a log search.
- Treat PII on purpose. Encrypt fields like national id and date of birth at the application layer. Store a keyed HMAC of an identifier for exact-match lookups without decrypting. Restrict access to those columns, and attach a retention or deletion policy to every table that holds personal data.
- Put the tenant id on every row, with composite indexes such as (tenant_id, created_at) and (tenant_id, status). A unique constraint on (tenant_id, external_reference) makes create requests idempotent.
- Keep fields you query or filter on as typed columns, and store raw vendor responses as JSONB. Vendor formats vary and change, but the normalised outcome has to stay queryable.
Follow-up
- A user asks for their data to be deleted, but audit records must be kept. How does the schema handle both?
- The same person applies through two different clients. Do you link the records, and what are the privacy implications?
- A new check type with different result fields is added. What changes in the schema?
Replace offset paging on the resource feed with keyset
Easy · keyset pagination · composite index · sort order
resource holds resource_id, tenant_id, owner_user_id, title, body_ref, version, status ('draft','active','archived','deleted'), created_at, updated_at, deleted_at, with an index on (tenant_id, status, updated_at DESC, resource_id DESC). The listing endpoint returns active resources for one tenant, newest update first, 50 per page, today with LIMIT 50 OFFSET n. Tenants reach page 400 and rows are created while they read. Write the keyset query, define what the cursor carries and how it is encoded, and say which part of the index each predicate uses. Assume PostgreSQL 16.
Approach
- Name the two failures separately. OFFSET 20000 makes the server produce and discard 20,000 rows, so page cost grows with depth rather than with page size. Independently, any write that changes how many rows sort above the offset moves the window between two fetches, and the direction decides which anomaly you get: an insert lands at the head of updated_at DESC and pushes already-returned rows down past the boundary, so they are returned a second time; a delete above the offset, or a row whose updated_at is bumped above the cursor, pulls rows up and one is never returned at all. Nothing in the response reveals either.
- Write the seek: WHERE tenant_id = $1 AND status = 'active' AND (updated_at, resource_id) < ($2, $3) ORDER BY updated_at DESC, resource_id DESC LIMIT 50. The row-value comparison is one index range rather than a disjunction, and both columns are NOT NULL, which is what makes that comparison well defined.
- Map each predicate onto the index: tenant_id and status are equality on the leading columns, (updated_at, resource_id) is the range, and the ORDER BY matches the index order so no Sort node appears and the scan stops after 50 rows. The DESC in the definition only matters for mixed directions — a plain ascending btree on the same columns is read backwards for this query.
- Put both sort columns in the cursor and nothing the client can tamper with into another tenant: base64 of (updated_at, resource_id), validated server-side, with tenant_id taken from the principal.
Follow-up
- The client asks for 'jump to page 400'. What do you offer instead, and what does the honest version cost?
- Sort order becomes user-selectable across four columns. How many indexes is that, and which would you refuse to add?
Write a functioning API endpoint in code that accepts a JSON payload, validates the input, and returns a mocke
Medium · Coding and Algorithms
Write a functioning API endpoint in code that accepts a JSON payload, validates the input, and returns a mocked response.
Approach
- Write the contract before the handler: method and path, the required and optional fields with their types and ranges, what happens to unknown fields, and the status codes. For example: 201 with the mocked body, and 400 for malformed JSON or failed validation (or 422 for validation, if I state it).
- In Node with Express, mount express.json(). Its default body limit is 100kb, and larger bodies get a 413. It skips bodies whose Content-Type is not JSON instead of rejecting them, so req.body stays empty. Returning 415 needs an explicit req.is('application/json') check before validation. Add an error middleware that turns the parser's SyntaxError into a 400 with a JSON error, not an HTML stack trace.
- Validate in a pure function that is separate from the route, using a schema library (zod, Joi or Ajv) or plain code. Check that the body is an object and not an array or null. Collect every field error into a list like [{field, message}] instead of stopping at the first one.
- Return the mocked response from a small service function behind the handler. Later a real data store can replace it without touching validation or routing.
- Test with supertest: a valid payload, each missing field, wrong types (a number sent as a string), an empty body, malformed JSON, and an oversized body.
Follow-up
- The client retries after a timeout. How do you make sure a POST is not applied twice?
- How would you version this endpoint once a field becomes required?
- Where would authentication and per-client limits go in this code?
Design a core banking ledger system that ensures data consistency and high availability.
Medium · System Design and Architecture
Approach
- Use double-entry bookkeeping. Every transaction writes two or more entries that sum to zero, and each entry carries an account, an amount in integer minor units and a currency. Entries are append-only, so a mistake is fixed with a reversing entry, never an UPDATE.
- Post each transaction inside a single ACID database transaction. Lock the affected account rows with SELECT ... FOR UPDATE, always in a fixed order (for example by account id) so two transfers cannot deadlock, and check sufficient funds inside the same transaction.
- Put a unique constraint on a client-supplied idempotency key, so a retried request returns the original result instead of posting twice.
- Store a cached balance with a version column next to the entries, and run a job that checks the cached balance against the sum of entries. Balance checks that guard a debit read from the primary, because replicas may lag.
- For availability, run a primary with a synchronous standby so a committed write survives failover. If I shard by account, a transfer across shards needs two-phase commit or a saga with pending entries and compensation, and I would name that cost.
Follow-up
- One account, such as a fee account, takes a write on almost every transaction. How do you remove that lock contention?
- How do you reconcile the ledger against an external bank statement?
- The primary fails mid-transaction. What does the client see, and what is the state after failover?
How would you architect a solution for a client scenario requiring real-time data ingestion and processing?
Medium · System Design and Architecture
Approach
- Clarify the numbers first: events per second at peak, acceptable end-to-end latency, whether per-entity ordering matters, and whether a duplicate or a lost event is worse. The design follows from these answers.
- Put a thin ingest API in front of a durable, partitioned log (Kafka or Kinesis, for example). Partition by entity or client id, which keeps per-key order and lets consumers scale up to the partition count. The log also absorbs bursts while consumers catch up.
- Stream processors in consumer groups validate, enrich and aggregate the events. Delivery is at-least-once, so sinks are idempotent (upsert by event id), and that gives effectively-once results. Records that fail parsing go to a dead-letter topic with the error.
- Handle time explicitly. Windowed aggregates use event time with a watermark and an allowed-lateness policy, so late events are counted or reported rather than silently misplaced.
- Keep the raw events in cheap object storage for replay after a bug, register schemas so producers cannot break consumers, and monitor consumer lag as the main health signal.
Follow-up
- A consumer falls hours behind. How do you notice, and how do you catch up without overloading the downstream store?
- A bug wrote wrong aggregates for a day. How do you reprocess that day?
- The client now needs exactly-once results. What would you change, and what does it cost?
Design an API rate limiter for a distributed system.
Medium · System Design and Architecture
Approach
- Compare the algorithms and pick one. A fixed-window counter is cheap but lets up to twice the limit through around a window boundary. A sliding-window log is exact but stores one timestamp per request. A sliding-window counter weights the previous window to approximate. A token bucket (capacity b, refill rate r) allows bursts up to b while holding the long-run rate at r.
- Distributed state: keep the counters in a shared store such as Redis, keyed by API key plus route. Update them atomically, with INCR and EXPIRE inside a Lua script or a token-bucket Lua script, so concurrent gateway nodes cannot both read 'under the limit' and both pass.
- Response: return 429 Too Many Requests with a Retry-After header, plus remaining-quota headers so clients can slow down before they hit the limit.
- Failure mode: decide whether the limiter fails open or closed when Redis is unreachable. A local in-memory bucket per node, sized at the limit divided by the node count, is a reasonable fallback. Use the Redis server's clock rather than each node's, to avoid clock-skew errors.
- Scale: shard the counters across a Redis cluster by key, keep the check to one round trip on the request path, and load per-tier limits from config.
Follow-up
- Different customers pay for different limits, and some limits are per day. How does the key and storage design change?
- Redis is down for ten minutes. What happens to traffic, and what would you alert on?
- How would you enforce one global limit across several regions without a cross-region call on every request?
How do you handle failure and retries in a microservices architecture?
Medium · System Design and Architecture
Approach
- Classify failures first. Timeouts, connection resets, 503 and 429 are worth retrying. A 400 or a validation error is not, because the same request will fail again. Give every outbound call a timeout, and pass a deadline budget downstream so inner calls do not outlive the caller.
- Retry with capped exponential backoff and jitter, for example a sleep of random(0, min(cap, base × 2^attempt)), so clients that failed together do not retry together. Limit the number of attempts and honour Retry-After when it is present.
- Only retry operations that are safe to repeat. GET and PUT are idempotent by HTTP semantics, but POST is not, so a create or payment call carries an idempotency key that the server stores along with its response.
- Retry at one layer only. If three layers each make up to four attempts, the bottom service can see 4 × 4 × 4 = 64 calls for one user request. Add a circuit breaker (closed, open, half-open) so a failing dependency gets fast failures instead of more load.
- For work that crosses services, use the transactional outbox pattern so a database write and its event publish commit together. Use a saga with compensating actions instead of a distributed lock, and send messages that keep failing to a dead-letter queue for inspection.
Follow-up
- A call to a payment provider timed out. How do you find out whether the charge happened before you retry?
- A dependency comes back after an outage and immediately falls over again. What caused that, and how do you prevent it?
- How would you test the retry and circuit-breaker behaviour before production?
Exports duplicate a row range about once a week
Hard · leases · clock skew · idempotency
Roughly once a week an export writes a file containing a duplicated range of rows. The affected job_run rows show attempt = 1, status = succeeded, one started_at, and a lease_owner naming a different host from the one whose logs show the job starting. Leases last 30 seconds and are heartbeated every 10 from inside the handler; lease_expires_at is computed on the worker and compared against the database's now(). Find the mechanism, and give a fix that holds even if you cannot fix the clocks.
Approach
- Start from the fact that eliminates the obvious answer. attempt = 1 means no retry was recorded, so this is not a re-run after failure; two workers ran the same row concurrently and the takeover path never touched the counter. lease_owner naming a host other than the one that started the job is the same statement from the other side.
- Enumerate the mechanisms that cause a premature takeover, then find the signal that separates them. Either the lease genuinely expired because the heartbeat did not fire, which is what happens when the heartbeat runs on the handler's own thread and the handler makes a long blocking call, or it only appeared expired because two clocks disagree, since lease_expires_at is written from the worker's clock and evaluated against the database's. The discriminator is the distribution: incidents clustered on the longest exports indict the heartbeat, incidents clustered on one host indict skew. Measure both, and measure each host's offset against the database directly.
- Read the reclaim query precisely. In PostgreSQL now() is transaction start time, not statement time, so a reclaimer holding a long transaction compares against an older timestamp than expected; clock_timestamp() is the statement-time function. This is worth ruling in or out before you redesign anything, because it changes which rows look expired.
- Remove the second clock rather than trying to synchronise it. Issue and extend the lease in the database, with lease_expires_at = now() + interval '30 seconds' in both the claim and the heartbeat, so exactly one clock is ever compared and worker skew stops mattering to this predicate.
Follow-up
- The displaced worker has already streamed half the file to object storage. What makes that side effect safe to repeat?
- You now count takeovers. What alert fires on that counter, and at what threshold?
Suggested practice checklist
The plan starts with the loop and a runnable JavaScript setup, then covers the reported coding questions, API building, the five reported designs and behavioral stories. Candidates list AWS or GCP and containers as nice-to-haves, so the design days map each system to managed services.
Day 1 — Map the loop and set up a runnable Node project
- Write the four reported rounds in order, note what each can contain, and mark the technical format you still need to ask the recruiter about.
- Create a blank Node.js project with a test runner and a minimal HTTP server so any exercise can start from it.
- Write your two project stories and your opening career summary in bullet form.
Deliverable: A one-page loop map, a Node project that starts and runs one passing test, and bullet notes for two project stories and a career summary.
Day 2 — String manipulation and data cleaning in JavaScript
- Write the rule-driven string formatter with rules held as data, then add a rule type after the first version works.
- Write the cleaning script: parse messy transaction-style lines into structured JSON, handling blank fields, quoted separators, odd whitespace and duplicate rows.
- Add tests for malformed input and state the time and memory cost of each function.
Deliverable: Two tested JavaScript functions (formatter and cleaner) with a list of the edge cases each test covers.
Day 3 — Graph search and complexity improvement
- Implement shortest path with breadth-first search over an adjacency Map, then switch to Dijkstra with a heap for weighted edges.
- Write cycle detection on a directed graph of transfers, using visiting and done states, and return the cycle found.
- Take an O(n^2) pair-matching loop and rewrite it as O(n log n) with sorting and two pointers, then as O(n) with a hash map, and state the trade-off.
Deliverable: Three tested graph and complexity solutions, each with a one-sentence statement of its time and space cost.
Day 4 — Build the JSON endpoint, drill async JavaScript, then page it
- Write a POST endpoint that validates a JSON payload, returns 400 or 422 with a consistent error shape, and returns a mocked response.
- Handle async errors correctly: Express 4 does not catch a rejected promise from an async handler, so wrap handlers or call next(err), while Express 5 forwards rejections automatically. Add an idempotency key so a repeated request returns the first result.
- Drill JavaScript async behaviour: predict the order of microtasks and macrotasks (promise callbacks against setTimeout), and compare Promise.all with Promise.allSettled on a mix of passing and failing calls.
Deliverable: A running endpoint with a list of curl requests and expected status codes, a short async-ordering write-up, and a completed keyset paging exercise.
Day 5 — Ledger and identity verification schema
- Outline the banking ledger: accounts, append-only entries, double-entry transfers inside one transaction, idempotency keys, reconciliation and replicas for reads.
- Write the table definitions for an identity verification product: applicants, verification requests, check results, decisions and an audit log, with PII handling noted.
- Say aloud where each design is consistent, where it may be stale, and what happens when the primary fails.
- Note how the ledger and the schema would sit on a managed database on AWS or GCP, and where the endpoint from day 4 would run as a container.
Deliverable: A ledger design sheet and table definitions for the identity schema, each with its consistency choices and a managed-service mapping written out.
Day 6 — Ingestion, rate limiting and retries
- Design the rate limiter: token bucket, per-client keys, shared counters in Redis with an atomic script, and behaviour when the store is unreachable.
- Design real-time ingestion: producers, a partitioned queue (a managed queue service on AWS or GCP is one option), consumers that deduplicate, a dead-letter queue and backpressure.
- Write a retry policy: which errors retry, exponential backoff with jitter, a retry budget, timeouts and a circuit breaker.
Deliverable: Three design outlines (rate limiter, ingestion, retries) and a retry policy table, plus a completed duplicate-rows exercise.
Day 7 — Behavioral stories, demo and questions for leadership
- Write the demo story, the Product Manager disagreement, the speed-versus-quality criteria and the mid-project pivot in the same structure, then say each aloud.
- Rehearse a short demo of one of your own projects: problem, diagram, trade-offs and what you would change.
- Write four to six questions for leadership, tied to what you learned in earlier conversations.
Deliverable: Four rehearsed stories, a recorded or spoken demo run-through, and a final list of questions for leadership.
Behavioural preparation
Candidates report behavioral conversations with Product Managers, Engineering Managers and sometimes leadership, centred on presenting technical work, disagreeing on implementation, balancing speed with quality and changing direction. For a Software Engineer building APIs, the stories need to show the decision you owned, the trade-off you accepted and how you brought non-engineers along. Prepare each prompt as a story with a clear outcome.
- Describe a situation where you had to present a complex technical concept to a non-technical stakeholder.
Tell me about a time you had to present a technical demo or architecture plan to your team.
Medium · Behavioral and Leadership
Approach
- Choose a presentation tied to a real decision, such as an architecture plan, a design review or a demo of a feature, where you owned the content. Name the audience and what you needed from them, for example approval of an approach or agreement on scope.
- Structure it as problem, options considered with their costs, chosen design with a diagram, a demo of the working path, and the open risks. The reasoning and rejected options are the substance; the feature description is only context.
- Show that you adapted to the audience: a sequence diagram and failure modes for engineers, impact and timeline for Product Managers. Say what you cut and why.
- Close with the outcome: the decision made, the change you made after feedback, and what you would restructure next time. This shape also works for a take-home demo.
- The story sinks if it is a line-by-line code walkthrough, or if the audience's reaction and your response to it are missing.
Follow-up
- Which objection from the room changed your plan, and what did you change?
- How did you decide what to leave out of the presentation?
- How would the same presentation differ for an audience of only Product Managers?
Describe a situation where you disagreed with a Product Manager on a feature's technical implementation.
Medium · Behavioral and Leadership
Approach
- Pick a disagreement where you understood the Product Manager's goal and state it fairly first, such as a launch date or a customer commitment, before giving your technical concern.
- Make the concern concrete: for example a synchronous call in the request path, a schema change that is hard to reverse, or a missing retry path. Explain the consequence in terms the Product Manager could weigh.
- Describe the evidence you used: a small prototype, a load estimate, a past incident, or a comparison of options with cost and risk for each.
- Offer a way forward that serves both goals, such as a reduced scope, a feature flag, or a staged rollout, and say what was decided and who decided it.
- Be honest about the outcome, including any part where you were wrong or compromised. A story where you simply won, or where the Product Manager is the villain, does not show collaboration.
Follow-up
- What would you have done if the Product Manager still disagreed after seeing the evidence?
- Tell me about a time the Product Manager was right and you changed your position.
- How did you present the cost of your approach so the trade-off was clear to a non-engineer?
How do you evaluate the trade-offs between shipping code quickly and maintaining technical excellence?
Medium · Behavioral and Leadership
Approach
- Answer with criteria rather than a slogan. Ask how reversible the change is, how large the blast radius is, whether it touches money, identity or personal data, what delay costs the customer, and whether the debt can be tracked and repaid.
- Describe concrete mechanisms: ship a thin vertical slice, keep tests on the critical path such as amount calculations and authorisation, hide unfinished work behind a flag, and log every shortcut as a ticket with a trigger for repaying it.
- Say where you set a higher bar: code that moves money, stores identity data or cannot be rolled back deserves more review and tests than an internal tool or a copy change.
- Back it with a real example of a shortcut you took knowingly, how you contained it, and when and how it was repaid.
- Avoid answering that it depends without saying on what, and avoid claiming you always choose quality or always choose speed.
Follow-up
- Tell me about technical debt you took on knowingly and what happened to it.
- How do you persuade a team to schedule debt repayment when the roadmap is full?
- What is something you would never compromise on, even under a deadline?
What questions do you have for leadership regarding the future direction of the organization?
Medium · Behavioral and Leadership
Approach
- Treat this as a prepared list of questions, not a story. Bring four to six, grouped by theme, and write them before the loop so they are specific to what you have learned in earlier conversations.
- Ask about direction in a way that shows engineering judgment: how the team balances client-specific requests against platform reliability, what the next year of the product looks like, and how architecture decisions are made when Product and Engineering disagree.
- Ask about the work itself: how a client scenario becomes a technical design, how incidents in the transaction pipeline are handled and reviewed, and what the first project for this role would be.
- Ask about the environment: how success in the role is measured, and how the team works day to day.
- Avoid questions the website answers and avoid opening with pay or perks. Do not ask all of them: pick the ones the conversation has not already covered.
Follow-up
- What would a different answer to that question change about your decision?
- What would you want to be true about this team a year after joining?
- What concerns do you still have about joining that we have not discussed?
Tell me about a time you had to pivot your technical approach halfway through a project.
Medium · Behavioral and Leadership
Approach
- Pick a project where you chose the original approach for sound reasons, then found out it would not work. Say what the plan was and why it was reasonable at the time.
- Name the signal that changed your mind: a failed load test, a measured bottleneck, a requirement change or an assumption that proved false. Explain how you confirmed it before abandoning the work.
- Describe the decision point: the options (fix, patch, replace, reduce scope), how you treated the sunk cost, and what you salvaged from the first attempt.
- Show communication: who you told, how you reset the timeline and expectations, and what the outcome was in concrete terms.
- Finish with the lesson as a changed practice, such as an earlier prototype or a load test before committing. The story sinks if the pivot was someone else's mistake or if nothing was lost.
Follow-up
- How did you decide the original approach could not be rescued rather than fixed?
- How did you tell stakeholders about the change and the new timeline?
- What check would have caught the problem sooner?