Medall Healthcare · Software Engineer
Updated · 2026-09-24

Medall Healthcare Software Engineer
Interview Questions & Guide 2026

THE 60-SECOND BRIEF

The Software Engineer role at Medall Healthcare is a foundational position focused on building and maintaining the robust digital infrastructure that supports modern healthcare delivery. As a member of the engineering team, you are responsible for developing scalable, reliable software solutions that bridge the gap between complex clinical data and actionable insights for practitioners and patients alike.

If the loop includes an asynchronous take-home, treat it as a code review of you rather than as a puzzle: structure, what you chose to test, and what you wrote down about the constraint you were working under. Hold the stated time box and say what you would have done with more of it.

Medall Healthcare candidates report 4 rounds · ≈ 3-5 weeks. The stages below are what candidates describe, not a published process.

Authorise every identified read against current consentModel bitemporal coverage and retroactive eligibility changesVersion clinical results instead of updating rows in place

40 min read

Browse Software Engineer questions

See the practice prompts

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

The Software Engineer role at Medall Healthcare is a foundational position focused on building and maintaining the robust digital infrastructure that supports modern healthcare delivery. As a member of the engineering team, you are responsible for developing scalable, reliable software solutions that bridge the gap between complex clinical data and actionable insights for practitioners and patients alike.

Your work will directly influence the efficiency of healthcare operations. Whether you are working on data processing pipelines, health record management, or patient-facing applications, your contribution ensures that Medall Healthcare can provide accurate and timely services. This role is ideal for engineers who are passionate about applying technical rigor to the healthcare domain and who thrive in environments where precision, security, and user accessibility are paramount.

01

Initial Screening

reported

The person on this call usually cannot evaluate your code and does not need to. They write a short paragraph, and that paragraph is what a hiring manager skims when deciding who to put on your loop. So the test is not whether your work was hard, it is whether a non-engineer can repeat it correctly. Name systems by what they did rather than by their internal codename, give each project a shape (what was breaking, what you changed, what happened after), and keep the whole walkthrough near ninety seconds. Depth that cannot survive a paraphrase reads as vagueness.

What to demonstrate

  • Whether a non-engineer can restate your projects without distorting them, since their paraphrase is what travels to the hiring manager, not your sentences
  • Whether each project has a shape rather than a stack list: the failure or constraint, the change you made, the result and how it was measured
  • Whether you can say what was yours inside a team project without either inflating it or disappearing into the plural

How to prepare

  • Rewrite each headline project as two sentences with no internal system names and no acronyms outside your company, then say them to someone outside engineering and have them repeat them back. Fix whatever came back wrong
  • Attach one measured number to each project: the baseline, the change, and the window it was measured over. Where nothing was ever measured, say that plainly rather than reaching for a plausible percentage
  • Time the background walkthrough against a clock. If it runs past two minutes, compress the earliest role to a single clause and spend the recovered time on the most recent one
PracHub interview research ↗
02

Technical Evaluation

reported

Most of the time lost in this format is not lost to thinking. It goes to a standard-library call you half-remember, an off-by-one in a loop bound, and a debugging loop that mutates code at random until something passes. When output is wrong, stop re-reading the whole function: take the smallest input that reproduces it and walk the state through by hand, printing intermediates if the environment allows. Guessing at a fix without a failing case you understand is how a five-minute bug becomes twenty, and the clock does not pause while you do it.

What to demonstrate

  • Whether you reach the right structure without a detour, and can write it from memory rather than only recall that one exists
  • Whether overflow is considered where the language has fixed-width integers, since a signed 32-bit value stops at 2,147,483,647 and then wraps in Java, is undefined behaviour in C++, and does not arise in Python, whose integers grow instead
  • Whether recursion depth is treated as a constraint on large inputs, given that CPython's default limit is 1000 frames and a deep recursion can exhaust the stack in any language where an iterative version would not
  • Whether a failing case is isolated and explained before any edit is made to the code

How to prepare

  • From an empty file and with no references open, implement the pieces you lean on most: a heap push and pop, an iterative DFS with an explicit stack, and a binary search whose midpoint is written lo + (hi - lo) / 2, which avoids the overflow that (lo + hi) / 2 can hit in a fixed-width integer type
  • Time yourself on the ten library calls you look up most, such as sorting with a custom comparator, splitting and joining strings, and finding the next key at or above a value in an ordered map, until the lookup is gone
  • Take a solution you know is broken and, before touching it, write one sentence naming the input, the expected value and the actual value. Repeat until you do it without deciding to.
PracHub interview research ↗
03

Collaborative Interviews

reported

You cannot drill a format you do not know, so put the preparation into material that travels. Three pieces of your own work, each rehearsed until you can take a follow-up you did not anticipate, will carry a conversation or a code walkthrough equally well. Specificity is what separates that from filler. A number needs its definition before it means anything: a p99 is over some window and measured at some hop, and a server-side figure excludes the queueing and network time a client would see. The number you cannot qualify is the one to leave out.

What to demonstrate

  • Whether your examples carry detail only someone who did the work would hold, such as what the binding constraint actually was, which alternative you rejected and why it was worse, and what you measured on each side of the change
  • Whether a number survives one follow-up, meaning you can say what it was measured over and whether it moved because of your change or merely alongside it
  • Whether a failure is described with the specific change that followed it, rather than a lesson stated in general terms
  • Whether your part in a team effort is stated accurately, including what other people did

How to prepare

  • Write a page on each of three projects covering the constraint, the option you rejected, the measurement before and after, and what went wrong. Cut any line you cannot take a follow-up on, since you are writing the parts you will be pressed on rather than a summary.
  • Recover the real figures while you still have access: request volume, data size, latency with its percentile and window, team size, timeline. Note where each came from, whether a dashboard, a design document or memory, and mark the estimates so you can say which they are out loud.
  • Take your weakest project story to someone who works in a different area and have them ask why four times in succession. The point where you run out of answer is the part to go and re-read before the round.
PracHub interview research ↗
04

Final Assessment

reported

Coding rounds mostly set a floor. They decide whether you clear the bar, not where you land on the ladder. Level tends to come out of the design discussion and the ownership stories, so the question worth auditing beforehand is whether the scope you describe matches the scope of the job. Work that stops at your own service, or a story whose hard part was writing the code rather than getting several people to agree on an interface, reads a level below where you think you are interviewing, and that gap is usually resolved downwards.

What to demonstrate

  • Whether the largest thing you describe owning ran end to end — the decision, the migration path, the rollout, and what you did when it went wrong — or stopped at the change you merged
  • Whether design answers include what you would not build, what you would defer, and what you would measure before committing, rather than only what the boxes are
  • Whether a disagreement in a story was settled with something checkable — a benchmark, a prototype, a written proposal — instead of by seniority or by waiting it out
  • Whether you can say which calls you made alone and which you escalated, and why the line sat where it did

How to prepare

  • Write your largest piece of owned work as a timeline of decisions — who decided what, when, and what you did when the plan broke — then delete every sentence whose subject is "we" and see how much survives
  • Take one system you know well and drill the migration answer: how old and new paths run side by side under live traffic, how you compare their outputs, what the rollback is once writes are going to both, and which step you would not automate
  • Map each line of the ladder in the job posting to a specific thing you have done, find the line you cannot support, and prepare the closest evidence you have plus an honest account of the gap
PracHub interview research ↗

PracHub editorial advice for the preparation topics above.

01

Treating a medical record number or a member ID as a globally unique key and joining on it directly.

These identifiers are unique only within the authority that issued them. Two facilities in one network routinely have the same medical record number for different people, and member IDs get reissued when someone changes plans. Joining on the bare value merges two patients' records, which is the most damaging failure available in this domain, and it passes every test written against a single-facility fixture because the collision only appears once a second source is connected.

02

Assuming admission, discharge and transfer messages arrive in the order the events happened.

Interface engines route by message type across separate queues and retry independently, so a discharge can land before the admission it closes and an update can land before the registration it modifies. Ordering has to come from the sender's event timestamp plus a per-encounter sequence, and the consumer has to apply out-of-order and late-arriving events correctly rather than rejecting them, because rejection turns a recoverable ordering issue into permanent data loss that nobody notices until a report is short.

03

Answering a debugging question with a guess instead of a bisection

Give a procedure that halves the search space at each step: confirm the symptom reproduces, establish the last known-good version, input or timestamp, then bisect over commits, over the data, or over the layers of the request path. A plausible cause with no way to confirm it is the same move whether it happens to be right or wrong, which is why it scores nothing.

04

Reading the constraints as preamble rather than as part of the problem

The bounds are usually there to eliminate the obvious approach: n up to 10^5 makes an O(n^2) scan roughly 10^10 operations, far outside any per-test time budget, and an input larger than memory rules out loading it at all. When a bound is not given, ask for it, then say out loud which approach it kills.

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

10 technical prompts3 include a worked solution

Group transfer-chained encounters into episodes with out-of-order arrival

medium
graph traversalcycle detectionmemoisation

You have up to 5 million encounter rows for a reporting month, in arbitrary order: encounter_id, enterprise_person_id, facility_id, encounter_class, admit_ts, discharge_ts (nullable), status, prior_encounter_id (nullable, set on transfer), source_event_ts. prior_encounter_id may reference a row that arrives later or never arrives. Group rows into episodes, one per maximal transfer chain, returning episode root, person, earliest admit_ts, latest discharge_ts (null if any member is still open) and member count. Report cycles instead of following them. Target O(N) expected time.

Approach
  1. Recognise the shape: every row has at most one prior_encounter_id, so this is a forest of parent pointers, not a general graph. A hash map from encounter_id to row is the whole index you need, and the work is O(N) expected rather than anything sort-shaped.
  2. Resolve roots by iterative pointer-following with write-back memoisation: from each node walk prior_encounter_id until you reach a node with no parent, a parent absent from the input, or a node whose root is already known, then stamp the discovered root onto every node on that path. Each node is finalised once, so total work stays O(N) even when one chain is very long.
  3. Do not recurse. A malformed feed can produce a chain tens of thousands deep, and a recursive resolver dies on stack depth taking the whole batch with it. An explicit loop with write-back is both faster and bounded.
  4. Detect cycles with three-state marking: unvisited, on the current path, finalised. On reaching a node that is on the current path, emit a data-quality record naming every encounter_id in the cycle and exclude that component from the episode output. Choosing an arbitrary root instead would produce an episode that looks plausible and will be believed.
  5. Keep a dangling prior_encounter_id distinct from a genuine root. It means the chain starts outside the window or has not arrived, so flag the episode left-truncated and carry that flag into the output: an episode with an unknown start cannot be used for length of stay or readmission counting without biasing both downward.
  6. Compute aggregates during the same pass that assigns roots: minimum admit_ts, maximum discharge_ts with null propagation so any open member leaves the episode open, and exclude cancelled and entered_in_error members from the aggregates while keeping them retrievable.
Follow-up
  • Two encounters name each other as prior_encounter_id. What does your detector emit, and who needs to see it?
  • One episode spans two facilities whose clocks differ by four seconds. Do you order on source_event_ts or admit_ts, and what does the choice cost?
  • A chain is cut in half by the month boundary. What does this month's report say, and how do you make next month's agree with it?

Merge twelve resource streams into one patient summary page

medium
k-way mergeheappagination

A patient summary fans out to between 8 and 12 resource types. Each returns a network-backed, paged iterator of resource versions sorted by issued_ts descending, up to 200,000 versions per type for one person. Return the 50 most recent current versions across all types, where current means no later version supersedes it within the same logical resource, and a logical resource whose current version is entered_in_error is omitted entirely. You may not materialise the iterators. Give time and space in terms of k types, the result size and the page size.

Approach
  1. k-way merge with a max-heap holding one head per iterator, keyed on issued_ts. Seeding is O(k), each pop is O(log k), so reaching R emitted rows costs O(k + P log k) for P pops, with O(k) heap space plus one page buffered per iterator. Fetching everything and sorting is O(V log V) over V up to 2.4 million versions and drags every page across the network to produce 50 rows.
  2. Suppress with a hash set of logical resource ids already seen, recorded on first sight whether or not that version is emitted. A logical resource has exactly one resource type, so all of its versions arrive on one iterator, and that iterator is descending in issued_ts: the first version you see for a logical resource is its newest. Deciding on first sight and suppressing every later pop for that id is therefore correct in one pass with no lookahead.
  3. Count emits, not pops. A correction-heavy chart can burn many pops per emitted row, so a loop that stops at 50 pops returns a short page. Put a bound on total pops as well, and when it trips, return what you have with a continuation token rather than spinning.
  4. Break issued_ts ties deterministically on (resource type, resource id). Without it two identical requests return two different orderings and the next page silently skips or repeats rows.
  5. Handle entered_in_error at first sight: the erroneous version still supersedes its predecessor, so record the id in the seen set and emit nothing, dropping the whole logical resource instead of falling back to the value it replaced. Recording it is the load-bearing half. Skip it and the next pop re-displays the value a clinician already retracted.
  6. Summarise the budget honestly: the composite p99 is what the user feels, and it is bounded below by the slowest of the k iterators, so the merge fixes the ordering cost but not the fan-out tail.
Follow-up
  • One of the twelve iterators has a p99 of 400ms while the rest return in 20ms. What is your composite p99 and what would you change first?
  • The user pages to rows 51 through 100. How do you resume without re-reading from the top, and what breaks if issued_ts is not unique?
  • One resource type is accidentally returning ascending order. How would your code detect that rather than quietly emitting the oldest rows?

Reconstruct what the chart displayed at five million past instants

hardWorked solution
external sortas-of joinio bound

observation_result holds 200 million versions: observation_id, enterprise_person_id, filler_order_id, loinc_code, value_numeric, result_status, collected_ts, issued_ts, version, supersedes_observation_id. An incident review hands you 5 million queries of (enterprise_person_id, filler_order_id, loinc_code, as_of_instant). For each, return the version that was visible at that instant, meaning the one with the greatest issued_ts at or before it. Neither side fits in memory. The per-query scan is correct. Explain precisely why it is too slow, then give a plan with its complexity.

Approach
  1. Name the clock before naming an algorithm. Visibility is issued_ts, the release time. collected_ts is when the specimen was drawn and can precede release by hours, so ordering on it reports a correction as visible long before anyone could have seen it. No amount of index work rescues the wrong column.
  2. Be exact about why the naive plan fails, because the interviewer is testing whether you can tell arithmetic cost from I/O cost. Per query the chain scan is O(V_k) and the arithmetic is trivial, but 5 million independent lookups into a 200-million-row structure that does not fit in RAM is 5 million random reads. The job is bounded by seeks per query, not by comparisons, and buying a faster comparison changes nothing.
  3. Convert random access into sequential access. Hash-partition both sides on the chain key (enterprise_person_id, filler_order_id, loinc_code) into P shards sized to fit memory, sort each shard's versions by (chain key, issued_ts) and its queries by (chain key, as_of_instant), and sweep the pair in lockstep. Total O((V + Q) log(V + Q)) with external sort, replacing Q seeks with two sequential passes.
  4. Inside a chain the sweep is linear, not logarithmic, because queries are visited in ascending as_of order and the version pointer only moves forward: O(V_k + Q_k) per chain. Binary search per query is the better shape only when Q is small relative to V and the versions are already indexed and resident.
  5. Return the empty answer as a distinct outcome. A query whose as_of precedes the first issued_ts means nothing was displayed, which is not the same as the earliest value, and is frequently the exact fact the review is chasing.
  6. Return a version later marked entered_in_error if it was live at the instant asked about. Reconstructing the past means reporting what was on the screen, including what was wrong, and quietly substituting today's truth defeats the purpose of the exercise.
Worked solution 45 min
  1. Choose P so a shard fits in memory: at P equal to 256, each shard holds about 781,000 versions and about 19,500 queries.
  2. Hash-partition versions and queries on the chain key, writing both to shard files.
  3. Per shard, sort versions by (chain key, issued_ts) and queries by (chain key, as_of_instant).
  4. Sweep the two sorted streams together, advancing the version pointer while issued_ts is at or before as_of and answering from the last version passed.
  5. Emit an explicit empty answer when the pointer has not advanced past any version for that chain, and concatenate the shard outputs.
EXPECTED RESULTA chain with version 1 preliminary 5.2 issued 09:12, version 2 final 5.4 issued 11:40, version 3 corrected 7.1 issued 14:02 answers: as_of 08:00 returns nothing displayed, 10:00 returns 5.2 preliminary, 12:00 returns 5.4 final, 14:10 returns 7.1 corrected. If version 3 is marked entered_in_error at 18:00, the 14:10 query still returns 7.1, because that is what was on the screen. The whole job is two sequential passes over 200 million rows instead of 5 million seeks.
Follow-up
  • Read replicas lagged 40 seconds at the time. Does your answer describe what the clinician actually saw, and how would you bound the difference?
  • Serve the same question online for a single chart at a p99 under 50ms. What changes?
  • One partner changed its filler_order_id format mid-year, so the chain key is not stable. How does that appear in your output, and how do you detect it rather than returning empty answers?

Roughly ninety minutes on weeknights with one longer weekend block. The plan cuts scope rather than compressing everything, on the assumption that one thing finished per night beats four half-started.

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
01Fix the scope and take a cold baseline
  • Read the role description and write the three things the loop will almost certainly test, then write an explicit not-doing list and keep it visible all week.
  • Take one twenty-five-minute coding problem and one fifteen-minute design prompt cold, and write the single sentence naming what blocked each, because those two sentences decide where the remaining evenings go.
  • Set the week's rule: one thing finished every night, including the night you only have forty minutes.

Deliverable: A one-page scope with a not-doing list and two cold attempts, each carrying one sentence on what blocked it.

Practice prompt ↗Practice prompt ↗Worked solution ↗
02One pattern, written three times from blank
  • Choose the single pattern most likely to appear in your loop and write it three times from an empty file rather than editing the previous attempt.
  • On the third pass, write the invariant as a comment before the loop body and the complexity before the first line of code.
  • Stop at ninety minutes even if the third version is imperfect, and write the one thing you would fix given another hour.

Deliverable: Three independent implementations of the same pattern plus a note on what changed between them.

Practice prompt ↗Practice prompt ↗
03One design, only to the depth you can defend
  • Take one system shape and go only as far as requirements, interface and data model, refusing to draw a box you could not survive a follow-up about.
  • Attach one number to each non-functional requirement, deriving it rather than asserting it, and write the assumption the number rests on.
  • Write the one tradeoff you are choosing against and the observation that would make you reverse it.

Deliverable: One design at interface-and-schema depth with derived numbers and one written reversible tradeoff.

Practice prompt ↗Practice prompt ↗
04Only the fundamentals you will have to defend
  • Write, in under two hundred words each, the answers to the two questions that follow almost any implementation: why this structure and not the obvious alternative, and what happens to this code at a hundred times the input.
  • Write what an index actually costs: faster lookups on the indexed columns against a write that now maintains a second structure, plus the cases where the planner declines to use it anyway, low selectivity, or a predicate wrapping the column in a function.
  • Delete any answer you cannot deliver aloud in under a minute, since an answer that needs reading is not an answer you have.

Deliverable: Three written answers, each under two hundred words and each timed aloud.

Practice prompt ↗Practice prompt ↗Worked solution ↗
05Your own work, timed
  • Write a ninety-second and a four-minute version of your main project and time both aloud rather than reading them.
  • Prepare the two follow-ups that always come: what you would do differently, and how you knew it worked.
  • Put one number in the first sentence and be ready to say exactly where it came from and what it excludes.

Deliverable: Two timed narratives with one defensible number in the opening line.

Practice prompt ↗Practice prompt ↗
06The one full rehearsal, in the weekend block
  • Run a sixty-minute mock covering a coding round and a design round in one sitting with no break, because sustained attention is the thing evenings have not trained.
  • Immediately afterwards, and before hearing any feedback, write the three moments you lost the thread.
  • Spend the rest of the block only on those three moments, and on nothing you merely feel shaky about.

Deliverable: Mock notes naming three failure moments with a specific fix written under each.

Practice prompt ↗Practice prompt ↗
07Taper
  • Write the twenty-minute warm-up you will actually do on the morning: one problem you can already solve from a blank file, one design you can narrate, and nothing you have never seen.
  • Re-read only your own notes from this week and open no new material.
  • Write the logistics down: the editor or shared document you will be working in, whether execution and lookups are permitted, and the sentence you will use when you do not know something.

Deliverable: A one-page card holding the design structure, the project numbers, and the logistics.

Practice prompt ↗Worked solution ↗

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

Every story you tell gets read for blast radius and judgement: what could have broken, who else it touched, what you knew at the moment you decided. Nobody can audit your code in an hour, so they audit your reasoning instead. Pick work where the call was genuinely yours and the consequences were real enough to remember.

Describe a time you had to optimize a slow-performing query or service…

medium
behavioural and engineering judgement

Describe a time you had to optimize a slow-performing query or service.

Approach
  1. Name the disagreement and how you resolved it with evidence.
  2. Give the blast radius: what could have broken, and what you measured.
  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?

Unblock an engineer whose deductible accumulator overshoots

easy
mentoringlost updateisolation levelsreproduction

An engineer on your team has a benefit-application path that occasionally leaves a member's accumulated deductible above the plan limit — a handful of times a day, never in tests. Their code SELECTs the remaining deductible, computes patient responsibility in application code, then UPDATEs the accumulator to an absolute value. They have spent three days adding logging and are now asking whether the database is losing writes. Describe unblocking someone in this position: what you did first, what you let them find themselves, and what you left them able to diagnose next time.

Approach
  1. The probe is whether you teach a method or hand over a patch. Reproduce before explaining: two sessions, both BEGIN, both SELECT the accumulator row, both compute, both UPDATE to an absolute value, both COMMIT. The second overwrites the first and neither errors. Fifteen minutes of that ends three days of logging and, more importantly, ends the theory that the database is at fault.
  2. Be precise about where the anomaly is and is not, because the imprecise version teaches the wrong lesson. A single UPDATE that does its arithmetic in SQL is safe under READ COMMITTED: the blocked statement re-reads the row after the first commits. The loss comes from computing the new value in application code across the statement boundary, so the UPDATE writes an absolute amount derived from a stale read.
  3. Lay out three fixes with their costs rather than naming one. SELECT ... FOR UPDATE serialises writers per member and holds the lock for the transaction, so nothing in that transaction may make an external call. SERIALIZABLE with a retry loop on SQLSTATE 40001 requires the operation to be safely retryable. Per-member partitioning removes contention entirely and adds routing and rebalancing.
  4. Let them pick and defend one. The outcome you want is that they can name the anomaly and the isolation level unprompted next time, not that this particular ticket closes today.
  5. Leave an artefact behind: the two-session reproduction checked in, so the next person meets the interleaving rather than the symptom, and the reasoning is not stored only in your head.
Follow-up
  • A claim is reversed and the accumulator must be credited back. What amount, given the plan design may have changed since?
  • They choose SERIALIZABLE. How do they make the retry safe when the transaction also wrote a claim adjudication row?
  • How would you have noticed this before a member saw it, and what would that check cost per adjudication?

Argue against rewriting foreign keys during a person merge

hard
merge and unmergeschema designtechnical disagreementread path

A proposal on your team simplifies merges: on merge, UPDATE enterprise_person_id across encounter, observation_result and claim_line to the surviving identity, then delete the link-resolution step so a patient-scoped read becomes one equality predicate. The author brings a p99 improvement on the patient summary, which fans out across eight to twelve resource types. You argued against it. Reconstruct the argument: the failure you predicted, the evidence you brought, the cost of your own alternative that you conceded, and who made the call.

Approach
  1. The probe is whether you can oppose a real performance win without retreating to data-hygiene arguments. Name the operation the proposal removes: unmerge. Once enterprise_person_id is rewritten in place, the row no longer records which source identity asserted the fact, and the only pair of columns that could — assigning_authority and source_person_id — lives in the link table the proposal deletes.
  2. Make it concrete with money rather than with charts. A claim_line posted under the losing identity carries coverage_id pointing at that identity's enrolment span. Rewriting the person while leaving coverage_id yields a row asserting the surviving person was covered under a span that was never theirs, which is a financial statement that adjudication and reconciliation will both act on.
  3. Do not argue that merges are rare, because that concedes the premise. Bring the rate of merges, the rejection rate on manually reviewed links, and the lag between a wrong merge and its discovery — false merges are a property of probabilistic matching, so the design has to assume them rather than hope against them.
  4. Concede the read cost honestly, since that is where the proposal's benefit is. Resolution through a versioned link table turns one equality predicate into a lookup feeding a predicate over a set of source identities, which changes index shape and raises the composite read's p99, and the composite is the number that matters, not the per-resource one.
  5. Offer the option that captures most of the win: a materialised current-link projection refreshed inside the merge transaction, so reads stay one predicate while the versioned link table remains authoritative and unmerge stays a supported operation rather than a recovery exercise.
  6. Finish on the decision process, not the technical point: what you wrote down, whether you blocked the change, who owned the call, and what you did once it was made — including if it went against you.
Follow-up
  • Your projection and the link table disagree after a failed merge retry. Which one is authoritative, and how does a reader find out?
  • An unmerge lands eight months later. What has to happen to the claims adjudicated under the merged identity in between?
  • The author says reversibility can be handled by a nightly backup restore. Take that seriously and say exactly what it does not recover.
  • 01

    Describe a time you had to optimize a slow-performing query or service.

  • 02

    An engineer on your team has a benefit-application path that occasionally leaves a member's accumulated deductible above the plan limit — a handful of times a day, never in tests. Their code SELECTs the remaining deductible, computes patient responsibility in application code, then UPDATEs the accumulator to an absolute value. They have spent three days adding logging and are now asking whether the database is losing writes. Describe unblocking someone in this position: what you did first, what you let them find themselves, and what you left them able to diagnose next time.

  • 03

    A proposal on your team simplifies merges: on merge, UPDATE enterprise_person_id across encounter, observation_result and claim_line to the surviving identity, then delete the link-resolution step so a patient-scoped read becomes one equality predicate. The author brings a p99 improvement on the patient summary, which fans out across eight to twelve resource types. You argued against it. Reconstruct the argument: the failure you predicted, the evidence you brought, the cost of your own alternative that you conceded, and who made the call.

PracHub interview preparation framework ↗
Is this an official Medall Healthcare interview guide?

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

PracHub interview research ↗
How long does the interview process typically take?

The timeline varies depending on the specific team and your availability, but most candidates complete the process within 3 to 5 weeks. The process aims to move efficiently while leaving the interviewers enough time to get to know you.

PracHub interview research ↗
What is the most important thing to prepare?

Focus on being able to explain the "why" behind your past technical decisions. Interviewers are less interested in memorized answers and more interested in how you think through problems and handle technical trade-offs.

PracHub interview research ↗
Is this role fully remote?

Working arrangements vary by team and location; discuss specific location and hybrid requirements with your recruiter during the initial screening.

PracHub interview research ↗
What defines a successful candidate at Medall Healthcare?

Successful candidates are those who combine strong technical execution with a genuine curiosity about how their work impacts patient outcomes. Candidates report that interviewers value engineers who are proactive, collaborative, and committed to continuous improvement.

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.