Введение: почему все перешли на build.gradle.kts
В новых проектах файлы сборки заканчиваются на .kts, а в старых — на .gradle. Если на собеседовании спросить, чем они отличаются, многие пожимают плечами: «ну, это Kotlin вместо Groovy». А за этим «ну» скрывается целая история про типизированные аксессоры и IDE-поддержку.
Kotlin DSL — это способ писать скрипты сборки Gradle на Kotlin вместо Groovy. Формально можно сказать «то же самое, только на другом языке», и не ошибиться. Но суть не в языке, а в том, что скрипт на Kotlin — это настоящий код: он компилируется, проверяется типами, и IDE помогает в нём ориентироваться.
Тема не самая хайповая, но на собеседованиях про сборку спрашивают регулярно: чем отличаются DSL, что такое типизированные аксессоры, почему implementation пишется без кавычек. Разберём, как это работает на самом деле.
Groovy DSL vs Kotlin DSL
У Gradle два варианта скриптов сборки, и официальная документация описывает их так:
- Groovy DSL — скрипты с расширением
.gradle. - Kotlin DSL — скрипты с расширением
.gradle.kts.
Kotlin DSL появился как альтернатива Groovy DSL и даёт улучшенное редактирование в IDE: автодополнение, рефакторинг, документацию. Он полностью поддерживается IntelliJ IDEA и Android Studio. При этом оба варианта построены на одном и том же Java API Gradle — это не две разные системы, а два способа описать одно и то же.
Ключевая мысль из документации: всё в Kotlin DSL-скрипте — это код Kotlin, который компилируется и исполняется Gradle. Не текст, который Gradle «читает», а программа, которую он собирает и запускает на фазе конфигурации.
Как запомнить
Groovy DSL — динамика: имена берутся из строк. Kotlin DSL — статика: всё проверяется типами при компиляции скрипта. Ошибка в build.gradle.kts видна в IDE ещё до запуска сборки.
Можно даже смешивать: Gradle разрешает в одном билде держать и .gradle, и .gradle.kts. Но новые проекты Android Studio создаёт только на Kotlin DSL, и Google выпускает официальный гайд по миграции с Groovy на Kotlin DSL.
Типизированные аксессоры
Главное отличие, которое стоит понимать, — type-safe model accessors (типизированные аксессоры). В Groovy DSL доступ к элементам модели сборки — конфигурациям, задачам, extension'ам — происходит по именам, которые резолвятся динамически, во время выполнения. Ошибка в имени проявится только при запуске сборки.
Kotlin DSL заменяет динамический поиск типизированными аксессорами: элементы, которые добавляют плагины, становятся доступны как типизированные функции и свойства. Это описано в Kotlin DSL primer. Сравните сами:
// Groovy: имена как строки, проверки нет
dependencies {
implementation 'androidx.appcompat:appcompat:1.8.0'
testImplementation 'junit:junit:4.13.2'
}// Kotlin: типизированные аксессоры, IDE знает про implementation
dependencies {
implementation("androidx.appcompat:appcompat:1.8.0")
testImplementation("junit:junit:4.13.2")
}В Groovy implementation — строка-имя. В Kotlin — настоящая функция, которую добавил плагин, и IDE подскажет её с автодополнением. То же с задачами и extension'ами:
plugins {
id("com.android.application")
}
android {
namespace = "com.example.myapp"
compileSdk = 36
}
tasks {
// ленивая настройка задачи: только если она реально нужна
test {
testLogging.showExceptions = true
}
}Важный нюанс: типизированные аксессоры формируются сразу после блока plugins {}. Если конфигурацию добавить вручную позже, аксессора для неё не будет — придётся обращаться по имени через named(), configure<T>() или строковые кавычки. Диагностировать такие случаи помогает задача ./gradlew kotlinDslAccessorsReport: она показывает, какие аксессоры доступны.
Тот же приём работает и для плагинов, подключённых старым способом через apply(plugin = "..."): типизированных аксессоров для них не будет, и конфигурации придётся настраивать по имени:
apply(plugin = "java-library")
dependencies {
"implementation"("junit:junit:4.13.2") // строка вместо аксессора
}
tasks {
named<Test>("test") {
testLogging.showExceptions = true
}
}Именно поэтому блок plugins {} так важен: он не только рекомендуемый способ подключения, но и источник типизированных аксессоров, которые делают скрипт безопасным и удобным.
Ошибка-классика: кандидат говорит, что Kotlin DSL — это «просто другой синтаксис». Нет: это другой подход к разрешению имён. Типизированные аксессоры — то, что отличает Kotlin DSL от Groovy DSL на уровне архитектуры, и именно это спрашивают на собеседовании.
Файлы проекта на Kotlin DSL
Весь проект на Kotlin DSL — это три файла с расширением .gradle.kts. Настройки проекта:
pluginManagement {
repositories {
gradlePluginPortal()
google()
mavenCentral()
}
}
dependencyResolutionManagement {
repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
repositories {
google()
mavenCentral()
}
}
rootProject.name = "My Application"
include(":app")Корневой файл с версиями плагинов (обратите внимание на apply false — плагин объявляется, но не применяется к корню):
plugins {
id("com.android.application") version "9.3.0" apply false
id("org.jetbrains.kotlin.android") version "2.3.21" apply false
}И модульный файл, который настраивает сам модуль:
plugins {
id("com.android.application")
}
android {
namespace = "com.example.myapp"
compileSdk = 36
defaultConfig {
applicationId = "com.example.myapp"
minSdk = 23
targetSdk = 36
}
buildTypes {
getByName("release") {
isMinifyEnabled = true
}
}
}
dependencies {
implementation(project(":lib"))
implementation("androidx.appcompat:appcompat:1.8.0")
}Обратите внимание на детали, которые выдают Kotlin: namespace = "..." — присваивание свойства, isMinifyEnabled — префикс is для boolean-свойств, getByName("release") — обращение к задаче по имени из контейнера. В Groovy всё это выглядело бы иначе, и кандидаты, которые «переписали» Groovy-скрипт в Kotlin механически, часто путают именно эти места.
Практика: что важно знать про Kotlin DSL
Несколько фактов, которые показывают глубину понимания:
- Implicit imports. Скрипты Kotlin DSL получают набор неявных импортов: API Gradle, пакет
org.gradle.kotlin.dslи несколько Java-классов (java.io.File,javax.inject.Inject). Поэтомуtasksиdependenciesработают без единой строки импорта. - Плагины через
plugins {}. Использование блокаplugins {}для подключения плагинов заметно улучшает редактирование в IDE — потому что именно оттуда берутся типизированные аксессоры. - Скрипт компилируется на фазе configuration. Ошибка компиляции build.gradle.kts — это ошибка сборки ещё до выполнения задач. Предупреждения Kotlin-компилятора показываются в консоли при конфигурации.
- Ленивая конфигурация. В Kotlin DSL принято использовать
registerиtasks { ... }, чтобы тяжёлые задачи настраивались только при необходимости — это ускоряет конфигурацию крупных проектов. - Precompiled script plugins. Общую конфигурацию модулей выносят в свои плагины-скрипты (convention plugins, обычно в каталог
buildSrc): тогда «подключение стандарта» в модуле — одна строка вplugins {}, а правки живут в одном месте. Это естественный следующий шаг после переезда на Kotlin DSL.
.gradle— Groovy DSL,.gradle.kts— Kotlin DSL; оба работают поверх Java API Gradle.- Типизированные аксессоры появляются после блока
plugins {}и дают автодополнение в IDE. implementation("...")— функция, а не строка;isMinifyEnabled,getByName— типичные Kotlin-конструкции в скриптах.- Kotlin DSL-скрипты компилируются на фазе configuration; ошибки типов видны до запуска сборки.
- Новые проекты Android Studio — на Kotlin DSL; для старых есть официальный гайд миграции.
На собеседованиях я часто вижу, как кандидаты уверенно отвечают про корутины и архитектуру, но теряются на вопросе про сборку — потому что «это же не программирование». А это программирование: типобезопасность, ленивость, компиляция. Тот, кто это понимает, выделяется сразу — и такие темы отлично закрывают разницу между junior и middle.
Хотите закрыть пробелы между junior и middle?
Kotlin DSL, сборка, архитектура — темы, которые отличают «пишущего код» от «понимающего систему». Бесплатная диагностика: разберу ваши пробелы и составлю план роста за 30–40 минут, без обязательств.
Итоги
Kotlin DSL — не косметическое изменение, а смена подхода к скриптам сборки.
- Формат:
.gradle.ktsвместо.gradle; скрипты — настоящий Kotlin-код, который компилируется. - Суть: типизированные аксессоры вместо динамических имён — автодополнение и проверка типов в IDE.
- Практика: новые проекты только на Kotlin DSL, для старых есть официальный гайд миграции.
Главное, что нужно запомнить
Kotlin DSL — это типобезопасность для скриптов сборки: аксессоры из plugins {}, компиляция на фазе configuration, поддержка в Android Studio. Объяснили это — вопрос про сборку закрыт.
Если хотите проверить себя — откройте build.gradle.kts своего проекта и попробуйте объяснить каждую строку. Не получилось — напишите в Telegram, разберём ваш проект и подготовку вместе.