Get started

Taking an assessment rather than buying one? This page is written for employers. Here is the page for candidates.

Software engineering · Mid level

How to assess a Mobile Engineer

Mobile is the specialism where the cost structure of a defect differs most from the rest of this family, and the standard screen is entirely blind to it. Server code can be rolled back in minutes. Mobile code goes into a store review queue, then reaches users only as fast as they choose to update, so a defect that ships has a tail measured in weeks and a population you cannot patch. That single fact should reorganise the whole assessment towards pre-release caution — but the generic algorithm test measures speed of production, which is the opposite disposition. The second blindness is environmental. Almost every expensive mobile bug lives in a state the developer cannot easily reach: the process killed in the background and restored, the network dropping mid-upload, a permission revoked in settings between sessions, an older OS version, a device with less memory, a locale that changes the date format. A take-home built and demonstrated on the candidate's own fast, online, current-OS simulator observes none of those states, so it functions as a test of whether the candidate can build the one path that always works.

A mobile engineer writes code that will run on hardware they do not own, in network conditions they cannot reproduce, under an operating system that is entitled to terminate their process at any moment, and that cannot be changed after it ships without a third party's permission. Every one of those constraints is absent from server and web work, and together they make mobile a genuinely distinct hiring problem rather than a language variant of front-end.

Start with irreversibility, because it drives the culture of the role. On the server, "ship it and see" is a defensible strategy with a rollback behind it. On mobile, the equivalent is a release that sits in a review queue, then propagates to a user base that updates on its own schedule, so at any given moment you are supporting several versions of your own app simultaneously — including versions whose bugs you fixed months ago. The competence this demands is a specific kind of pre-release paranoia: feature flags for anything risky, defensive parsing of server responses because an old client will one day receive a new payload, and an instinct to make the client tolerant rather than clever. A candidate who treats server responses as guaranteed contracts is telling you they have never supported an old build.

Then lifecycle. The distinguishing question in a mobile interview is not "what are the lifecycle callbacks" — that is trivia and an assistant recites it perfectly — but "the user is halfway through this form, takes a call, comes back twenty minutes later, and the OS reclaimed the process; what do they see?" The strong answer describes what was persisted, when, and what deliberately was not. The weak answer is that it works because the developer tested it by switching apps for four seconds.

Connectivity is the third axis. Mobile users are routinely on a connection that is present, slow, and lying about being present. The bad hire writes code that waits, times out at thirty seconds, and shows a spinner for the duration. The good hire has an opinion about optimistic updates, about what is queued for retry, about what happens to a queued action if the user closes the app, and about the difference between an error worth showing and one worth silently retrying.

Finally, platform policy is a real constraint that engineers are expected to navigate rather than be surprised by: permission prompts that can only be asked once, background execution limits, store review rules about what an app may do. This is one of the few places in software engineering where a technical decision can be blocked by an external reviewer, and where the engineer is expected to know that in advance.

The sandbox for this role is therefore adversarial about environment rather than about algorithms. The candidate gets an existing app screen with a defect that manifests only after a process restart, an upload path with no failure handling, and a permission requested in the wrong place. The follow-up conversation is where it becomes decisive, because these questions have exactly one honest source: your app was killed here — what does the user lose, and what did you choose to persist? This upload fails at 80 percent on a train; what happens, and what does the user see? A user on the version you shipped last month receives this new response shape from the server — does your parser survive it? You requested the notification permission on launch; make the case for and against moving it. Someone who has shipped a mobile app answers all four from experience and usually names a time it went wrong. Someone who has built one on a simulator answers the first and stalls on the rest.

What the job actually needs

How people fail in this seat

What most employers do instead

CV screen, a generic algorithm test, a platform trivia interview about lifecycle methods or view hierarchies, and sometimes a take-home app built and run on the candidate's own simulator.

Mobile is the specialism where the cost structure of a defect differs most from the rest of this family, and the standard screen is entirely blind to it. Server code can be rolled back in minutes. Mobile code goes into a store review queue, then reaches users only as fast as they choose to update, so a defect that ships has a tail measured in weeks and a population you cannot patch. That single fact should reorganise the whole assessment towards pre-release caution — but the generic algorithm test measures speed of production, which is the opposite disposition. The second blindness is environmental. Almost every expensive mobile bug lives in a state the developer cannot easily reach: the process killed in the background and restored, the network dropping mid-upload, a permission revoked in settings between sessions, an older OS version, a device with less memory, a locale that changes the date format. A take-home built and demonstrated on the candidate's own fast, online, current-OS simulator observes none of those states, so it functions as a test of whether the candidate can build the one path that always works.

The assessment

About 75 minutes end to end.

The systems it runs in

A native application in the buyer's platform — Swift and SwiftUI in Xcode against the iOS Simulator, or Kotlin and Jetpack Compose in Android Studio against an emulator. The harness drives its four events through the platform's own documented mechanisms rather than through anything bespoke: process death as the OS performs it, network conditioning, an unrecognised field added to the response payload, and a permission revoked between launches. The crash data in t2 is a crash-reporting console of the kind every shipped app has, and the release decision is taken inside App Store Connect or Google Play Console, where phased release and staged rollout are the instruments actually available to halt a bad build.

React Native or Flutter, which a substantial minority of mobile teams build on and both of which are offered as fixtures rather than translated into. Process death, connectivity loss, response drift and permission revocation all occur under them, but the mechanisms and the code that survives them differ enough that the fixture must match the buyer's platform. Teams on Kotlin Multiplatform get the shared layer as the fixture with the platform layer stubbed. What cannot be swapped away is the release console: the irreversibility in t2 comes from the store, not from the framework.

Working speed is not scored. An await with a spinner and a retry is the fastest upload to write and works perfectly on the simulator's connection. Every correct behaviour in t1 — persisting the pending upload, surviving process death, resuming or requeueing, showing the user something true — costs time and buys nothing visible in the fixture. Scoring speed would pay for the version that loses the user's work on a train, which is the failure this design was built around.

What the candidate actually does

TaskWhat happens
Killed, offline, and asked twice
coding_sandbox · 40 min
An existing native mobile application, Swift and SwiftUI or Kotlin and Jetpack Compose, with the source in the sandbox and a scripted harness driving a simulator or emulator rather than a physical device. The harness can do four things to the running app on command and does them without warning: terminate the process and relaunch it as the OS would, drop the network mid-request, return a response payload containing a field the client's model does not know about, and report a permission as denied that was granted last session. The ticket is ordinary: finish a two-screen photo-upload flow that is half built. The fork is the upload. The cheap path — and the one a model produces — is an await with a spinner and a retry, which works perfectly on a fast connection and loses the user's work on a train. The correct path persists the pending upload, survives the process death, resumes or requeues, and shows the user something true. The permission request is currently on launch; nothing in the ticket says to move it. AI assistance is permitted and logged.
The release you cannot take back
judgment_scenario · 12 min
A structured scenario with no code. A build shipped nine days ago. Crash reporting shows a crash affecting a small but non-trivial share of sessions, concentrated on one older OS version, in a code path the candidate's team owns. A fix is ready. The store review queue is unpredictable this week, the build is partway through a staged rollout the candidate can still halt, a marketing campaign starts on Thursday, and roughly a third of the active user base has not updated in two months. The candidate chooses and justifies a course of action, and is then given one new fact partway through — the crash is in the payment screen — and asked whether their answer changes. What is scored is not the choice but whether the reasoning contains the facts that actually govern it: the unpatchable population, the propagation delay, whether a server-side or flag-based mitigation exists that does not need a release at all.
Interview on your own app
live_call · 23 min
A spoken conversation over the candidate's own code with the harness available. Your process was killed here — what does the user lose, and what did you choose to persist? Show me the line. This upload fails at eighty percent on a train; what happens, and what does the user see? A user still on last month's build receives this new response shape — does your parser survive it, and where? You left the notification permission request on launch; make the argument for moving it and the argument for leaving it. Then the live change: the product now wants uploads to continue when the app is backgrounded — tell me what in your implementation stops being true. That final question is the separator, because backgrounding invalidates whatever assumption the generated flow quietly made about the app staying in the foreground, and only the person who understood the flow can find it.

The mark scheme

Each criterion is scored 1 to 5 against written anchors, and every score is reported with the excerpt that earned it. A criterion marked floored is reported as a finding rather than averaged into the total. The first is open; open any other to read its anchors in full.

Survives process deathweight 0.3Persists deliberately, can point at the line where the decision is made, and can say what was deliberately not persisted and why — the distinction, no…
1 State lives only in memory. After the harness terminates and relaunches, the user is back at the first screen with the selection gone, and the candidate did not notice until shown.
3 Persists the important state but restores it partially or restores it in a way that loses the in-flight operation; can describe the gap when asked.
5 Persists deliberately, can point at the line where the decision is made, and can say what was deliberately not persisted and why — the distinction, not just the mechanism.
Behaviour on a bad connectionweight 0.25Queues the operation durably, distinguishes an error worth showing from one worth retrying silently, and states what happens to a queued action if the…
1 Single await, indefinite or thirty-second spinner, failure surfaces as an unhandled error or as nothing at all. Retry loop with no ceiling.
3 Timeouts and a retry with backoff; the user is told something, but a failure mid-upload discards the work and the queue does not survive a relaunch.
5 Queues the operation durably, distinguishes an error worth showing from one worth retrying silently, and states what happens to a queued action if the user closes the app and never returns.
Tolerance of a server it does not controlweight 0.2Parses defensively by intent, says out loud that a build shipped today will still be running in six months, and can name which fields are treated as r…
1 Strict decoding throws on the unknown field; the screen fails entirely for a payload it could have used most of.
3 Handles the unknown field but treats the rest of the response as a guaranteed contract, with no reasoning about old builds.
5 Parses defensively by intent, says out loud that a build shipped today will still be running in six months, and can name which fields are treated as required and why those specifically.
Ownership of the lifecycle designweight 0.15Names a weakness in their own flow unprompted, and under the backgrounding change identifies the specific assumption that breaks and what it would tak…
1 Answers lifecycle questions with textbook callback names rather than with what their own code does; the backgrounding change produces a general answer.
3 Explains their own persistence and retry decisions, hesitating on one.
5 Names a weakness in their own flow unprompted, and under the backgrounding change identifies the specific assumption that breaks and what it would take to fix it.
Proportion in the release decisionweight 0.1Reasons from the population that cannot be patched and the time to propagate, asks whether a server-side or flagged mitigation exists first, and updat…
1 Decides on instinct with no reference to the unpatchable population or propagation delay; does not consider any mitigation short of a release; does not move when the payment-screen fact arrives.
3 Weighs the release trade-off sensibly but treats a new build as the only instrument available.
5 Reasons from the population that cannot be patched and the time to propagate, asks whether a server-side or flagged mitigation exists first, and updates cleanly and explicitly when the payment fact lands.

How it is scored

Weighted mean of five criteria, 1-5 against the anchors, each reported with the code excerpt, harness event, or transcript line behind it. The harness events are timestamped against the candidate's session, so a score on the first criterion always points at a specific termination and what the application did after it.

Integrity

The log describes what happened. It does not produce a cheating verdict — the follow-up conversation is the control, because a statistical accusation is not something we would ask a reviewer to defend.

What you receive

Who decides

Recommended, with a reviewer who has shipped a mobile application. The tolerance criterion in particular is easy to mark wrongly by someone who has only worked server-side, because defensive parsing looks like sloppiness to a reviewer who has never had to support a build they cannot recall.

What this does not measure

Be clear about the boundary. This runs against source and a scripted harness, not against hardware. It does not observe behaviour on a real device matrix, does not measure memory or battery under real load, does not exercise a real radio, does not touch platform store review, and does not observe how a candidate uses a native profiler or debugger on an attached handset. Crashes that only occur on one manufacturer's older device are exactly the class of defect that costs mobile teams the most and exactly the class this cannot see. A team should treat it as a strong filter on lifecycle, connectivity and release reasoning, and keep a device-based exercise or a paid trial period for the rest. It also does not measure platform-specific API breadth, which is frequently what the job advertisement asks for and is the part that is learnable in weeks. Two fairness notes: the harness fixture is in one platform and one framework, which advantages recent users of it, so offer alternatives and hold the rubric constant, since no criterion here is platform-specific; and the judgment scenario rewards having lived through a bad release, which correlates with years rather than ability, so reviewers should score the factors named in the reasoning rather than the confidence of the delivery. Offer the spoken segment with captions, extra time, or in writing on request.

Everything expensive about mobile engineering lives in a state the developer cannot easily reach, and every part of the standard screen is arranged so that those states are never reached. A take-home built and demonstrated on the candidate's own fast, online, current-OS simulator tests exactly one thing: whether they can build the path that always works. That path is now abundant. Ask a model to finish a photo-upload flow and it will produce a clean, readable, entirely foreground implementation with an await and a spinner, and it will be correct in every condition the candidate is likely to test it in.

So the harness is the design. It terminates the process without warning. It drops the connection mid-request. It hands the client a payload with a field the model does not know about. It reports a permission as denied that was granted last session. Every candidate gets the same four events on the same schedule, which means every candidate's implementation is put into the states that actually generate mobile support tickets, during the assessment, while someone is recording what it did. This is the closest a remote sandbox gets to the hostile environment the job is performed in, and the honest limit of it is stated in the adverse-impact note above: it is a simulation of the environment, not the environment.

The second task carries no code on purpose. Release irreversibility is the fact that most distinguishes this role from the rest of the hub, and it is a judgment competence rather than a coding one. Server code can be rolled back in minutes; a mobile build goes into a queue owned by someone else and then propagates at the users' convenience, so at any moment a team supports several versions of its own app including ones whose bugs it fixed months ago. The scenario is constructed so that the naive framing — ship the fix or do not — is the weakest available answer. The strong candidates ask first whether the crash can be mitigated without a release at all, and reason explicitly about the third of the user base that will not update either way. The mid-scenario fact injection then tests something separate and equally important: whether a candidate can change their answer out loud without treating it as a loss.

The permission timing detail in t1 is small and revealing. Nothing in the ticket mentions it, the request sits on launch where the previous developer left it, and moving it is not required. A candidate who notices, and who can then argue both sides in the interview, is demonstrating that they understand a permission prompt as a one-shot resource rather than as a function call. A candidate who never sees it has told you where their attention goes.

The interview closes with backgrounding for the same reason the other files in this hub close with a live requirement change: it invalidates an assumption rather than adding a feature. A generated upload flow assumes the app stays in the foreground, quietly, in a way that is invisible while it holds. Asked to support background continuation, the person who wrote the flow finds the assumption in about fifteen seconds and says which line depends on it. The person who received the flow describes background execution limits in general terms, correctly, and cannot connect any of it to their own file. That gap is the measurement, and it is the only part of this assessment that cannot be completed by anyone other than the candidate.

Sources

Every figure on this page is traceable. Where a claim could not be sourced it is stated qualitatively instead.

  1. Stack Overflow, 2025 Developer Survey, Developers section, roughly 49,000 respondents worldwide, developer-type question answered by 43,560, https://survey.stackoverflow.co/2025/developers
  2. US Bureau of Labor Statistics, Occupational Outlook Handbook, Software Developers, Quality Assurance Analysts, and Testers, 2025, https://www.bls.gov/ooh/computer-and-information-technology/software-developers.htm

See what the employer actually receives. A full report for one role, with every score shown beside the excerpt that earned it, conduct findings reported rather than averaged, and a reviewer sign-off required before any decision. No form.

Read a sample reportOr talk to us about this role