Acuity Analytics · Software Engineer
Updated · 2026-10-02

Acuity Analytics Software Engineer
Interview Guide

THE 60-SECOND BRIEF

Acuity Analytics builds software for survey programming and data analysis that it delivers to clients. Candidates describe a Software Engineer role spent writing, reviewing and deploying code for the survey programming work. That includes the Decipher ecosystem, where survey requirements are turned into interactive web experiences for clients. The stack candidates report is C# on the server and React in the browser. Candidates describe code reviews and regular work with product managers to refine requirements.

This guide is for candidates interviewing for the Software Engineer role at Acuity Analytics, including postings that carry the "Analyst - Decipher (Survey Programmer)" focus that candidates mention. It covers the five reported technical questions (React state, the C# class-versus-interface distinction, dependency injection, React performance and React lifecycle methods). It also covers the fundamentals candidates list alongside them: OOP, data structures, algorithmic complexity, memory management, C# async/await and threading, and API data fetching. Finally, it covers how to talk about survey-driven work and past projects.

Candidates report a sequence that starts with an initial technical screening and ends with a final assessment. Along the way there are technical screenings, deep dives into past projects and live coding problems. No round count or durations have been reported.

OOP ConceptsReactC#

32 min read

Browse Software Engineer questions

See the practice prompts

14Practice promptsAcross five skill areas

The reported questions are all framework and language fundamentals rather than puzzles. Two are about how React holds state and runs component code over time, two are about C# design (interfaces and dependency injection), and one is about React performance. Candidates also cite two example scenarios: speeding up a slow-loading data grid in React, and tracking down a memory leak in a C# application. Together they point to a full-stack web role where you need to explain why a pattern works, not just name it.

The listed requirements are C# and React, OOP principles, and data structures and algorithms. Survey programming tools, cloud deployments and SQL are listed as nice to have. Candidates also mention memory management and algorithmic complexity as theory that gets covered, and C# async/await and threading as a topic to be ready for. So plan two kinds of practice: spoken explanations of language and framework mechanics (hooks, the class lifecycle, async/await, DI lifetimes, interface rules) and live coding in C# where you state the complexity of what you wrote.

Some postings under this title carry a Decipher survey-programmer focus. Prepare one or two examples that link your engineering work to survey-style problems: long multi-page forms, conditional skip logic, validation of answers, and moving response data from a web front end into storage and analysis. A React survey form backed by a small C# API covers most of the reported topics in one project you can talk about.

The deep-dive sessions candidates describe centre on past projects, so pick two projects you can explain end to end. For each, know the architecture, why you chose it, one bug you diagnosed and one trade-off you would revisit. The listed soft skills include explaining technical decisions to non-technical stakeholders, so practise a plain-language version of each project.

01

Preparation focus

editorial

Candidates report a process that runs from an initial technical screening to a final assessment. It mixes technical screenings, deep-dive conversations about past projects and live coding problems. The reported technical questions cover React (state management, performance, lifecycle methods) and C# (classes versus interfaces, dependency injection), with OOP and software fundamentals alongside. The reported preparation advice is to be comfortable writing basic code on a whiteboard or in a shared editor. Prepare in three layers: spoken explanations of the five reported questions, live C# coding on data-structure problems where you state the complexity, and two past projects you can walk through in depth. Ask your recruiter early whether your posting carries the Decipher survey-programmer focus, because that changes which project examples you lead with.

What to demonstrate

  • Working knowledge of C# and React as shown in the reported framework questions
  • OOP principles and software fundamentals such as data structures, complexity and memory management
  • Working code in the live coding problems candidates report
  • Your ability to explain the design choices in your past projects

How to prepare

  • Give each of the five reported React and C# questions out loud, with one code example per answer
  • Solve two data-structure problems in C# in a plain shared editor without autocomplete, and state the time and space complexity
  • Build or revisit a small React form backed by a C# API, so you have a concrete project for the state, data-fetching and DI questions
  • Write a story about diagnosing a C# memory leak and an outline of how you would speed up a slow React data grid, since candidates cite both scenarios
PracHub preparation framework ↗

PracHub editorial advice for the preparation topics above.

01

Answering the lifecycle question with only class methods or only hooks, and not mapping one to the other

Learn the three phases (mount, update, unmount) plus error boundaries. For each class method, know its hook equivalent and the one place the mapping fails, such as effects running after paint or error boundaries still needing a class. Practise drawing the table from memory.

02

Saying interfaces cannot contain any implementation, then having no answer about abstract classes

Update your C# model: default interface methods since C# 8, static abstract members since C# 11, single class inheritance versus multiple interface implementation. Prepare one concrete pair, an interface with two implementations, that you can also reuse for the dependency injection question.

03

Listing React.memo and useMemo for the performance question without saying how you found the bottleneck

Open every performance answer with measurement (Profiler, Performance panel) and a diagnosis: is it load, render or data? For the slow data grid, have virtualisation, server-side paging and sorting, and deferred filter input ready, along with how you would confirm the fix.

04

Preparing only React and C# trivia and stalling on the live coding or fundamentals

Candidates report that data structures, algorithmic complexity and memory management are covered too. Write solutions to array, hash map, interval and graph-traversal problems in C# without IDE help, and state the Big-O after every solution. Be ready to explain the garbage collector, IDisposable and why a lingering event subscription keeps an object alive.

05

Having no answer when a Decipher or survey-programming posting asks how your work relates to surveys

Confirm with your recruiter whether your posting carries the survey-programmer focus. Either way, prepare one example covering form state, conditional skip logic, answer validation and getting response data to the server reliably, so you can connect your engineering work to survey data collection.

Choose a category, try a prompt, then open its approach, worked solution or follow-up when you need it.

11 technical prompts0 include a worked solution

Canonicalise a request body into a stable idempotency fingerprint

medium
parsingcanonicalisationhashing

idempotency_key.request_fingerprint is a SHA-256 over the method, path and canonicalised body, and a retry whose fingerprint differs must be rejected with 422 rather than served the stored response. Write the canonicaliser. Bodies are JSON up to 256 KB nested at most 32 levels; clients vary key order, whitespace and unicode escaping, and some send 64-bit ids as JSON numbers. Produce a deterministic byte string such that semantically identical bodies match and any semantic difference does not. State your complexity and name two normalisations you refuse to perform.

Approach
  1. Parse once into a tree, then re-serialise under fixed rules: object keys sorted, array order preserved, one escaping convention, no insignificant whitespace. Parsing is O(n) and sorting keys is O(k log k) per object, so O(n log n) overall with O(depth) stack, and the 32-level cap is enforced during parsing because hostile nesting is how a canonicaliser becomes a stack overflow.
  2. Sort keys by their UTF-8 bytes and say why the obvious implementation is wrong in some runtimes: a default string comparison that orders by UTF-16 code units places surrogate pairs, meaning code points from U+10000 up, below U+E000 to U+FFFF, which is not UTF-8 byte order, so two services written in different languages disagree on the same document.
  3. Do not re-encode numbers through a double. IEEE-754 binary64 represents integers exactly only up to 2^53, so normalising a 19-digit id through a float changes it, and 1 against 1.0 cannot be reconciled without deciding whether they are the same value. Preserve the literal token, and require ids as strings at the API boundary if you want them comparable.
  4. Reject duplicate keys rather than picking one. JSON permits them and parsers disagree, most keeping the last, so any choice you make ties the fingerprint to a parser detail that the code handling the request does not necessarily share.
Follow-up
  • A client sends the same logical request with an extra field your API ignores. Same key, different fingerprint, so you return 422. Is that the right answer?
  • Where does the fingerprint get computed relative to request decompression and the body-size limit?

Archive a resource graph without breaking live references or recursing

medium
graph traversaltopological ordertenant isolation

Resources reference other resources within a tenant; for the largest tenant the reference table holds up to 2,000,000 nodes and 8,000,000 edges. Archiving a resource must archive everything reachable from it that nothing outside the set still references, refuse when a live external referrer exists, and terminate when references form cycles, which they legitimately do. Produce the archive order and the refusal list, targeting O(V+E). Say what stops the traversal crossing a tenant boundary, and why recursion is the wrong control structure at this size.

Approach
  1. Load the subgraph with the tenant predicate on both endpoints of the edge, not only on the side you started from. Scoping the left table alone is the classic cross-tenant leak: one mis-entered edge then pulls another tenant's resources into the traversal and, worse, into the archive.
  2. Traverse iteratively with an explicit stack. A 2,000,000-node graph can hold a chain deep enough to exhaust a native stack in the low tens of thousands of frames, and that failure is a process crash rather than an error you can return.
  3. Treat cycles as data rather than corruption: compute strongly connected components with Tarjan in O(V+E) using its own explicit stack, then condense. The condensation is a DAG, so a topological order over it gives the archive order, and every member of a component archives in one transaction because no order within a cycle is valid.
  4. Decide refusals with reverse edges. A candidate is archivable only if every in-edge originates inside the candidate set, so build the transpose or count in-degrees restricted to the visited set, and emit each blocked resource with the id of the external referrer, which is the only part of the answer an operator can act on.
Follow-up
  • The graph is read in one query and the archive writes a minute later. What can change in between, and how do you make the write safe?
  • The candidate set is 400,000 resources. Is that one transaction, and if not, what does a half-finished archive look like to a reader?

Find overlapping job attempts and peak concurrency from lease records

medium
sweep lineintervalsleases

A day of job_run history yields about 50,000,000 attempt records: (job_run_id, job_type, attempt, started_at, finished_at which is NULL when the worker died, lease_expires_at). Leases expire on a clock, so a job that outran its lease ran twice. Produce (a) every job_run_id whose attempts overlapped in wall-clock time and (b) the peak number of simultaneously running attempts per job_type with the minute it occurred. Target O(n log n). State how you treat a NULL finished_at and what clock skew does to your answer.

Approach
  1. Define the interval before sorting anything: an attempt occupies [started_at, COALESCE(finished_at, lease_expires_at)). finished_at is observed and lease_expires_at is only a promise, so every attempt without a finish contributes an estimate and the whole result is a lower bound on overlap rather than an exact count.
  2. For peak concurrency, sweep: emit 2n endpoints, sort by (timestamp, kind) with ends ordered before starts at equal timestamps, then walk the sequence maintaining a counter per job_type and record each type's maximum with its timestamp. O(n log n) dominated by the sort, O(n) space, or O(1) extra if the sort is external and the walk streams.
  3. For overlap detection, do not compare attempts pairwise. A single global sort by (job_run_id, started_at) gives both the grouping and the order; within a group, keep the maximum end seen so far and report an overlap exactly when the next start is less than that running maximum, which is one linear pass after the sort.
  4. Half-open intervals matter and are easy to get wrong: with closed intervals an attempt ending at the same millisecond another begins reads as concurrency two, and across 50,000,000 records that artefact swamps the real signal.
Follow-up
  • A handler is not idempotent and you have found 400 overlapping jobs. Which of them actually caused damage, and what would you query to find out?
  • Peak concurrency for one job_type is 4 against a configured cap of 4. Is the cap working, or is the data hiding attempts that never started?

Each day takes one of the topic areas candidates report (C# and OOP, dependency injection and async, React state and lifecycle, React performance, live coding, survey programming, project deep dives) and practises the reported questions that belong to it.

Small steps. Visible outcomes.0 / 7 completed
ONE WEEK · YOUR PACE

Prepare, practise & reflect

One practical outcome each day. Spend longer where you need it.

0 / 7 done
01C# types and OOP fundamentals
  • Write and speak a short answer on class versus interface in C#, covering single inheritance, multiple interfaces, default interface methods and abstract classes
  • Code an IAnswerValidator interface with two implementations and one abstract base class, and note where each choice fits
  • Write one-sentence definitions with a C# example for encapsulation, inheritance, polymorphism and abstraction

Deliverable: A recorded class-versus-interface answer, a compiling validator example with an abstract base, and a one-page OOP definitions sheet.

Practice prompt ↗
02Dependency injection, async/await and memory in C#
  • Wire the Day 1 validators into a small console app or ASP.NET Core API through constructor injection, and write one unit test that injects a fake
  • Write examples of the transient, scoped and singleton lifetimes and of a captive dependency, then explain out loud why the captive one is a bug
  • Write a C# async note with code: what await compiles to (a state machine that frees the thread during I/O), why .Result or .Wait() can deadlock under a UI or classic ASP.NET synchronization context, why async void belongs only in event handlers, Task.Run for CPU-bound work versus await for I/O, ConfigureAwait(false) in library code, and passing a CancellationToken
  • Write a STAR story about troubleshooting a C# memory leak (or a performance bug if you have no leak story): the symptom, the tool (dotMemory, Visual Studio diagnostics, dotnet-counters), the cause and the fix

Deliverable: A DI-wired project with one passing test using a fake, a lifetimes note with the captive-dependency example, an async note with a deadlock example and a cancellable call, and a written memory-leak story.

Practice prompt ↗
03React state and the component lifecycle
  • Build a three-page survey form in React using useReducer, with answers keyed by question id and skip logic derived during render
  • Rewrite one component as a class and mark which lifecycle method matches each hook in your function version
  • Answer the state-management and lifecycle questions out loud, each with one example from the form

Deliverable: A working React survey form, a class-to-hooks mapping table, and two recorded spoken answers.

Practice prompt ↗Practice prompt ↗
04React performance and the slow data grid
  • Render 10,000 rows in a table, profile it with React DevTools, then add virtualisation and memoised rows and profile again
  • Add a debounced filter and code-split the grid route with React.lazy, then measure the bundle before and after
  • Write a five-step outline for speeding up a slow-loading data grid: measure, classify, fix render, fix data, verify

Deliverable: Before-and-after profiler screenshots, a bundle-size comparison, and a written five-step grid optimisation outline.

Practice prompt ↗
05Live coding in C# with stated complexity
  • Solve the request-fingerprint canonicalisation problem in C# in a plain editor, then state its time and space complexity
  • Solve the overlapping-job-attempts problem with a sort and sweep: explain why peak concurrency takes O(n log n), and why listing every overlapping pair takes O(n log n + k) for k overlaps
  • Solve the resource-graph archive problem iteratively with an explicit stack, and list the edge cases (cycles, shared nodes)

Deliverable: Three C# solutions, each with a complexity line and a list of the edge cases you tested.

Practice prompt ↗Practice prompt ↗Practice prompt ↗
06Survey data, the API layer and SQL
  • Add a C# endpoint that accepts survey responses from the Day 3 form using async/await, and handle validation errors and retries on the client
  • Write the update query that detects a concurrent edit, in case SQL comes up for database work
  • Write a short explanation of how your form handles skip logic, partial saves and validation, aimed at a non-technical project manager

Deliverable: A running React-to-C# submission flow, one SQL concurrent-edit query, and a plain-language explanation of the survey flow.

Practice prompt ↗
07Project deep dives and a full mock
  • Prepare two past projects with architecture, a key decision, one bug you diagnosed and one trade-off you would change
  • Rehearse the behavioral prompts on explaining a decision to a non-technical stakeholder, the code-review disagreement and the ambiguous requirements, plus the memory-leak story from Day 2
  • Run a mock with a friend covering the React state-management question, the C# class-versus-interface question and one coding problem, then write three questions to ask about the team's work

Deliverable: Two project walkthrough outlines, four rehearsed stories, notes from a completed mock, and three questions for your interviewers.

Practice prompt ↗Practice prompt ↗

Expand any day for tasks and deliverables. Your progress is saved on this device.

Candidates describe deep-dive sessions about past projects, and the listed soft skills are clear communication, collaboration and explaining technical decisions to non-technical stakeholders. The responsibilities candidates mention include code reviews and refining requirements with product managers. Your stories should show a technical decision, its reasoning, and how you communicated it.

Tell callers you do not own that their integration breaks

medium
deprecationcompatibilitystakeholders

A field in a write endpoint's response must change shape. You own the endpoint; you do not own the four internal callers or the outbound webhook consumers who read it. Describe a deprecation you were responsible for: what you shipped first, how you established who was actually reading the field, the window you gave and what set its length, what you did about the consumer who never moved, and how you decided removal was safe. Name the signal you used, not the announcement you sent.

Approach
  1. Establish the reader set empirically rather than from a wiki of owners: per-field usage counters keyed by principal, or access logs attributed to a consumer. State the blind spot of whichever you pick, since a consumer that reads the field only on a monthly job will not appear in a week of logs.
  2. Ship additive first. Populate the new field alongside the old one so no reader is forced to move, which is also what keeps a rolling deploy safe, because old and new instances answer the same requests at the same time and a rollback must still find the old shape present.
  3. Set the window from the slowest legitimate consumer's release cadence, not from your calendar, and decide separately what to do for a consumer with no release process at all, such as an external webhook endpoint you can only email.
  4. Convert silence into evidence before you rely on it: a short, low-traffic removal window that makes a still-dependent consumer fail visibly and loudly while you are watching, rather than at three in the morning after you have moved on.
Follow-up
  • How would you detect a consumer that reads the field only during a monthly export?
  • One caller refuses to move and has a commercial relationship behind it. What changes in your plan and what does not?

Ship under a deadline and bound the debt you chose

medium
paginationtechnical debttradeoffs

You have four days to ship a tenant-facing listing endpoint. The version you would defend uses keyset pagination over (tenant_id, status, updated_at DESC, resource_id DESC); the version you can finish uses LIMIT/OFFSET with no matching index. Describe a deadline call you actually made of this shape: what you shipped, what you knowingly deferred, how you bounded the damage with a mechanism rather than an intention, and the specific numeric condition that would force the follow-up. Name who you told and where you wrote it down.

Approach
  1. Name the deferred failure precisely instead of calling it slow. OFFSET n makes the database produce and discard n rows, so cost grows with page depth; without an index matching the sort, every matching row is read and sorted before the limit applies; and rows inserted between two page fetches shift across the boundary so items are skipped or repeated with nothing in the response to signal it.
  2. Bound the blast radius with something mechanical rather than a promise: cap maximum page depth, cap page size, restrict the endpoint to one internal caller, or keep it behind a flag. State which failure each cap removes and which it leaves standing.
  3. Attach a number to the trigger and wire it to an alarm: the first tenant crossing N resources, or the endpoint's p99 crossing its share of the 400 ms budget, so the debt announces itself instead of waiting to be remembered.
  4. Write it where the next engineer looks, which is the code and the ticket, not a chat message: what was deferred, why, the cap, and the trigger.
Follow-up
  • At what page depth does the offset version breach your latency budget, given your page size and row counts?
  • What breaks first when you switch to keyset pagination later, and what does a client holding an old page token see?

Unblock an engineer without taking the keyboard

easy
mentoringleasesat-least-once

A teammate has spent two days on a job handler that occasionally writes duplicate rows. They are certain the queue is delivering twice by mistake. You suspect a lease expiring under a slow handler, so the job is running concurrently with itself. Describe how you have unblocked someone in this position: what you asked before offering a hypothesis, what you showed them rather than told them, and what you left them owning. Then say what you would do if their theory turned out to be the right one.

Approach
  1. Ask before diagnosing, and ask for things answerable from data they already have: the attempt count on the job rows that produced duplicates, the handler's observed duration against its lease expiry, and whether the duplicate rows share a natural key that a unique constraint could have caught.
  2. Teach the shape rather than the answer. A lease cannot distinguish a dead worker from a slow one, so a handler that outruns its lease is running twice by design, and deploys deliver the other half by killing handlers mid-run on every rollout. Both of their candidate theories produce identical duplicate rows, which is why the evidence has to come from timings rather than from argument.
  3. Hand over a checklist they execute: a natural key on every write the handler performs so the second copy collides rather than appends, the record of intent written before any external effect, a lease heartbeat while running, and the metric that shows it working.
  4. Keep ownership with them deliberately. Pair on the first write, then step back; if you finish it yourself you have closed one ticket and left the same person stuck on the next redelivery.
Follow-up
  • How would you distinguish a genuine double-delivery from a lease expiry using only the data already stored?
  • Their handler calls an external endpoint before recording that it did. What do you tell them to change first?
  • 01

    Describe a time you had to troubleshoot a memory leak in a C# application.

  • 02

    Tell me about a technical decision you had to explain to a non-technical stakeholder. What did you leave out, and how did you check they understood?

  • 03

    Describe a code review where you gave feedback a peer disagreed with, or received feedback that changed your design. What happened next?

  • 04

    Tell me about a time requirements from a product manager or client were ambiguous. How did you turn them into something buildable?

  • 05

    Describe a question you could not answer on the job and the steps you took to find the answer.

PracHub preparation framework ↗
How difficult are the technical interviews?

Candidates describe the questions as focused on fundamentals rather than syntax trivia. In practice you need precise explanations of React state, the lifecycle, performance, C# interfaces and dependency injection, plus working code on standard data-structure problems. Spend your time on the basics before niche topics.

Acuity Analytics Software Engineer candidate reports ↗
How much time should I spend preparing?

The preparation advice reported for this role suggests two to three weeks focused on C# and React, plus enough practice to write basic code on a whiteboard or in a shared editor. If you have less time, compress the seven-day plan above. Do not drop the live coding day, since candidates report live coding problems.

Acuity Analytics Software Engineer candidate reports ↗
Which topics do candidates report for this role?

The reported topics are OOP concepts, React, C#, software development fundamentals and survey programming. Within those, candidates mention React hooks and state management, C# async/await and threading, API integration and data fetching, memory management, data structures and algorithmic complexity. SQL, cloud deployment experience and survey programming tools are listed as nice to have rather than required.

Acuity Analytics Software Engineer candidate reports ↗
What is the Analyst - Decipher (Survey Programmer) focus, and do I need survey experience?

Candidates report that some Software Engineer postings carry this focus, which involves work in the Decipher ecosystem turning survey requirements into interactive web experiences. Survey tooling is listed as nice to have, not required. Prepare one example that applies your engineering to survey-style problems such as multi-page forms, skip logic, validation and response storage, and ask your recruiter whether your posting has this focus.

PracHub Software Engineer practice ↗
Will I write code live, and in what language?

Candidates report live coding problems alongside technical screenings. The reported preparation advice is to be comfortable writing basic code on a whiteboard or in a shared editor. Since C# is a listed must-have, practise your data-structure problems in C# without IDE autocomplete. Confirm the language and editor with your recruiter.

PracHub Software Engineer practice ↗
Is this a remote-friendly role?

Nothing consistent has been reported about remote or office arrangements, and candidates say it can depend on the team and office. Ask your recruiter about the location policy for your specific posting.

Acuity Analytics Software Engineer candidate reports ↗
Sources & methodology 3 sources ↗

No official company page is cited. Rounds and questions come from candidate reports and PracHub editorial material; each source shows the date it was read.