Meta Mobile Developer (Junior Level) Interview Preparation Guide
Meta's interview process for Mobile Developers follows a comprehensive evaluation approach consisting of recruiter screening, technical phone screen, multiple onsite technical rounds, and behavioral assessment. For junior-level candidates, the process emphasizes coding fundamentals, mobile platform knowledge, and cultural fit. Expect 4-6 weeks from initial contact to final offer decision. The technical rounds focus on problem-solving ability, code quality, and understanding of mobile development challenges. Meta uses AI-enabled coding tools in some assessments and evaluates candidates on real-world thinking and communication alongside technical execution.
Interview Rounds
Recruiter Screening
What to Expect
Initial 30-minute conversation with Meta recruiter to assess basic qualifications, background, and career goals. This combines the initial recruiter phone screen and any follow-up recruiter calls. The recruiter will discuss your experience with mobile development, why you're interested in Meta, timeline, and explain the interview process. They will also verify your technical background and ensure you meet baseline requirements. At this stage, you'll receive a Metacareers account and access to preparation resources.
Tips & Advice
Be genuine and concise in your responses. Have a clear 2-3 minute 'Tell me about yourself' story prepared that highlights your mobile development experience. Show enthusiasm for Meta's mission and mobile products. Ask thoughtful questions about the role and team. Mention specific Meta products you use and appreciate. Be honest about your experience level as a junior developer—recruiters expect you to be early in your career. Confirm logistics (interview schedule, preparation resources, expected timeline). Create your Metacareers account immediately and review the email with preparation resources.
Focus Topics
Availability and Timeline Clarification
Confirm your availability for upcoming interview rounds, any potential scheduling constraints, and your expected start date if hired.
Practice Interview
Study Questions
Learning Ability and Growth Mindset
Share examples of how you've learned new technologies, solved difficult technical problems, and adapted to changing project requirements. Highlight curiosity and proactive learning.
Practice Interview
Study Questions
Mobile Development Skills Inventory
Clearly communicate your technical skills: which mobile platforms (iOS, Android), languages (Swift, Kotlin, Java, JavaScript), frameworks (React Native, Flutter), and tools you're proficient with. Be honest about your current level.
Practice Interview
Study Questions
Why Meta and Mobile Product Knowledge
Explain why Meta specifically appeals to you. Demonstrate familiarity with Meta's mobile applications (Facebook, Instagram, WhatsApp, Threads) and discuss what you find interesting about their technical or product approach.
Practice Interview
Study Questions
Professional Background and Mobile Development Journey
Articulate your path to mobile development, key projects you've worked on, technologies you've used (iOS/Android/React Native), and what excites you about mobile development as a career.
Practice Interview
Study Questions
Technical Phone Screen - Coding
What to Expect
45-60 minute technical coding interview conducted over video call via CoderPad or similar platform. You'll solve 1-2 coding problems with moderate complexity, typically involving data structures and algorithms relevant to mobile development scenarios. The interviewer observes your problem-solving approach, code quality, communication, and ability to handle feedback. This round assesses your core algorithmic thinking and coding fundamentals.
Tips & Advice
Start by clarifying the problem—ask clarifying questions even if the problem seems clear. Think out loud and explain your approach before coding. Write clean, readable code with proper variable names. Test your solution against the provided examples and edge cases. If stuck, communicate the difficulty and ask for hints rather than staying silent. Optimize for clarity first, then optimization. For mobile context, relate problems to real mobile scenarios when relevant (e.g., memory constraints, list rendering). Don't over-complicate; junior-level problems are designed to be solvable with fundamental techniques. If you use the CoderPad AI assistant, use it strategically—don't let it write entire solutions but let it help with syntax or refactoring.
Focus Topics
Hash Maps and Set-Based Problem Solving
Using hash maps and sets for efficient lookups, counting, duplicate detection, and multi-step problem solving. Understanding trade-offs between space and time complexity.
Practice Interview
Study Questions
Code Quality and Testing
Writing readable code with meaningful names, proper error handling, considering edge cases, and testing against examples. Ability to identify and fix bugs during execution.
Practice Interview
Study Questions
Linked Lists and Basic Tree Operations
Understanding linked list properties (cycle detection, reversal, merging), binary tree traversal (in-order, pre-order, post-order), tree properties (balance, height, lowest common ancestor).
Practice Interview
Study Questions
Problem-Solving Methodology and Communication
Ability to break down problems, articulate your approach, explain trade-offs, ask clarifying questions, and incorporate interviewer feedback. Communicating complexity analysis (time and space).
Practice Interview
Study Questions
Array and String Manipulation
Problems involving searching, sorting, filtering, and transforming arrays or strings. Includes finding subarrays with specific properties, detecting patterns, and manipulation of character data.
Practice Interview
Study Questions
Onsite Technical Round 1 - Mobile-Specific Coding
What to Expect
45-60 minute in-depth coding interview focused on mobile platform-specific concepts. This round may present problems that require knowledge of iOS/Android development or discuss how to implement features on mobile. Problems may involve mobile-specific considerations like performance constraints, device diversity, or common mobile development patterns. You'll be expected to think about real mobile app implementation challenges while solving algorithmic problems.
Tips & Advice
Demonstrate familiarity with the mobile platform (iOS or Android) you've worked with most. If a problem relates to mobile concepts (e.g., managing UI state, handling async operations), connect your solution to mobile-specific patterns. Be ready to discuss how your solution would perform on real devices with limited memory or battery. For junior level, interviewers expect you to know fundamentals of your chosen platform but won't expect expert knowledge of every framework. If given a choice of language, use what you're most comfortable with. Be clear about trade-offs: sometimes an optimal algorithmic solution isn't practical for mobile due to memory constraints. Discuss testing considerations for mobile (different screen sizes, OS versions). Ask questions about the mobile context if it's not clear from the problem statement.
Focus Topics
Cross-Platform Framework Knowledge (React Native or Flutter if applicable)
If your experience includes React Native or Flutter: understanding component lifecycle, state management, platform-specific code, performance considerations, and debugging approaches.
Practice Interview
Study Questions
Mobile Performance and Optimization
Understanding memory constraints on mobile devices, efficient list rendering (RecyclerView/UITableView), battery optimization, reducing network calls, image optimization, and profiling tools.
Practice Interview
Study Questions
Algorithm Implementation with Mobile Context
Solving coding problems while considering mobile constraints—optimizing for memory usage, battery, and network bandwidth. Adapting solutions based on device capabilities.
Practice Interview
Study Questions
iOS Development Fundamentals (if iOS focus)
Swift syntax, iOS app lifecycle, view controllers, delegates, view hierarchies, memory management, common design patterns (MVC, MVVM). Understanding UIKit or SwiftUI basics.
Practice Interview
Study Questions
Asynchronous Programming and State Management
Handling async operations in mobile (networking, database queries), managing UI state, preventing memory leaks, understanding threading models, and using appropriate tools (AsyncTask, coroutines, RxJava, reactive frameworks).
Practice Interview
Study Questions
Android Development Fundamentals (if Android focus)
Kotlin/Java syntax, Android activity and fragment lifecycle, view layouts, intent system, async programming with coroutines, common architectural patterns (MVVM, MVI). Understanding Material Design.
Practice Interview
Study Questions
Onsite Technical Round 2 - Standard Coding or AI-Enabled
What to Expect
45-60 minute coding interview following Meta's standard format or the newer AI-enabled format. If AI-enabled, you'll work through one thematic multi-part problem (understand existing code, implement new functionality, extend the system). You have access to AI assistance in CoderPad but aren't required to use it. If standard coding, expect 1-2 conventional algorithmic problems. Both formats emphasize your ability to think critically, write quality code, and communicate effectively.
Tips & Advice
If this is the AI-enabled round: treat the AI as a helpful tool, not a solver. Use it for scaffolding or refactoring, but understand every line you submit. Read error messages carefully and explain what you're fixing. For the multi-part structure: Part 1 focuses on understanding existing code—show you can read and comprehend code that you didn't write. Part 2 is implementing clear requirements—this is where you show competence. Part 3 is extending/improving—show architectural thinking. If standard coding: same approach as Round 2 but potentially slightly harder problems. For junior level, expect questions at the level where you can solve them with time and thought, not instant solutions. Communicate your reasoning throughout. Show your verification process—run test cases, check edge cases, explain why your solution works.
Focus Topics
Effective Use of Tools and AI Assistance
If applicable, leveraging AI tools strategically without becoming dependent on them. Understanding when to use AI scaffolding vs. writing code yourself. Knowing how to prompt effectively.
Practice Interview
Study Questions
System Extension and Refactoring
Extending existing systems with new functionality, improving code quality, maintaining consistency with existing architecture, and considering future extensibility.
Practice Interview
Study Questions
Debugging and Problem-Solving Under Pressure
Finding and fixing errors efficiently, reading test failures, understanding root causes, and iterating toward solutions when initial approaches don't work.
Practice Interview
Study Questions
Code Reading and Understanding
Ability to navigate unfamiliar codebases, understand existing implementations, identify bugs, and build on working code. This is critical in real work where you inherit and extend existing systems.
Practice Interview
Study Questions
Feature Implementation and Requirement Translation
Taking clear requirements and implementing them correctly. Breaking down requirements into steps. Testing implementation against requirements. Handling user stories and specification-driven development.
Practice Interview
Study Questions
Onsite Technical Round 3 - Product Design or Mobile Architecture
What to Expect
45-minute discussion-based technical round focused on product design or mobile architecture at a component/feature level. For junior level, this is lighter than full system design interviews. You may be asked to design a feature in a Meta product, architecture for a mobile application, or discuss how you'd approach a mobile problem. The round emphasizes practical thinking about mobile constraints, user experience, and engineering trade-offs. Expect open-ended questions where you guide the conversation.
Tips & Advice
This is not a complex distributed systems design round—focus on component-level and feature-level thinking appropriate for junior level. Start by clarifying requirements and constraints. Make reasonable assumptions about scale (e.g., millions of users, but you're not designing planet-scale infrastructure). Draw diagrams if possible (on a whiteboard or CoderPad). Discuss trade-offs: performance vs. complexity, user experience vs. engineering effort, speed vs. completeness. For mobile specifically: consider device constraints, offline support, sync strategies, battery efficiency, and network reliability. Reference Meta's actual products when relevant—what design choices does Instagram make? Why might WhatsApp use end-to-end encryption? Show understanding of real mobile challenges. Ask clarifying questions: What's the target audience? What are key features? What devices/platforms? Be realistic for junior level—you're not expected to architect Netflix-scale systems, but you should think clearly about feature design.
Focus Topics
Real Product Knowledge - Meta's Mobile Apps
Understanding design choices and constraints in Meta products (Facebook, Instagram, WhatsApp, Threads). Being able to discuss why certain features are designed certain ways and what mobile challenges they solve.
Practice Interview
Study Questions
Mobile Performance and Trade-off Analysis
Understanding performance implications of design decisions. When to cache, when to lazy-load, balancing feature richness with app size, considering memory and battery implications.
Practice Interview
Study Questions
State Management Architecture
Approaches to managing application state in mobile apps. When to use local storage, in-memory state, or server-sourced state. Handling complex state transitions and preventing UI inconsistencies.
Practice Interview
Study Questions
Data Synchronization and Offline Support
Strategies for syncing data between client and server, handling offline scenarios, conflict resolution, and keeping users' experiences smooth despite network issues.
Practice Interview
Study Questions
Mobile API Design and Integration Patterns
Designing or working with APIs for mobile consumption. Considering mobile constraints: minimize data transfer, optimize for latency, batch operations. Understanding pagination, filtering, and caching strategies.
Practice Interview
Study Questions
Mobile Feature Architecture and Design
Designing features from scratch at the mobile app level. Thinking through UI/UX, data flow, state management, and API requirements. Breaking down complex features into implementable components.
Practice Interview
Study Questions
Onsite Behavioral and Cultural Fit Round
What to Expect
45-60 minute behavioral interview focused on your values, teamwork, problem-solving approach, and alignment with Meta's culture. The interviewer will ask about past experiences, how you handle challenges, conflicts, ambiguity, and feedback. This round evaluates Meta's core values: Impact, Speed, Focus, Integrity, Community. For junior level, expect discussion of learning experiences, teamwork, and how you've grown technically. The interviewer is assessing whether you'll thrive in Meta's fast-paced, engineering-driven culture and whether you fit the team.
Tips & Advice
Prepare 4-5 concrete stories from your work experience covering: overcoming a technical challenge, collaborating with teammates, receiving critical feedback and responding to it, working in ambiguity, and a project you're proud of. Use the STAR method (Situation, Task, Action, Result) but keep stories concise (2-3 minutes). Align your stories with Meta's values—show Impact (what did your work enable?), Speed (how did you move fast?), Focus (what did you prioritize?), Integrity (what's an example of doing the right thing?), Community (how did you help your team?). For junior level, don't overstate your impact—be humble but confident. Talk about what you learned from challenges. Show growth mindset: how did you improve? How did you handle not knowing something? Ask questions that show you understand Meta's mission and culture. Be authentic—interviewers can tell when you're faking alignment. Prepare questions about the team, role expectations, and how to succeed at Meta.
Focus Topics
Handling Ambiguity and Change
Examples of working with unclear requirements, changing priorities, or ambiguous problems. How you bring structure to chaos and stay productive despite uncertainty.
Practice Interview
Study Questions
Technical Problem-Solving and Ownership
Examples of taking ownership of problems, debugging issues, pushing through challenges, and delivering solutions. Showing persistence and problem-solving mindset.
Practice Interview
Study Questions
Teamwork and Collaboration
Examples of effective collaboration, cross-functional work, helping teammates, and building positive team relationships. How you communicate and resolve disagreements constructively.
Practice Interview
Study Questions
Learning Ability and Growth Mindset
Demonstrating openness to feedback, examples of learning new technologies, adapting to challenges, and growing from mistakes. Showing curiosity and proactive learning.
Practice Interview
Study Questions
Meta Core Values Alignment
Understanding and demonstrating Meta's core values (Impact, Speed, Focus, Integrity, Community) through concrete examples from your experience. Showing how your approach to work aligns with Meta's culture.
Practice Interview
Study Questions
Frequently Asked Mobile Developer Interview Questions
Users report your Android app freezes and shows an 'App Not Responding' dialog, but only for some of them. How would you find what's blocking the main thread?
Sample Answer
Direct answer
Android flags an ANR when the main thread ignores input for about 5 seconds. Capture a Perfetto/systrace around the freeze and look for one long block on the main thread track, or pull the stack Play Console or Crashlytics already captured for users you can't reproduce on.
Structured elaboration
- Reproduce under Android Studio's Profiler if possible, or pull the ANR trace from Play Console's Android vitals for wild reports.
- Look for a synchronous disk write (
SharedPreferences.commit()), a synchronous network call, or a slowonDrawoccupying the main thread for the full gap. - Cross-reference affected devices/OS versions; concentration on low-end hardware suggests CPU-bound work that's just too slow there.
- Add
StrictModedisk and network detectors in debug builds to catch this before it ships.
Worked example
The ANR threshold is 5,000 ms:
6,200 ms (blocked)>5,000 ms (threshold)
A single commit() blocking 6,200 ms is sufficient on its own to trigger the ANR.
Trade-offs and pitfalls
Swapping to apply() fixes the freeze but slightly weakens the durability guarantee, a queued write instead of a confirmed one, usually the right trade for responsiveness.
What the interviewer probes next
How StrictMode would have caught this, and how you'd choose between apply(), a coroutine, or WorkManager.
How do you keep track of the decisions made during a cross-functional project so the reasoning behind them doesn't get lost or re-litigated later?
Sample Answer
Direct answer
Keep a single, easy-to-find decision log tied directly to the work it affects: what was decided, the options considered, the reasoning, and who owns it, updated by whoever is making the decision at the moment it is made, not reconstructed later from memory.
Structured elaboration
What belongs in an entry
A short, consistent structure works better than a long one, because people will actually fill it out: a title, the date, who owns it, the context in one or two sentences, the options considered with their trade-offs, the decision itself, and the reasoning behind it in a few bullet points.
Where it lives
The log needs to be one discoverable place, linked from the tickets, docs, or roadmap items it affects, not scattered across meeting notes and chat threads. A shared doc or wiki page with a simple table works; the tool matters less than the discipline of always linking to it.
Who keeps it current
The person who owns the decision, not a rotating scribe with no stake in it, writes or finalizes the entry, ideally right after the decision is made, while the reasoning is still fresh and easy to state accurately.
How it gets used afterward
In retrospectives, revisit decisions that affected the outcome and check whether the original assumptions held. For onboarding, a short list of the most consequential recent decisions gives a new team member the context that would otherwise take weeks of osmosis to pick up.
Worked example
A team is deciding between two ways to notify users of an event: a push notification versus an in-app banner. The entry, once decided, looks like this: title, "Notification channel for event alerts"; date and owner, the decision owner's name and the date; context, users were missing time-sensitive alerts under the current in-app-only approach; options considered, push notification (faster delivery, requires a new permission prompt), in-app banner only (no new permission needed, slower to be seen), and both channels (best coverage, more engineering and support surface); decision, push notification with an in-app banner as a fallback for users who decline the permission; reasoning, the delay in the in-app-only approach was the specific problem being solved, and the fallback covers users who opt out.
Anyone who later asks why the team does not just use an in-app banner, since it is simpler, can read this entry and see the trade-off was already considered, rather than re-litigating it from scratch.
Trade-offs and pitfalls
A log nobody updates is worse than no log: it creates false confidence that the reasoning is captured somewhere, while actually going stale. The fix is keeping entries short enough that updating one takes minutes, rather than requiring a formal write-up every time.
A log can also be used as a weapon later, such as insisting a past decision still holds in a situation where circumstances genuinely changed and revisiting was the right call. The log should record reasoning, not lock in a decision forever; a review date or a note on when to re-evaluate keeps it a living reference instead of a trap.
Design an offline-first sync strategy for a mobile notes app that supports create/edit/delete while offline, background sync when connectivity returns, and deterministic conflict resolution. Describe data model on client, change tracking, server API endpoints, sync algorithm (push/pull), and conflict resolution approaches (LWW, operational transforms, CRDTs).
Sample Answer
Clarify goals & constraints
Offline-first mobile notes app must allow create/edit/delete while offline, minimize data/battery, guarantee deterministic conflict resolution, and resume sync in background when connectivity returns.
Client data model
- Note: { id: UUID, title, body, updatedAt: ISO, deleted: bool, tombstoneAt?: ISO, version: int/lamport }
- Local metadata: { lastSyncedAt, pendingOps: [] }
- Persist in SQLite/Realm for durability.
Change tracking
- Append-only local operation log (pendingOps): { opId: UUID, noteId, type: create/update/delete, payload, clientTs, lamport }
- Keep tombstones for deletes until server ack.
Server API endpoints
- POST /sync/push — accept batch ops, return per-op ack + server version
- GET /sync/pull?since=timestamp — return all server-side changes since timestamp
- POST /notes/resolve — optional for manual conflict resolution audit
Sync algorithm (push/pull)
- Background job/network callback triggers sync.
- Push: send batched pendingOps (limited size), retry with exponential backoff, optimistic UI.
- Server applies ops (idempotent using opId), updates server version, responds with applied list.
- Pull: request changes since lastSyncedAt, merge into local DB, mark pendingOps as synced.
- Resolve conflicts deterministically on client using agreed policy.
Conflict resolution approaches
- LWW (last-writer-wins): easy (use lamport or serverTs). Loses intermediate edits.
- Operational Transforms: good for rich collaborative editing; complex, needs server OT engine.
- CRDTs (recommended for notes text/blocks): converge without central ordering; use sequence CRDT (RGA/Yjs) for body, tombstone-aware for deletes. Combine with per-field LWW for metadata.
- Practical hybrid: use CRDT for body text, LWW (lamport) for title/metadata, tombstones for deletes.
Mobile specifics & best practices
- Use WorkManager (Android) / BackgroundTasks (iOS) for reliable background sync.
- Compress batches, limit frequency, respect battery/data settings.
- Provide UI conflict indicators and manual merge when automatic resolution discards content.
Design an algorithm to find the first non-repeated word in a very large text file that cannot be fully loaded into memory. Discuss streaming approaches, two-pass algorithms, external sort, or probabilistic methods. Provide a solution that balances memory with accuracy and explain complexity.
Sample Answer
Direct answer
The clean solution is a two-pass, hash-map-based streaming algorithm: pass one builds a hash map
of word to frequency count without holding the file in memory; pass two re-scans the file in
original order and returns the first word whose count is exactly 1. Peak memory is bounded by
the number of DISTINCT words, not the file size, which is the property that makes this work when
the file itself does not fit in RAM. External sort and probabilistic counting are the fallbacks
when even the distinct-word count is too large to hold in memory.
Structured elaboration
Two-pass streaming (the default answer). Read the file once, line by line (or in fixed-size
chunks), splitting into words and incrementing a hash map word -> count. This pass never holds
more than one chunk plus the running map in memory. Read the file a SECOND time, in the same
original order, and return the first word whose final count (from pass one) equals 1. This
requires the file to be re-readable (a normal disk file, or a cursor that can seek back to the
start), which is the usual case for "a file too large for memory" rather than a live network
stream.
Why two passes and not one. A single pass cannot know a word's FINAL count while still
partway through the file, so a naive "return the first word not seen before" is wrong: that word
might repeat later. You need the complete counts from a first pass before you can trust any
word's non-repeating status during a second, order-preserving pass.
When the hash map itself does not fit (extremely large vocabulary). Fall back to external
sort: sort the words (using external merge sort, since the word list itself may not fit in
memory) so identical words become adjacent, then a linear scan of the sorted output counts each
run of identical words. This trades hashing's expected O(n) for sorting's O(n log n), but
removes the requirement that the distinct-word count fit in memory, since sorted runs can be
merged from disk. Recovering "first non-repeated IN ORIGINAL ORDER" from a sorted pass requires
carrying along original position as a secondary sort key, then a small final step to pick the
minimum position among words with count 1.
When exactness itself is negotiable. A Count-Min Sketch gives an approximate frequency count
in sublinear memory in one pass, at the cost of occasionally over-counting a word (never
under-counting), which could cause a truly non-repeated word to be misreported as repeated. Use
this only when a small, disclosed false-negative rate ("might miss the true answer") is an
acceptable trade against a hard memory ceiling that even a hash map of distinct words cannot
meet.
Complexity. Two-pass hashing: O(n) time for n total words across both passes, O(d)
space for d distinct words. External sort: O(n log n) time, O(chunk size) space per merge
step. Probabilistic (CMS): O(n) time, O(sketch size) space, independent of d, with a
disclosed error rate instead of exactness.
Worked example
import io
def first_non_repeated_word_two_pass(file_like):
counts = {}
file_like.seek(0)
for line in file_like:
for word in line.split():
counts[word] = counts.get(word, 0) + 1
file_like.seek(0)
for line in file_like:
for word in line.split():
if counts[word] == 1:
return word
return None
text = "the quick brown fox jumps over the lazy dog the fox runs"
print(first_non_repeated_word_two_pass(io.StringIO(text)))
text2 = "a b a b c"
print(first_non_repeated_word_two_pass(io.StringIO(text2)))
def broken_single_pass_first_sight(text_str):
seen = set()
for w in text_str.split():
if w not in seen:
return w
seen.add(w)
return None
print(broken_single_pass_first_sight(text2))
Running this: against "the quick brown fox jumps over the lazy dog the fox runs", it prints
quick. Manually counting confirms why: the appears 3 times, fox appears 2 times, and every
other word (quick, brown, jumps, over, lazy, dog, runs) appears once; scanning in
original order, quick is the first word whose count is 1. Against the harder case
"a b a b c", the two-pass function prints c, while the naive single-pass "first word not seen
before" check prints a, which is wrong: a looks unrepeated the first time it is seen, and only
a completed count (available after pass one) reveals that a repeats later, exactly the bug
two-pass counting avoids.
Trade-offs and pitfalls
- The most common mistake is trying to answer this in a single pass by returning the first
word not yet in a "seen" set. That is provably wrong whenever a word's later repeat has not
been read yet, as shown above with"a b a b c". - External sort adds
log nfactor but removes the hash-map memory requirement; prefer it
when the number of DISTINCT words is itself too large for memory, not just the raw file size. - A Count-Min Sketch trades exactness for a fixed, disclosed error budget; only acceptable
when the interviewer's stated constraint is a hard memory ceiling that no exact structure can
meet, and only with the error trade-off stated explicitly, not silently assumed. - Re-readability matters: this two-pass approach assumes the file can be scanned a second
time from the start. If the input is a genuinely single-pass stream (no seek), you cannot do
this exactly at all and must accept probabilistic counting or reduce the guarantee to
"first non-repeated among the lastWwords" instead.
Design a push notification delivery system capable of handling bursts of up to 1,000,000 notifications per second targeting 10,000,000 active devices across multiple regions. Specify components (ingest, queueing, sharding, provider-specific pools for APNs/FCM), token management, batching, retry/backpressure, prioritization, monitoring, and latency guarantees for high-priority messages (target P95 <= 2s).
Sample Answer
Requirements & constraints
- Burst: 1,000,000 notif/s; 10M active devices across regions. High-priority P95 ≤ 2s.
- Multi-region, cross-platform (APNs for iOS, FCM for Android).
High-level architecture
- Ingress API layer (HTTP/gRPC) with auth, validation, QoS headers (priority, ttl, topic).
- Global front-door load balancer + regional gateways to reduce latency.
- Write-to durable ingress stream (Kafka / Pulsar) partitioned by region + tenant + priority.
Sharding & queueing
- Kafka topics sharded by (region, device-shard = hash(device_id) % N, priority).
- Consumer pool per shard reads and batches for provider pools.
Provider-specific pools & batching
- APNs pool and FCM pool per region with configurable connections (HTTP/2 for APNs, HTTP v1 for FCM).
- Batching: group by provider token, same payload, and rate limits — send in batches up to provider limits (e.g., APNs concurrent streams).
- Adaptive batch size based on latency and backpressure.
Token management
- Central token store (Redis + persistent DB) storing device_token, platform, app_version, last_active, expiry.
- Token refresh workflow: mobile app reports token; backend validates and replaces; bad-token marking from provider feedback (unregistered, expired) and scheduled cleanup.
Retry, backpressure & prioritization
- Priority queues: high, normal, low. High-priority bypasses bulk-delayed tiers.
- Exponential backoff + limited retries; move persistent failures to DLQ for analysis.
- Backpressure: when provider pool saturated, throttle low-priority streams, shed non-critical bursts, and buffer to cold storage.
Monitoring & SLOs
- Metrics: inbound rate, queue lag, per-provider throughput, per-region latency, error rates, token failure rates.
- Alerts on queue lag and provider error spikes. Dashboards, distributed tracing.
- Autoscaling rules for consumer pools based on partition lag and CPU.
Latency guarantees
- For high-priority: reserved partitions and dedicated provider connections; preemptive batching timeout tuned low (e.g., 10-50ms) to meet P95 ≤ 2s including network and provider. Sizing: capacity planning to keep provider concurrency and throughput such that worst-case pipeline adds <1s, leaving budget for provider delivery.
Trade-offs
- Kafka for durability/ordering vs simpler in-memory queues for ultra-low latency. Chosen durable stream for burst absorbtion and multi-region resilience.
You need to migrate an Objective-C codebase that uses NSOperation heavily to Swift async/await. What are the key considerations around cancellation, operation dependencies, KVO-based progress reporting, and compatibility with older iOS versions? Sketch how you would wrap an Operation to expose an async function that preserves cancellation semantics.
Sample Answer
Approach & key considerations
- Cancellation: Map Task cancellation to Operation.cancel() and ensure the Operation checks isCancelled frequently and completes promptly. Also make async wrapper observe Task.isCancelled and cancel the Operation to keep semantics symmetrical.
- Dependencies: NSOperation dependencies run-order must be preserved. When bridging to async/await, await the dependencies’ async wrappers or schedule Operations in the same OperationQueue maintaining dependencies.
- KVO-based progress: Progress APIs (Foundation.Progress / KVO) should be forwarded. Wrap KVO with Combine, async streams, or publish Progress changes to support Swift APIs.
- Compatibility: async/await requires iOS 13+? (actually Swift concurrency is available from iOS 13 with compiler support but full runtime features need iOS 15+). Provide guarded availability checks and fallback implementations (completion handlers/OperationQueue) for older OS versions.
Wrapper sketch (preserves cancellation)
import Foundation
// Generic wrapper to run an Operation and await its completion
func awaitOperation(_ operation: Operation, queue: OperationQueue = .main) async throws {
// Quick availability guard if using Task cancellation features on older OS
try Task.checkCancellation() // will throw if already cancelled
return try await withCheckedThrowingContinuation { continuation in
// When the Task is cancelled, cancel the operation
let cancellationHandler = {
if Task.isCancelled {
operation.cancel()
}
}
// KVO: observe isFinished / isCancelled to resume continuation
var finishedObs: NSKeyValueObservation?
finishedObs = operation.observe(\.isFinished, options: [.new]) { op, _ in
if op.isFinished {
finishedObs?.invalidate()
// If cancelled propagate CancellationError
if op.isCancelled {
continuation.resume(throwing: CancellationError())
} else if let opError = (op as? ErrorReportingOperation)?.error {
continuation.resume(throwing: opError)
} else {
continuation.resume()
}
}
}
// Ensure operation is enqueued
queue.addOperation(operation)
// Tie Task cancellation to operation
Task {
// Monitor the Task; if cancelled, propagate
while !operation.isFinished {
if Task.isCancelled {
operation.cancel()
break
}
try? await Task.sleep(nanoseconds: 50_000_000) // 50ms polling, inexpensive
}
}
}
}
// Example: Operation that reports error via property
class ErrorReportingOperation: Operation {
var error: Error?
override func main() {
if isCancelled { return }
// ... work, set error if needed
}
}
Why this works
- withCheckedThrowingContinuation bridges callback-style Operation completion into async/await.
- Observing isFinished is reliable; cancelling Task triggers operation.cancel() so both sides agree.
- For dependencies, await dependent operations first (or rely on OperationQueue dependencies).
- For older OS, provide the same semantics via callbacks and keep a single code path that async/await calls into when available.
Design an API and server-side protocol for resumable uploads supporting 10k concurrent clients, files up to 200MB, and intermittent mobile connectivity. Specify endpoints for initiating an upload, uploading chunks, resuming, validating integrity, and finalizing. Explain what server state you would persist, how idempotency applies at each step, and how you would handle abandoned uploads and abuse.
Sample Answer
Direct answer
Model the upload as a stateful resource, an upload session with its own id, and make idempotency work at two different levels: session creation is protected by a client-supplied Idempotency-Key so a retried "start upload" call cannot spin up two competing sessions for the same file, and each chunk is naturally idempotent because it is addressed by its byte range plus a checksum, so re-sending the same range is a safe no-op rather than a duplicate write. Everything the server needs to persist is small: the session's metadata and the set of byte ranges already received; the file bytes themselves live in object storage, not in the session record.
Structured elaboration
Endpoints:
POST /uploads(initiate). Body:filename,total_size,content_type. Headers:Idempotency-Key(recommended). Response201:{ upload_id, expires_at, chunk_size_hint }.PATCH /uploads/{upload_id}(upload a chunk). Headers:Content-Range: bytes {start}-{end}/{total}, a chunk checksum header. Response200:{ received_ranges: [...], next_offset }. Accepts chunks out of order.GET /uploads/{upload_id}(resume). Returnsreceived_rangesandnext_offsetso a reconnecting mobile client knows exactly what is missing.POST /uploads/{upload_id}/complete(finalize). Body: client-computed whole-file checksum. Server assembles/validates and returns the final file id.DELETE /uploads/{upload_id}(abandon explicitly).
Server state persisted:
- Session row:
upload_id,user_id,filename,total_size,content_type,state(initiated / in_progress / completed / aborted),created_at,last_activity_at,expires_at. - Received-ranges record: a compact list of
{start, end, checksum}entries per chunk actually stored, not the chunk bytes themselves (those go straight to object storage). - Nothing here requires holding an open connection between chunks; a mobile client can drop off the network for minutes and resume against the same
upload_id.
Idempotency at each step:
- Initiate:
Idempotency-Keyplus a fingerprint of(filename, total_size, content_type)maps to oneupload_idfor a bounded window (documented, e.g., 24 hours); replaying the same initiate call returns the same session instead of creating a second one. - Chunk upload: idempotent by construction through
Content-Range. If a range that was already received arrives again with a matching checksum, the server responds200and does nothing further (safe retry after a lost response). If the same range arrives with a different checksum, that is a real conflict (409), not a retry, because the client is now sending different bytes for a range it already committed. - Finalize: idempotent on
upload_id; callingcompletetwice after success returns the same final file id both times rather than re-assembling or erroring, so a client that couldn't tell whether its firstcompletecall landed can safely call it again.
Handling intermittent mobile connectivity:
- Small chunk sizes (server hints a size, e.g., a few hundred kilobytes to a few megabytes) so a dropped connection loses at most one chunk's worth of progress, not the whole upload.
GET /uploads/{upload_id}is the resume contract: the client asks what ranges are already received and only re-sends what's missing, rather than restarting from byte zero.
Abandoned uploads and abuse:
expires_aton the session (returned at initiate time so the client can see its own deadline); a background sweeper deletes sessions and their stored chunks only afterexpires_athas passed, never touching a session with recentlast_activity_at.- Per-user quotas (maximum concurrent sessions, maximum total bytes in flight) enforced at initiate time, returning
429when exceeded, the same documented-quota pattern used for any other rate-limited endpoint. total_sizeis validated against the declared 200MB ceiling at initiate time, and each chunk's checksum is verified on arrival so a corrupted or tampered chunk is rejected before it is ever assembled into a final file.
Worked example
Initiate:
// POST /uploads Idempotency-Key: up-init-9f21
{ "filename": "trip-video.mp4", "total_size": 52428800, "content_type": "video/mp4" }
// 201 Created
{ "upload_id": "up_7c14", "expires_at": "2026-07-20T09:00:00Z", "chunk_size_hint": 262144 }
Upload the first chunk (256KB, matching the hinted chunk size, so the byte range is 0 through 262143 of the 52428800-byte total):
PATCH /uploads/up_7c14
Content-Range: bytes 0-262143/52428800
// 200 OK
{ "received_ranges": [[0, 262143]], "next_offset": 262144 }
Client drops off the network, reconnects later, and asks what it still needs:
GET /uploads/up_7c14
{ "upload_id": "up_7c14", "received_ranges": [[0, 262143]], "next_offset": 262144, "total_size": 52428800 }
It resumes exactly at byte 262144, no re-upload of the first chunk. Finalize once all ranges are in:
// POST /uploads/up_7c14/complete
{ "checksum_algorithm": "sha256", "checksum": "<client-computed full-file digest>" }
// 200 OK
{ "file_id": "file_31a0", "state": "completed" }
Trade-offs and pitfalls
- Server-proxied chunk uploads (as shown) are simpler to validate per-chunk but cost server bandwidth; direct-to-object-store multipart uploads (client uploads parts straight to storage using short-lived credentials) save that bandwidth but push part-tracking and checksum bookkeeping onto a more complex client-storage handshake. For 10k concurrent clients, the bandwidth savings usually win, at the cost of that added complexity.
- Chunk size is a real trade-off: smaller chunks tolerate flaky mobile networks better (less to re-send after a drop) but add per-chunk request overhead at scale; larger chunks are more efficient per byte but riskier on an unreliable connection.
- A pitfall specific to idempotency here: treating "same range, different checksum" as a silent overwrite instead of a
409hides a real client bug (a chunk that got corrupted or a retry that picked up stale data) and can quietly assemble a corrupted final file. - Garbage-collecting by
expires_atalone, without checkinglast_activity_at, risks deleting a session that is still actively (if slowly) being uploaded to from a poor connection right at the boundary of its TTL; the sweeper should treat both signals together, the same discipline as garbage-collecting any other long-lived job resource.
What is the difference between 'culture fit' and 'culture add', and which do you think better describes you as a candidate? Give one concrete example of a perspective, skill, or way of working you would bring to a team that is not already well represented there.
Sample Answer
Direct answer
Culture fit asks whether you already share a team's existing norms and behaviors; culture add asks what you would bring that the team does not already have. I would describe myself mostly as a culture add: I share the fundamentals a team needs to trust me (reliability, candor, respect for other people's time), but the useful thing I offer beyond that is a genuinely different working background rather than a mirror of the team that is already there.
Structured elaboration
- Define both terms precisely before answering for yourself. Culture fit is about alignment on shared behaviors and values: does this person operate the way we already operate. Culture add is about complementary difference: does this person's background, working style, or perspective fill a gap the team doesn't currently have.
- Explain why the distinction matters, not just define it. A team optimized purely for fit tends toward groupthink: everyone reasons the same way, so blind spots go unchallenged and the same kinds of mistakes recur. A team that only adds without any shared fit becomes uncoordinated: people can't predict each other's reasoning enough to move fast together. The healthy target is fit on a small number of load-bearing behaviors (honesty, follow-through, respect) plus deliberate add on everything else.
- Give a genuine, specific example of your own add, not a generic trait. Vague claims ("I bring diverse perspectives") are the single most common failure mode here; a strong answer names the concrete gap and the concrete evidence.
- Anticipate the natural follow-up: how do you know your difference is actually useful, versus just different for its own sake. The answer is to point at a specific decision, disagreement, or piece of feedback that changed because of the difference you brought, not just a credential or background fact.
Worked example
Suppose your last two teams were both product engineering teams building consumer-facing features, and the team you're interviewing for is mostly staffed by engineers with that same background. Your own prior role was on a data-platform team, closer to the systems that feed those consumer features than to the features themselves. A concrete add-story: in a past project, a product team wanted to ship a new recommendation feature quickly; because of your platform background, you asked a question the rest of the team hadn't raised (whether the upstream data pipeline's freshness guarantees actually matched what the feature's UI implied to users), which surfaced a real gap between a 24-hour batch refresh and a UI copy that said "updated just for you." The team fixed the copy and adjusted the refresh cadence before launch rather than after a user complaint. That is a genuine add: a different background produced a question the existing team composition was less likely to ask on its own, and it changed a real outcome.
Trade-offs & pitfalls
The common failure is answering only the definitional half (correctly explaining fit versus add) and then, when asked for a personal example, retreating to generic self-description ("I'm a good communicator", "I care about quality") that any candidate could say and that does not actually demonstrate difference. A second pitfall is overcorrecting into implying you don't fit at all; the strongest answers are explicit that you also share the small set of behaviors every functioning team needs, and that add is about everything on top of that baseline, not a replacement for it.
Before you commit to a technology you have not used, what do you actually do to find out whether it holds up? Take one check you would run and tell me how you would set it up, how long you would give it, and what result would settle the question.
Sample Answer
Direct answer
I pick one cheap, decisive check rather than trying to evaluate everything, I decide in advance exactly what result would change my mind in either direction, and I treat the answer as provisional until it survives a check against conditions close to my actual environment, not the vendor's easiest demo.
Structured elaboration
- Choose a check that's cheap and likely to be decisive, not exhaustive. Options I'd draw from: a load test against a traffic shape similar to what I'd actually see, a compatibility check against the messier parts of my real data, a "does the failure mode make sense" test where I deliberately break it and see what happens, or a rough cost-at-scale estimate. I pick whichever is most likely to actually kill the option if it's wrong, not whichever is easiest to run.
- Set it up against realistic conditions. As close to my real environment as is cheap to arrange, representative data volume and shape, realistic concurrency, rather than the vendor's polished happy-path demo.
- Time-box it with a fixed number of days. An evaluation with no deadline tends to drift on indefinitely, so I decide up front how long I'll give it.
- Pre-register the threshold before I see the result. I decide in advance what number or behavior counts as pass, fail, or genuinely needing more evidence. That's what makes an improvement believed rather than just accepted: I said in advance what would have counted as no improvement, so the result can actually surprise me.
- Keep the check away from anything that could hurt what's already running. It happens in an isolated environment that can't touch production, and if it passes, the first real use is staged behind a flag (a toggle that turns the new option on for only a slice of traffic, cheap to switch back off) or on a small, low-stakes slice, not a full rollout.
- Write the result down either way, pass or fail, so it isn't re-litigated from scratch the next time someone considers the same option.
Worked example
Say a team is considering a new caching layer that claims a large latency improvement over what they're currently running. The one check I'd pick is a load test against a replay of a real day's traffic, not a synthetic benchmark, because that's the check most likely to actually kill the claim if it doesn't hold up under real conditions rather than the vendor's ideal load pattern. I'd set a threshold before running it: the new layer needs to beat the current setup's latency at the ninety-fifth percentile, the level that reflects the slower end of typical requests rather than just the average, by a meaningful and pre-agreed margin under that same replayed traffic, or it's a no. I'd give it three days, run it in an isolated environment with no path to real traffic, and if it clears the threshold, roll it out first behind a flag on a small fraction of traffic with its own explicit monitoring before considering a wider switch. If it fails the threshold, I'd write that up too, so the option doesn't get re-proposed and re-tested from scratch in six months.
Trade-offs and pitfalls
The most common trap is trusting a benchmark the vendor ran under their own, more favorable conditions instead of your own. A close second is an open-ended "let's keep evaluating," where nobody ever set a threshold, so the check never actually resolves the decision either way. And testing directly against production instead of an isolated environment turns an evaluation into an incident risk, which defeats the purpose of a cheap, safe check in the first place.
In Kotlin, show how to start a second Activity with Intent extras and retrieve those extras safely in the receiving Activity. Include an example for a simple String extra and a Parcelable object. Demonstrate null-safety when reading extras and mention any preferred modern API for returning results to the caller.
Sample Answer
Brief approach
Show how to send extras (String + Parcelable) via Intent, read them in the receiving Activity in a null-safe way, and note the modern Activity Result API for returning results.
Sending Activity (MainActivity)
// create intent and start SecondActivity
val intent = Intent(this, SecondActivity::class.java).apply {
putExtra(SecondActivity.EXTRA_MESSAGE, "Hello from Main")
putExtra(SecondActivity.EXTRA_USER, User("alice", 30)) // User implements Parcelable
}
startActivity(intent)
// Preferred for returning results:
// val launcher = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result -> ... }
// launcher.launch(intent)
Receiving Activity (SecondActivity)
class SecondActivity : AppCompatActivity() {
companion object {
const val EXTRA_MESSAGE = "extra_message"
const val EXTRA_USER = "extra_user"
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// Null-safe retrieval
val message: String? = intent.getStringExtra(EXTRA_MESSAGE)
// Use safe-call or default:
val safeMessage = message ?: "Default message"
// Parcelable retrieval (null-safe). For API 33+, prefer passing Class<T> parameter.
val user: User? = intent.getParcelableExtra(EXTRA_USER)
// If you need non-null:
user?.let {
// use it
} ?: run {
// handle missing user
}
}
}
Parcelable example
@Parcelize
data class User(val name: String, val age: Int) : Parcelable
Null-safety & best practices
- Always treat extras as nullable and provide defaults or graceful handling.
- Use companion object constants for keys to avoid typos.
- For Android 13+ (API 33) prefer the overload:
intent.getParcelableExtra( key, User::class.java )
which returns a nullable User safely.
Returning results
- Prefer the Activity Result API (registerForActivityResult with ActivityResultContracts) over startActivityForResult for clearer lifecycle-safe code and typed contracts.
Want to create your own tailored preparation guide using our deep research?
Get Started for FreeInterview-Ready Courses
Visual-first, interactive, structured learning paths
Browse Mobile Developer jobs
AI-enriched listings across hundreds of company career pages
Explore Jobs