Android · 14 min
Android architecture interview questions: layers and modules
Ten Android architecture interview questions and how senior answers are scored: layers, the domain layer, UDF, Hilt, modules, navigation and testing.
Senior and Staff loops · 11 min read
Architecture interview questions that do not depend on the platform: modules, shared code, server-driven UI, flags, old app versions and who owns what.
This page is for senior and Staff mobile engineers whose loop has an architecture conversation that is not about one platform: a lead or Staff round, a cross-platform team, or an interviewer from the platform group. You get ten mobile architecture interview questions that hold whether the app is native, Flutter or React Native, the answer that scores for each, a worked example on the problem nobody owns, and where to go for the platform-specific rounds. The iOS, Android and Flutter pattern questions are deliberately not here; they have their own pages, linked at the end.
At senior level you are judged on the screen you shipped. At Staff level you are judged on whether the boundary you drew two years ago still lets teams move. The questions below are about decisions that are expensive to reverse, and mobile makes reversal harder than on the backend for three reasons: everything links into one binary, so any module’s regression is everyone’s problem; old app versions stay installed for months, so you cannot roll forward instantly; and the build becomes a shared resource that a growing team will saturate.
| Signal | Strong | Weak |
|---|---|---|
| Reversibility | Knows which decisions are cheap to change and which are not | Treats a library choice and a module boundary the same |
| Mechanism | Enforces decisions in the build and in CI | Writes a document and hopes |
| Ownership | Names who owns it after launch | “The team” |
| Old versions | Designs for the app that is already installed | Assumes everyone updates |
If the Staff step is a career question as much as an interview one, the salari.dev essay Staff engineers change the decisions a team can make covers the part no interview asks directly.
The answer that scores: along teams and product surfaces that change slowly, not along technical layers. Cut by product and a typical change stays in one team; cut by layer and the same change touches every team. Pull code into a shared platform module once you know what the shared part looks like; share it earlier and every team is coupled to a guess. And granularity is decided from evidence: watch which changes keep crossing which boundaries, and move the boundary.
The answer that scores: boundaries enforced by the build system rather than by convention, so a forbidden dependency is a compile error. Clean boundaries are also what make build caching and parallel work possible. And the investment starts before CI is the bottleneck, because by then the fix is a migration that takes quarters.
The follow-up: “Why a build-time dependency graph rather than wiring things at runtime?” Risk moves: a missing runtime dependency ships a crash to users; the same mistake caught at build time stops one engineer.
The answer that scores: the integration cost of too many boundaries: a small change that crosses five modules and three owners, reviews waiting on each other, interfaces that exist only to satisfy the structure. The line is specific to each organisation and invisible on a diagram. You find it the same way as the right boundary: from where the work keeps crossing.
The answer that scores: it starts with what is shared: business logic only, or the UI too. Sharing logic keeps native UI and moves risk into the shared module and its build. Sharing the UI with Flutter or React Native moves more, including the product’s look and the release model. Then the team: who can debug the layer underneath when the abstraction stops matching the platform. Cross-platform engineering does not remove iOS and Android behaviour. It concentrates the risk at the places where the abstraction stops matching them: permissions, background execution, memory pressure, accessibility, release behaviour. And the exit: what it costs to undo in two years.
The trap: answering with a framework preference. The question is about which risks you are choosing to own.
The follow-up: “It saves nine engineer-months a year. Sign it off.” That number covers building it. It says nothing about running it. I want to know who owns the bridging code three years from now, what upgrades, support and reviewer training will cost, and how we would back out without breaking any app version we still support. If those have no answers yet, fund a small pilot with an end date instead of the whole platform, and have the pilot prove the hard parts, releasing and removing it, not just that it compiles. If the ask is “standardise everything”, shrink it to what is being decided: share code only where two products behave the same, and name who owns that shared code.
The answer that scores: delivery speed, and a compatibility problem. Which native versions can run the new bundle? What happens to state persisted by the old code? How is a bad update stopped, and which changes still require the store? The senior signal is the rollback and compatibility model, not the speed.
The answer that scores: it depends on where the screen sits between built into the binary, shipped behind a flag, and configured from the server. Server-driven UI pays off on screens of lists and cards that change every week, where waiting for a release is the real cost. It is a poor fit for screens with heavy gestures, animation, or offline use. You pay for it with a second renderer to run, with the server now owning how the screen looks, and with bugs that only reproduce for one response on one client version. So the dial is set per screen, not per app.
The answer that scores: separate deployment from release. Code ships dark behind a flag, the flag has an owner, a default and an expiry date, and a kill switch exists for anything risky. The store release goes out in stages with a metric that can halt it. And completed flags are removed, or the codebase fills with branches nobody dares to delete.
The answer that scores: additive changes by default. New fields and new section types are added; old clients skip what they do not understand. The meaning of an existing field or type is never changed. When a break cannot be avoided, the contract is versioned and the old version is supported until usage data says it can go. The installed app is a client you cannot patch, so the server has to be tolerant on its behalf.
The answer that scores: centralise what many teams build on and what is costly to undo: the module graph, networking, authentication, release, the performance budgets. Leave the cheap, contained decisions local, such as screen-level state. Both mistakes are real: centralise too much and a platform team becomes the queue everyone waits in; too little and five teams build five networking layers.
The answer that scores: a fitness function is an automated check that an architectural property holds: a dependency rule, a startup budget, a binary size limit. A rule in a wiki erodes. A rule in CI holds, and it tells you the day it breaks rather than the quarter after. The document still has a role: a short decision record of why the rule exists, so the next person can argue with the reason rather than the rule.
The follow-up: “What goes in the decision record?” The constraints in force, the decision, the alternatives rejected, the cost accepted, and the conditions that would reopen it. The last one is the point. A record that says server-driven UI holds while these screens stay online-only and change weekly tells the next architect exactly when to revisit it. For every property you care about, ask what would tell you it had broken. “We would probably spot it” means nothing enforces it.
Prompt: “App launch has become slower over the last year. No single commit caused it. What do you do?”
Senior answer: “Measure launch on a representative device, find what runs before the first frame, and fix the worst offenders.” That is correct, and it fixes this quarter.
Staff answer: “Several teams each added a little synchronous work to launch, because nobody owns launch and everyone can add to it. So after the fix, I would give it an owner, set a launch budget, add an automated check in CI that fails when a change exceeds it, and give teams a supported way to defer their initialisation. Otherwise we are back here next year.”
Push: “A team says its SDK must initialise at launch.” Then it is a budget negotiation with data: what breaks if it is deferred, what it costs in milliseconds, and who decides. That is an ownership conversation, and it is the one the interviewer wanted.
The difference between the two answers is not technical depth. It is that the second one changes the system so the problem cannot come back unnoticed.
The pattern questions live on the platform pages, so they are not repeated here: Android architecture interview questions, iOS architecture interview questions and Flutter architecture interview questions. If the round is a design exercise rather than a conversation, see Mobile system design interview.
Whichever you pick, answer out loud and time yourself. Saying the answer is the part a page cannot do for you, and it is the part the round scores.

Android · 14 min
Ten Android architecture interview questions and how senior answers are scored: layers, the domain layer, UDF, Hilt, modules, navigation and testing.

iOS · 14 min
Ten iOS architecture interview questions and how senior answers are scored: MVVM, TCA, navigation, dependency injection, SPM modules, testing.

Flutter · 10 min
Flutter architecture interview questions on layering, state ownership, packages and testing, with the decision each one tests and what it costs a team.