раздел 11 · рецепт

Миграция фреймворка

Vue 2 → Vue 3, Python 3.9 → 3.12, Express → Fastify, Redux → Zustand, Pydantic v1 → v2. Это не рефакторинг (там код тот же, имена меняются), это миграция (меняется парадигма, API, иногда мышление). Этот рецепт - универсальный шаблон для миграции любого фреймворка.

Когда применять

  • Major-версия фреймворка (breaking changes)
  • Замена одной библиотеки на другую (state-management, routing, форм)
  • Обновление языка (Python, Node, TS)
  • Переход на новый стек (Vite вместо Webpack, esbuild вместо Babel)

Шаги

Шаг 1. Migration guide от вендора

Перед тем как лезть в код, попросите Claude найти и прочитать миграционный гайд.

Промпт (с подключенным Context7 MCP):
"Через context7 найди migration guide с Pydantic v1 на v2.
Дай мне список breaking changes для нашего использования:
@dataclass, validator, root_validator, Config класс.
Что меняется, что остаётся, что deprecated."

Если Context7 не подключён - попросите Claude через WebFetch скачать страницу гайда с официального сайта.

Шаг 2. Inventory старых паттернов

Промпт:
"Делегируй Explore: найди все использования pydantic.BaseModel
с Config-классом, root_validator, validator. Верни таблицу
файл:строка:паттерн."

Шаг 3. Pilot - мигрируем одну директорию

Не мигрируйте всё разом. Выберите одну директорию (10-20 файлов), мигрируйте её, прогоните тесты.

Промпт:
"Мигрируй файлы в app/models/users.py с Pydantic v1 на v2.
Шаги: (1) запусти текущие тесты test_users.py - запомни прохождение,
(2) сделай миграцию по migration guide, (3) запусти тесты снова -
должны проходить так же, (4) если падают - откати, не пытайся
чинить тесты под новый код."

Шаг 4. Точки выбора стратегии

После пилота решите:

  • Big bang - мигрируем всё разом. Подходит для маленьких проектов (< 50 файлов) и когда невозможна co-existence версий.
  • Incremental - мигрируем директория за директорией. Старая и новая версии работают одновременно (если фреймворк позволяет). Безопаснее, дольше.
  • Strangler fig - новый код пишем на новом стеке, старый постепенно переписываем. Подходит для огромных кодобаз.

Шаг 5. Прогон всего

После пилота - параллелим через worktree:

git worktree add ../app-migrate-routes migrate-routes
git worktree add ../app-migrate-models migrate-models
git worktree add ../app-migrate-services migrate-services

В каждом worktree - свой Claude мигрирует свою директорию.

Шаг 6. Финальная сборка

В main:

git merge migrate-routes
git merge migrate-models
git merge migrate-services
npm test
./test/smoke.py http://localhost:3000

Антипаттерны

| Что не делать | Почему | |---|---| | Мигрировать без migration guide | Половина изменений будет реверс-инжинирингом - неточно. | | Мигрировать без pilot | Узнаете о подводных камнях на 200-м файле. | | Менять API под нагрузкой | Пользователи попадут на полу-смигрированный код. | | Удалять старый код сразу | Сделайте 1-2 релиза с обеими версиями. | | Обновлять deps на новые мажоры в одной ветке с миграцией | Не разберётесь, что сломалось. |

Конкретный пример: Pydantic v1 → v2

# Pydantic v1 (старый код)
from pydantic import BaseModel, validator

class User(BaseModel):
    name: str
    age: int

    class Config:
        orm_mode = True

    @validator("age")
    def age_positive(cls, v):
        if v < 0:
            raise ValueError("age must be positive")
        return v
# Pydantic v2 (мигрированный)
from pydantic import BaseModel, field_validator, ConfigDict

class User(BaseModel):
    model_config = ConfigDict(from_attributes=True)

    name: str
    age: int

    @field_validator("age")
    @classmethod
    def age_positive(cls, v):
        if v < 0:
            raise ValueError("age must be positive")
        return v

Полезные ссылки