JavaRush /Курси /Claude code /Граф залежностей і матриця сумісності

Граф залежностей і матриця сумісності

Claude code
Рівень 28 , Лекція 3
Відкрита

1. Ви мігруєте не рядок версії, а мережу залежностей

Коли розробник уперше чує слова dependency graph, у голові інколи вимальовується монструозна схема із сотні коробочок і стрілок, від якої хочеться закрити ноутбук і піти вирощувати помідори. На практиці все набагато прозаїчніше. Граф потрібен для одного: перестати гадати, що ви оновлюєте — одну бібліотеку, ланцюжок бібліотек чи інструмент збирання, від якого залежить усе інше.

На прикладі CashFlow Dashboard це особливо помітно. Здається, ви хочете «просто оновити Spring Boot». Але Boot не живе у вакуумі: він тягне Spring Framework, security-шар, Jackson, валідацію, частину тестової інфраструктури, конфігураційні ключі, іноді — поведінку Gradle-плагіна. Оновіть один рядок версії в build.gradle, решту вважатимете дрібницею — і це вже не міграція, а технолотерея.

Тут корисно розрізняти два артефакти:

Артефакт На яке запитання відповідає
Dependency graph Хто від кого залежить і через який ланцюжок це потрапляє в проєкт
Compatibility matrix Що ця залежність означає для міграції: чи безпечно оновлювати, що зламається, чи потрібен проміжний крок

Прямі залежності — це те, що ви явно написали в build.gradle. Транзитивні залежності — це те, що прийшло «в навантаження». Якщо прямі залежності — це гості, яких ви запросили на вечірку, то транзитивні — друзі гостей, які прийшли разом із ними, а потім ще привели своїх знайомих. І зазвичай саме вони створюють найцікавіші розмови на кухні.

Наприклад, прямі залежності CashFlow Dashboard можуть виглядати цілком невинно:

dependencies {
    implementation 'org.springframework.boot:spring-boot-starter-web'
    implementation 'org.springframework.boot:spring-boot-starter-security'
    implementation 'org.postgresql:postgresql'
}

Але якщо подивитися трохи глибше, ви побачите вже ланцюжок:

+--- org.springframework.boot:spring-boot-starter-web -> 2.7.18
|    \--- com.fasterxml.jackson.core:jackson-databind -> 2.13.x
+--- org.springframework.boot:spring-boot-starter-security -> 2.7.18
|    \--- org.springframework.security:spring-security-config -> 5.7.x
\--- org.postgresql:postgresql -> 42.5.x

Ось тут і починається зріла інженерія. Міграція ламається не на слові web starter як такому, а на ланцюжку сумісності між Java, Gradle, Boot, Security, Jackson, JPA і вашим власним кодом. Тому перший корисний висновок цієї лекції звучить нудно, але дуже практично: ви мігруєте не рядок версії, а мережу залежностей.

2. Спочатку evidence, потім інтерпретація

Коли граф уже отримано, виникає друге запитання: як його взагалі читати, якщо ви не хочете провести вечір, дивлячись на тисячу рядків виводу? Тут допомагає просте правило: не все потрібно аналізувати однаково глибоко. Спочатку відокремте важливі вузли від фонових шумів.

Для міграції CashFlow Dashboard я б подумки ділив залежності на три шари. Платформний: Java, Spring Boot, Gradle, Spring Security, JPA, драйвер БД. Інфраструктурний: JSON, логування, міграції схеми, серіалізація, інтеграційні клієнти. Тестовий і службовий: JUnit, Mockito, test starters, плагіни перевірки. Новачки часто дивляться лише на runtime, забуваючи, що тести й збирання також мають пережити міграцію, — а потім застосунок «майже збереться», а CI завалиться.

Щоб не читати граф у сирому вигляді, корисно зберігати evidence окремо: заведiть каталог evidence/ і складайте туди вивід залежностей. Тоді Claude Code, ви й будь-який рецензент дивитеся в один файл, а не переказуєте одне одному враження.

./gradlew dependencies > evidence/dependencies.txt
./gradlew dependencyInsight --dependency spring-security-config > evidence/security.txt

Цінність тут не команда, а звичка: спочатку зафіксувати evidence, потім інтерпретувати. З Claude Code це окуповується одразу — ви даєте йому конкретний evidence/dependencies.txt, а не «ну там, здається, багато залежностей, подивіться».

Ще один важливий момент для початківців: не кожен рядок графа зобов’язаний стати рядком матриці — до матриці потрапляє лише той, що реально впливає на міграційне рішення. Умовний commons-lang3 живе в проєкті без пригод. А spring-security-config, jakarta.persistence, hibernate-core, postgresql driver, Gradle wrapper і Java toolchain майже напевно заслуговують окремого рядка.

3. Sequence constraints — це частина сумісності

Дуже спокусливо думати, що compatibility matrix — це просто список: компонент, версія, статус, ризик. Але без зафіксованого порядку ви отримаєте красиву таблицю, по якій усе одно не можна безпечно рухатися. У міграції порядок важливий майже так само, як і самі версії, а інколи важливіший: технічно сумісні компоненти можуть вимагати суворої послідовності кроків.

На CashFlow Dashboard це видно особливо добре. Spring Boot 3.x вимагає новішу Java, новий Gradle wrapper — інший toolchain, а перехід із javax.* на jakarta.* безглуздо вносити, поки збирання живе в старому середовищі й не може це перевірити. «Що оновлювати» і «в якому порядку» — це одне завдання на двох рівнях.

Невелика схема допомагає це побачити:

flowchart LR
    A[Поточний стан міграції] --> B[Граф залежностей]
    C[Офіційна документація / примітки до релізів] --> D[Статус і обмеження]
    B --> D
    D --> E[COMPATIBILITY_MATRIX.md]

Всередині Status and constraints якраз і живуть sequence constraints. Наприклад, у вас може бути така логіка:

Компонент Поточна Цільова Важливе обмеження порядку
Java
8
21
Має бути оновлена перед переходом на Boot 3.x
Gradle
7.6.4
8.x
Потрібен проміжний крок до нового Boot plugin
Spring Boot
2.7.18
3.x
Йде після Java та оновлення частини build-середовища

Це не означає, що для кожного проєкту порядок буде однаковим, але для кожного проєкту він має бути явним. Якщо sequence constraint не записано, воно все одно існує — просто в голові автора. А все, що живе лише в голові автора, під час міграції зазвичай потім стає багом, якого «чомусь ніхто не очікував».

У матриці sequence constraint можна зберігати прямо в рядку компонента. Коротко і практично:

## Компонент
Gradle

## Поточна версія
7.6.4

## Цільова версія
8.x

## Статус сумісності
requires intermediate version

## Обмеження послідовності
Оновити до переходу на Boot 3.x і перевірити toolchain під Java 21

Такий запис здається надмірним рівно до того моменту, поки хтось не вирішить «одразу спробувати Boot 3, а Gradle потім». Після цього надмірність різко перетворюється на рятівне коло.

4. Словник статусів сумісності

Найчастіша проблема поганих migration-артефактів — розпливчаста мова. «Треба перевірити», «нібито сумісно», «може знадобитися адаптація», «подивимося в процесі». Усе це звучить ввічливо, але не допомагає приймати інженерні рішення. Compatibility matrix добра лише тоді, коли в ній є фіксований словник статусів. Інакше в кожного автора буде свій діалект, а в рецензента — головний біль.

І тут корисно пам’ятати різницю між двома шарами. confirmed / assumption / unknown живуть у research notes і показують, наскільки ми впевнені у висновку. Матриця відповідає на інше запитання: що з цим робити з погляду міграції. Тому незакритий unknown не стає магічно рішенням — зазвичай він потрапляє сюди як needs manual validation, а іноді доживає до Open risks у MIGRATION_PLAN.md.

Для цього рівня корисно триматися одного набору статусів:

Статус Що означає на практиці
safe update
Оновлення виглядає прямим і не потребує помітних змін коду
requires intermediate version
Не можна стрибнути одразу; потрібен проміжний крок
blocked
Наразі перехід заблоковано несумісністю або відсутністю умов
needs replacement
Компонент простіше замінити, ніж тягнути далі
needs code changes
Код проєкту має бути адаптований під нову версію
needs config changes
Потрібні зміни конфігурації, властивостей, налаштувань збирання
needs manual validation
За кодом і docs не можна чесно підтвердити сумісність без ручної перевірки

Для початківців особливо корисний останній статус. Він дуже дисциплінує. Замість того щоб вдавати впевненість, коли evidence бракує, ви чесно пишете needs manual validation. Це не слабкість, а ознака нормальної інженерної роботи. Слабкість — написати safe update, бо так спокійніше виглядає таблиця.

На практиці один компонент іноді потребує двох позначок одразу. Наприклад, Spring Boot 2.73.x для CashFlow Dashboard майже напевно означатиме і needs code changes, і needs config changes. У такому разі краще вибрати один основний статус, а другий явно описати в Required action. Але якщо вашій команді зручніше писати подвійний статус, на кшталт needs code changes + needs config changes, це теж допустимо — головне, щоб правило було єдиним по всій матриці.

Ось хороший приклад рядка, який не ховається за туманом формулювань:

## Компонент
Spring Boot

## Поточна версія
2.7.18

## Цільова версія
3.x

## Статус сумісності
needs code changes + needs config changes

За таким рядком уже зрозуміло, що це не «оновили і забули». А далі рецензент іде в Required action і Evidence, де бачить уже конкретику.

5. Читабельний COMPATIBILITY_MATRIX.md

Хороша матриця сумісності — це не величезна Excel-таблиця з пекла і не роман у дванадцяти томах. Це повторюваний, читабельний артефакт, де в кожного рядка один і той самий каркас. Важлива не форма заради форми, а те, що по ній легко пройти поглядом і швидко побачити: де безпечно, де ризик, де blocker, де недостатньо evidence.

Для CashFlow Dashboard я б рекомендував такий шаблон рядка:

## Компонент
...

## Поточна версія
...

## Цільова версія
...

## Статус сумісності
...

## Ризик
...

## Потрібна дія
...

## Обмеження послідовності
...

## Докази
...

Зверніть увагу на поле Evidence. Саме воно відрізняє матрицю від набору розумних думок. В Evidence мають лежати посилання на реальні джерела: build.gradle, gradle-wrapper.properties, вивід dependencies, конкретний клас у коді, розділ migration guide, release notes. Якщо evidence немає, у вас не рядок матриці, а заготовка для обговорення.

Нижче — три короткі приклади, які добре показують різницю між типами рядків.

## Компонент
Spring Boot
## Поточна версія
2.7.18
## Цільова версія
3.x
## Статус сумісності
needs code changes
## Докази
build.gradle; migration guide: Jakarta EE 9

Тут рядок одразу говорить: оновлення впиратиметься не лише у версію, а й у код.

## Компонент
Gradle
## Поточна версія
7.6.4
## Цільова версія
8.x
## Статус сумісності
requires intermediate version
## Докази
gradle-wrapper.properties; Gradle release notes

А тут уже видно, що не можна перестрибнути крок «бо хочеться швидше».

## Компонент
Custom Hibernate UserType
## Поточна версія
legacy implementation
## Цільова версія
jakarta-compatible implementation
## Статус сумісності
needs manual validation
## Докази
src/main/java/.../MoneyUserType.java; docs insufficient

Це чудовий приклад чесного рядка. Код є, проблема видна, але офіційне джерело не дає гарантії, що все переживе міграцію без ручної перевірки. Отже, так і пишемо.

Ще одна корисна звичка: включати до матриці не лише бібліотеки, а й системні компоненти середовища. Java — це компонент. Gradle wrapper — це компонент. Spring Boot plugin — це компонент. PostgreSQL driver — це компонент. Іноді навіть тестовий стек — окремий компонент. Бо міграція ламається не лише в runtime-коді, а в будь-якій точці, де сходяться версія, toolchain і ваша реальна кодова база.

6. Claude Code як аналітик, а не ворожка

Коли у вас уже є current-state inventory, evidence-файли та нотатки з official docs, Claude Code стає дуже корисним помічником. Але саме помічником-аналітиком, а не автоматичним мігратором. Його завдання тут — читати фіксовані входи, допомагати групувати залежності, пропонувати рядки матриці й показувати, де evidence бракує. Не більше. Щойно він починає в дусі «ну зазвичай тут усе сумісно», час повертати розмову на землю.

Хороший запит до Claude Code в цій темі звучить приблизно так:

Побудуйте рядки compatibility matrix для CashFlow Dashboard.
Використовуйте лише:
- build.gradle
- gradle-wrapper.properties
- evidence/dependencies.txt
- migration research notes
Для кожного рядка поверніть:
component, current, target, status, risk, sequence constraint, evidence.
Якщо підтвердження бракує, ставте needs manual validation.
Нічого не оновлюйте і не запускайте.

Зверніть увагу: тут є три важливі обмеження. По-перше, ви задаєте фіксовані входи. По-друге, ви задаєте фіксований словник полів. По-третє, ви прямо забороняєте execution. Це сильно знижує шанс, що Claude піде в жанр «зараз я вам ще й пів проєкту оновлю, раз уже відкрив термінал».

При цьому фінальне рішення по кожному рядку все одно залишається за вами. Claude може допомогти швидко помітити, що spring-boot-starter-security тягне стару гілку security-конфігурації, або що кастомний MoneyUserType не має явної сумісності з jakarta-світом. Але статуси blocked, needs replacement і навіть safe update має затверджувати людина, яка прочитала evidence і розуміє ризик для системи.

Корисна практична перевірка дуже проста. Відкрийте будь-який рядок своєї матриці й спробуйте вголос відповісти на три запитання: що це за компонент, чому в нього такий статус і на яке джерело ви спираєтеся. Якщо на одному із запитань ви починаєте говорити щось на кшталт «ну це Claude припустив», рядок ще не готовий. А якщо кожен рядок читається так само впевнено, як коментар до звичайного PR, значить COMPATIBILITY_MATRIX.md справді виконує свою роботу: показує не лише список залежностей, а реальну карту ризику та сумісності для міграції CashFlow Dashboard.

Коментарі
ЩОБ ПОДИВИТИСЯ ВСІ КОМЕНТАРІ АБО ЗАЛИШИТИ КОМЕНТАР,
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ