1. build.gradle.kts: читання за блоками
Наразі в нас уже є три опори: plugins{} визначають поведінку збирання, repositories{} кажуть, де шукати бібліотеки, а dependencies{} перелічує, що потрібно проєкту. Тепер нам важливий не новий виток теорії, а вміння швидко орієнтуватися у файлі: де ви зараз перебуваєте і який блок узагалі редагуєте.
Для орієнтиру тримайте ось таку «карту» файлу:
| Блок | На яке питання відповідає | Проста асоціація |
|---|---|---|
|
«Які можливості має збирання?» | які інструменти лежать у ящику |
|
«Звідки завантажити бібліотеки?» | до якого магазину йдемо |
|
«Що саме завантажуємо і куди кладемо?» | що купуємо і на яку полицю вдома |
Мінімальний «скелет» виглядає приблизно так:
plugins {
// Базові можливості Java-проєкту: компіляція, тести тощо
java
// Можливість запускати застосунок через `gradlew run`
application
}
repositories {
// Maven Central — основний публічний репозиторій Java-бібліотек
mavenCentral()
}
dependencies {
// Поки порожньо, але ненадовго: сюди додамо бібліотеки проєкту
}
Важливо помітити одну тонкість: dependencies{} сам по собі не існує окремо. Конфігурації на кшталт implementation зʼявляються тому, що Java‑плагін приносить стандартну модель Java‑проєкту. Але під час редагування нам зазвичай достатньо тримати в голові просту картину: плагіни задають поведінку збирання, репозиторії — джерела бібліотек, а залежності формують classpath.
2. Рядок залежності: роль і координати
Один рядок у dependencies{} — це лише дві речі: роль залежності та її координати. Якщо тримати в голові цю коротку формулу, редагувати файл збірки стає значно спокійніше.
<конфігурація>("group:artifact:version")
Наприклад:
dependencies {
// Jackson — бібліотека для роботи з JSON (потрібна в основному коді)
implementation("tools.jackson.core:jackson-databind:3.0.4")
}
Читається буквально так: «для основного коду проєкту (implementation) мені потрібна бібліотека з координатами tools.jackson.core:jackson-databind:3.0.4».
У Kotlin DSL це виглядає як виклик функції: implementation(...). Тому типові помилки тут зазвичай суто синтаксичні, як і в звичайному коді: забули лапку, закривну дужку або випадково поставили одинарні лапки замість подвійних. Gradle у такому разі не здогадається, що ви мали на увазі, а чесно скаже: «Я не розумію цей файл».
3. Правки dependencies{} маленькими кроками
Найчастіша проблема новачка не в тому, що він «не розуміє залежності», а в тому, що редагує файл одразу на 20 рядків, потім Gradle падає, і починається ворожіння: «Який із двадцяти рядків він не перетравив?». Тому золоте правило сьогоднішньої лекції дуже просте: змінюйте по одній речі за раз, а потім перевіряйте, що проєкт і далі збирається та запускається.
Спокійний робочий сценарій зазвичай такий. Ви відкриваєте build.gradle.kts, знаходите dependencies{} (пошук за словом dependencies — не соромно, це професійна лінь), додаєте рівно один рядок, зберігаєте файл, даєте IDE підхопити зміни або просто запускаєте знайому Gradle‑команду з рівня 2 (наприклад, ./gradlew run). Якщо все гаразд — чудово, рухаємося далі. Якщо ні — ви точно знаєте, який рядок винен, тому що саме його ви додали останнім.
Наприклад, акуратне додавання однієї залежності може виглядати так:
dependencies {
// SLF4J — це API для логування (реалізацію підʼєднаємо окремо)
implementation("org.slf4j:slf4j-api:2.0.17")
}
Якщо після цього Gradle повідомляє, що «не може знайти залежність», це майже завжди означає одне з трьох: ви помилилися в координатах (описка), забули репозиторій (немає mavenCentral()) або взяли координати не тієї версії чи не того сімейства бібліотеки. І це теж приємно: проблем зазвичай не тисяча, а кілька типових — просто в різних обгортках.
Окрема маленька звичка, яка швидко окупається: після правки build.gradle.kts, коли все працює, робіть невеликий коміт у Git. Не тому, що «так треба», а тому, що це найдешевший спосіб мати кнопку «повернутися до робочого стану» без сліз і драм.
4. Читабельність dependencies{}: порядок і групи
Gradle зазвичай не надто переймається порядком рядків у dependencies{}, але людей він хвилює дуже. І це нормально: через тиждень ви відкриєте файл і захочете зрозуміти, що тут відбувається, без квесту «знайди Jackson серед хаосу». Тому ми робимо блок залежностей не лише робочим, а й читабельним — особливо в навчальному проєкті, де кожен наступний рівень спиратиметься на попередній.
Подивіться на «хаотичний» варіант. Він може працювати, але читати його неприємно — як книжку, у якій сторінки перемішали:
dependencies {
// Приклад: усе впереміш — Gradle переживе, а людина страждатиме
runtimeOnly("ch.qos.logback:logback-classic:1.5.32")
implementation("tools.jackson.core:jackson-databind:3.0.4")
implementation("org.slf4j:slf4j-api:2.0.17")
implementation("tools.jackson.core:jackson-core:3.0.4")
runtimeOnly("ch.qos.logback:logback-core:1.5.32")
}
Тепер той самий зміст, але по-людськи: схожі бібліотеки стоять поруч, є короткі коментарі-розділювачі та порожній рядок між змістовими групами. Це вже не «магія», а документ:
dependencies {
// JSON
implementation("tools.jackson.core:jackson-core:3.0.4")
implementation("tools.jackson.core:jackson-databind:3.0.4")
// Логування
implementation("org.slf4j:slf4j-api:2.0.17") // API: на нього посилатиметься код
runtimeOnly("ch.qos.logback:logback-classic:1.5.32") // реалізація: потрібна під час запуску
runtimeOnly("ch.qos.logback:logback-core:1.5.32") // у базовому варіанті курсу залишаємо модуль явно поруч із classic
}
Тут важливо не перетворювати коментарі на роман. Достатньо коротких маркерів на кшталт // JSON і // Логування. Це як підписи на коробках під час переїзду: ви не пишете «коробка №7 з різними предметами, які можуть знадобитися в теорії», ви пишете «КУХНЯ» — і всім одразу легше жити.
Ще один корисний принцип: тримайте «сімейства» бібліотек поруч. Якщо у вас є дві залежності одного group, майже напевно вони логічно пов’язані. Це не абсолютне правило, але в навчальному проєкті працює чудово й робить структуру блоку очевидною.
5. Мінікейс: ReadLater Starter і зростання залежностей
У ReadLater Starter ми спеціально йдемо крок за кроком: спочатку каркас, потім базова грамотність щодо залежностей, а далі вже реальні бібліотеки. Наша нинішня мета — не «підключити все на світі», а підготувати dependencies{} так, щоб завтра і за тиждень він і далі виглядав акуратно й зрозуміло.
Уявіть, що ви відкрили файл і хочете зрозуміти дві речі: «що належить до JSON?» і «що належить до логів?». Якщо блок згруповано, відповідь знаходиться за 3 секунди. Якщо все перемішано, ви починаєте бігати очима по файлу і витрачати енергію не на розуміння бекенд-теми, а на пошук потрібних рядків.
Тому в межах ReadLater Starter корисно тримати блок залежностей у вигляді маленької карти. Навіть якщо сьогодні ви додали лише одну бібліотеку, можна одразу залишити структуру-заготовку, щоб не збирати її потім поспіхом. Наприклад, такий каркас цілком нормальний:
dependencies {
// Тут будуть залежності для роботи з JSON
// Тут будуть залежності для логування
// Тестові залежності (поки порожньо)
}
Так, це виглядає як порожні коробки. Але це чесні порожні коробки, які через пару лекцій стануть змістовними — і при цьому файл збереже читабельність. І тут є маленький практичний момент: ви починаєте бачити проєкт не як «набір рядків», а як структуру, якою керуєте.
6. Типові помилки під час редагування dependencies{}
Помилки в dependencies{} зазвичай не «складні», а найлюдськіші: ми поспішаємо, копіюємо шматок з інтернету, не дочитуємо, де він має бути, і отримуємо червоний екран із помилкою Gradle. Це нормально. Важливо навчитися не боятися таких помилок і швидко розуміти, що саме зламалося, — майже як у звичайному Java‑коді.
Помилка №1: намагатися писати залежності в блок plugins{}.
Це класична плутанина: побачили рядок на кшталт something("group:artifact:version") і вирішили, що це також про плагіни. Але правило просте: плагіни описують поведінку збирання, а бібліотеки для коду — у dependencies{}. Якщо ви кладете бібліотеку в plugins, Gradle не стане здогадуватися — він просто відмовиться це розуміти.
Помилка №2: редагувати половину файлу за один підхід, а потім не розуміти, який рядок усе зламав.
Коли ви одразу додаєте пʼять бібліотек, змінюєте порядок, коментуєте старе і заодно редагуєте репозиторії, ви самі позбавляєте себе нормальної діагностики. Один маленький крок — одна зрозуміла перевірка. Це набагато нудніше, зате не перетворює build на лотерею.
Помилка №3: дублювати залежність або залишати стару версію поруч «про всяк випадок».
Так у файлі швидко зʼявляються майже однакові рядки, і через пару днів уже незрозуміло, який із них робочий, а який — випадковий хвіст. Корисна звичка проста: після правки перечитати весь блок цілком і прибрати все, що стало зайвим.
Помилка №4: використовувати runtimeOnly, а потім імпортувати класи цієї бібліотеки в основному коді.
Це тонка пастка. runtimeOnly означає: бібліотека буде на classpath під час запуску, але не обовʼязково під час компіляції. Якщо ви спробуєте написати import ... із такої залежності, компіляція може впасти. Якщо бібліотека потрібна в коді безпосередньо, їй місце в implementation.
Помилка №5: редагувати блок без погляду на його читабельність.
Gradle, можливо, переживе хаос із рядків, але людина — не завжди. Якщо після правки ви самі не можете за 10 секунд пояснити, де у вас JSON, де логування і чому бібліотеки розкладені саме так, значить блок уже починає працювати проти вас.
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ