
Explore advanced topics in Android system design, focusing on modern Android app architecture and privacy and security, taught by Stefan with insights from real interviews and industry experience.
Welcome to introductory notes that outline practical guidance on the Android system design interview, modern Android app architecture, privacy and security, and upcoming Kotlin data structures topics.
Master modern android app architecture with dry and solid principles and patterns like mvc, mvp, mvvm, and prepare with interview tips and mock interviews.
Explore privacy and security foundations in Android, from permissions and data minimization to cryptography, secure storage, network protection, and authentication workflows.
Learn how to write clean code and build a solid foundation for future chapters by exploring key system design principles, including dry and solid, with practical application at chapter end.
Define the goals of clean code, explore core system design principles, including the dry principle and the five solid principles, and present six demos for practical examples.
Identify the goals of system design principles, including clean code, robustness, and testability. Emphasize maintainability, readability, separation of concerns, and reuse of well-tested libraries.
Apply the kiss principle by keeping code simple and avoiding overengineering or unnecessary features. Break problems into smaller subproblems, solve them first, and then assemble for better readability and maintainability.
Embrace YAGNI to avoid unnecessary complexity and premature optimization, implement only what is needed now, and keep future features easy to add, aligning with the kiss principle.
Apply the dry principle by avoiding duplicated code and sometimes allowing small duplication for modularization concerns, promoting code reuse across functions and components to improve maintainability and reduce bugs.
Explore the SOLID five principles—single responsibility, open-closed, Liskov substitution, interface segregation, and dependency inversion—and apply them to a practical app to improve maintainability, readability, and flexibility.
The single responsibility principle requires a class to have one responsibility and one reason to change, such as database or networking logic, reducing coupling, easing testing, and improving readability.
Apply the open/closed principle: extend a class without modifying it, using abstract bases or interfaces with polymorphism, and favor composition over inheritance.
Master the Liskov substitution principle by ensuring subclasses replace superclasses without changing behavior, enforce identical input parameters for overridden methods, and adhere to supertype return rules to avoid hidden bugs.
Split large interfaces into smaller, purpose-specific ones to apply interface segregation. This lets clients depend only on what they use, reducing side effects and changes.
Explore the dependency inversion principle, where high level and low level models depend on abstractions and interfaces, enabling decoupling, easier testing, and flexible model replacement.
Merge the shareable and unshareable node managers into a single nodes manager to remove duplication and apply the dry principle across database and file system storage in the demo app.
Explore how the single responsibility principle refactors the nodes manager and persistence classes to separate concerns, improve testability, reduce coupling, and enhance code readability in the demo app.
Explore the open closed principle by using a node persistence interface with file and database implementations. Extend with new persistence forms without modifying existing code.
Apply the Liskov substitution principle in the demo app using a common interface for file and database persistence, with Kotlin contracts and require for smart casting in save and delete.
Apply the interface segregation principle to split large interfaces into focused ones in the demo app, separating note persistence (load, save, delete) from note sharing, improving flexibility and reducing no-ops.
Explore the dependency inversion principle to decouple components using interfaces, aligning with open-closed and Liskov substitution principles, demonstrated in notes persistence classes with Kotlin contracts.
Explore commonly used Android architectural patterns mvc, mvp, and mvvm, and learn how each supports a maintainable, well-structured, and testable codebase as apps grow.
Explore MVC, MVP, and MVVM, their components and data flows, and learn when to apply each pattern in Android apps with a notes demo.
Explore the model-view-controller pattern in Android, where the model handles data, the view renders the UI, and the controller coordinates between them for separation of concerns and improved unit testing.
Demonstrates the Android MVC pattern in a notes app demo, mapping model, view, and controller roles, data persistence, and how main activity orchestrates data flow, highlighting testing and maintainability concerns.
Learn MVP: model, view, and presenter. The presenter orchestrates data flow, formatting, and UI rendering, while interfaces decouple Android framework code for testable components.
The MVP demo showcases Android’s model-view-presenter pattern with a refactored notes app, detailing the model, view, and presenter structure and data flow.
Explore the model-view-viewmodel (mvvm) pattern, where the view reacts to viewmodel state via LiveData or State Flow, enabling separation of concerns and robust, testable UI.
Explore the MVVM pattern in practice with a refactored notes app, detailing model, view, and viewmodel roles, reactive state flow, and how the UI updates via compose.
Trace the evolution of mvc, mvp, and mvvm and how each pattern models data, separates concerns, and enables testability. Learn which pattern suits small or large android projects.
Explore clean architecture, its goals and strategies, and its components, and learn when to apply or avoid it, review use cases, and examine a practical example.
Define the goals of clean architecture, explore strategies to achieve them, identify key components and their relationships, discuss when to use it and when not, and conclude with a demo.
Explore clean architecture goals: improve development, deployment, operation, and maintenance while minimizing lifetime maintenance costs and boosting programmer productivity through modular, well-defined components with stable interfaces to enhance maintainability.
Learn strategies for clean architecture, keeping policies independent from details, using vertical and horizontal layering, and choosing decoupling modes from source level to deployment and service level.
Implement clean architecture by organizing code into inner entities and use cases, with controllers, gateways, and presenters, while layers like UI and database depend inward according to the dependency rule.
Explore clean architecture in action as we refactor a notes demo app into domain, data, and use cases layers, routing between file and database data sources with a repository pattern.
Explore layout architecture, the google-recommended structure for android apps, compare layered and clean architectures, and examine the UI layer, domain layer, and the data layer with a practical demo.
Explore layered architecture as the recommended android app structure, covering UI, data, and domain layers, with UI state, unidirectional state flow, repository patterns, and offline support.
Master layered architecture and key Android principles, including separation of concerns, driving UI from data models, and unidirectional state flow, with best practices for robustness, testability, and offline readiness.
Explore the recommended Android app architecture as a reactive, layered model using coroutines and flows, with unidirectional data flow across the UI layer, domain layer (optional), and data layer.
Apply unidirectional data flow by using a state holder, typically a ViewModel, to transform data from the data layer into UI state and handle UI events.
Explore the UI layer, which comprises activities and fragments, using viewmodels to transform data from the data layer into UI state and render screens via live data or state flow.
Explore the ui state production pipeline, from local and external inputs through the state holder to the ui state, using coroutines and streams to update views.
Expose produced UI state to the UI with a unidirectional data flow, using streams such as StateFlow or LiveData, for cached, automatic updates and consistent single or multiple state streams.
Consume UI state with observable streams like LiveData or state flow, respect lifecycle via repeatOnLifecycle so collection runs only when visible, and expose loading, error, or content.
Explore data layer and repository pattern, where repositories act as the single entry point. Ensure immutability, a single source of truth, and conflict resolution for local and remote data sources.
Explore nested repository layers and model separation with mappers to return only relevant data. Ensure main-safe repositories, error handling strategies, testing with interfaces, and work manager for business tasks.
Adopt offline first design by making the local data source the single source of truth in repositories, and synchronize with remote data using pull, push, or hybrid strategies.
Explore the optional domain layer between the UI and data layers, encapsulating business logic in small, immutable use cases exposed via suspend functions or Kotlin flows.
Compare layered architecture and clean architecture for Android apps. The layered model uses UI, domain, and data layers; Clean architecture emphasizes inner domain entities and dependency inversion.
Explore layered Android architecture with UI, data, and domain layers, applying the repository pattern, use cases, and node syncing.
Transform the demo to a layered architecture by reorganizing into UI, domain, and data layers, exposing UI state from the notes ViewModel and implementing data sources, repositories, and reactive APIs.
The demo shows a layered architecture with the app model in the UI layer, domain use cases, and a merged data layer, illustrating unidirectional data flow to UI state.
Explore the UI and domain layer updates, including the notes UI state (loading, error, content) exposed via state flow, and the viewmodel's load, add, delete, share, and sync use cases.
Explore the data layer changes, including repository and local/remote data sources, offline-first and reactive flows, with read/save/delete operations, conflict resolution, and pull-based synchronization.
Explore layered architecture with separation of concerns, unidirectional state flow from repository to UI via Kotlin flows, and a single source of truth with offline persistence.
Explore Android architecture components and Jetpack libraries across UI and data layers, including view binding, ViewModel, LiveData, coroutines, Datastore, Room, WorkManager, and Paging, with practical demos.
Explore Android architecture components across the UI and data layers, including view binding, data binding, lifecycle API, ViewModel, LiveData, coroutines, Room, SharedPreferences, and Paging.
Explore the view binding library for Android UI layers. It generates binding classes from XML layouts, offers null and type safety, and replaces findViewById, with usage in activities and fragments.
Learn how the Android data binding library connects xml layouts to app data in a declarative way, offering null safety, two-way binding, binding expressions, and lifecycle-aware updates for complex UIs.
Explore advanced data binding with binding adapters, custom naming, and binding converters; learn two-way binding, inverse binding adapters, and how LiveData, observable ViewModel, and ViewModel integrate with binding and lifecycle.
Leverage the Android lifecycle API to decouple lifecycle logic from activities and fragments. Observe lifecycle events with a lifecycle observer and lifecycle owner to manage tasks and avoid race conditions.
Demonstrate how the lifecycle API integrates with Jetpack Compose by making the note screen lifecycle aware using the local lifecycle owner, state flow, and lifecycle event and start effects.
Explore how the ViewModel serves as a screen-level stakeholder that handles UI state and events, delegates them to the domain or data layer, and persists UI state across configuration changes.
Learn how the ViewModel's saved state handle preserves UI state across process death using a key-value map, with integration to live data, State flow, and a Jetpack Compose state APIs.
Explore strategies to prevent state loss across configuration changes, resource pressure, and unexpected app closures using viewmodel saved state handle, rememberSaveable, onSaveInstanceState, and Room or DataStore.
Adopt view models as screen level stakeholders to manage the total UI state, avoid exposing implementation details and using a shared view model for reusable components due to scoping.
Show how a notes view model persists UI state with saved state handle, integrates with flows, and uses a factory and creation extras to load, add, delete, and share notes.
Explore how LiveData acts as a lifecycle-aware observable data holder, notifying active observers via lifecycle owners, surviving configuration changes, and preventing memory leaks while syncing with the UI and ViewModel.
Compare LiveData and flows to decide when to use each. Use LiveData for simple, lifecycle-bound UI updates; use flows for asynchronous processing, backpressure, and rich coroutine-based transformations.
Discover how Kotlin coroutines integrate with app architecture, ViewModel scope, lifecycle scope, and LiveData. Learn about coroutine context, dispatchers, flows, and lifecycle-aware collection.
Explore coroutines with Kotlin flows in an Android app, using ViewModel and lifecycle scopes. Collect flows with lifecycle-aware state in Compose and optimize with sharing started while subscribed and repeatOnLifecycle.
Jetpack data store and Proto Datastore replace SharedPreferences with asynchronous, type-safe APIs, offering transactional reads and safe IO, plus migration paths from SharedPreferences.
Examine Room, the Jetpack abstraction over SQLite, for Android data layer persistence with compile-time query verification, boilerplate-reducing annotations, and the Room database, entities, and data access objects.
Master WorkManager for persistent Android background work, covering immediate, long running, and deferrable tasks, one-time and periodic scheduling, constraints, retries, and work chaining.
Explore WorkManager advanced topics, including unique work policies, and query and observe work with LiveData and flows. Learn to manage progress and cancellation with work chaining for long-running tasks.
Demonstrates using WorkManager in practice to sync data with one-time work, unmetered wifi constraints, expedited execution, and linear backoff. Explore unique work, progress observation, and on-demand initialization for logging.
Android paging library enables infinite loading of data from local or network sources, with in-memory caching, deduplication, refresh and retry error handling, and UI integration via RecyclerView or Jetpack Compose.
Explore a demo app that showcases paging in Jetpack Compose with Google Maps, Flickr photo sourcing, and infinite scrolling powered by the Jetpack paging library.
Master the Android navigation component by exploring the navigation controller, backstack, host, and graph, and see a practical demo that builds a solid foundation.
Explore the navigation controller, destination types host, dialog, activity, backstack, navigation graph, deep links, typesafe navigation with fragments and Jetpack Compose, and integrations with Dynamic Navigator and navigation UI demo.
Master the Android navigation component by understanding the fixed starting destination, the backstack, push and pop operations, up navigation, and deep linking that builds a synthetic back stack.
Explore the Android navigation component, including the navigation controller, navigation graph, and navigation host, to automate fragment transactions and backstack, enable deep linking, animations, Safe Args, and Jetpack Compose integration.
Explore the navigation controller as the central navigation API that manages the navigation graph and backstack, establishing a single source of truth across activities, fragments, and views.
Explore the three destination types in Android navigation: hosted destinations fill the screen, dialogue destinations overlay the host with independent lifecycle and saved state, and activity destinations launch new activities.
Explore how the navigation controller manages the backstack of visited destinations, pushing with navigate and popping with popBackStack, using options like inclusive, save state, restore state, and launch single top.
Explore the navigation graph as a data structure that contains destinations and their connections, with hosted destinations, dialogue destinations, or activity destinations, for fragments or Jetpack Compose.
Master nested navigation graphs in Jetpack Compose to encapsulate onboarding and login flows, keep the main graph simple, and reuse subgraphs accessed via a single entry point.
Explore explicit and implicit deep links within navigation graphs, building a synthetic backstack from start destinations of nested graphs, and map them to activities via manifest, intents, and filters.
Explore how to pass typed arguments to destinations with type-safe navigation, compare fragment-based and compose navigation, and implement safe-args generated APIs with default values.
Explore integrations for the navigation component, including the Dynamic Navigator with feature models and on-demand delivery, and how navigation UI coordinates top app bar, drawer, and bottom navigation with menus.
Explore how to implement navigation in a travel companion app using Jetpack Compose, including nested graphs, type safe navigation, deep linking, and bottom navigation.
Explore dependency injection to supply dependencies to classes in a scalable and testing-friendly Android app architecture, compare popular di frameworks, and examine service locator patterns in a practical demo.
Explore the fundamentals of dependency injection, compare it with the service locator pattern, review popular Android dependency injection frameworks and their features, and conclude with a practical demo.
Explore dependency injection in Android app architecture, learning how dependencies flow through an application graph and why supplying dependencies from outside improves decoupling, testability, and flexibility.
Compare the service locator pattern with dependency injection, detailing how a locator creates and stores dependencies and how classes request them on demand, noting testing challenges and lack of scoping.
Dagger, the long-standing framework, generates an app graph and injects dependencies at compile time, using annotations, singleton and custom scopes, subcomponents, and supports binds, provides, and field injection.
Hilt builds on dagger to deliver compile-time correctness, runtime performance, and Android-focused boilerplate reduction through pre-built components, binding, models, and entry points for Activity, Fragment, and ViewModel.
Koin implements the service locator pattern in Kotlin, delivering singleton dependencies via a concise graph and the inject delegate, offering multiplatform support for ViewModel and Jetpack Compose with less code.
Explore codegen, a Kotlin dependency injection framework using the service locator pattern to create and supply dependencies, with bindings, named annotations, and Kotlin multiplatform support, compared to Dagger and Hilt.
Compare dependency injection frameworks—tag and tilt versus coin and codeine—covering compile-time vs runtime construction, language compatibility, testing support, ViewModel integration, and community backing.
Explore how Hilt and Kodein enable dependency injection in a Kotlin multiplatform travel app, comparing service locator and dependency injection patterns, with practical ViewModel and factory usage.
Explore modularization strategies to build a well maintainable multi-model Android app, understand underlying principles, and learn when to apply each approach through practical examples.
Explore modularization principles for maintainable multimodal Android apps, focusing on cohesion and coupling, and explain separation by layer, separation by feature, and data, feature, app, core, and test models.
Apply component cohesion to Android modular design. Explore the release reuse equivalency principle, the common closure principle, and the common reuse principle, and balance their tensions for scalable models.
Understand acyclic dependencies, stable dependencies, and stable abstractions in Android, and learn to break cycles using dependency inversion with interfaces and dependency injection frameworks such as Dagger, Hilt, or Coin.
Structure Android apps as modular models to improve readability, scalability, and testability while balancing granularity, cohesion, and coupling. Expose public APIs, enable on-demand features, and reduce build times.
Explore typical android module types, including data models with repositories and internal data sources, feature models with ui and view models, and app, core, network, and test models.
Explore Android app modularization strategies, from layer-based to feature-based and hybrid approaches. Evaluate cohesion, coupling, and granularity to optimize scalability and build times.
Apply modularization to a notes demo app using a layered architecture with data, domain, and UI modules; implement dependency injection with Hilt and Gradle version catalogs for clean architecture.
Explore architecture by layer, centralizing dependencies with Gradle version catalogs, and implementing a domain–data–UI structure where the domain defines use cases and a nodes repository interface, injected by Hilt.
Demonstrate architecture by feature, organizing data, domain, and UI per feature, with an app model coordinating them; highlight cohesion, coupling, and build-time trade-offs.
Review modern Android app architecture and clean code patterns, including MVC, MVP, and MVVM, with ViewModel and Workmanager, and outline next focus on privacy, security, and interview prep.
Explore Android privacy and security foundations, from permissions and location minimization to data handling, privacy UI elements, app hibernation, secure storage, cryptography, and network and authentication safeguards.
Take your mobile system design interview skills to the next level with this advanced course, building on the foundations laid in "Mastering the Android System Design Interview". If you’ve already mastered the basics, this course is your gateway to make you stand out in challenging and advanced system design topics — privacy, security, and modern Android app architecture — to ace your interviews at FAANG companies like Google, Apple, and beyond.
Led by Stefan, a seasoned Tech Lead from a Google Developer Agency, this course is built with over a decade of hands-on experience designing and developing Android, iOS, and multiplatform apps. Having successfully navigated system design interviews himself, Stefan understands the challenges and will share his expertise, practical tips, and interview-tested strategies to set you apart.
Mobile system design interviews are notoriously tough, with privacy and security being some of the least understood yet often critical areas. Additionally, modern Android app architecture requires a deep understanding of patterns, different architectural styles, and best practices to build scalable, maintainable apps. This course is specifically designed to address these gaps, giving you a competitive edge in your interviews. Despite the course being especially targeted at Android, many concepts are also applicable to iOS.
Over 20 hours of on-demand video content will cover what you need to know for your mobile system design interview:
Clean Code Principles: Apply DRY and SOLID principles to create codebases that are maintainable and easy to scale.
Architecture Patterns: Master MVC, MVP, and MVVM, and learn how to choose the best approach for your app’s complexity and development team.
Clean vs. Layered Architecture: Learn how Clean Architecture focuses on the independence of business logic from frameworks, while Layered Architecture emphasizes logical separation into data, domain, and UI layers.
Android Architecture Components: Streamline your system design with ViewModel, LiveData, Flow, Room, DataStore, WorkManager, and other essential libraries.
Seamless Navigation: Simplify complex app flows using the Android navigation component.
Dependency Injection (DI): Leverage frameworks like Dagger, Hilt, Kodein, or Koin to make your code cleaner, more modular, and easier to test.
Mastering Modularization: Break down complex codebases into feature-based and/or layer-based modules for better scalability based on the principles of component cohesion and component coupling.
Android Privacy Fundamentals: Explore essential topics like permissions, location handling, data, transparency & control, app hibernation, and the Privacy Sandbox.
Cryptography: Understand symmetric cryptography, asymmetric cryptography, and hashing. Learn when to use each technique effectively.
Local Data Protection: Learn how to safeguard sensitive data stored on devices using encryption and secure storage solutions.
Network Data Protection: Explore strategies for securing data in transit, including SSL/TLS, certificate pinning, certificate transparency, and Android's network security configuration.
Authentication & Authorization: Implement secure user authentication based on standards like OAuth 2.0 and OpenID Connect, and session management.
Practical tips & tricks: Get additional tips & tricks, and a toolbox of clarifying questions to ask to tackle system design questions related to app architecture, privacy, and security.
Hands-On Learning: Practice solving architectural, and privacy & security challenges through 2 extensive mock interviews from requirements definition to high-level and detailed designs.