JavaRush /Курсы /Claude code /Migration discovery и точка старта

Migration discovery и точка старта

Claude code
28 уровень , 1 лекция
Открыта

1. Migration discovery как защита от хаоса

Current-state assessment легко принять за бумажную разминку перед «настоящей работой». Но в миграциях настоящая работа как раз и начинается с того, что вы перестаёте гадать. Не с правок в build.gradle, а с точного ответа — из какой технической точки проект стартует прямо сейчас.

Когда вы мигрируете проект, вы меняете не только код. Вы меняете договорённость между кодом, сборкой, рантаймом, библиотеками, конфигами, тестами и CI. Не зафиксируете её до первого upgrade — потом не скажете честно, что сломала миграция, а что ломалось и раньше. Такое бывает пугающе часто: команда обновляет Spring Boot, а через час выясняется, что часть тестов неделю красная, просто все успели философски привыкнуть.

Полезно думать о migration discovery как об инвентаризации перед переездом офиса. Скажете «столы есть, компьютеры вроде тоже, грузим» — в день переезда серверная стойка не пройдёт в лифт, принтер окажется на древнем переходнике, а ключ от архива будет у человека в отпуске. В проекте роль этих сюрпризов играют Gradle Wrapper, несовместимые плагины, скрытые transitive dependencies, старые API и конфиги, про которые вспоминают, только когда они начинают гореть.

Поэтому вопрос discovery не «как бы красиво обновиться», а более приземлённый — что у нас есть на самом деле. Первый профессиональный фильтр против хаоса.

2. Migration Current State vs обычный inventory

На этом этапе многие пытаются переиспользовать старый CODEBASE_INVENTORY.md: «карта проекта же есть». Формально да, практически мало. Inventory и migration current state отвечают на разные вопросы — путать их так же полезно, как путать паспорт и медицинскую карту.

Что сравниваем
CODEBASE_INVENTORY.md
Migration Current State
Главный фокус Архитектура, модули, entry points, потоки выполнения Версии, build, runtime, конфиги, CI, deprecated API
Основные источники Код, тесты, роуты, структура каталогов build.gradle, wrapper, docker-compose.yml, CI, application.yml, вывод команд
Главный вопрос «Как устроен проект?» «Из какой технической точки мы стартуем?»
Итоговый смысл Навигация по codebase Основа для планирования миграции

Хорошая новость в том, что один документ не отменяет другой — наоборот, они хорошо работают в паре. Старый inventory даёт карту территории. Current state — температуру воздуха, состояние моста и список дорог, закрытых на ремонт.

3. Evidence для CashFlow Dashboard

Дальше — самая полезная часть. Чтобы inventory был не «ощущением проекта», а опорой, собирайте evidence из конкретных файлов и команд. В CashFlow Dashboard интересен не абстрактный «legacy-репозиторий», а всё, что меняет поведение при смене стека.

Сначала почти всегда смотрят в build.gradle — там большая часть правды про framework, плагины и direct dependencies:

plugins {
    id 'java'
    id 'org.springframework.boot' version '2.7.18'  // Текущая линия Boot
}

sourceCompatibility = '1.8' // Проект реально живёт на Java 8

Даже этот крошечный фрагмент уже даёт два стартовых условия: Spring Boot 2.7.18 и Java 8. Не зафиксируете — будете обсуждать Boot 3.x, не заметив, что он в принципе не дружит с Java 8.

Следом почти всегда открывают wrapper, потому что версия Gradle — не декоративная мелочь, а часть среды сборки.

distributionUrl=https\://services.gradle.org/distributions/gradle-7.6.4-bin.zip
# Wrapper фиксирует текущую версию Gradle для всей команды

Этот файл особенно полезен тем, что отрезает соблазн «локально стоит новый Gradle, значит проект почти современный». Source of truthwrapper, а не настроение вашей машины.

Дальше нужен взгляд на инфраструктурные файлы, даже если вы пока не собираетесь «мигрировать инфраструктуру». docker-compose.yml сразу показывает database baseline:

services:
  db:
    image: postgres:12  # Текущая база проекта
    ports:
      - "5432:5432"

Это важно не только из-за версии PostgreSQL. Часть поведения бывает привязана к старому диалекту БД, к сериализации времени, к старым индексам. На discovery это не чинят — признают частью текущей среды.

Очень полезный источник — CI: он часто показывает то, что локальная машина разработчика стыдливо скрывает, — другую JDK, другой шаг сборки, другой профиль запуска.

- name: Запуск тестов
  run: ./gradlew clean test  # Команда, которую проект реально считает baseline

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

Наконец, не забывайте про конфиги приложения. Даже небольшой кусок application.yml бывает важнее большого сервиса, если свойства менялись между major-версиями:

spring:
  jackson:
    serialization:
      WRITE_DATES_AS_TIMESTAMPS: false  # Текущее поведение дат

Такие параметры особенно неприятны тем, что долго выглядят безобидно, а потом внезапно меняют поведение API или тестов. Поэтому assessment — не только про зависимости, но и про то, как проект живёт на настройках.

4. Direct и transitive dependencies проекта

«У нас немного зависимостей» говорят, глядя только на dependencies в build-файле. Это как «я переезжаю налегке», глядя на чемодан и игнорируя антресоль, гараж и пять коробок с проводами «на всякий случай». В миграциях эти коробки называются transitive dependencies.

Direct dependency вы записали в build.gradle сами. Transitive она тащит за собой. На практике именно transitives часто устраивают вечеринку с разбитыми стёклами: вы о них не думали, а они давно живут в проекте как полноправные жильцы.

Чтобы увидеть реальную картину, мало читать build-файл — нужно ещё сохранять вывод команд как evidence:

./gradlew -version > evidence/gradle-version.txt      # Фиксируем реальные Gradle и Java
./gradlew dependencies > evidence/dependencies.txt    # Сохраняем дерево зависимостей
./gradlew test > evidence/test-baseline.txt           # Видим базовое состояние тестов

Здесь важно не то, что команды красиво выглядят. Важно, что эфемерное состояние терминала превращается в файлы, к которым можно вернуться. Особенно это полезно, если вы работаете с Claude Code: ему проще анализировать сохранённый вывод, чем гадать, что было в консоли три сообщения назад.

Типичный фрагмент дерева зависимостей:

+--- org.springframework.boot:spring-boot-starter-web
|    \--- org.springframework:spring-web:5.3.x
\--- org.springframework.boot:spring-boot-starter-data-jpa
     \--- org.hibernate:hibernate-core:5.6.x

Даже этот короткий кусок уже показывает, что за одним стартёром — целая толпа библиотек. Вы обновляете не «один Boot», а букет: Spring Framework, Hibernate, Jackson, Security и всё прилипшее. Поэтому assessment без дерева рассказывает, кого вы пригласили сами, но молчит о гостях, пришедших плюс-один.

5. Known failures, deprecated APIs и unknowns

Готовясь к миграции, хочется писать только «чистые» факты — версии, файлы, команды. А неприятное (падающие тесты, устаревшие API, странные самописные адаптеры) мозг предлагает не замечать. Именно оно — самая ценная часть.

Начать полезно с known failures. Если тест уже падает до миграции, это не повод прятать его под ковёр — это повод записать его в baseline.

## Известные сбои
- SubscriptionIT.testProrationAtPeriodSwitch падает и на текущем стеке
- BillingReportIT нестабилен при локальном часовом поясе UTC+3

Такой кусок выглядит немного обидно, зато делает документ честным: он экономит часы споров «это миграция сломала» — «нет, оно и раньше было странным».

Отдельно стоит фиксировать deprecated API и старые точки расширения. В CashFlow Dashboard типичные кандидаты — старый Spring Security и javax.*:

import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;

@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    // Старый способ конфигурации security
}

И второй классический сигнал:

import javax.persistence.Entity;
import javax.persistence.Id;

@Entity
public class Subscription {
    @Id
    private Long id;
}

Немедленно чинить не нужно — нужен честный статус: здесь точка риска на старой линии фреймворка, её учитываем как часть current state.

И, наконец, самое ценное — секция Unknowns. Новички часто думают, что unknown — это признание слабости. На деле — признание реальности. Не уверены, как поведёт себя кастомный JSON-адаптер, старый платёжный SDK или самописный Hibernate type на новом стеке — не прячьте, записывайте.

## Неизвестное
- Совместимость кастомного JsonAdapter с новой линией Jackson не подтверждена
- Поведение timezone-логики в monthly reports требует ручной проверки
- Реакция старого payment SDK на Java 21 пока не проверена

Хороший документ не делает вид, что команда знает всё: он отделяет подтверждённое от предположительного — потому на него и можно опираться.

6. Claude Code как аналитик, не апгрейдер

Claude Code здесь очень полезен — если правильно задать роль. Не задать — он с энтузиазмом начнёт предлагать обновления, рецепты миграции, рефакторинг и всю ту активность, от которой мы сегодня держимся подальше. На discovery это не исполнитель, а аналитик с хорошей памятью и терпением к скучным документам.

Хорошая инструкция на этот шаг:

Собери current-state inventory для репозитория.
Источники: build.gradle, gradle-wrapper.properties, docker-compose.yml,
.github/workflows/*, application.yml, src/main/**.
Ничего не меняй. Не предлагай upgrade.
Каждое утверждение подтверждай file path или выводом команды.
Всё неподтверждённое выноси в секцию Unknowns.

Если у вас уже есть проектный CLAUDE.md, туда полезно добавить короткий режим именно под migration discovery:

## Режим migration discovery
- Работать только в read-only режиме
- Версии подтверждать file path или выводом команды
- Не предлагать update dependencies без явного запроса
- Всё сомнительное писать в Unknowns

Схема процесса простая:

flowchart LR
    A[Файлы репозитория] --> C[Черновик inventory]
    B[Вывод команд] --> C
    C --> D[Проверка человеком]
    D --> E[Migration Current State]

Обратите внимание на последнюю стрелку. Claude не выпускает документ в прод из своей головы: готовит черновик, собирает evidence, помогает ничего не забыть — но «да, это confirmed» остаётся за человеком. И это правильный баланс: AI ускоряет анализ, а не подменяет инженерное решение.

7. Сборка документа Migration Current State

Когда evidence собраны, важно не оставить их жить разрозненно: кусок в терминале, кусок в голове, кусок в переписке. Соберите в один артефакт — не красивый, а рабочий. Держите рядом с другими migration-материалами, в docs/migrations/current-state.md.

Минимальный каркас:

# Текущее состояние миграции — CashFlow Dashboard

## Текущие версии
## Инструменты сборки и runtime
## Прямые и транзитивные зависимости
## CI-команды
## Устаревшие API
## Известные сбои
## Неизвестное
## Заметки о доказательствах

А небольшой заполненный фрагмент — так:

## Текущие версии
- Java: 8
- Spring Boot: 2.7.18
- Gradle: 7.6.4
- PostgreSQL: 12

## Устаревшие API
- WebSecurityConfigurerAdapter в SecurityConfig.java
- javax.persistence.* в entity-класcах

## Неизвестное
- Совместимость payment SDK с Java 21 не подтверждена

Документ не обязан быть литературным — чем суше, тем лучше. В миграциях много полезного выглядит скучно, и это нормально: скука здесь — признак того, что вы перестали фантазировать и начали работать с реальным проектом.

И в какой-то момент вы замечаете очень приятную вещь. После такого assessment проект перестаёт выглядеть чёрным ящиком с надписью «legacy» — он становится набором конкретных фактов, ограничений и неизвестных. А с конкретными фактами уже можно разговаривать без паники — даже если впереди Spring Boot major upgrade, старая база и код, который писал человек с очень богатой внутренней жизнью.

1
Задача
Claude code, 28 уровень, 1 лекция
Недоступна
Current-state inventory через Claude Code
Current-state inventory через Claude Code
1
Задача
Claude code, 28 уровень, 1 лекция
Недоступна
Зафиксировать текущий Java baseline в Migration Current State
Зафиксировать текущий Java baseline в Migration Current State
Комментарии
ЧТОБЫ ПОСМОТРЕТЬ ВСЕ КОММЕНТАРИИ ИЛИ ОСТАВИТЬ КОММЕНТАРИЙ,
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ