Как структурировать модули и навигацию в многомодульном Android приложении
Что проверяют
Понимаете ли вы, зачем делить приложение на модули: скорость сборки, изоляция команд, явные границы, и как фичи открывают экраны друг друга, не зная друг о друге. Следом спрашивают про циклические зависимости и про то, где живёт DI.
Как отвечать
:app: тонкая точка сборки. Подключает все фичи, собирает общийNavHostи граф DI;- *`:feature:
**: экраны и ихViewModel. Фича не зависит от других фич. Если связь нужна, фичу делят наapiс контрактом иimplс реализацией, соседи видят толькоapi`; - *`:core:
**:data,network,database,designsystem,ui`. От них зависят фичи, обратное запрещено; - сборка: версии в
libs.versions.toml, общие настройки в convention plugins вbuild-logic,implementationвместоapi, чтобы правка не пересобирала полпроекта.
Навигация. Фича экспортирует маршрут и расширения вроде NavGraphBuilder.profileScreen() и NavController.navigateToProfile(), а :app склеивает граф и передаёт колбэки. Фича сообщает «пользователь хочет открыть заказ», а куда вести, решает приложение. В Navigation Compose с версии 2.8 маршруты типобезопасные: @Serializable классы вместо строк. Для новых проектов стоит знать Navigation 3, где back stack это обычный список под контролем приложения. На фрагментах аналог: вложенный граф в каждой фиче и deep link для переходов между ними.
DI: Hilt-модули в impl связывают интерфейсы из api с реализациями, а :app видит всё и собирает граф.
Где спотыкаются
Разрешают фичам зависеть друг от друга напрямую. Через полгода граф зависимостей превращается в клубок, и любая правка пересобирает всё.
Предлагают обмен данными между модулями через общую ViewModel или LiveData. Фичи обмениваются через слой данных и аргументы навигации, а ViewModel остаётся внутри экрана.
Делят проект по слоям (:data, :domain, :ui на всё приложение) и называют это многомодульностью. Сборка почти не ускоряется, а границ между фичами так и нет.