Почему обновление фреймворка иногда дороже переписывания
Разбираем, почему апгрейд фреймворка может оказаться дороже переписывания: скрытые зависимости, регрессии, тесты, риски релиза и сроки.

О чем речь и почему вопрос цены неожиданно сложный
Обновление фреймворка почти всегда звучит как «аккуратный ремонт»: чуть подтянуть версии, прогнать сборку — и поехали дальше. Но на практике вопрос цены оказывается сложнее, потому что фреймворк редко живет отдельно. Он связан с библиотеками, сборкой, инфраструктурой, привычками команды и самим стилем кода, который формировался годами.
Какие проекты чаще всего «застревают» на старых версиях
Чаще всего это продукты, которые долго развивались без пауз на профилактику: много точечных правок, дедлайны, постепенное накопление компромиссов. Классические признаки — «у нас работает, не трогайте», редкие релизы, отсутствие времени на обновления зависимостей и тестов.
Еще одна группа — проекты с сильной кастомизацией: когда вокруг фреймворка построено много внутренних утилит, расширений и нестандартных интеграций.
Почему апгрейд кажется безопаснее, чем переписывание — и где ошибка
Апгрейд воспринимается как путь с меньшим риском: код «тот же», бизнес-логика «не меняется». Ошибка в том, что при крупных версиях меняется контекст выполнения: API, жизненный цикл компонентов, конфигурация, сборщик, правила безопасности, поведение по умолчанию.
Итог — изменения расползаются по коду и превращают «обновление» в цепочку переделок.
Какие расходы обычно не видны на старте
На старте редко учитывают время на разбор breaking changes, миграцию зависимостей, обновление линтеров и пайплайнов, адаптацию документации и обучение команды. Часто всплывают и «скрытые владельцы» модулей: никто уже не помнит, почему сделано именно так, и любое изменение становится исследованием.
Как читать статью
Дальше — практичные признаки и решения: где именно растут затраты, как заранее увидеть риск, и когда обновление действительно выгоднее переписывания, а когда — нет.
Обновление vs переписывание: что мы сравниваем
Когда говорят «обновить фреймворк», это звучит как простая смена версии. А «переписать приложение» — как капитальный ремонт. На практике сравнивают не «поменять цифры в package.json» против «начать с нуля», а два разных сценария изменений: минимально вмешиваться в продукт или пересобрать его заново.
Апгрейд: сохранить основу, пережить несовместимости
Апгрейд обычно означает: архитектура и логика остаются прежними, вы поднимаете версии фреймворка и библиотек, а затем чините всё, что перестало собираться, запускаться или работать как раньше.
Для бизнеса плюс в том, что функциональность формально не меняется: можно планировать релиз как «техническое обновление». Для команды плюс — меньше продуктовых решений. Минус — много точечных правок «по месту», где трудозатраты плохо предсказываются: несовместимости, изменения API и требования к инфраструктуре часто всплывают по ходу.
Переписывание: переосмыслить и собрать продукт заново
Переписывание — это не только про новый стек. Обычно это:
- пересборка архитектуры (как разделены модули, где хранятся данные, как устроены интеграции);
- перепроверка требований (что реально нужно сейчас, а что осталось «исторически»);
- повторная реализация функциональности и проверка качества.
Для бизнеса это шанс убрать лишнее и ускорить развитие, но есть риск «не догнать» текущий продукт по возможностям. Для команды — больше свободы и ясности, но выше цена ошибок в проектировании.
Гибрид: поэтапная замена и «страглер»-подход
Часто выигрывает компромисс: обновлять основу там, где это проще, и переписывать самые проблемные части постепенно (модуль за модулем). Такой подход снижает риск больших остановок и позволяет выпускать улучшения чаще.
Практически это выглядит как серия маленьких проектов с отдельными критериями готовности и измеримым эффектом.
Дальше важно договориться, какой результат считается успехом: «просто поддерживаемость» или реальное ускорение разработки. От этого зависит выбор пути и план работ (см. /blog/plan-migration-without-surprises).
Скрытая стоимость: зависимостей больше, чем кажется
Обновление фреймворка редко ограничивается командой update в package manager. Почти всегда вы тянете за ниточку — и вместе с ядром меняется половина экосистемы.
Именно поэтому оценка «пара дней на апгрейд» внезапно превращается в недели: работа размазывается по множеству связанных компонентов, которые формально «не про фреймворк», но без них приложение не собирается и не запускается.
Цепочки зависимостей: пакет → пакет → инфраструктура
Типичный сценарий выглядит так: вы поднимаете версию фреймворка, а он требует новую версию роутера. Роутер — новую версию TypeScript/JS runtime. Дальше подтягиваются обновления транспайлера, а затем — новые требования к сборке и CI.
В итоге «один апгрейд» превращается в проект по согласованию версий, где узкое место может быть в самом неожиданном месте.
Плагины, middleware и инструменты вокруг кода
Даже если бизнес-логика почти не меняется, вокруг неё есть слой, который часто ломается первым:
- плагины и middleware (логирование, авторизация, валидация, i18n);
- сборка и dev-сервер (Vite/Webpack, loaders, polyfills);
- линтеры и форматтеры (ESLint-конфиги, правила, плагины);
- транспайлеры и типизация (Babel/TS, генераторы типов).
Эти компоненты могут быть привязаны к конкретным API или внутренним деталям фреймворка, и их обновление не всегда линейно: иногда нужная версия плагина ещё не вышла, а иногда проект использует заброшенный пакет, который придётся заменять аналогом.
Неявные зависимости: форки, патчи и «временные» хаки
Отдельная статья расходов — то, что не видно в обычном списке зависимостей: приватные репозитории, форкнутые библиотеки, патчи в postinstall, временные фиксы «до следующего релиза», настройки окружения, о которых помнит один человек.
При апгрейде это всплывает как серия блокеров: «почему падает сборка только на CI?» или «почему прод ведёт себя иначе?».
Как заранее составить карту зависимостей и оценить объём работ
Чтобы не гадать, полезно до начала работ собрать «карту»:
-
Зафиксировать текущие версии: фреймворк, плагины, сборка, runtime, базы/SDK.
-
Проверить матрицы совместимости в релиз-ноутах ключевых пакетов (что требуется минимум).
-
Выявить «критичные» узлы: пакеты без мейнтейнера, собственные форки, редкие плагины.
-
Оценить трудоёмкость по группам: обновить, заменить, переписать интеграцию, удалить.
Такая инвентаризация часто занимает 1–2 дня, но экономит недели: вы заранее видите, где апгрейд остановится, и можете решить — лечим зависимость, меняем подход или пересматриваем план целиком.
Breaking changes и каскад правок по всему коду
Мажорный апгрейд редко сводится к «поменяли версию — собралось». Breaking changes — это не только удалённые или переименованные методы. Чаще всего меняются договорённости: что библиотека гарантирует на входе и выходе, какие значения используются по умолчанию, какие исключения бросаются и как трактуются крайние случаи.
Что ломается на самом деле
Первый слой — API. Методы исчезают, классы переезжают в другие пространства имён, параметры меняют порядок или смысл. На этом этапе кажется, что всё просто: IDE подсветила ошибки — исправили.
Второй слой опаснее: изменения поведения. Например, маршрутизация начинает по‑другому матчить пути и приоритеты, сериализация иначе обрабатывает даты и null‑значения, валидация становится строже, а настройки безопасности по умолчанию закрывают ранее доступные эндпоинты.
Код компилируется, но продукт ведёт себя иначе — и это обнаруживается поздно.
Почему правки расползаются
Проблема в том, что приложение обычно не использует фреймворк «точечно». Он прошит через контроллеры, middleware, модели, обработчики ошибок, формат ответов, авторизацию.
Одно изменение контракта в базовом слое вызывает цепочку: нужно обновить адаптеры, затем места вызова, затем тестовые фикстуры, затем документацию и мониторинги.
Конфликты зависимостей: домино из версий
Даже если сам фреймворк обновился, экосистема может не совпасть по мажорным версиям. Типичный сценарий: новый фреймворк требует свежий пакет A, но пакет B ещё не совместим с ним и тянет старый A.
В итоге команда либо ищет замены, либо пишет прослойки, либо временно форкает библиотеки — и «маленькая правка» превращается в проект.
Чтобы оценить стоимость, полезно заранее составить карту точек интеграции: где фреймворк «проходит через весь код», и какие зависимости критичны для релиза. Это помогает понять, будет ли каскад управляемым или затронет почти каждую подсистему.
Технический долг превращает апгрейд в бесконечный рефакторинг
Апгрейд фреймворка часто выглядит как «поменять версии и починить ошибки сборки». Но если проект годами жил с техническим долгом, обновление быстро упирается не в новые API, а в старые решения — и превращается в рефакторинг без четкого финала.
Старые практики, которые всплывают первыми
В legacy-коде обычно накоплены устаревшие паттерны: монолитные модули, сильная связанность слоев, «глобальные» сервисы, прямые зависимости между частями системы.
Пока версия фреймворка старая, это может работать за счет привычных обходов. После обновления такие места начинают ломаться цепочкой, потому что фреймворк становится строже к типам, жизненному циклу компонентов, конфигурации, безопасности или способу сборки.
Почему рефакторинг становится неизбежным
Даже если цель — «только апгрейд», вы вынуждены менять архитектурно значимые узлы, чтобы вообще дойти до компиляции и запуска. Например: выделять границы модулей, убирать циклические зависимости, переписывать самодельные обертки над роутингом/DI/валидацией, приводить к единым контрактам API.
Это не «косметика» — это пересборка несущих конструкций.
Эффект «сломанных окон»
Технический долг редко выглядит как один большой дефект. Чаще это десятки исключений из правил: временные хаки, ручные обходы, «заглушки на релиз», отключенные проверки, кастомные патчи.
Обновление фреймворка повышает стоимость каждого такого исключения: то, что раньше сходило с рук, теперь конфликтует с новой конфигурацией, линтерами, системой типов или сборщиком.
Признаки, что апгрейд уже превратился в переписывание
Если вы замечаете, что:
- объем «временных правок ради совместимости» растет быстрее, чем список реальных задач апгрейда;
- команда тратит время на выравнивание архитектуры и границ модулей, а не на замену устаревших вызовов;
- исправления ломают соседние части из-за сильной связанности;
- сроки постоянно сдвигаются, потому что каждый шаг открывает новые «исторические» проблемы,
— значит, вы фактически переписываете систему, но без выигрыша в новом дизайне.
В этот момент важно остановиться и переоценить план: что именно нужно бизнесу — новая платформа или долгий ремонт старой.
Тесты и регрессии: платить придется либо до, либо после
Обновление фреймворка часто ломает не только компиляцию, но и поведение: роутинг, валидацию, рендеринг, работу с датами, безопасность, сбор ошибок.
Если у проекта низкое покрытие тестами, любая миграция превращается в игру «поймай баг в проде»: команда правит очевидные ошибки, выпускает релиз — и неделями получает неожиданные регрессии в самых разных местах.
Почему низкое покрытие резко увеличивает цену
Без тестов вы вынуждены проверять всё руками. Ручная регрессия занимает много часов и всё равно пропускает крайние случаи.
Итог — больше итераций, больше откатов, больше «горячих» фиксов, а значит и выше стоимость разработки.
E2E/интеграционные тесты: долго, дорого, но окупаются
Интеграционные и E2E-тесты медленнее и сложнее в поддержке, зато они ловят то, что чаще всего ломается при обновлениях: взаимодействие модулей, авторизацию, платежи, цепочки событий, реальные пользовательские сценарии.
Фиксация поведения: что именно тестировать
Полезные подходы, когда важно «заморозить» текущую функциональность:
- снапшоты для UI (с осторожностью, чтобы не плодить шум);
- контрактные тесты между сервисами и фронтендом;
- тесты API (на коды ответов, схемы, важные бизнес-правила).
Иногда дешевле сначала построить тестовый контур
Парадоксально, но верный шаг перед апгрейдом — вложиться в минимальный тестовый контур для критичных потоков (логин, покупка, основные формы). Это снижает риск регрессий и делает сроки миграции предсказуемыми.
По сути, вы платите либо заранее — за тесты, либо после — за инциденты, простой и срочные исправления.
Инфраструктура и сборка: мигрирует не только приложение
Когда говорят «обновим фреймворк», обычно представляют изменения в коде. Но на практике апгрейд часто тянет за собой цепочку правок в сборке и окружении: то, что вчера собиралось «на автопилоте», внезапно начинает падать в CI или у половины команды локально.
CI/CD: пайплайны тоже завязаны на версии
CI/CD — это набор инструментов с собственными зависимостями. Обновление фреймворка может потребовать новые версии:
- раннеров и базовых Docker-образов;
- языка и его toolchain (Node/Java/.NET, SDK, компиляторы);
- менеджеров пакетов и lock-файлов (npm/yarn/pnpm, Maven/Gradle, NuGet);
- шагов сборки (например, другой формат артефактов или новые флаги).
В итоге «мелочь» превращается в отдельную задачу: починить пайплайн так, чтобы он снова был воспроизводимым и быстрым.
Локальная среда: несовпадения съедают дни
Апгрейд нередко поднимает минимальные требования к версиям Node/Java/.NET и меняет поведение сборки. Плюс всплывают вопросы секретов и конфигурации: где хранить переменные окружения, как прокидывать токены, как запускать сервисы-спутники.
Если это не стандартизировать, команда начинает тратить время на «у меня не собирается».
Наблюдаемость: логи и метрики тоже могут «сломаться»
После обновления могут перестать работать интеграции логирования, метрик и трассировки: меняются middleware, форматы, библиотеки, агенты. Это опасно тем, что проблемы проявятся уже после релиза — когда отладка сложнее и дороже.
Как оценивать инфраструктуру отдельно от продукта
Чтобы не занижать бюджет, оцените инфраструктурные работы отдельным списком: обновление образов и раннеров, правки CI, обновление секретов/конфигов, проверка наблюдаемости, прогон сборки и деплоя на тестовом окружении.
Это помогает сравнивать «обновление фреймворка» и «переписывание приложения» честно — по полной стоимости.
Релизные риски: простой бизнеса и цена ошибок
Даже если оценка апгрейда «по коду» выглядит умеренной, в продакшене цена ошибки часто перекрывает работу разработчиков. Обновление фреймворка меняет поведение системы целиком: от авторизации и рендеринга страниц до обработки очередей и логирования.
Поэтому основной счёт нередко выставляет не разработка, а простой бизнеса, потери конверсии и срочные откаты.
Почему откат апгрейда может быть сложнее, чем кажется
Откат — это не кнопка «вернуть версию». За время релиза обычно успевают измениться миграции БД, форматы кэша, схемы событий, конфиги инфраструктуры.
В итоге rollback превращается в отдельный проект: нужно откатывать данные, чистить кэш, восстанавливать совместимость между сервисами.
Практический вывод: ещё до старта апгрейда стоит описать план отката как артефакт релиза — что откатываем, как проверяем, сколько это занимает, кто принимает решение.
Параллельная разработка фич и апгрейда
Если команда продолжает пилить функциональность параллельно с миграцией, почти неизбежны конфликты:
- ветка с апгрейдом долго живёт и «протухает»;
- фичи используют старые API/паттерны, которые уже меняются;
- тесты и фиксы гоняются между двумя мирами.
Иногда дешевле временно заморозить часть потока фич или выделить отдельную «миграционную» команду с чёткими интерфейсами, чем неделями разруливать мердж-конфликты и расхождения поведения.
Безопасность: риск в обе стороны
Сидеть на старых версиях опасно из-за уязвимостей и отсутствия патчей. Но и миграция рискованна: новые зависимости, обновлённые TLS/шифры, изменённые политики CORS/CSRF могут внезапно сломать интеграции.
Нужен баланс: приоритизировать обновления, которые закрывают известные CVE, и отдельно планировать изменения, влияющие на совместимость.
Практика релизов, которая снижает цену ошибок
Лучше всего работают поэтапные релизы: feature flags для переключения поведения, канареечные выкладки на малую долю трафика, постепенное увеличение нагрузки с наблюдением метрик (ошибки, задержки, бизнес-показатели).
Такой подход превращает «один большой риск» в серию маленьких, управляемых шагов.
Команда и знания: обучение и потеря экспертизы в legacy
Цена апгрейда часто определяется не только строками кода, а тем, сколько «знания в головах» нужно перенести в новую версию. В legacy‑проекте много решений держится на негласных договоренностях: почему выбран этот хак, где «тонкое место», какие версии библиотек совместимы.
Когда люди уходят, эта карта местности исчезает.
Почему знания в legacy быстро обесцениваются
Документация устаревает первой: README и wiki не успевают за реальными правками, а комментарии в коде описывают прошлую архитектуру.
В итоге при обновлении фреймворка команда тратит время не на миграцию, а на археологию: разбирать цепочки причин, проверять гипотезы, воспроизводить старые баги.
Дополнительный удар — «потеря экспертизы по старому миру». Люди, которые знали, как обходить ограничения прежней версии, могут уже не работать в компании, а новые разработчики не видят ценности изучать то, что все равно будет выброшено.
Парадоксально, но апгрейд требует глубокого понимания старой системы, иначе невозможно безопасно менять поведение.
Новые версии требуют новых привычек
Миграция — это не только замена API. Меняются подходы: структура проекта, стиль написания компонентов/модулей, правила типизации, конфигурация линтеров, принципы работы с состоянием, маршрутизацией, сборкой.
Даже если изменения «простые», их нужно закрепить через обучение, ревью и новые стандарты, иначе кодовая база быстро превращается в смесь старых и новых практик.
Как уменьшить потери
Чтобы апгрейд не стал бесконечным курсом обучения, полезно заранее подготовить «рельсы» для команды:
- внутренний гайд миграции: что меняем, что запрещаем, как проверяем результат;
- шаблон PR с чек‑листом (затронутые модули, breaking changes, обратная совместимость, тесты);
- короткие примеры «как теперь правильно» (минимальные эталоны кода);
- регулярные синки по спорным решениям и единые правила ревью.
Так вы покупаете не только новую версию фреймворка, но и предсказуемость: меньше разночтений, меньше повторной работы и меньше зависимости от конкретных людей.
Как выбрать путь: критерии «обновлять или переписывать»
Главный вопрос — не «что дешевле по смете на разработку», а какой вариант даст предсказуемый результат и минимизирует суммарные потери за 1–3 года.
Обновление и переписывание — это инвестиции с разными рисками: апгрейд чаще сохраняет бизнес-логику, а переписывание открывает возможность поменять продукт и архитектуру, но увеличивает неопределенность.
Когда апгрейд оправдан
Обновление фреймворка обычно выигрывает, если разрыв версий небольшой и изменения хорошо локализуются:
- Небольшой разрыв версий (например, 1–2 мажорные версии), есть понятный migration guide.
- Хорошее покрытие тестами: ключевые бизнес-сценарии проверяются автоматически, регрессии ловятся быстро.
- Модульность: приложение разбито на слои/модули, зависимости изолированы, есть четкие контракты.
В этом случае апгрейд — это контролируемый проект: исправили несовместимости, прогнали тесты, выпустили.
Когда переписывание оправдано
Переписывание имеет смысл, когда «починить» старое почти равно «переделать заново»:
- Кардинально изменились требования: продукту нужны новые сценарии, а текущая модель данных/логика мешает.
- Архитектура “не тянет”: производительность, масштабирование, безопасность или сопровождение упираются в фундаментальные ограничения.
- Высокий технический долг: много костылей, устаревшие подходы, изменения постоянно ломают соседние части.
Важно: переписывание — не про «перенести один-в-один», а про пересборку решения с новым набором компромиссов.
Как посчитать TCO (total cost of ownership)
Сравнивайте не только сроки разработки:
TCO = разработка + тестирование + поддержка после релиза + стоимость рисков.
К «рискам» отнесите: вероятность срыва сроков, потери выручки из‑за простоев, рост нагрузки на поддержку, регуляторные/безопасностные последствия.
Чек-лист решения для владельца продукта
- Какой горизонт планирования: 6 месяцев или 3 года?
- Есть ли тесты, которые можно считать «страховкой» при изменениях?
- Что важнее: быстрее снизить риски (апгрейд) или получить новые возможности (переписывание)?
- Сколько критичных интеграций и насколько они завязаны на текущий стек?
- Какой вариант дает более предсказуемую дату релиза и меньшую цену ошибки?
Если ответы про предсказуемость и проверяемость — выбирайте апгрейд. Если про невозможность развития и смену требований — рассматривайте переписывание.
Планирование миграции без сюрпризов: этапы и артефакты
Почти любой «дорогой апгрейд» становится дорогим не из‑за самого фреймворка, а из‑за отсутствия плана: что именно меняем, в каком порядке и как поймём, что не сломали бизнес.
Хорошая новость — это можно приземлить в понятные этапы и артефакты, которые снимают неопределённость.
1) Инициализация проекта миграции
Начните с инвентаризации и целей. Это не бюрократия, а способ увидеть объём работ до того, как вы открыли первую ветку.
Что фиксируем:
- Карту зависимостей: фреймворк, ключевые библиотеки, плагины, внутренние пакеты, версии, кто владелец.
- Матрицу совместимости: что уже поддерживает новую версию, а что придётся заменить.
- Цели миграции: «обновиться» — не цель. Целью могут быть поддержка безопасности, снижение времени сборки, уход от end-of-life, улучшение производительности, разблокировка новых фич.
Артефакты: короткий документ на 1–2 страницы + таблица зависимостей (часто достаточно spreadsheet).
2) Стратегия поэтапного апгрейда
Чтобы не превратить релиз в лотерею, делите систему на модули и границы: где можно обновляться автономно, а где есть жёсткие связки.
Практика, которая работает:
- выделить «вертикальные срезы» (часть UI + API + хранилище) и мигрировать их по очереди;
- обозначить приоритеты: сначала то, что чаще ломается/блокирует остальное;
- заранее решить, где допустимы временные адаптеры и совместимость «двух миров».
Артефакты: миграционный бэклог, план релизов по итерациям, схема модулей.
3) План коммуникаций
Во время миграции важно синхронизировать ожидания:
- что замораживаем (например, новые фичи в затронутых модулях);
- что продолжаем развивать (критичные для бизнеса изменения, но по правилам совместимости);
- как часто и в каком формате даём статус (демо, короткие отчёты, риск‑лог).
Артефакты: календарь релизов/окна изменений, список стейкхолдеров, риск‑реестр.
4) Определение «готово»
«Мы обновились» должно быть измеримо: метрики качества, производительности и стабильности.
Примеры критериев:
- тесты проходят, покрытие не падает ниже оговорённого порога;
- ключевые пользовательские сценарии без регрессий;
- время сборки/деплоя не хуже базовой линии;
- количество ошибок/алертов после релиза в пределах SLO.
Артефакты: чек‑лист готовности, базовые метрики «до/после», план отката и условия его запуска.
Практический инструмент: быстрые прототипы и проверка гипотез
Иногда полезно сделать небольшой «технический прототип» в стороне от основного репозитория: проверить совместимость критичных библиотек, оценить новые требования к сборке, понять, насколько меняется жизненный цикл или конфигурация.
Если команде нужно быстро «пощупать» новый стек или собрать тестовый контур без долгого разворачивания окружений, можно использовать TakProsto.AI: это vibe-coding платформа для создания веб-, серверных и мобильных приложений через чат. Такой прототип помогает уточнить риски миграции (например, связку React на фронтенде и Go + PostgreSQL на бэкенде), прежде чем заходить в дорогую переделку основного продукта.
Как не попадать в ситуацию снова: профилактика дорогих апгрейдов
Дорогие апгрейды почти всегда выглядят как «внезапная» катастрофа, но корни у них накопительные: годами откладываются мелкие обновления, разрастается набор библиотек, а знания о системе остаются в головах нескольких людей.
Профилактика — это не разовая активность, а часть нормального жизненного цикла продукта.
Обновляйте чаще и меньшими шагами
Лучше планировать регулярные обновления (например, раз в квартал), чем ждать 2–3 года и потом столкнуться с прыжком через несколько мажорных версий.
Небольшие апдейты:
- проще протестировать и откатить;
- реже требуют переписывать большие куски;
- уменьшают риск «всё сломалось одновременно».
Автоматизация — как функциональность продукта
Тесты, линтеры, статический анализ, CI/CD — это не «дополнительно», а страховка стоимости.
Практичный ориентир: если вы не можете безопасно обновить зависимость без ручного обхода ключевых сценариев, значит вы платите за отсутствие автоматизации — просто позже и дороже.
Снижайте связанность системы
Чем сильнее компоненты «переплетены», тем дороже любое изменение. Помогают:
- модульность и явные границы ответственности;
- контрактные границы (интерфейсы, схемы, API-first);
- минимизация прямых импортов/вызовов между слоями.
Идея простая: обновляете одну часть — остальные остаются стабильными, потому что взаимодействие держится на контрактах.
Регулярная гигиена зависимостей
Заведите привычку:
- пересматривать зависимости по расписанию;
- удалять неиспользуемые пакеты и дублирующие решения;
- фиксировать причины добавления библиотек (короткая заметка в репозитории).
Меньше зависимостей — меньше неожиданных breaking changes и меньше цепных реакций при миграции.
Ускоряйте изменения, не наращивая «хрупкость»
Полезный принцип: чем быстрее вы можете собрать, проверить и выкатить изменение, тем дешевле вам обходятся и апгрейды, и частичные переписывания.
В этом смысле инструменты, которые сокращают цикл от идеи до рабочего прототипа (с возможностью экспортировать исходники, делать снапшоты и откаты), помогают удерживать обновления в «малых шагах» — без много-недельных заморозок и страха перед релизом.