FTI Defense · Software Engineer
Updated · 2026-09-24

FTI Defense Software Engineer
Interview Questions & Guide 2026

THE 60-SECOND BRIEF

As a Software Engineer at FTI Defense, you will play a pivotal role in developing sophisticated technical solutions that support critical defense and national security operations. This position is not merely about writing code; it is about engineering high-stakes systems that require precision, reliability, and a deep understanding of complex requirements. You will work within a mission-driven environment where your contributions directly influence the efficacy of the tools used by FTI Defense's clients.

Ask how many rounds there are and what each one is before you plan your weeks, because the composition is what your hours should follow. A loop with three coding rounds and one short design conversation deserves a different split from the reverse, and whoever schedules it will usually say plainly which it is.

PracHub has no confirmed round sequence for FTI Defense. Treat the sections below as preparation areas and confirm the format with your recruiter.

Make every determination replayable from a frozen snapshotVersion rules by statutory effective date, not releaseEnforce audit writes at the data-access boundary

34 min read

Browse Software Engineer questions

See the practice prompts

12Practice promptsAcross five skill areas
3With worked solutionsIncluded in the practice prompts

As a Software Engineer at FTI Defense, you will play a pivotal role in developing sophisticated technical solutions that support critical defense and national security operations. This position is not merely about writing code; it is about engineering high-stakes systems that require precision, reliability, and a deep understanding of complex requirements. You will work within a mission-driven environment where your contributions directly influence the efficacy of the tools used by FTI Defense's clients.

The role demands a balance of robust technical execution and the ability to adapt to a fast-moving, high-impact industry. You will be expected to tackle challenging engineering problems, collaborate with multidisciplinary teams, and deliver results that meet rigorous standards. Whether you are working on legacy system integration or modern software development, your work will be central to the strategic objectives of FTI Defense.

01

Preparation focus

editorial

No round sequence has been reported for this company, so work the categories below and confirm the format with your recruiter.

What to demonstrate

  • Breadth across SQL, experimentation and product reasoning
  • Ability to state assumptions before choosing a method

How to prepare

  • Drill the practice exercises below and time yourself
  • Prepare three quantified stories about decisions you drove
PracHub interview preparation framework ↗

PracHub editorial advice for the preparation topics above.

01

Implementing eligibility rules as ordinary application code that ships on the release train, with thresholds as constants and reference tables edited in place

Rules change on statutory effective dates, are frequently backdated, and are sometimes corrected after decisions have already been issued under them. If the only record of a threshold is the value currently deployed, every historical determination becomes unreproducible the moment it changes, and an appeal cannot be adjudicated because nobody can demonstrate what the rule was. The fix is bitemporal: a rule_version keyed on the period it governs, plus the transaction time at which that text was recorded, so you can ask both 'what applied to this case' and 'what did we believe applied when we decided it'. Reference data the rules read has to be versioned the same way, because an UPDATE to a rate table is a silent rewrite of history.

02

Leaving accessibility conformance to a review at the end of the project

The obligation is usually statutory and expressed against WCAG success criteria at AA, and those criteria cut straight through component architecture rather than sitting on top of it. Custom select menus, modals and date pickers have to manage focus and expose correct roles and names; 2.4.11 Focus Not Obscured (AA) constrains sticky headers and cookie bars; 2.5.8 Target Size (Minimum) (AA) requires a 24 by 24 CSS pixel target unless a listed exception applies; 3.3.8 Accessible Authentication (Minimum) (AA) rules out a login step that depends on a cognitive function test with no alternative; and 2.2.1 Timing Adjustable (Level A) collides directly with the short session timeout a security review asked for, since the user must be able to extend it. Retrofitting these means rewriting the component layer and the session design, so they belong in the component contract and in the definition of done from the first sprint.

03

Hardcoding to the sample inputs

Solve the stated problem rather than the two examples; special-casing a literal to make a sample pass is obvious immediately and reads as either a misunderstanding or an attempt to fake progress. If you genuinely cannot generalise yet, say which part is a stub and what would replace it.

04

Starting work without saying what you are about to spend time on

State the plan before executing it: the approach, roughly how long it will take, and what you intend to leave hand-waved. That gives the interviewer a chance to redirect you in ten seconds rather than watching you spend fifteen minutes on the wrong sub-problem.

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

9 technical prompts3 include a worked solution

Find every determination a corrected reference table can change

medium
graph-traversalblast-radiusversioning

A reference table (a rate schedule, threshold list or jurisdiction list) is corrected: version v is superseded by v' governing [p1, p2]. You have a graph of about 1,800 rule_version nodes, 40,000 clause nodes and 5,000 reference-table-version nodes, with roughly 90,000 reads edges from clause to table version; each rule_version has a governing date range. Determinations number 60 million, each carrying rule_version_id and effective_from. Return the determination set that could change. Name the traversal, its complexity, and what you do if the graph contains a cycle.

Approach
  1. Traverse backwards from the corrected table version, not forwards from every rule. Reverse the reads edges once into an adjacency list keyed by table version, then breadth-first from v' to collect the clauses that read it and the rule_versions that own those clauses. One BFS is O(V + E), about 135k nodes and edges; the forward alternative asks reachability per rule_version and is O(V times E).
  2. Filter each edge by period intersection as you traverse. A rule_version only reads the corrected text if its governing range intersects [p1, p2]; an edge to a rule whose period ended before p1 is a historical fact, not a dependency, and following it inflates the replay set with determinations that provably cannot move.
  3. Intersect at the determination level with a second predicate, not by scanning 60 million rows: the affected rule_version_id set drives an index range scan on (rule_version_id, effective_from), and effective_from must fall inside [p1, p2]. The graph part is milliseconds; the determination part is what the index has to be built for.
  4. Detect cycles rather than assuming a DAG. A reference table derived from aggregate determination output and read back by a rule is a real configuration, and it is a defect, but a naive BFS with a visited set will terminate quietly and give an answer that hides it. Mark the cycle, report it, and cap the traversal depth so a malformed edge cannot stall the job.
  5. Report the set with its provenance: which clause chain connects each rule_version to the corrected table. A blast radius nobody can explain is a number an auditor will not accept, and the same chain is what lets a reviewer overrule an over-broad inclusion.
Follow-up
  • The corrected table is read by a clause that is itself behind a feature guard never enabled in that period. Do you keep those rule_versions in the set?
  • Two reference tables are corrected in the same maintenance window. Is the combined blast radius the union of the two, and when is it larger?
  • The reads edges are inferred from a static scan of clause source rather than declared. What does that do to the soundness of your answer?

Replay sixty million determinations after a retroactive rule correction

hardWorked solution
bulk-replayinverted-indexdeterminism

A regulator corrects three clauses of a ruleset with effect six years back. Sixty million determination rows fall under the affected rule family, each carrying rule_version_id, evidence_snapshot_hash and a trace of the clauses that fired. Evaluation is a pure function costing about 8 ms of CPU, but each replay must rehydrate the frozen evidence snapshot from a content-addressed store capped at 500 fetches per second shared with live traffic. Replaying everything is correct. Explain why it is not viable, and give the algorithm that is.

Approach
  1. Cost the naive run before optimising it. CPU is not the constraint: 60 million evaluations at 8 ms is about 133 CPU-hours and parallelises freely. The store is: 60 million fetches against a 500 per second ceiling is 120,000 seconds, roughly 33 hours of wall clock while consuming the entire budget live traffic also needs. The run is correct because replay is deterministic and unaffected determinations converge on the existing row through the partial unique index, so it is purely a cost problem.
  2. Build an inverted index from clause to determination. Either a separate determination_clause table indexed on clause_id, or a GIN index over the trace array. The three corrected clauses then yield a candidate set by index scan instead of a full scan, typically well under one percent of the 60 million rows.
  3. Recognise that the fired-clause filter alone is unsound. A correction that widens a guard makes a clause newly reachable, so determinations that never reached it before can change now, and those are precisely the denials the correction was issued to reverse. If the trace only records clauses that fired, the filter silently omits the population the regulator cares about.
  4. Close the gap with what the trace can actually support, and be explicit that the target is a sound superset, not an exact set. If the trace records evaluated-and-false clauses as well as fired ones, include both: every determination that can change is then selected, along with some that cannot — a determination that already passed the widened guard is selected and replays identical, because widening a guard cannot exclude an input it already admitted. That asymmetry is the correct trade. A false positive costs one rehydration; a false negative is an uncorrected determination. If the trace records only fired clauses, fall back to a wider superset: every determination under the affected rule_versions whose effective period intersects the corrected period, which is far larger than the clause filter and still orders of magnitude under 60 million.
  5. Deduplicate the rehydration, not the evaluation. Distinct evidence_snapshot_hash values are the unit of store work, and a single snapshot attached to several cases in a household or an appeal chain is fetched once and evaluated per determination. Order the candidate scan by hash so the cache hits are adjacent rather than scattered across the run.
  6. Make the run resumable and rate-limited by construction: a durable cursor over the candidate set, a token bucket sized to the share of the 500 per second ceiling you are permitted, and writes that rely on the uniqueness key rather than a read-then-insert, so a restart after a crash converges instead of producing a second current determination.
Worked solution 40 min
  1. Write out the naive budget explicitly: 60,000,000 divided by 500 fetches per second, converted to hours, next to the 133 CPU-hours, and state which number is the constraint.
  2. Construct a ruleset with a guard clause G and a downstream clause C, where G is a pure reachability guard — it admits or blocks, and changing it changes nothing C reads. Build 1,000 determinations: 60 passed G and fired C, 90 evaluated G and failed it so C was never reached, and 850 took an earlier branch and never evaluated G at all.
  3. Apply a correction that widens G so all 90 previously-failing determinations now pass it and reach C. Establish ground truth first by replaying all 1,000 and recording which results differ; then run the fired-clause filter and count how many of that changed set it selects.
  4. Re-run with the filter extended to evaluated-and-false clauses, and compare its candidate set against the control's changed set in both directions separately.
EXPECTED RESULTThe control run changes exactly the 90 that the widened guard now admits. The fired-clause filter selects 60 and none of them changed, so it selects 60 useless candidates and misses all 90 real ones. The extended filter selects 150: a sound superset of the changed set, not a match for it. It contains all 90 changed determinations, and its other 60 candidates are the ones that already fired C — they are selected and replay byte-identical, which is the expected cost of soundness, not a defect. The 850 that never evaluated G are outside both filters and also replay identical, confirming they were correctly excluded rather than luckily unchanged.
Follow-up
  • The correction changes an amount rather than an outcome. Does your candidate filter change, and does the notice obligation?
  • A replayed determination comes back identical. Do you write anything at all, and what does an auditor need to see that you checked it?
  • Halfway through the run the regulator issues a correction to the correction. What happens to the work already done?

Add N business days in constant time over amendable calendars

hard
rank-selectcivil-timeprecomputation

Case Service computes sla_due_on at 1 to 2 thousand transitions per second, with higher bursts when overnight intake lands. A holiday table holds (jurisdiction_code, holiday_date, observed_date, calendar_version_id) across 200 jurisdictions and a 1990-2040 civil date span; a jurisdiction may not observe a given holiday, and calendar versions are amended over time. The statutory convention is that the period begins the day after the triggering act. Design the structure that answers 'add N business days to civil date D in jurisdiction J' in constant time, and state its memory cost.

Approach
  1. Work entirely in civil date ordinals, never in instants. A civil day is not always 86,400 seconds across a daylight-saving transition, so any arithmetic that adds an interval to a UTC timestamp is wrong twice a year in the direction that reports a late case as on time. Convert the triggering instant to a civil date in the case's zone once, at the boundary, and stay in ordinal space after that.
  2. Precompute two arrays per (jurisdiction, calendar_version): rank[d], the count of business days in the span up to and including ordinal d, and select[i], the ordinal of the i-th business day. Build both in one linear pass over the span using observed_date, not holiday_date, so a holiday shifted off a weekend lands where the jurisdiction actually observes it.
  3. The query is then two array reads: r = rank[D], answer = select[r + N]. This is correct for both cases without branching. If D is a business day, rank counts it and select[r + N] is N business days later; if D is a weekend or holiday, rank[D] equals rank of the last preceding business day, so select[r + N] still lands N business days after the period begins on the following business day. O(1) per query after an O(span) build.
  4. Cost it: 18,628 days in the span, two int32 arrays of roughly 74 KB and 52 KB, so about 126 KB per jurisdiction-version. Two hundred jurisdictions at six live versions each is 1,200 array pairs, roughly 150 MB resident. That is a deliberate trade of memory for a constant-time query at 2,000 per second; a day-walking loop is O(N) per query and, at a 45 business-day standard, is 45 bounds-checked iterations per transition instead of two.
  5. Select the calendar version bitemporally, because there are two different questions. A due date being set now uses the currently recorded version; recomputing a past due date for an audit uses the version recorded as in force when the original computation was made. Key the cache on calendar_version_id so an amendment invalidates exactly the affected arrays rather than the whole cache.
  6. Guard both ends of the span. A query for D outside [1990, 2040], or an r + N beyond the last business day, must raise rather than clamp: a clamped due date is a plausible wrong date, and this is the arithmetic that decides whether a case is late by law.
Follow-up
  • A jurisdiction amends its calendar with retroactive effect, adding a holiday in a period whose sla_due_on values are already stored. Which stored dates are wrong and how do you enumerate them?
  • The statute for one program counts calendar days, not business days, but still rolls a deadline off a non-business day. Does your structure answer that, and what changes?
  • Two jurisdictions share a holiday list except for three dates. Is it worth sharing the arrays, and what does the sharing cost you when one of them amends?

For a candidate senior enough that the loop turns on design and judgement rather than on whether the coding round gets finished. Five days build one system properly and then stress it; coding gets a single maintenance day, on the assumption that the risk at this level is an unexamined tradeoff rather than a missed algorithm.

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
01Numbers before diagrams
  • Build your own reference card of the figures you will re-derive all week: bytes for a realistic record, requests per second implied by a given daily active count, and the storage that a year at a given write rate produces. Derive each one rather than copying it, because the derivation is what survives a follow-up.
  • Turn one product statement into capacity requirements. From ten million daily users at four writes and forty reads each, state the peak-to-average factor you are assuming and why, then produce peak write QPS, peak read QPS and a year of storage.
  • Write the two numbers whose order of magnitude changes the design, the read-to-write ratio and the working-set size against memory per node, and state the threshold at which each one flips your answer.

Deliverable: A one-page numbers card and one worked capacity estimate with every assumption written down.

Practice prompt ↗Practice prompt ↗Worked solution ↗
02One system, from requirements to schema
  • Spend the first ten minutes producing only functional requirements, non-functional targets with numbers attached, a p99 latency, a durability expectation, a consistency requirement, and an explicit out-of-scope list.
  • Define the interface before the boxes: the three or four endpoints, their parameters, what each returns, and which of them are idempotent.
  • Write the data model, then write the single access pattern that justifies it, and state what the schema would have to become if the dominant access pattern were the other one.

Deliverable: One design carried to endpoint-and-schema depth, with non-functional targets expressed as numbers and a written out-of-scope list.

Practice prompt ↗Practice prompt ↗
03The consistency you are actually buying
  • Write out what a client sees under asynchronous replication when its write commits on the leader and its next read is served by a lagging follower, then write the two fixes, pinning that session's reads to the leader for a bounded window or carrying a version token the replica must reach, and the cost of each.
  • Work the quorum arithmetic on paper for N of three with W and R of two, and separate what R + W > N does guarantee, that any read set intersects any write set, from what it does not: on its own it is not linearizability, and a sloppy quorum that accepts writes on nodes outside the preference list breaks even the intersection.
  • Take two storage choices with different defaults, a single-leader relational store committing synchronously and a quorum-replicated store that converges eventually, and write the specific product behaviour that would be wrong under each, rather than a general statement about which is stronger.

Deliverable: A page separating what quorum overlap guarantees from what it does not, with one concrete product misbehaviour attached to each gap.

Practice prompt ↗Practice prompt ↗
04Failure is the design
  • For one write path, work through the case where the client times out after the server has already committed, then design the idempotency key: who generates it, how long it is retained, and what the duplicate request returns.
  • Express the retry policy as parameters rather than as a word: maximum attempts, base delay, backoff factor, jitter, and which error classes are retried at all. Then state why retrying a non-idempotent write without a key is a correctness bug and not merely waste.
  • Compute the fan-out effect on tail latency. If a request waits on ten backends and each independently exceeds its p99 one percent of the time, the chance at least one is slow is 1 - 0.99^10, about ten percent. Then write why independence is the optimistic assumption and what correlates them in practice.
  • Name the backpressure mechanism for one queue or one dependency in the design, a bounded queue with shedding or a concurrency limit, and write what the caller is told when it engages.

Deliverable: One write path with an idempotency design, a parameterised retry policy, and a written tail-latency calculation with its assumption named.

Practice prompt ↗Practice prompt ↗Worked solution ↗
05Scaling the hot path
  • Choose cache-aside or write-through for one read path and write the staleness window each produces, then name the invalidation event and what the system does when that event is lost.
  • Design against the stampede: either coalesce requests so only one recomputes a missing key, or refresh early with jittered expiry, and write why identical TTLs on keys populated in the same moment produce a synchronised expiry and a thundering herd.
  • Shard one table by a key you choose, then answer the two questions that break the choice: which queries now require a scatter-gather, and what happens to the distribution when one tenant is a hundred times larger than the median.
  • Write the cost of adding a node under plain modulo placement, where nearly every key moves, against consistent hashing, where roughly one key in n+1 moves, and state what virtual nodes are for.

Deliverable: A caching and sharding decision for one path, each with its failure mode and its rebalancing cost written beside it.

Practice prompt ↗Practice prompt ↗
06Keep the coding hand in, at the bar that applies to you
  • Solve one medium problem in thirty minutes, then spend twenty more making it production-shaped: named invariants, validation at the boundary, and errors that distinguish a caller mistake from an internal fault.
  • Write the tests you would require of a colleague's version of that function: one for empty input, one for the boundary, and one for the case the implementation is most likely to get wrong.
  • Read a piece of your own code from six months ago and write the change you would ask for, phrased as you would actually phrase it in review.

Deliverable: One problem hardened to review standard, with its test list and one written review comment.

Practice prompt ↗
07Defend it while being interrupted
  • Run a forty-five-minute design mock with an interviewer briefed to change a requirement halfway, a tenfold traffic increase or a new strict consistency requirement, and to push on one number you estimated.
  • Rehearse the two sentences a senior loop is listening for: naming the tradeoff you are choosing against and why, and saying what you would measure to learn that the choice was wrong.
  • Prepare the design you regret: a real decision, the constraint that produced it, what it cost, and what you changed afterwards.

Deliverable: Mock notes recording how the design changed under the new requirement, plus a written account of one regretted decision.

Practice prompt ↗Worked solution ↗

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

Engineers over-index on what they repaired. A stronger answer covers something you knowingly left broken: the alert you tuned down, the data inconsistency you documented instead of chasing, the cleanup you deferred past two quarters. Give the reasoning and the condition that would have reopened it, so it reads as a decision and not as neglect.

Can you explain your experience with specific software development lif…

medium
behavioural and engineering judgement

Can you explain your experience with specific software development lifecycles?

Approach
  1. State the situation in two sentences and spend the rest on the reasoning.
  2. Name the disagreement and how you resolved it with evidence.
  3. Close with what you would do differently, concretely.
Follow-up
  • How did you know your change caused the improvement?
  • What did you decide not to do, and why?

How do you handle working in a fast-paced environment with shifting pr…

medium
behavioural and engineering judgement

How do you handle working in a fast-paced environment with shifting priorities?

Approach
  1. Close with what you would do differently, concretely.
  2. State the situation in two sentences and spend the rest on the reasoning.
  3. Give the blast radius: what could have broken, and what you measured.
Follow-up
  • What would you do differently if you ran that again?
  • What did you decide not to do, and why?

Why do you want to work at FTI Defense?

medium
behavioural and engineering judgement

Why do you want to work at FTI Defense?

Approach
  1. Give the blast radius: what could have broken, and what you measured.
  2. Pick a story where you made the decision, not one where you watched it.
  3. State the situation in two sentences and spend the rest on the reasoning.
Follow-up
  • What did you decide not to do, and why?
  • What would you do differently if you ran that again?
  • 01

    Can you explain your experience with specific software development lifecycles?

  • 02

    How do you handle working in a fast-paced environment with shifting priorities?

  • 03

    Why do you want to work at FTI Defense?

PracHub interview preparation framework ↗
Is this an official FTI Defense interview guide?

No. It is PracHub's own research and practice material for the Software Engineer role at FTI Defense. Rounds and questions reflect what candidates have reported, not a process FTI Defense has published, and they change over time. Confirm the current format and scope with your recruiter.

PracHub interview research ↗
How difficult are the technical interviews?

The difficulty level is typically considered average, provided you have a solid grasp of your listed skills. The focus is on practical application rather than obscure trivia.

PracHub interview research ↗
What is the typical timeline from the first screen to an offer?

The process is designed to be efficient, and candidates often report hearing back very quickly after their interviews.

PracHub interview research ↗
Is there a specific focus on "culture fit"?

Yes, FTI Defense values candidates who are mission-oriented and professional. Being able to explain why you want to contribute to this specific industry is a key part of the conversation.

PracHub interview research ↗
Should I expect a coding test?

You should be prepared for assessment-style questions that test your hard skills and your ability to apply your knowledge to specific scenarios.

PracHub interview research ↗
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.