0Pricing
Android Academy · Урок

Зачем нужна модульность

Скорость сборки, зоны ответственности и повторное использование

«Зачем нужна модульность» — бесплатный урок Android Academy на CoddyKit. Это урок 1 из 4. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения Android Academy, и твой прогресс синхронизируется между веб-версией и приложением CoddyKit. Курс Android Academy содержит 4 уроков всего.

Проблема монолита

По мере роста приложения Android весь его код часто остаётся в одном модуле app. Это монолит. Сначала это удобно, но со временем начинает мешать: каждое изменение затрагивает один и тот же модуль, сборки становятся медленными, а участники команды постоянно мешают друг другу.

Модульность означает разделение одного большого модуля на множество небольших специализированных модулей Gradle. В этом уроке Вы узнаете, зачем команды это делают и какие конкретные преимущества это даёт.

Что такое модуль на самом деле

В Gradle модуль — это независимо собираемая единица кода со своим файлом build.gradle.kts. В Вашем приложении уже есть как минимум один такой модуль: :app. Каждый модуль объявляется в settings.gradle.kts.

Добавить модуль так же просто, как подключить его. Каждый модуль создаёт собственный результат сборки и может зависеть от других модулей.

// settings.gradle.kts
include(":app")
include(":core:designsystem")
include(":core:data")
include(":feature:home")
include(":feature:profile")

Преимущество 1: более быстрые сборки

Самое заметное практическое преимущество — скорость сборки. Gradle может собирать модули параллельно и, что особенно важно, кэшировать и пропускать модули, входные данные которых не изменились.

Если Вы изменили только :feature:profile, Gradle повторно использует уже собранные результаты всех остальных модулей. В монолите любое изменение может потребовать повторной сборки всего приложения.

  • Параллельное выполнение для разных модулей
  • Инкрементальные сборки: повторно собирается только изменившееся
  • Более высокая эффективность удалённого кэша и кэша сборки
// gradle.properties
org.gradle.parallel=true
org.gradle.caching=true
org.gradle.configuration-cache=true

Преимущество 2: чёткие границы

Модули устанавливают границы. Код одного модуля видит только то, что другой модуль намеренно предоставляет. Это предотвращает запутанную структуру, в которой каждый класс обращается к любому другому классу.

Видимостью управляют конфигурации Gradle api и implementation. implementation делает зависимость внутренней для модуля, поэтому потребители не смогут случайно использовать её.

// feature/profile/build.gradle.kts
dependencies {
    // Exposed to whoever depends on :feature:profile
    api(project(":core:model"))

    // Private: hidden from consumers of this module
    implementation(project(":core:network"))
}

Преимущество 3: повторное использование

Если логика находится в специализированном модуле, её можно повторно использовать в любом месте. Модуль :core:designsystem, содержащий тему, цвета и повторно используемые компонуемые элементы, может быть общим для всех функций.

То же относится и к нескольким приложениям: компания может использовать модуль :core:network в нескольких продуктах вместо копирования кода.

// Any feature can pull in shared building blocks
// feature/home/build.gradle.kts
dependencies {
    implementation(project(":core:designsystem"))
    implementation(project(":core:data"))
}

Преимущество 4: принадлежность командам

Модули удобно сопоставлять с зонами ответственности команд. Команда платежей отвечает за :feature:payments, а команда профиля — за :feature:profile. Они могут работать параллельно, сталкиваясь с меньшим числом конфликтов при объединении изменений, поскольку их код находится в разных папках и файлах сборки.

Такие инструменты, как файл CODEOWNERS, могут автоматически запрашивать проверку у нужной команды на основе пути к модулю.

# .github/CODEOWNERS
/feature/payments/   @org/payments-team
/feature/profile/    @org/profile-team
/core/designsystem/  @org/platform-team

Преимущество 5: инкапсуляция с помощью видимости

Внутри модуля модификатор Kotlin internal становится особенно полезным. Класс или функция с модификатором internal видны только внутри собственного модуля. Другие модули буквально не могут обратиться к ним.

Это позволяет предоставлять небольшую общедоступную часть и скрывать детали реализации, чего невозможно строго добиться в одном огромном модуле.

// In :core:data
// Public API other modules may use
fun interface UserRepository {
    suspend fun loadUser(id: String): User
}

// Hidden from other modules
internal class DefaultUserRepository(
    private val api: UserApi
) : UserRepository {
    override suspend fun loadUser(id: String) = api.fetch(id).toUser()
}

Цена: дополнительные затраты

Модульность не даётся бесплатно. Для каждого модуля нужно поддерживать отдельный build.gradle.kts, а также решать, какому модулю принадлежит каждый фрагмент кода. Чрезмерное разделение небольшого приложения на модули создаёт лишнюю работу без заметной пользы.

Практическое правило: используйте модули, когда сборка становится слишком долгой, команды мешают друг другу или у Вас есть чёткие повторно используемые уровни. Для небольшого приложения, созданного в свободное время, редко требуется 30 модулей.

Типичная структура модулей

Распространённая масштабируемая структура разделяет модули на уровни app, feature и core. Модуль :app связывает всё воедино, функции содержат экраны для пользователя, а модули core — общую инфраструктуру.

// Conceptual project tree
// app/                  <- single entry point, wires features
// feature/
//   home/
//   profile/
//   settings/
// core/
//   designsystem/       <- theme + reusable composables
//   data/               <- repositories
//   network/            <- Retrofit/Ktor
//   model/              <- shared data classes

Плагины соглашений упрощают структуру

При большом количестве модулей копирование одной и той же настройки Gradle повсюду становится ловушкой. Команды выносят общую конфигурацию в плагины соглашений (в модуль build-logic). После этого каждый настоящий модуль подключает один плагин вместо повторения десятков строк.

Вы увидите этот подход в крупных приложениях с открытым исходным кодом, например в Now in Android. Пока достаточно знать цель: файлы сборки должны оставаться небольшими и единообразными.

// feature/home/build.gradle.kts
plugins {
    // One convention plugin sets up Android + Compose + Kotlin
    id("myapp.android.feature")
}

android { namespace = "com.myapp.feature.home" }

Образ мышления: думайте уровнями

Самая полезная ментальная модель: зависимости должны идти сверху вниз. Функции зависят от core, а core не зависит от функций. Модуль :app находится на самом верхнем уровне и зависит от всего необходимого для сборки приложения.

Если сохранять это направление, граф модулей останется чистым, а циклических зависимостей удастся избежать. Их Вы изучите в одном из следующих уроков.

// Allowed:  app -> feature -> core
// Forbidden: core -> feature (upward) or feature -> feature (sideways)
// app/build.gradle.kts
dependencies {
    implementation(project(":feature:home"))
    implementation(project(":feature:profile"))
}

Быстрая проверка

Какое из перечисленных преимуществ является наиболее конкретной повседневной пользой от разделения растущего приложения Android на модули?

Итоги: зачем нужна модульность

Вы узнали, зачем команды разделяют монолит на модули:

  • Более быстрые сборки благодаря параллельному выполнению и инкрементальному кэшированию
  • Чёткие границы с помощью api/implementation и internal
  • Повторное использование базовых уровней, таких как система дизайна и сеть
  • Зоны ответственности команд с меньшим числом конфликтов при объединении изменений

Вы также увидели цену этого подхода — дополнительные файлы сборки — и главное правило: зависимости идут сверху вниз, app -> feature -> core. Далее Вы начнёте проводить фактические границы между модулями функций и core.

Часто задаваемые вопросы

Урок «Зачем нужна модульность» бесплатный?

Да — полный текст урока «Зачем нужна модульность» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс Android Academy, подпишись на CoddyKit PRO. Курс Android Academy содержит 4 уроков всего.

Чему я научусь в уроке «Зачем нужна модульность»?

Скорость сборки, зоны ответственности и повторное использование Ты практикуешь Android Academy с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.

Нужен ли мне опыт, чтобы начать Android Academy?

Предыдущий опыт не требуется. Android Academy на CoddyKit структурирован для всех уровней — от новичков до продвинутых, поэтому ты можешь начать отсюда или с самого начала и учиться в своем темпе. Это урок 1 из 4.

Сколько времени занимает урок «Зачем нужна модульность»?

Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.

Можно ли писать и запускать код в этом уроке Android Academy?

Да. Каждый урок Android Academy включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.

Все уроки этого курса

  1. Зачем нужна модульность
  2. Модули функций и ядра
  3. Управление зависимостями модулей
  4. Навигация между модулями
← Назад к Android Academy