Откройте для себя простые многомодульные Kotlin-приложения: структура, технологии и готовые примеры!
Погрузитесь в мир эффективной Android-разработки с четким разделением на app, feature и core модули, используя Compose, Retrofit, MVI, DI и навигацию.
Современная разработка Android-приложений все чаще склоняется к многомодульной архитектуре. Этот подход не только улучшает организацию кода, но и приносит значительные преимущества в масштабируемости, поддержке и скорости сборки. Если вы ищете примеры простых Kotlin-приложений с классической структурой из модулей app, feature и core, использующих Jetpack Compose, Retrofit, MVI, Dependency Injection (DI) и навигацию (и при этом не являющихся Kotlin Multiplatform проектами), то вы пришли по адресу.
Ключевые моменты многомодульной архитектуры
- Четкое разделение ответственности: Модули
app,featureиcoreобеспечивают логическую изоляцию различных частей приложения, упрощая разработку и тестирование. - Современный стек технологий: Использование Jetpack Compose для UI, Retrofit для сети, MVI для управления состоянием, DI (Hilt/Koin) для внедрения зависимостей и Jetpack Navigation для навигации является стандартом для производительных приложений.
- Улучшенная масштабируемость и поддержка: Модульность позволяет командам работать параллельно над различными фичами и облегчает внесение изменений без риска затронуть другие части системы.
Анатомия многомодульного Android-приложения
В рассматриваемой архитектуре приложение делится на три основных типа модулей, каждый со своей четко определенной ролью. Такой подход способствует созданию чистого, поддерживаемого и легко тестируемого кода.
Общая схема архитектуры Android-приложения, иллюстрирующая разделение на слои и модули.
Модуль app: Оркестратор приложения
Модуль app является точкой входа в ваше приложение. Его основные задачи:
- Инициализация: Запуск основных компонентов приложения, настройка DI (например, Hilt).
- Корневая навигация: Управление глобальными навигационными потоками между различными
feature-модулями с использованием Jetpack Navigation Component. - Сборка приложения: Объединение всех
feature-модулей иcore-модулей в единое целое. Он зависит от модулейfeatureиcore, но сам обычно не содержит сложной бизнес-логики. - Build Variants: Может использоваться для компиляции различных версий приложения (например, для разных сред или брендов).
Модули feature: Изолированная функциональность
Каждый feature-модуль инкапсулирует отдельную функциональность или экран приложения (например, "Профиль пользователя", "Лента новостей", "Оформление заказа").
Ключевые характеристики feature-модулей:
- Независимость: Разрабатываются и тестируются изолированно. В идеале,
feature-модули не должны напрямую зависеть друг от друга, взаимодействие происходит черезapp-модуль или общие интерфейсы изcore. - Пользовательский интерфейс (UI): Реализуется с использованием Jetpack Compose.
- Управление состоянием: Применяется архитектурный паттерн MVI (Model-View-Intent) для предсказуемого управления состоянием UI. Kotlin Coroutines и Flow (StateFlow/SharedFlow) часто используются для реализации MVI.
- Локальный DI: Могут иметь свой собственный граф зависимостей, если это необходимо, или получать зависимости из
appилиcore. - Зависимости: Зависят от
core-модуля для доступа к общим утилитам, моделям данных и сетевым сервисам.
Модуль core (или common, library): Общая база
Модуль core содержит код и ресурсы, которые используются несколькими другими модулями в приложении.
Содержимое core-модуля:
- Сетевое взаимодействие: Конфигурация и реализация Retrofit-клиентов для работы с API.
- Утилиты: Общие вспомогательные классы и функции (например, работа с датами, строками, ресурсами).
- Модели данных: Общие DTO (Data Transfer Objects) и доменные модели.
- Базовые компоненты: Абстракции для репозиториев, базовые ViewModel (если применимо), интерфейсы для навигации.
- DI-модули: Общие модули для Dagger/Hilt или Koin, предоставляющие зависимости, такие как Retrofit-сервисы, базы данных и т.д.
- Ресурсы: Общие строки, стили, цвета, если они не специфичны для конкретной фичи.
Такое разделение помогает избежать дублирования кода и обеспечивает консистентность во всем приложении.
Визуализация преимуществ многомодульной архитектуры
Многомодульная архитектура предлагает ряд преимуществ по сравнению с монолитным подходом, особенно для Android-приложений, построенных на Kotlin и современных технологиях. На диаграмме ниже сравниваются ключевые аспекты такой архитектуры с традиционным монолитным подходом.
Как видно из диаграммы, многомодульный подход значительно выигрывает в масштабируемости, поддерживаемости, тестируемости и скорости инкрементальных сборок. Изоляция ошибок также упрощается, так как проблемы в одном модуле с меньшей вероятностью затронут другие.
Структура зависимостей в многомодульном проекте
Понимание того, как модули взаимодействуют друг с другом, является ключом к успешной реализации многомодульной архитектуры. Представленная ниже ментальная карта иллюстрирует типичные зависимости между модулями app, feature и core.
(Точка входа, Навигация, DI Root)"] id_app_dep1["Зависит от Feature Modules"] id_app_dep2["Зависит от Core Module"] id_feature_modules["Feature Modules
(Изолированный функционал)"] id_feature_item["Feature A (экран/поток)"] id_feature_tech1["UI (Jetpack Compose)"] id_feature_tech2["Логика (MVI)"] id_feature_tech3["Локальный DI (при необходимости)"] id_feature_dep["Зависит от Core Module"] id_feature_item2["Feature B (экран/поток)"] id_feature_tech4["UI (Jetpack Compose)"] id_feature_tech5["Логика (MVI)"] id_feature_dep2["Зависит от Core Module"] id_feature_no_dep["Feature модули НЕ зависят
друг от друга напрямую"] id_core_module["Core Module
(Общие компоненты)"] id_core_net["Сеть (Retrofit)"] id_core_di["DI (Hilt/Koin модули)"] id_core_utils["Утилиты, Модели данных"] id_core_base["Базовые классы, Интерфейсы"] id_core_res["Общие ресурсы"] id_technologies["Ключевые технологии"] id_tech_compose["Jetpack Compose"] id_tech_retrofit["Retrofit"] id_tech_mvi["MVI (Model-View-Intent)"] id_tech_di["DI (Hilt/Koin)"] id_tech_nav["Jetpack Navigation"]
Эта карта показывает, что app модуль является своего рода "собирателем", зависящим от feature и core модулей. Feature модули, в свою очередь, изолированы друг от друга и зависят только от core модуля для получения общих данных и утилит. Core модуль не зависит ни от кого, предоставляя базовую функциональность.
Интеграция технологий в многомодульную структуру
Jetpack Compose для UI
Jetpack Compose идеально подходит для многомодульных проектов. UI каждого feature-модуля создается с помощью Compose функций, что обеспечивает декларативный и эффективный способ построения интерфейсов. Компоненты могут быть легко переиспользованы как внутри одного feature-модуля, так и, при необходимости, вынесены в core-модуль для общего доступа.
Retrofit для сетевых запросов
Retrofit, популярная библиотека для работы с HTTP API, обычно размещается в core-модуле. Это позволяет централизованно настроить клиент Retrofit, определить интерфейсы API и модели данных (DTO). Feature-модули затем получают доступ к этим сервисам через DI, не заботясь о деталях реализации сетевого слоя.
MVI (Model-View-Intent) для управления состоянием
Архитектурный паттерн MVI хорошо сочетается с Jetpack Compose и многомодульностью. Каждый feature-модуль может реализовывать MVI для управления своим состоянием.
- Model: Представляет состояние экрана или фичи. Часто реализуется как data class и управляется через
StateFlow. - View: Отображает состояние (Compose функции) и отправляет пользовательские действия (Intents).
- Intent: Представляет действия пользователя или события системы, которые могут изменить состояние.
Dependency Injection (DI) с Hilt или Koin
DI является неотъемлемой частью современной Android-разработки. Фреймворки, такие как Hilt (рекомендованный Google) или Koin, используются для управления зависимостями между модулями.
- Hilt-модули, определенные в
core, могут предоставлять зависимости (например, Retrofit-сервисы, репозитории) дляfeature-модулей иapp-модуля. - В
app-модуле обычно настраивается корневой компонент DI. - Это позволяет легко заменять реализации для тестирования (например, мокировать репозитории).
Навигация с Jetpack Navigation Component
Jetpack Navigation Component упрощает реализацию навигации в приложении. В многомодульных проектах:
- Навигационный граф (или его части) может быть определен в
app-модуле, который управляет переходами междуfeature-модулями. - Для навигации между экранами внутри одного
feature-модуля может использоваться локальный навигационный граф. - Переходы между фичами могут быть реализованы через интерфейсы, определенные в
coreилиapp, чтобы избежать прямых зависимостей междуfeature-модулями.
Видео выше ("Navigation In Multi-Module Android Apps - Why You're Doing...") рассматривает важные аспекты правильной реализации навигации в многомодульных Android-проектах, что является критически важным для поддержания чистой архитектуры.
Примеры проектов и репозиториев
Ниже приведен список примеров проектов на GitHub, которые демонстрируют описанную многомодульную архитектуру с использованием Kotlin, Jetpack Compose, Retrofit, MVI, DI и навигации. Эти проекты могут служить отличной отправной точкой для изучения и создания собственных приложений.
| Название проекта / Ссылка | Ключевые особенности и технологии | Структура модулей |
|---|---|---|
| emirhanemmez/ComposeSample | Multi Module Clean Architecture, Jetpack Compose, Retrofit, Hilt (DI), Navigation Component, MVI-подобный подход. | app (presentation, navigation), domain, data (core-like), feature modules. Хорошо структурирован. |
| naeemdev/Multi-Module-Jetpack-Compose-Example | Kotlin, Jetpack Compose, Clean Architecture, Retrofit, Dagger-Hilt (DI), Navigation. Демонстрирует MVI. | app (презентация, навигация), domain, data (сеть, база данных - core-like), feature modules. |
| basaransuleyman/Compose-FeatureBase-Multi-Module-Clean-Hexagonal-Architecture-Android-Kotlin | Feature-based модульность, Clean Architecture, Jetpack Compose, Retrofit, Hilt (DI), навигация через отдельный модуль. MVI. | app, feature (с разделением на data, domain, presentation), core (common, navigation). |
| EduDev06/MVIComposeProject | Сильный акцент на MVI с Jetpack Compose, Retrofit, DI. Архитектура совместима с многомодульным подходом. | Модульная структура, где core-подобный модуль содержит Retrofit и DI. |
| wellingtoncabral/android-compose-mvi-navigation | Демонстрация MVI, Jetpack Compose и Navigation Component в многомодульном контексте. | app (навигация), feature-модули (экраны), core-модуль (Retrofit, Hilt). |
Примечание: Структура модулей в некоторых проектах может незначительно отличаться в названиях (например, data или common вместо core), но концептуально они следуют принципам разделения на точку входа, фичи и общую логику.
Часто задаваемые вопросы (FAQ)
В чем основное преимущество многомодульной архитектуры перед монолитной?
Многомодульная архитектура улучшает масштабируемость, так как команды могут работать над разными модулями параллельно. Она ускоряет время сборки (особенно инкрементальные сборки, так как пересобираются только измененные модули и их зависимости), упрощает тестирование за счет изоляции модулей, и повышает общую поддерживаемость кода благодаря четкому разделению ответственности.
Как Retrofit интегрируется в структуру app, feature, core?
Обычно конфигурация Retrofit (создание клиента, определение API интерфейсов и моделей данных) размещается в core-модуле. Этот модуль затем предоставляет экземпляры Retrofit-сервисов через DI (например, Hilt) для feature-модулей, которым необходим доступ к сети. Таким образом, feature-модули не знают о деталях реализации сетевого слоя.
Какова роль MVI в feature-модулях?
MVI (Model-View-Intent) используется в feature-модулях для управления состоянием UI. Он помогает создать предсказуемый однонаправленный поток данных: View (Compose UI) отправляет Intents (действия пользователя), которые обрабатываются (например, в ViewModel или процессоре), изменяя Model (состояние). Обновленная Model затем отображается View. Это хорошо сочетается с реактивным подходом Jetpack Compose и Kotlin Flow.
Как организовать навигацию между различными feature-модулями?
Навигация между feature-модулями обычно координируется из app-модуля с использованием Jetpack Navigation Component. Чтобы избежать прямых зависимостей между feature-модулями, можно использовать интерфейсы навигации, определенные в core или app модуле. Feature-модуль вызывает метод интерфейса, а app-модуль предоставляет его реализацию, осуществляя фактический переход. Также могут использоваться deep links.
Нужно ли использовать Kotlin Multiplatform (KMP) для такой архитектуры?
Нет, для описанной многомодульной архитектуры app, feature, core в контексте Android-приложения использование Kotlin Multiplatform (KMP) не является обязательным. Примеры и концепции, обсуждаемые здесь, сосредоточены на чистой Android-разработке на Kotlin. KMP предназначен для совместного использования кода между различными платформами (Android, iOS, Desktop, Web), что является другой задачей.
Рекомендуемые запросы для дальнейшего изучения
- Каковы лучшие практики управления зависимостями в многомодульных Android проектах с Gradle?
- Как сравнить Hilt и Koin для внедрения зависимостей в многомодульных Kotlin приложениях?
- Какие существуют подходы к тестированию feature-модулей в Android с MVI и Jetpack Compose?
- Как можно оптимизировать время сборки в крупных многомодульных Android проектах?
Источники и полезные ссылки
Last updated May 17, 2025