<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:sy="http://purl.org/rss/1.0/modules/syndication/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/">
  <channel>
    <language>ru</language>
    <title>Legacy</title>
    <description>Всё о legacy-системах: технические и бизнес-риски, управление наследием, примеры успешной модернизации и перехода на современные технологии</description>
    <link>https://tproger.ru/tag/legacy</link>
    <atom:link href="https://tproger.ru/tag/legacy/feed" rel="self" type="application/rss+xml"/>
    <lastBuildDate>Tue, 06 Oct 2026 16:16:20 GMT</lastBuildDate>
    <sy:updatePeriod>hourly</sy:updatePeriod>
    <sy:updateFrequency>12</sy:updateFrequency>
    <image>
      <title>Legacy</title>
      <link>https://tproger.ru</link>
      <url>https://tproger.ru/apple-touch-icon.png</url>
    </image>
    <item>
      <title>Технический долг в деньгах: как считать ROI рефакторинга легаси-системы</title>
      <link>https://tproger.ru/articles/tehnicheskij-dolg-v-dengah-kak-schitat-roi-refaktoringa-legasi</link>
      <comments>https://tproger.ru/articles/tehnicheskij-dolg-v-dengah-kak-schitat-roi-refaktoringa-legasi?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Дима Дмитриев]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/articles/tehnicheskij-dolg-v-dengah-kak-schitat-roi-refaktoringa-legasi</guid>
      <description><![CDATA[<p>Как перевести техдолг в деньги: отделяем от багов и новых требований, считаем текущие потери и обосновываем рефакторинг бизнесу через скорость, предсказуемость и риски.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/articles/tehnicheskij-dolg-v-dengah-kak-schitat-roi-refaktoringa-legasi">Технический долг в деньгах: как считать ROI рефакторинга легаси-системы</a>»</p>]]></description>
      <category><![CDATA[Рефакторинг]]></category>
      <category><![CDATA[Бизнес]]></category>
      <category><![CDATA[Legacy]]></category>
      <category><![CDATA[Статьи]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Tue, 30 Jun 2026 11:14:40 GMT</pubDate>
      <content:encoded><![CDATA[<p>Для бизнеса это выглядит как внутренняя проблема разработки. Система работает, пользователи продолжают пользоваться продуктом, релизы выходят. Поэтому рефакторинг часто проигрывает задачам, которые напрямую связаны с продуктовым роадмапом.</p><p>В статье разберём этот эффект на примере легаси-систем, с которыми работает Centicore Group. Компания занимается модернизацией устаревшего кода, баз данных и инфраструктуры, а также системным и бизнес-анализом, разработкой ПО и контролем качества.</p><p>Дальше узнаете, как перевести техдолг легаси-системы в деньги: отделить его от багов и новых требований, оценить объём работ, увидеть текущие потери и объяснить, когда модернизация становится дешевле, чем дальнейшая разработка поверх старой архитектуры.</p><h2>Что считаем техдолгом</h2><p>Чтобы посчитать ROI рефакторинга, сначала нужно определить, что именно команда считает техническим долгом. Без этого в один список попадут баги, старые библиотеки, слабые тесты или желание сменить стек. У таких задач разные причины, цена и источники бюджета, поэтому их нельзя приоритизировать как одну категорию.</p><p>Термин «технический долг» ввёл программист Уорд Каннингем в 1992 году. Он использовал финансовую метафору: команда может выбрать более быстрое техническое решение, получить выгоду сейчас, а позже заплатить за это доработкой и дополнительными расходами.</p><p>В этой статье будем использовать узкое рабочее определение: <b>технический долг — это осознанное отклонение от технических соглашений команды ради понятной выгоды.</b> Команда понимает целевое состояние, но пока этого не делает, чтобы быстрее выпустить фичу, проверить гипотезу или уложиться в ограничение по срокам.</p><p>Из этого определения следует, что не каждую техническую проблему стоит записывать в техдолг:</p><ol><li>Баг — это ошибка в реализации. Техдолга здесь нет: никто не принимал осознанного решения сделать хуже. Поэтому баги относятся к дефект-менеджменту и финансируются из бюджета на поддержку, а не из бюджета на рефакторинг.</li><li>Желание применить новую технологию — это новое требование к продукту. Команда хочет заменить PostgreSQL на что-то другое или перейти с REST на gRPC. Если это обосновано и полезно — отлично, но это отдельная задача со своей оценкой и своим источником финансирования.</li><li>Устаревший код без измеримых последствий — тоже не долг. Если модуль написан пять лет назад, но команда работает с ним без дополнительных затрат времени, он никого не тормозит и не создаёт рисков — переписывать его ради переписывания не нужно. Техдолг возникает в момент, когда команда признаёт: вот это решение замедляет нас, и мы можем точно сказать, как именно.</li></ol><p>У каждой категории своя логика и бюджет. Баги относятся к дефект-менеджменту, новые технологии — к развитию продукта, обучение — к развитию команды. Если всё сложить в один бэклог и назвать техдолгом, ресурсы будут расходоваться непрозрачно, а разговор с бизнесом снова сведётся к просьбе выделить время на внутренние задачи.</p><h2>Как техдолг превращается в расходы</h2><p>После фиксации техдолга у команды появляются два параметра: <b>объём работ и текущие потери</b>. Они нужны, чтобы отделить саму задачу по исправлению техдолга от расходов, которые команда и так тратит каждый спринт.</p><p><b>Объём работ</b> — это всё, что нужно сделать, чтобы вернуться в целевое состояние. Раздробить монолитный модуль, заменить самописную библиотеку на поддерживаемую, переписать слой работы с БД. Объём работ оценивается в часах или стори-поинтах — это конечная сумма, которую команда выплатит один раз.</p><p><b>Текущие потери</b> — это то, что команда теряет каждый спринт, пока долг не закрыт. Они накапливаются постепенно и часто не видны явно, пока их не начинают считать. Несколько типичных примеров: медленная сборка съедает по 20 минут на каждый деплой при восьми деплоях в день — это больше двух часов потерь ежедневно на каждого разработчика, который её ждёт. Запутанная структура модуля добавляет час к онбордингу каждого нового члена команды и увеличивает время оценки задач. Отсутствие тестов на критическом участке означает ручную проверку при каждом релизе.</p><p>Текущие потери важнее объёма работ для обоснования приоритета. Именно они показывают, сколько стоит бездействие — и растут с каждой итерацией: кодовая база вокруг расширяется, зависимостей становится больше, а проблемный участок затрагивает всё больше задач.</p><p>Откуда берётся бюджет на закрытие долга? На практике его берут из нескольких источников: остаток капасити после основных задач, риск-буфер проекта, иногда закладывают в оценку соседних фич. Последний вариант наименее прозрачный, но встречается чаще всего.</p><h2>Какие задачи по техдолгу считать через ROI</h2><p>Не каждую задачу по техдолгу нужно считать через ROI. Часть работы должна быть встроена в обычный процесс разработки: тесты к изменяемому коду, обновление документации, небольшие правки рядом с текущей задачей.</p><p>Через ROI стоит считать задачи, которые конкурируют с фичами за время команды. У таких задач есть цена, влияние на скорость разработки и понятный конфликт с продуктовым планом. Например:</p><ul><li>рефакторинг проблемного модуля,</li><li>замена устаревшей зависимости,</li><li>переработка слоя интеграций,</li><li>доработка тестового покрытия на критическом участке.</li></ul><p>Отдельно стоят системные решения — их нельзя решать на уровне одного спринта. Для них нужна отдельная оценка, архитектурное решение и согласование с бизнесом. Например:</p><ul><li>вывод старых сервисов из эксплуатации,</li><li>изменение требований к отказоустойчивости,</li><li>обновление платформы,</li><li>пересмотр архитектурных ограничений.</li></ul><p>После такого отбора остаются задачи, которые действительно нужно считать. Следующий шаг — понять, где именно легаси будет создавать дополнительные расходы.</p><h2>Где искать расходы в легаси перед расчётом ROI</h2><p>После фиксации техдолга нужно понять, где именно он влияет на стоимость работы. Для легаси-системы это не всегда весь продукт целиком: чаще дополнительные затраты создают отдельные модули, интеграции или участки инфраструктуры.</p><ul><li>Сначала проверяют зоны частых изменений. Если команда регулярно дорабатывает один и тот же модуль, а перед каждой задачей тратит время на разбор старой логики, такой долг стоит учитывать в первую очередь, потому что он возвращается в каждой новой задаче.</li><li>Затем оценивают поддержку и эксплуатацию. Старые решения могут увеличивать время на инциденты, ручные операции, деплой, проверку интеграций и передачу знаний внутри команды. Эти затраты не всегда явно видны в разработке фич, но они каждый раз сокращают общий ресурс команды.</li><li>Отдельно смотрят ограничения для будущего развития. Если текущая архитектура мешает новым интеграциям, требованиям к безопасности, масштабированию или изменению бизнес-логики, долг влияет уже не только на поддержку, но и на продуктовый план.</li></ul><p>В результате у вас появляется список участков, где легаси создаёт дополнительные расходы, например: замедляет разработку, усложняет поддержку, повышает риски или ограничивает будущие изменения. Этот список нужен для следующего шага — оценки ROI рефакторинга.</p><h2>Как считать ROI</h2><p>Полностью оцифровать каждую задачу по техдолгу в рублях на практике невозможно: слишком много переменных и слишком высокая стоимость самого подсчёта. Но для принятия решений точная оцифровка и не нужна. Нужно уметь сравнивать задачи между собой и понимать, когда рефакторинг выгоднее очередной фичи.</p><p><b>Шаг 1. Посчитайте текущие потери.</b> Зафиксируйте, сколько дополнительного времени команда тратит из-за конкретной проблемы прямо сейчас. Медленная сборка — сколько минут в день суммарно по команде. Сложный для понимания модуль — сколько часов уходит на оценку задач в нём. Отсутствие тестов — сколько времени занимает ручная проверка перед каждым релизом. Переведите это в деньги через стоимость часа работы команды.</p><p><b>Шаг 2. Оцените объём работ.</b> Сколько займёт исправление — в часах, с буфером на непредвиденное. Это тоже деньги: стоимость часа умножить на объём.</p><p><b>Шаг 3. Посчитайте горизонт окупаемости.</b> Если текущие потери составляют 20 000 рублей в неделю, а объём работ стоит 80 000 рублей, рефакторинг окупается за четыре недели. Дальше каждая неделя — чистая экономия. Если горизонт окупаемости укладывается в срок, на который планируется развитие продукта, рефакторинг финансово обоснован.</p><p><b>Шаг 4. Введите два порога вместо полного ранжирования.</b> Определите верхний порог — задачи выше него идут в работу в приоритете над новыми фичами, потому что их текущие потери слишком высоки. И нижний порог — задачи ниже него откладываются, потому что их стоимость исправления не окупится в обозримом горизонте. Всё между порогами сравниваете через RICE: потенциальный эффект умножить на охват и коэффициент уверенности, разделить на трудоёмкость.</p><p>Оценки на втором и третьем шаге будут частично экспертными — это нормально. Главное, чтобы все задачи оценивались по одной шкале: тогда их можно сравнивать между собой, даже если абсолютные цифры приблизительны.</p><h2>Как обосновать рефакторинг бизнесу</h2><p>Если задачи по техдолгу регулярно появляются в бэклоге и приоритизируются наравне с фичами, отдельного разговора с бизнесом обычно не требуется. Но когда техдолг накопился до уровня, где нужно остановить разработку фич и заниматься только стабилизацией, этот разговор неизбежен.</p><p>Аргумент «там плохой код» не работает, потому что для бизнеса это не проблема — проблема это замедление или остановка поставки фич. Поэтому аргументы должны быть на том же языке.</p><ol><li>Скорость поставки. Покажите данные из трекера: сколько времени уходило на задачи в конкретном модуле полгода назад и сколько уходит сейчас. Если время выросло в полтора раза при сопоставимой сложности задач, это измеримое замедление с понятной причиной.</li><li>Предсказуемость оценок. Команда с накопленным техдолгом не может точно эстимировать: задача на три дня превращается в две недели, потому что в процессе обнаруживаются связанные проблемы. Для бизнеса это означает срыв сроков и невозможность планировать релизы. Покажите расхождение между оценками и фактом за последние несколько спринтов.</li><li>Риски. Неподдерживаемые зависимости, отсутствие покрытия тестами на критических участках, архитектура, которая не выдержит роста нагрузки при следующем масштабировании. Риски переводятся в деньги через вероятность и стоимость инцидента.</li></ol><p>Если легаси уже влияет на скорость разработки, поддержку или риски эксплуатации, полезно начинать не с переписывания, а с обследования системы. На этом этапе нужно понять, какие части кода, базы данных и инфраструктуры действительно требуют модернизации, где достаточно локального рефакторинга, а где проблема лежит в процессах или качестве проверки.</p><p>Когда легаси уже влияет на скорость разработки, поддержку и риски эксплуатации, задачу лучше начинать с обследования системы. Centicore Group занимается модернизацией таких систем: помогает разобраться с устаревшим кодом, базами данных и инфраструктурой, а затем спланировать изменения без хаотичного переписывания всего подряд.</p><h2>Итого</h2><p>Технический долг становится управляемым, когда у него есть не только описание, но и цена: что нужно исправить, какие проценты команда платит сейчас и как эти проценты будут расти, если продолжать разработку поверх проблемного участка.</p><p>По факту, это обычное инженерно-финансовое решение: либо команда закрывает объём долга сейчас, либо продолжает оплачивать его через более дорогие фичи, поддержку, регресс и риски в проде.</p>]]></content:encoded>
    </item>
    <item>
      <title>Как приручить legacy-код: безопасная модернизация без заморозки фич</title>
      <link>https://tproger.ru/articles/kak-priruchit-legacy-kod-bezopasnaya-modernizaciya-bez-zamorozki</link>
      <comments>https://tproger.ru/articles/kak-priruchit-legacy-kod-bezopasnaya-modernizaciya-bez-zamorozki?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[KODE]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/articles/kak-priruchit-legacy-kod-bezopasnaya-modernizaciya-bez-zamorozki</guid>
      <description><![CDATA[<p>Как модернизировать legacy-код без остановки продукта: Strangler Fig Pattern, feature flags, shadow testing и безопасная миграция данных. Практика и антипаттерны.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/articles/kak-priruchit-legacy-kod-bezopasnaya-modernizaciya-bez-zamorozki">Как приручить legacy-код: безопасная модернизация без заморозки фич</a>»</p>]]></description>
      <category><![CDATA[Интернет]]></category>
      <category><![CDATA[API]]></category>
      <category><![CDATA[Java]]></category>
      <category><![CDATA[Git]]></category>
      <category><![CDATA[Опрос]]></category>
      <category><![CDATA[Python]]></category>
      <category><![CDATA[Ruby]]></category>
      <category><![CDATA[MySQL]]></category>
      <category><![CDATA[Практика]]></category>
      <category><![CDATA[SQL]]></category>
      <category><![CDATA[Рефакторинг]]></category>
      <category><![CDATA[Работа]]></category>
      <category><![CDATA[Tor]]></category>
      <category><![CDATA[GitHub]]></category>
      <category><![CDATA[Боты]]></category>
      <category><![CDATA[HR]]></category>
      <category><![CDATA[MIT]]></category>
      <category><![CDATA[Финтех]]></category>
      <category><![CDATA[ICO]]></category>
      <category><![CDATA[Redis]]></category>
      <category><![CDATA[QA]]></category>
      <category><![CDATA[Бэкенд]]></category>
      <category><![CDATA[Twitter]]></category>
      <category><![CDATA[Игра]]></category>
      <category><![CDATA[Приложение]]></category>
      <category><![CDATA[Сервер]]></category>
      <category><![CDATA[Kubernetes]]></category>
      <category><![CDATA[Библиотеки]]></category>
      <category><![CDATA[аналитик]]></category>
      <category><![CDATA[OpenTelemetry]]></category>
      <category><![CDATA[PostgreSQL]]></category>
      <category><![CDATA[DeFi]]></category>
      <category><![CDATA[Grafana]]></category>
      <category><![CDATA[Бизнес]]></category>
      <category><![CDATA[Legacy]]></category>
      <category><![CDATA[Техника]]></category>
      <category><![CDATA[Статьи]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Tue, 23 Jun 2026 06:16:57 GMT</pubDate>
      <content:encoded><![CDATA[<p>Legacy-код — одна из самых болезненных тем в инженерных командах. Обычно все понимают, что система устарела: архитектура мешает быстро выпускать изменения, новые фичи приходится встраивать через обходные пути, тесты либо неполные, либо отсутствуют, а любое изменение в одном модуле неожиданно ломает другой.</p><p>Но при этом к такому коду часто боятся прикасаться. И не без причины. В старых системах редко бывает понятная карта зависимостей. Документация устарела, часть знаний живет только в головах нескольких разработчиков, а бизнес при этом продолжает ждать новых релизов, интеграций и продуктовых экспериментов.</p><p>Так появляется классическая ловушка legacy: систему надо модернизировать, но остановить развитие нельзя. Переписать всё с нуля страшно, поддерживать как есть — всё дороже. В результате продукт обрастает временными решениями, скорость разработки падает, а стоимость каждого следующего изменения растет.</p><p>Хорошая новость в том, что модернизация legacy-кода не обязана быть большим взрывом. Старую систему можно менять постепенно, сохраняя рабочий продукт, не замораживая фичи и не устраивая один критический релиз, от которого зависит всё.</p><h2>Почему Big Bang-переписывание чаще всего заканчивается плохо</h2><p>Когда команда долго живет с устаревшей системой, идея переписать всё с нуля выглядит очень соблазнительно. Кажется, что можно наконец избавиться от технического долга, выбрать нормальную архитектуру, перепроектировать модули, покрыть всё тестами и начать «правильно».</p><p>На старте такой план часто звучит логично. Особенно если текущая система действительно мешает развитию. Например, мобильное приложение растет, у него уже миллионы пользователей, бэкенд написан несколько лет назад как монолит, а каждая новая фича требует изменений в десятке мест. Команда устала чинить регрессии, бизнес устал ждать, и всем хочется «один раз нормально переписать».</p><p>Проблема не в самой идее переписывания, а в условиях, при которых оно проваливается. Большой риск возникает, когда совпадают четыре фактора: переписывание занимает много месяцев, в это время бизнес продолжает развивать старую систему, новая версия покрывает сразу большую часть функциональности, а откат связан с миграцией данных. Если все четыре пункта присутствуют, Big Bang почти гарантированно превратится в долгий и дорогой проект.</p><p>Допустим, команда решила переписать модуль заказов в e-commerce-продукте. В старой версии есть корзина, промокоды, доставка и оплата. Команда планирует за полгода сделать новый сервис заказов. Но за эти полгода бизнес добавляет подписки, подарочные сертификаты, частичную оплату бонусами и новую логику возвратов. В итоге новая система, которую проектировали под старые требования, к моменту релиза уже нуждается в доработке.</p><p>Есть и другая проблема: большой релиз почти всегда несет максимальный риск. Если вы заменяете крупный кусок системы целиком, ошибка влияет сразу на большую часть пользователей. Откат тоже становится сложным, потому что новая логика уже связана с новыми данными, контрактами и интеграциями.</p><p>Big Bang всё-таки бывает оправдан — но в узких условиях. Если кодовая база молодая (год-два), пользователей мало, у системы нет критичного состояния в БД и продукт можно временно заморозить или вести в обоих контурах параллельно, полное переписывание может оказаться дешевле постепенной миграции. Это редкая ситуация, и она быстро исчезает по мере роста продукта. В зрелых системах безопаснее работает другой подход — постепенная архитектурная эволюция.</p><h2>Пример: как команда переписала сервис документов и потеряла полгода</h2><p>Команда сопровождала сервис — старый модуль на aiohttp с Pydantic v1, через который проходила вся обработка путевых листов и актов осмотра транспорта. Сервис существовал шесть лет, был покрыт тестами фрагментарно, а его API использовали мобильное приложение водителей, диспетчерская веб-панель и пакетный импорт.</p><p>Команда решила переписать сервис целиком: перейти на FastAPI, обновить Pydantic до v2, заодно почистить контракты и заменить внутреннее хранилище документов с MongoDB на PostgreSQL. План был рассчитан на четыре месяца.</p><p>Через восемь месяцев проект всё ещё не был готов к выкатке, а к десятому месяцу команда откатила миграцию полностью. Причин было несколько.</p><p>Во-первых, переписывание шло параллельно с продуктовой разработкой. За время миграции бизнес добавил два новых типа документов и изменил правила подписи актов. Новая система проектировалась под старые требования и к моменту готовности уже не соответствовала продукту.</p><p>Во-вторых, команда не написала характеристических тестов. Поведение «как есть» нигде не было зафиксировано, и расхождения находились только в продакшене после переключения.</p><p>В-третьих, у старого сервиса были скрытые побочные эффекты, о которых никто не помнил. При смене статуса документа публиковал событие в Kafka, которое читал биллинг и сервис аналитики. В новой реализации это поведение не было воспроизведено, потому что в коде оно выглядело как «лишний» вызов. После переключения биллинг перестал получать события, и расхождение обнаружили только через две недели — по жалобе финансового отдела.</p><p>В-четвёртых, переключение было сделано «в лоб»: маршрут в API Gateway просто перенаправили на новый сервис. Фича-флага не было, теневого запуска не было, плана отката не было. Когда выяснилось, что новый сервис строже валидирует исторические форматы документов и отклоняет часть старых записей, быстро вернуться на старую реализацию не получилось — её к тому моменту уже отключили на стенде, а в БД успели уйти записи в новом формате.</p><p>В итоге миграцию свернули, потратив около десяти человеко-месяцев и потеряв доверие бизнеса. Сервис до сих пор работает в исходной реализации, а команда переходит к плану, описанному ниже.</p><h2>Strangler Fig Pattern: как заменить систему по частям</h2><p>Один из самых практичных подходов к модернизации legacy-кода — Strangler Fig Pattern. В софтверном виде паттерн был сформулирован Мартином Фаулером в 2004 году под названием StranglerFigApplication. Идея проста: не переписывать систему целиком, а постепенно выносить отдельные части в новую реализацию.</p><p>Название пришло из биологии. Фикус-душитель растет вокруг дерева-хозяина и постепенно вытесняет его. В архитектуре принцип похожий: старая система продолжает работать, новая функциональность появляется рядом, а затем отдельные потоки постепенно переводятся на новую реализацию.</p><p>Представим старый монолит интернет-магазина. Внутри него есть каталог, корзина, заказы, платежи, скидки, личный кабинет и уведомления. Переписать всё сразу — рискованно. Но можно начать с относительно изолированного участка, например с уведомлений.</p><p>Сначала команда описывает текущий контракт: какие события приходят в модуль уведомлений, какие каналы используются, какие шаблоны отправляются, какие ошибки считаются допустимыми. Затем рядом создается новый сервис уведомлений, который реализует тот же контракт. На первом этапе он может даже не отправлять реальные сообщения, а только принимать события и логировать результат. После проверки часть трафика переводится на новую реализацию. Когда сервис стабилизируется, старый код уведомлений удаляется из монолита.</p><p>Strangler Fig хорошо работает там, где между старым и новым кодом есть сетевая граница: HTTP, message bus, RPC. Если такой границы нет — например, нужно постепенно заменить функцию или класс внутри одного процесса — используется родственный паттерн Branch by Abstraction: над старой реализацией создается абстракция, рядом пишется новая реализация, переключение происходит через конфигурацию или фича-флаг, после стабилизации старая ветка удаляется. Снаружи это выглядит как Strangler Fig, но без сетевого прокси.</p><p>Такой подход снижает риск. В системе нет одного большого релиза, где всё меняется сразу. Есть серия небольших контролируемых изменений. Каждое можно протестировать, измерить и откатить.</p><h2>Главное правило: сначала повторить поведение, потом улучшать</h2><p>Одна из частых ошибок при модернизации legacy-кода — попытка одновременно переписать систему и улучшить бизнес-логику. Команда смотрит на старый модуль и думает: «Раз уж мы его трогаем, давайте сразу сделаем нормальную архитектуру, изменим контракты, уберем странные кейсы и перепишем поведение».</p><p>Это опасный путь. В legacy-системах странное поведение часто существует не случайно. За ним может стоять неочевидное бизнес-правило, старый клиент, интеграция с внешней системой или исторический баг, на который уже кто-то завязался.</p><p>Например, в системе расчета налогов может быть правило: для контрактов, заключенных до 2018 года, НДС округляется в меньшую сторону до целого рубля, а для всех остальных — по математическим правилам. Новый разработчик может решить, что это ошибка, и «исправить» округление. Но потом выяснится, что часть крупных клиентов держит это поведение в своих сверках, а смена правила приведет к расхождениям в актах и претензиям.</p><p>Прежде чем менять поведение, его нужно зафиксировать. Для этого пишут характеристические тесты (characterization tests, иногда называемые golden master или approval tests). Идея простая: на реальных данных или их обезличенных копиях прогоняется старая реализация, её ответы сохраняются как эталон, и любые будущие изменения, отклоняющиеся от эталона, отлавливаются автоматически. Тесты пишутся не для красоты, а для того, чтобы зафиксировать существующее поведение — даже странное — перед тем, как его трогать. Подробно эта техника описана у Майкла Физерса в книге Working Effectively with Legacy Code; на практике её удобно реализовать через библиотеки семейства approval-tests (approvaltests-python, approvaltests-java и аналоги).</p><p>Поэтому первый этап модернизации — не улучшение, а воспроизведение текущего поведения. Новая реализация должна вести себя так же, как старая. Даже если старое поведение кажется странным. Только после стабилизации можно отдельно обсуждать, что именно стоит менять.</p><h2>Feature toggles: как включать новую логику без риска</h2><p>Feature toggles, или фича-флаги, — один из главных инструментов безопасной миграции. Они позволяют включать и выключать новую логику без деплоя.</p><p>В обычной разработке релиз часто выглядит бинарно: код либо выкатили, либо нет. При миграции legacy это неудобно. Гораздо безопаснее иметь возможность включить новую реализацию для 1% пользователей, затем для 10%, потом для половины аудитории и только после этого для всех.</p><p>Например, команда переносит расчет стоимости доставки из монолита в новый сервис. С помощью фича-флага это выглядит так:</p><p>user_id передается явно, чтобы решение «попал ли пользователь в новый сегмент» было стабильным от запроса к запросу. Иначе один и тот же клиент будет получать разные ответы при обновлении страницы, и поведение системы станет непредсказуемым.</p><p>На первом этапе флаг включают только для внутренней команды. Потом для тестового сегмента пользователей. Затем для небольшой доли реального трафика. Если метрики стабильны, долю увеличивают. Если появляются ошибки, флаг выключают, и пользователи снова идут в старую реализацию.</p><p>Важно различать два разных типа флагов. Флаг постепенной выкатки (rollout flag) меняется редко и контролирует, какой процент пользователей видит новую логику. Kill switch — отдельный флаг, единственная задача которого — мгновенно выключить новую реализацию при инциденте. Kill switch должен опрашиваться на каждом запросе, его кэширование должно жить секунды, а не минуты, и он принципиально не должен зависеть от той системы, которую он выключает. Иначе в момент аварии может оказаться, что выключатель сам недоступен.</p><p>В качестве инфраструктуры для флагов команды обычно берут одну из платформ: LaunchDarkly, Unleash, Flagsmith, GrowthBook, либо собирают собственную поверх Redis или конфигурационного сервиса. Для миграции важны три свойства: быстрое распространение изменений (секунды, а не минуты), поддержка таргетинга по пользователю/сегменту и аудит — кто и когда менял флаг.</p><p>Важно, что фича-флаг — это не просто if в коде. Для серьезной миграции нужны правила: кто может включать флаг, как быстро его можно отключить, какие метрики отслеживаются, когда флаг должен быть удален.</p><p>Последний пункт особенно важен. Если флаги не удалять, система быстро превращается в набор ветвлений, где никто уже не понимает, какая логика актуальна.</p><h2>Shadow testing: как проверить новую систему на реальном трафике</h2><p>Feature toggles помогают безопасно переключать пользователей. Но перед этим хорошо бы понять, совпадает ли новая логика со старой. Для этого используют shadow testing.</p><p>Shadow testing — это запуск новой реализации параллельно старой, но без влияния на пользователя. Пользовательский запрос по-прежнему обрабатывает старая система, а новая получает копию запроса и считает результат «в тени». Пользователю этот результат не показывается. Команда только сравнивает ответы.</p><p>Например, есть старый модуль расчета скидок. Он учитывает промокоды, сегмент пользователя, историю покупок, регион и партнерские условия. Команда пишет новый сервис скидок. Чтобы не переключать пользователей сразу, можно запустить теневой режим:</p><p>Два момента, на которые стоит обратить внимание в этом коде. Теневой вызов запускается через asyncio.create_task — корутина сразу планируется в event loop и начнёт выполняться, как только функция вернёт управление. И весь блок завернут в try/except: исключение в новой логике не должно ронять основной запрос. Без этих двух свойств shadow testing рискует ухудшить продакшен вместо того, чтобы безопасно его проверить.</p><p>Небольшая оговорка для продакшена: event loop держит на task только слабую ссылку, и без сохранённой ссылки задача может быть собрана сборщиком мусора прямо во время выполнения. В реальном коде Task имеет смысл класть в set фоновых задач и удалять оттуда через add_done_callback. В примере выше эта обвязка опущена для читаемости.</p><p>Для критичной доменной логики — платежей, биллинга, расчета тарифов — допустимый уровень расхождения должен быть около нуля: цель в shadow-режиме не «как можно меньше различий», а «понимаем каждое расхождение». Для менее чувствительных доменов (рекомендации, ранжирование результатов поиска) можно жить с расхождением в долях процента, но и там расхождения нужно классифицировать, а не игнорировать. Возможно, это баги новой реализации. А возможно, старая система содержит устаревшую логику, которую нужно отдельно обсудить с бизнесом.</p><p>Shadow testing особенно полезен для критичных доменных частей: платежей, биллинга, расчета тарифов, персональных предложений, транзакций. Там нельзя просто «попробовать на пользователях» и посмотреть, что будет.</p><p>При этом важно отличать теневую проверку чтения от теневой проверки записи. Чтение проверить относительно дёшево: запрос идёт в обе системы, ответы сравниваются, никаких внешних эффектов нет. С записью всё сложнее. Если новая реализация в shadow-режиме действительно создаст заказ, спишет деньги или отправит письмо, у пользователя возникнут двойные эффекты. Поэтому для writes либо вводят идемпотентные ключи и shadow-режим без реальных побочных действий (внешние вызовы заменены no-op-стабами, БД — отдельной shadow-копией), либо вообще отказываются от теневой проверки записи в пользу постепенной выкатки за фича-флагом.</p><p>Сравнение ответов в реальной системе тоже не сводится к одной функции compare. Нужно отдельно решать, как игнорировать «нормальный» шум (метки времени, идентификаторы, порядок коллекций), как сэмплировать трафик, чтобы не утопить хранилище расхождений, и как организовать триаж — кто и в каком ритме разбирает накопившиеся диффы. Готовые решения этого класса — GitHub Scientist (Ruby и его порты в другие языки), Twitter Diffy, либо собственный лёгкий регистратор поверх Kafka и таблицы расхождений.</p><h2>С чего начинать модернизацию</h2><p>Начинать лучше не с самого больного и не с самого центрального модуля. Это звучит контринтуитивно, потому что обычно хочется сразу взяться за главный источник проблем. Но если начать с ядра системы, команда быстро упрется в максимальное количество зависимостей и рисков.</p><p>Удобный способ выбрать первый кусок — оценить кандидатов по двум осям: насколько модуль критичен для бизнеса (low / high) и насколько сильно он связан с остальной системой (low / high). Начинать стоит с квадранта low-criticality + low-coupling: ошибки в нем не уронят бизнес-показатели, а малое количество зависимостей позволит провести миграцию полностью, не утянув за собой смежные модули. Высоко-критичные и сильно связанные части (платежи, ядро авторизации) трогают в последнюю очередь — на этот момент команда уже наберёт опыт безопасной миграции.</p><p>Хорошие точки входа обычно: уведомления, генерация отчетов, поиск, история операций, профиль пользователя, отдельная часть каталога. Важно, чтобы у команды была возможность описать контракт: какие данные входят, какие выходят, какие ошибки возможны, какие внешние системы участвуют.</p><p>Допустим, в банковском приложении есть старый модуль истории операций. Он медленный, сложно расширяется, но при этом не выполняет сами транзакции. Это хороший кандидат для первой миграции. Ошибка в истории операций неприятна, но обычно менее критична, чем ошибка в списании денег.</p><p>Команда может вынести чтение истории в отдельный сервис, сначала запустить его в shadow-режиме, потом включить для части пользователей, затем полностью перевести чтение на новую реализацию. При этом критичная транзакционная логика останется в старой системе до тех пор, пока команда не наберет опыт безопасной миграции.</p><h2>Миграция данных: самая сложная часть</h2><p>Большая часть статьи говорит о маршрутизации запросов и переключении трафика. Но в реальных проектах основная сложность лежит ниже — в данных. Старая и новая реализации почти всегда работают с общим состоянием: одной БД, одним хранилищем документов, одним набором очередей. Переехать туда «одним коммитом» нельзя.</p><p>Базовый рабочий приём — Expand-Contract (он же Parallel Change). Изменение схемы делается в три такта. На этапе expand в БД добавляются новые поля, таблицы или индексы, при этом старое поведение полностью сохраняется. Затем — migrate: обе реализации начинают писать и в старое, и в новое место (dual writes), а отдельный фоновый процесс делает backfill — заполняет новые поля историческими данными. После этого читатели по одному переключаются на новую схему. Только когда никто из читателей не использует старую структуру, наступает contract — удаление лишних колонок и таблиц.</p><p>Несколько практических деталей, которые часто упускают:</p><p>·         Dual writes — это не бесплатная операция. Две записи означают две точки отказа. Если одна из них упала, нужно решать, что делать: продолжать ли работу, ставить ли событие в очередь на повтор, помечать ли запись как несогласованную. Простое «сначала пишем туда, потом сюда» в продакшене на нагрузке приводит к расхождениям.</p><p>·         Backfill часто длиннее, чем кажется. На большой таблице миграция в одном UPDATE блокирует продакшен. Поэтому backfill делают батчами по N тысяч строк с паузами, отслеживают прогресс и предусматривают возможность остановить и продолжить.</p><p>·         Онлайн-изменения схемы на крупных таблицах делаются не штатным ALTER TABLE, а специализированными инструментами: gh-ost или pt-online-schema-change для MySQL, встроенные онлайн-механизмы PostgreSQL для индексов и колонок, Liquibase/Flyway — для управления версионированием изменений в репозитории.</p><p>·         Shadow testing данные не покрывает. Можно сравнить, что новая реализация возвращает то же, что и старая, но если за этим стоит другая схема в БД, проверка корректности самой миграции данных — это отдельная работа: сверки, контрольные суммы, выборочный аудит исторических записей.</p><p>Без этих шагов любая красивая фасадная архитектура наталкивается на разъезжающиеся данные — и тогда даже идеальный Strangler Fig снаружи не спасает.</p><h2>Прокси-слой как точка контроля</h2><p>Чтобы постепенно заменять legacy-код, нужно управлять маршрутизацией запросов. Для этого часто создают прокси-слой, API Gateway или фасад, через который проходит обращение к старой и новой логике. В терминах Domain-Driven Design такой слой часто называют Anti-Corruption Layer: он защищает новую реализацию от старых контрактов и наоборот, позволяя двум моделям сосуществовать без взаимного «загрязнения».</p><p>Без такой точки контроля миграция становится хаотичной. Часть клиентов ходит напрямую в старый модуль, часть — в новый, часть использует обходные пути, а команда теряет возможность централизованно переключать трафик.</p><p>Прокси-слой решает несколько задач. Он скрывает детали реализации от клиентов, позволяет направлять часть запросов в новую систему, поддерживает фича-флаги, собирает метрики и упрощает откат.</p><p>В качестве технической основы команды обычно берут один из трех вариантов: классический API gateway (Kong, AWS API Gateway), service mesh (Envoy, Istio) или более простой reverse proxy (NGINX, HAProxy). Service mesh особенно удобен, когда трафик уже идёт внутри Kubernetes-кластера: маршрутизацию можно менять конфигурацией, без правок кода клиентов и сервисов.</p><p>Например, мобильное приложение обращается к endpoint /orders/history. Раньше этот endpoint напрямую обслуживал монолит. После введения API Gateway приложение продолжает ходить по тому же контракту, но внутри gateway может решать, куда направить запрос: в legacy-модуль или новый сервис истории заказов.</p><p>Управление маршрутизацией обычно делается не «всё или ничего», а на основании атрибутов запроса: значения заголовка (X-Migration-Cohort: new), куки, хэша от user-id (стабильное разбиение пользователей на сегменты) или географического региона. Это позволяет выкатывать новую реализацию сначала на одну страну, на сотрудников самой компании или на тестовый сегмент — и только потом расширять охват.</p><p>Для клиента ничего не меняется. Для команды появляется управляемость.</p><h2>Наблюдаемость: без метрик миграция превращается в гадание</h2><p>Постепенная модернизация невозможна без нормальной наблюдаемости. Если команда не видит, что происходит внутри системы, она не сможет безопасно переключать трафик.</p><p>Минимальный набор — это логи, метрики и распределенная трассировка (distributed tracing). Нужно понимать, сколько запросов идет в старую и новую реализацию, сколько ошибок возникает, как меняется latency, где появляются таймауты, какие статусы возвращаются, какие бизнес-метрики проседают.</p><p>Технические метрики стоит формулировать не как «средний ответ» и «процент ошибок», а в терминах SLI и SLO: целевые показатели вида «99.9% запросов на /orders/history отвечают быстрее 300 ms за 30 дней» с явным error budget. Latency измеряется по перцентилям (p50, p95, p99) — среднее значение почти всегда обманчиво, а хвосты распределения говорят о реальном опыте пользователя. На время миграции имеет смысл выставить отдельные SLO для нового и старого пути и сравнивать их.</p><p>В качестве инструментов де-факто стандартом стал OpenTelemetry для трассировок, метрик и логов — единый протокол, который пишет в практически любое хранилище. Дальше — Prometheus и Grafana для метрик, Jaeger или Tempo для traces, Sentry или аналог для ошибок. Для миграции важна возможность фильтровать метрики по «варианту» — отдельно по старому и новому пути — иначе все цифры смешаются и реальную динамику будет не видно.</p><p>Технических метрик недостаточно. Если команда переносит оформление заказа, важно смотреть не только на 500 ошибки и время ответа, но и на конверсию в оплату, количество брошенных корзин, повторы запросов, обращения в поддержку.</p><p>Пример: новая система формально отвечает быстрее старой и не дает ошибок. Но после включения на 10% пользователей падает конверсия в оплату. Причина может быть не в серверной ошибке, а в изменении порядка полей, другом тексте сообщения или потере какого-то edge-case. Без бизнес-метрик команда может решить, что миграция успешна, хотя для продукта она уже создает проблему.</p><h2>Практическая последовательность миграции</h2><p>Рабочая последовательность обычно выглядит так.</p><p>Сначала команда выбирает ограниченный участок системы. На этом этапе важно не просто назвать модуль, а описать его границы. Какие сценарии он закрывает? Кто его вызывает? Какие данные он читает и пишет? Какие внешние интеграции использует? Какие неочевидные бизнес-правила в нем есть?</p><p>Затем поверх legacy-логики создается стабильный контракт. Это может быть API, фасад, gateway или отдельный слой внутри приложения. Главная задача — сделать так, чтобы клиенты зависели не от внутренней реализации, а от понятного интерфейса. На этом этапе полезно вспомнить про contract testing (Pact, Spring Cloud Contract): автотесты со стороны потребителей фиксируют, что именно они ожидают от API, и предупреждают о ломающих изменениях до того, как они доедут до продакшена.</p><p>После этого рядом пишется новая реализация. Она должна повторять текущее поведение, а не сразу становиться «идеальной версией будущего». На этом этапе полезно фиксировать все расхождения: где старая система работает странно, где требования не описаны, где бизнес-правила требуют уточнения.</p><p>Следующий этап — shadow testing. Новая система получает копии реальных запросов, считает результат, но пользователю по-прежнему возвращается ответ legacy. Команда сравнивает результаты и устраняет расхождения.</p><p>Когда новая реализация достаточно стабильна, начинается постепенное переключение через feature toggles. Сначала внутренние пользователи, потом 1% реального трафика, затем 5–10%, затем 50% и только после этого 100%.</p><p>На каждом этапе команда смотрит на метрики. Если всё стабильно, движение продолжается. Если появляются проблемы, флаг выключается, трафик возвращается в legacy, а команда разбирает причины.</p><p>Последний этап — удаление старого кода. Это не формальность, а обязательная часть миграции. И «удалить старый код» — это не один коммит, а явный Definition of Done: вырезана старая ветка кода, удалён фича-флаг, обновлена документация и схемы архитектуры, переименованы или удалены устаревшие дашборды и алерты, обновлены runbook’и для on-call и проведено короткое внутреннее обучение. Если этого не сделать, через полгода никто уже не вспомнит, какой путь актуален, и легаси-ветвление останется в коде навсегда.</p><h2>Откат миграций: дешёвый только пока не пошли записи</h2><p>Откатить миграцию, в которой ещё не было записи в БД, легко: достаточно переключить фича-флаг, и трафик снова идёт через старую реализацию. Откатить миграцию, в которой новая система уже неделю писала данные в новые таблицы, — отдельный, гораздо более тяжёлый разговор.</p><p>Поэтому ещё на этапе проектирования каждое изменение должно сопровождаться явным планом отката. Удобно различать три типа шагов.</p><p>Полностью обратимые шаги. Чтение через новый сервис, расчёт «в тени», новые метрики. Откат — выключить флаг. Это самый комфортный режим, и в нём стоит держать миграцию как можно дольше.</p><p>Обратимые с компенсацией. Новая реализация пишет дополнительные данные (например, дублирует операции в новую таблицу), но старый источник тоже обновляется. Откат возможен, но требует решить, что делать с уже записанными данными: оставить, очистить, синхронизировать. План этих действий должен быть написан до выкатки, не во время инцидента.</p><p>Forward-only. После некоторой точки откат становится невозможен — например, после того, как старая схема удалена или внешние интеграции перенастроены на новый сервис. Такие шаги допустимы, но к ним нужно приходить отдельно, осознанно, с особенно строгими SLO в предыдущем этапе. До forward-only-перехода имеет смысл подержать систему в режиме параллельной работы дольше, чем по графику.</p><p>Базовое правило: ни один шаг миграции не должен уходить в продакшен, если у команды нет письменного ответа на вопрос «как мы откатываемся в случае проблемы». Иначе при инциденте откатываться будут на ходу — и не факт, что успешно.</p><h2>Пример: как тот же сервис мигрировали со второй попытки</h2><p>После неудачного опыта команда взялась за тот же сервис заново, но изменила подход.</p><p>На первом шаге они зафиксировали поведение существующего сервиса. На самые часто используемые сценарии (создание путевого листа, подпись акта осмотра, выгрузка пакета документов за период) написали характеристические тесты на реальных продакшен-данных, обезличенных и сохранённых как фикстуры. Любое будущее изменение поведения теперь падало в CI как явное расхождение.</p><p>Параллельно команда провела инвентаризацию побочных эффектов. Из исходного кода и логов выяснилось, что сервис не только хранит документы, но и: публикует событие в Kafka при смене статуса, инкрементирует счётчик в Redis для рейтинга водителей, отправляет webhook во внешнюю систему партнёра, пишет в таблицу аудита. Каждый из этих эффектов попал в отдельный пункт чек-листа «что должно остаться» в новой реализации.</p><p>Затем команда выбрала первый кусок для выноса — не весь сервис, а только чтение документов (GET /documents/{id} и GET /documents/by-driver/{driver_id}). Это была наименее рискованная часть: ошибки в чтении неприятны, но не ломают финансовые потоки.</p><p>Новый сервис написали на FastAPI рядом со старым. На уровне API Gateway появилось правило маршрутизации: запросы на чтение шли в старый сервис, но в фоне дублировались в новый. Ответ пользователю всегда возвращал legacy, а ответ нового сервиса сравнивался с эталоном и записывался в отдельную таблицу для разбора. Использовали обёртку поверх asyncio.create_task — на ответ пользователя теневой вызов не влиял.</p><p>За три недели shadow-режима команда нашла четыре расхождения. Два оказались багами новой реализации (округление времени, неправильная сортировка вложений). Два — давно забытыми особенностями старого сервиса (одно поле возвращалось в UTC, другое — в локальной зоне; так было исторически, бизнес не возражал, но в новой реализации захотели единый формат). Все четыре зафиксировали явно: баги — починили, особенности — согласовали с продуктовой командой как осознанное изменение.</p><p>Когда расхождений не осталось, включили фича-флаг на сотрудников самой компании. Через неделю — на 1% реальных водителей. Дальше шаг по 5%, 25%, 50%, 100% с паузой в несколько дней между этапами. На каждом шаге следили не только за HTTP-ошибками и latency, но и за продуктовыми метриками: количество подписанных актов, время от открытия документа до подписи, доля повторных запросов. Один раз пришлось откатиться с 25% на 5% — в одном из регионов выросло время отклика из-за неэффективного запроса. Исправили, выкатили снова.</p><p>Через два месяца чтение полностью перешло в новый сервис. Старый код чтения и фича-флаг удалили в том же релизе. После этого по той же схеме мигрировали запись документов, потом публикацию событий, потом импорт из внешних систем. Полная миграция заняла девять месяцев — почти столько же, сколько провалившийся Big Bang, — но продукт всё это время продолжал развиваться, инцидентов не было, и в конце команда осталась с системой, которую понимает.</p><h2>Типичные ошибки при работе с legacy</h2><p>Первая ошибка — пытаться улучшить всё сразу. Команда одновременно меняет архитектуру, бизнес-логику, контракты и инфраструктуру. В результате становится невозможно понять, какая именно часть вызвала проблему. Правильнее сначала воспроизвести поведение, стабилизировать новую реализацию и только потом улучшать.</p><p>Вторая ошибка — недооценивать скрытые зависимости и побочные эффекты. Legacy-код часто делает больше, чем кажется. На один и тот же вызов могут быть навешаны: запись в таблицу аудита, инкремент счётчика в кэше, публикация события в очередь, обновление статуса связанной сущности, инвалидация кэша, дёрганье webhook’а во внешнюю систему. Если в новой реализации воспроизвести только явный путь, скрытые потребители молча перестанут получать данные — и узнают об этом через жалобу бизнеса, а не через ошибку в логах. Поэтому перед выносом любого модуля имеет смысл составить инвентаризацию побочных эффектов: пройтись по коду и логам и выписать каждое нелогичное действие отдельным пунктом чек-листа.</p><p>Третья ошибка — отсутствие наблюдаемости. Без логов, метрик и трассировки команда не управляет миграцией, а угадывает. Особенно опасно смотреть только на технические ошибки и игнорировать бизнес-показатели.</p><p>Четвертая ошибка — не договариваться с бизнесом. Модернизация не должна быть невидимой «инженерной активностью в стол». Её нужно встраивать в roadmap, объяснять эффект и договариваться о приоритетах. Если бизнес не понимает, зачем команда тратит время на миграцию, работа будет постоянно проигрывать новым фичам.</p><p>Пятая ошибка — не удалять старый код. Временное сосуществование старой и новой логики нормально. Вечное сосуществование — нет. Если legacy не удаляется, технический долг не уменьшается, а просто меняет форму.</p><p>Шестая ошибка — не удалять фича-флаги после миграции. Флаг, который сыграл свою роль и больше никогда не выключается, превращается в постоянное ветвление в коде. Через год команда не помнит, можно ли удалить такую ветку или там сидит важный edge-case. Через два — кода с такими «мёртвыми» флагами становится больше, чем основной логики. Поэтому каждый флаг должен заводиться с условием удаления («после полной выкатки и двух недель стабильной работы») и иметь ответственного, кто этим удалением займётся.</p><p>Отдельно стоит упомянуть организационную сторону. Закон Конвея работает и в обратную сторону: если новый и старый код владеются разными командами с разными приоритетами, миграция будет тормозиться независимо от выбранного паттерна. На время миграции имеет смысл явно проговорить, кто отвечает за переход, и не разделять старую и новую реализации между несовместимыми roadmap’ами.</p><h2>Компромиссы, к которым нужно быть готовыми</h2><p>Постепенная модернизация безопаснее Big Bang-переписывания, но она не бесплатна. Некоторое время система будет сложнее, чем раньше. В ней появятся старый и новый код, прокси-слой, фича-флаги, дублирование логики, дополнительные метрики.</p><p>Shadow testing увеличит нагрузку на инфраструктуру, потому что часть запросов будет обрабатываться дважды. Команде придется поддерживать дисциплину: документировать контракты, отслеживать флаги, удалять старую реализацию после миграции, поддерживать contract-тесты в актуальном состоянии.</p><p>Но это контролируемая сложность. Она распределена во времени и управляется инженерными практиками. В отличие от Big Bang-риска, где команда долго работает с минимальной обратной связью, а потом выкатывает один большой релиз с максимальной неопределенностью.</p><h2>Когда Strangler Fig особенно оправдан</h2><p>Постепенная миграция особенно хорошо подходит для систем, где downtime невозможен или слишком дорог. Это финтех, e-commerce, биллинг, мобильные бэкенды с большой аудиторией, высоконагруженные продукты, старые монолиты и системы с большим количеством интеграций.</p><p>Если продуктом ежедневно пользуются сотни тысяч или миллионы людей, нельзя позволить себе «переписать и посмотреть, что будет». Нужно менять архитектуру так, чтобы пользователь не замечал процесса миграции.</p><p>Этот подход также полезен там, где бизнес продолжает активно развивать продукт. Если фичи нельзя заморозить на полгода, модернизация должна идти параллельно с продуктовой разработкой.</p><h2>Когда модернизацию лучше не делать</h2><p>Постепенная миграция — мощный инструмент, но у неё тоже есть стоимость, и иногда правильный ответ — оставить систему как есть. Несколько сценариев, в которых модернизация плохо окупается.</p><p>Продукт, который уходит из эксплуатации. Если через год сервис будет выключен или заменён на покупное решение, тратить квартал на его рефакторинг бессмысленно. Достаточно стабилизировать то, что есть.</p><p>Модуль, который никто не трогает. Если код десятилетней давности продолжает работать, не падает, не требует изменений и не вызывает инцидентов, его «уродливость» — не повод его переписывать. Цель модернизации — упростить будущие изменения; если будущих изменений нет, цели тоже нет.</p><p>Регулируемые системы с тяжёлой ресертификацией. В банковских, медицинских и государственных контурах любое изменение в критичной системе может потребовать повторной сертификации, перепрохождения аудитов, обновления договорной обвязки. В таких условиях стоимость модернизации может на порядок превышать стоимость поддержки текущей реализации, и решение нужно принимать вместе с владельцем продукта и юристами, а не только инженерным составом.</p><p>Простой тест: если на вопрос «какой бизнес-сценарий мы откроем после миграции» нет внятного ответа — модернизацию имеет смысл отложить и заняться чем-то другим.</p><h2>Что получает команда</h2><p>Главный результат постепенной модернизации — управляемость. Команда начинает лучше понимать систему, контролировать изменения и снижать риск инцидентов.</p><p>Появляются понятные контракты, наблюдаемость, практика безопасных релизов, культура удаления старого кода. Разработчики перестают бояться legacy, потому что у них появляется метод, а не только желание «когда-нибудь всё переписать».</p><p>Для бизнеса это тоже выгодно. Продукт продолжает развиваться, сроки становятся более прогнозируемыми, риски крупных сбоев снижаются, а технический долг постепенно уменьшается.</p><h2>Модернизация — это процесс, а не проект</h2><p>Legacy нельзя «починить за квартал». Если система развивалась годами, она не станет простой после одного рефакторинга. Но её можно системно улучшать.</p><p>Strangler Fig Pattern, Branch by Abstraction, feature toggles, shadow testing и аккуратная миграция данных дают рабочую модель: выбрать ограниченный участок, описать контракт, реализовать новую версию, проверить её на реальном трафике, постепенно переключить пользователей и удалить старый код.</p><p>Это не самый быстрый путь. Зато он управляемый. А в зрелых продуктах управляемость важнее скорости.</p><p>Потому что цель модернизации — не написать красивую новую систему. Цель — сделать так, чтобы продукт продолжал развиваться, команда могла безопасно вносить изменения, а пользователи не становились участниками инженерного эксперимента.</p>]]></content:encoded>
    </item>
    <item>
      <title>Linux-ядро сделает TSC обязательным требованием для x86-процессоров</title>
      <link>https://tproger.ru/news/linux-yadro-sdelaet-tsc-obyazatelnym-trebovaniem-dlya-x86-processo</link>
      <comments>https://tproger.ru/news/linux-yadro-sdelaet-tsc-obyazatelnym-trebovaniem-dlya-x86-processo?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Евгений Стребков]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/news/linux-yadro-sdelaet-tsc-obyazatelnym-trebovaniem-dlya-x86-processo</guid>
      <description><![CDATA[<p>Разработчики Linux-ядра готовятся сделать поддержку TSC безусловным требованием для x86. Узнайте, какие процессоры потеряют поддержку и когда ждать изменений.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/news/linux-yadro-sdelaet-tsc-obyazatelnym-trebovaniem-dlya-x86-processo">Linux-ядро сделает TSC обязательным требованием для x86-процессоров</a>»</p>]]></description>
      <category><![CDATA[Linux]]></category>
      <category><![CDATA[Legacy]]></category>
      <category><![CDATA[Новости]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Wed, 03 Jun 2026 08:00:49 GMT</pubDate>
      <content:encoded><![CDATA[<p>Разработчики ядра Linux готовятся сделать поддержку TSC безусловным требованием для всех x86-процессоров. Это стало возможным после снятия поддержки устаревших чипов: Intel 486 уже исключён из кодовой базы, а поддержка AMD K5 и AMD Elan находится в процессе удаления.</p><p>TSC (Time Stamp Counter) — это высокоточный счётчик тактов процессора, появившийся ещё во времена Intel Pentium. Он позволяет ядру измерять время с минимальными накладными расходами и используется в задачах от профилирования до планирования процессов.</p><p>Ранее код ядра содержал альтернативные пути для систем без TSC, поскольку поддержка распространялась на процессоры i486 и другие старые чипы, где счётчик отсутствовал. Теперь, когда эти архаичные платформы исключены из кодовой базы, мейнтейнеры подготовили патч, который делает TSC обязательным через систему конфигурации ядра (Kconfig).</p><p>Параллельно из ядра вырежут альтернативные ветви кода без TSC: лишние проверки и резервные реализации уйдут, что упростит кодовую базу.</p><p>Ядро Linux готовится сделать TSC безусловным требованием для x86-процессоров.</p><p>Решение стало возможно благодаря снятию поддержки устаревших чипов: Intel 486, AMD K5 и AMD Elan.</p><p>Патч уже находится в подготовительной ветке ядра и ожидается в цикле разработки Linux 7.2.</p><p>Удаление альтернативных ветвей кода упростит кодовую базу.</p><h2>Что изменится для x86-процессоров в Linux</h2><p>Для современного железа — ничего: все актуальные x86-процессоры (от Intel Core и Xeon до AMD Ryzen и EPYC) давно имеют TSC. Изменение затронет только разработчиков, которые всё ещё собирают ядро для ретро-совместимости.</p><p>Поддержка Intel 486 держалась в ядре десятилетиями из-за принципа максимальной совместимости, но в 2025–2026 годах мейнтейнеры начали массовую чистку legacy-кода. Удаление non-TSC путей — логичное продолжение этого процесса: раз чипов без счётчика больше не поддерживают, зачем тащить обходные механизмы?</p><h2>Выводы</h2><p>Отказ от альтернативных ветвей кода без TSC — ещё один шаг к чистке legacy-кода в Linux. Упрощение архитектуры x86-платформы ускорит дальнейшую разработку ядра и снизит нагрузку на мейнтейнеров, которые больше не будут тестировать редкие конфигурации без счётчика тактов.</p><p>Источник: <a href="https://www.phoronix.com/news/Linux-Kernel-TSC-Unconditional" rel="noopener noreferrer">Phoronix</a></p>]]></content:encoded>
    </item>
    <item>
      <title>Как Pizza Tycoon симулировала трафик на 25 МГц процессоре в 1994 году</title>
      <link>https://tproger.ru/translations/kak-pizza-tycoon-simulirovala-trafik-na-25-mgc-processore-v-1994</link>
      <comments>https://tproger.ru/translations/kak-pizza-tycoon-simulirovala-trafik-na-25-mgc-processore-v-1994?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Евгений Стребков]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/translations/kak-pizza-tycoon-simulirovala-trafik-na-25-mgc-processore-v-1994</guid>
      <description><![CDATA[<p>Pizza Tycoon крутил живой городской трафик на Intel 386 25 МГц. FinnKuhn 14 лет не мог это повторить — пока не прочитал оригинальный ассемблер.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/translations/kak-pizza-tycoon-simulirovala-trafik-na-25-mgc-processore-v-1994">Как Pizza Tycoon симулировала трафик на 25 МГц процессоре в 1994 году</a>»</p>]]></description>
      <category><![CDATA[Legacy]]></category>
      <category><![CDATA[Переводы]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Fri, 10 Apr 2026 13:30:02 GMT</pubDate>
      <content:encoded><![CDATA[<p>Если ваша симуляция десятка сущностей на экране уже уехала в графы сцены, pathfinding и полноценный collision detection — возможно, вы решаете не ту задачу. FinnKuhn 14 лет писал систему движения машин для DOS-игры 1994 года Pizza Tycoon — и каждый раз упирался в переусложнённую архитектуру. Пока не <a href="https://pizzalegacy.nl/blog/traffic-system.html">прочитал оригинальный ассемблер</a> и не увидел: направление движения там зашито прямо в тип тайла дороги, а машинам вообще не нужно ничего планировать. Ниже — его рассказ о том, как это крутится на Intel 386 25 МГц.</p><p>Мы перевели <a href="https://pizzalegacy.nl/blog/traffic-system.html">статью FinnKuhn</a>. Далее — от первого лица.</p><h2>Контекст</h2><p>Я работаю над <a href="https://pizzalegacy.nl">Pizza Legacy</a> — опенсорсной реимплементацией DOS-игры 1994 года <i>Pizza Tycoon</i>. В игре есть режим крупного плана: когда прокручиваешь карту, видишь постоянный поток машин на улицах. Одновременно — штук двадцать-тридцать маленьких спрайтов, но они ездят по сетке улиц, выстраиваются в очередь на перекрёстках и в целом создают ощущение живого города. Иногда они проезжали сквозь друг друга — был такой баг, — но этого хватало, чтобы карта выглядела населённой. И всё это крутилось на 386-м процессоре на 25 МГц.</p><figure><img src="https://media.tproger.ru/user-uploads/133946/2026-04-10/77e7a0e2-a0af-4bea-b449-0852cab6dd5d.webp" alt="Карта города в Pizza Tycoon в режиме крупного плана" /><figcaption>Режим крупного плана города в Pizza Tycoon: машины двигаются по сетке улиц.</figcaption></figure><p>Первое, что я реализовал в 2010 году, когда только начал проект, — это как раз режим крупного плана. Но потребовалось 14 лет, чтобы машины на нём наконец ездили так, как мне нравилось. За эти годы я несколько раз подступался к задаче и каждый раз утыкался в проблему: моя система получалась слишком сложной, в ней было тяжело разбираться и невесело её поддерживать.</p><p>Одна из попыток, в 2017-м, выглядела так: каждая клетка карты помнила, какие позиции заняты, и каждая машина перед движением должна была спрашивать у сетки разрешение, резервировать слоты и освобождать их по мере движения. По сути получилась распределённая система блокировок — только ради того, чтобы сдвинуть спрайт на несколько пикселей. Машины и тайлы постоянно пытались синхронизироваться друг с другом.</p><p>И всё это время в голове сидела одна мысль: оригинальный Pizza Tycoon крутил эту симуляцию на 25 МГц. Почему у меня реализации всегда получались такими сложными?</p><p>В итоге я пошёл в ассемблер, который к тому моменту уже несколько лет потихоньку документировал. Разобраться с x86 помогли языковые модели — они читали его лучше меня.</p><p>Теперь, когда всё заработало, я вижу, где ошибался: я заходил в задачу с мозгом, забитым современными концепциями — графы сцены, поиск пути, обнаружение столкновений. И, конечно, с ощущением, что у меня сколько угодно CPU, чтобы это всё крутить.</p><h2>Как устроены города</h2><p>Сначала посмотрим, из чего вообще состоит город. Видно двухполосные дороги, T-перекрёстки, четырёхсторонние перекрёстки и углы. Карты в Pizza Tycoon — это сетка 160×120 тайлов, где каждый тайл берётся из файла landsym.vga.</p><figure><img src="https://media.tproger.ru/user-uploads/133946/2026-04-10/a445d651-c798-490c-8b7e-b968432d0d4d.webp" alt="Оригинальный landsym.vga с разметкой тайлов" /><figcaption>Оригинальный landsym.vga с добавленными границами между тайлами и координатами столбца и строки.</figcaption></figure><h2>Дорожная система</h2><p>Возвращаемся к трафику. Ключевой инсайт, благодаря которому всё это крутится на таком медленном процессоре: <b>машинам не нужно знать, куда они едут</b>. Направление зашито в сам тип дорожного тайла.</p><p>Тайл 0x16 — это нижняя часть горизонтальной дороги, то есть машины здесь могут ехать только слева направо. Соответственно, 0x06 — справа налево, а 0x26 и 0x36 — то же самое, но для вертикального движения.</p><p>Получается, что город — это просто набор односторонних дорог. Как только машина знает, на каком тайле стоит, она может просто ехать дальше без всякого планирования.</p><p>С углами та же история. 0x56 (CORNER_SW в моём enum) — это угол, на котором машина может либо ехать дальше на запад, либо повернуть на юг. Когда машина доезжает до угла, она подбрасывает монетку: 50% — едет прямо, 50% — поворачивает. Карты спроектированы так, чтобы дорожная сеть всегда оставалась согласованной: рядом с CORNER_SW обязательно стоит либо тайл с движением с юга на север (то есть машине придётся свернуть на юг), либо ещё один угловой тайл, который тоже допускает и поворот, и проезд прямо.</p><p>Есть ещё одно правило, чтобы трафик выглядел естественно: если машина только что сделала левый поворот, то на следующем углу её принудительно пустят прямо. Никаких двух левых поворотов подряд.</p><figure><img src="https://media.tproger.ru/user-uploads/133946/2026-04-10/9f75dd80-1c1e-4b10-8186-1dc4b2dd45f8.webp" alt="Допустимые направления движения для разных типов тайлов" /><figcaption>Допустимые направления движения для разных типов тайлов, показаны стрелками.</figcaption></figure><h2>Движение: один пиксель за такт</h2><p>Машины двигаются на один пиксель за такт игрового цикла. На каждом такте главный цикл проверяет, не заблокирована ли машина, и если нет — прибавляет или вычитает один пиксель у её экранной координаты в зависимости от направления. Восток: +1 к X. Север: −1 к Y. Никакой векторной математики.</p><p>Есть второй счётчик — progress, который идёт от 16 к 1. Когда он доходит до нуля — сбрасывается в 16, и игра запускает тайловую логику: смотрит, какой там следующий тайл, решает новое направление, обновляет кадр спрайта (чтобы визуально развернуть машину в новую сторону).</p><p>Поскольку каждый тайл имеет размер 16×16 пикселей, тайловая логика срабатывает ровно один раз на пересечение тайла. Движение на один пиксель — каждый такт, тяжёлая тайловая логика — только в 1 из 16 тактов.</p><p>Когда машина только спавнится, progress устанавливается в случайное значение от 1 до 16. Это разносит проверки границ тайлов между разными тактами, так что нагрузка размазывается равномерно — примерно 25 машин не упираются в тайловую логику одновременно.</p><h2>Обнаружение столкновений: дешёвый O(n²)</h2><p>В отличие от моих попыток навернуть что-то умное, оригинал использует самую банальную попарную проверку: для каждой машины пробегаешь весь список машин и спрашиваешь — «а не пересекутся ли эти две на следующем такте?». Если да — ставишь на заблокированную машину счётчик ожидания в 10 тактов и идёшь дальше.</p><p>Но код обнаружения столкновений написан так, чтобы выходить из проверки как можно раньше. Первое, что он делает, — извлекает направление второй машины. А так как дороги односторонние, восточная и западная машины в принципе не могут оказаться на одной дороге. Значит, такая пара возвращается мгновенно, даже не читая координат. То же самое для пар «восток — юг», «запад — север» и так далее.</p><p>Допустим, в городе видимо примерно 25 машин — это около 625 попарных вызовов за такт. Примерно половина из них возвращается после нескольких инструкций процессора на одной только проверке направления. Из оставшихся большинство отсеивается на следующем шаге: у машин, едущих в одну сторону, должна совпадать координата поперёк движения — одно сравнение на равенство. Пар, которые реально доходят до арифметики с координатами, обычно буквально единицы.</p><p>Когда машину всё-таки блокирует, 10-тактовая пауза создаёт естественные пробки: машины накапливаются, передняя рано или поздно находит свободный путь, очередь рассасывается. В системе есть баги — некоторые комбинации направлений вообще не проверяются (например, восточная машина никогда не пересекается с южной), и именно поэтому машины иногда проезжают сквозь друг друга. Но цель тут — не точная симуляция дорожного движения, а просто живое движение на экране. И для этой цели алгоритм работает отлично.</p><h2>Спавн машин</h2><p>Когда игрок входит в режим крупного плана, игра сканирует все 132 тайла видимой области (12 столбцов × 11 строк) и для каждого дорожного тайла кидает кубик против плотности трафика района, чтобы решить, спавнить ли там машину. Районы с высокой плотностью получаются загруженнее, с низкой — пустыми. Угловые тайлы из точек спавна исключены: машины появляются только на прямых участках.</p><p>Машины, которые уезжают за край экрана, переспавниваются — появляется новая машина случайного цвета, едущая в обратную сторону, на встречном тайле. То есть игра вообще не беспокоится о полноценном цикле жизни машин: каждый раз, когда одна уезжает на восток, она просто спавнит новую на другом краю, едущую на запад. И наоборот.</p><p>Когда игрок прокручивает карту, новая полоса только что открывшихся тайлов получает такую же обработку — шанс спавна по плотности района.</p><h2>Почему это работает</h2><p>Оглядываясь на свои провальные попытки, я вижу, что проектировал решения для проблем, которых у оригинала вообще не было.</p><ul><li><b>Машинам не нужен поиск пути</b> — карта сама говорит им, куда можно ехать.</li><li><b>Обнаружение столкновений дешёвое</b>, потому что ранний выход по направлению делает большинство пар практически бесплатными.</li><li><b>Нет скорости и физики</b> — один пиксель за такт выглядит достаточно убедительно.</li><li><b>Если врезался — просто подожди 10 тактов.</b> А если надо повернуть — просто проехал половину тайла и повернул. Работает на любом тайле в любом направлении.</li></ul><p>Прежде чем тащить в свой проект поиск пути и граф сцены, стоит спросить себя: сколько у меня реально сущностей на экране? Какие ограничения у домена? Маленький экран, односторонние дороги, двадцать пять объектов — всё это аргументы за тривиальный алгоритм, а не за универсальный движок.</p><p>Я переписал систему довольно близко к ассемблеру оригинала — по сути, пара switch-блоков с разными вариантами маршрутизации в зависимости от типа тайла. Код можно посмотреть в методе decide_desired_direction в <a href="https://github.com/FinnKuhn/pizza-legacy/blob/main/src/Car.cpp">Car.cpp</a> репозитория проекта.</p><ul><li><b>Intel 386 25 МГц (1994)</b>, карта 160×120 тайлов, каждый тайл 16×16 пикселей, видимая область 12×11</li><li><b>Направление зашито в тип тайла</b> (0x16, 0x06, 0x26, 0x36) — машинам не нужен поиск пути, они просто читают тип клетки под собой</li><li><b>625 попарных проверок за такт</b> (при ~25 машинах) — но большинство возвращается после нескольких инструкций за счёт раннего выхода по направлению</li><li><b>Один пиксель за такт + счётчик 16→1</b> разносит тяжёлую тайловую логику между тактами, нагрузка размазывается равномерно</li><li><b>Главный урок</b>: встроенные ограничения домена (односторонние дороги, маленький экран, заранее известные маршруты) дают такие упрощения, о которых современный разработчик просто не подумает</li></ul><p>Источник: <a href="https://pizzalegacy.nl/blog/traffic-system.html">«How Pizza Tycoon simulated traffic on a 25 MHz CPU»</a> — блог Pizza Legacy. Публикуется с разрешения автора в рамках <a href="https://pizzalegacy.nl">открытого проекта</a>.</p>]]></content:encoded>
    </item>
    <item>
      <title>Google представила Code Wiki — ИИ, пишущий и обновляющий документацию для любых GitHub-репозиториев</title>
      <link>https://tproger.ru/news/google-predstavila-code-wiki---ii--piwushhij-i-obnovlyayushhij-dokumentaciyu-dlya-lyubyh-github-repozitoriev</link>
      <comments>https://tproger.ru/news/google-predstavila-code-wiki---ii--piwushhij-i-obnovlyayushhij-dokumentaciyu-dlya-lyubyh-github-repozitoriev?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Булат Яббаров]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/news/google-predstavila-code-wiki---ii--piwushhij-i-obnovlyayushhij-dokumentaciyu-dlya-lyubyh-github-repozitoriev</guid>
      <description><![CDATA[<p>Google запустила Code Wiki — ИИ, который генерирует и обновляет документацию GitHub-репозиториев, связывает её с кодом и ускоряет понимание проектов</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/news/google-predstavila-code-wiki---ii--piwushhij-i-obnovlyayushhij-dokumentaciyu-dlya-lyubyh-github-repozitoriev">Google представила Code Wiki — ИИ, пишущий и обновляющий документацию для любых GitHub-репозиториев</a>»</p>]]></description>
      <category><![CDATA[Git]]></category>
      <category><![CDATA[Google]]></category>
      <category><![CDATA[Искусственный интеллект]]></category>
      <category><![CDATA[GitHub]]></category>
      <category><![CDATA[Боты]]></category>
      <category><![CDATA[Legacy]]></category>
      <category><![CDATA[Новости]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Mon, 17 Nov 2025 05:50:02 GMT</pubDate>
      <content:encoded><![CDATA[<p>Google <a href="https://codewiki.google/">запустила</a> <b>Code Wiki</b> — сервис, который <b>автоматически генерирует</b> живую, постоянно обновляемую <b>документацию</b> для открытых GitHub-репозиториев.</p><p>Компания называет проект попыткой решить одну из самых дорогих и медленных задач в разработке — <b>необходимость разбираться в чужом коде вручную</b>.</p><h2>Что делает Code Wiki</h2><p>Сервис сканирует весь репозиторий, строит структурированную wiki-документацию и перегенерирует ее после каждого коммита.</p><p>Таким образом, мы получаем не просто статичный README и не набор заметок. Локальная «Википедия по проекту» <b>остается синхронизированной</b> с кодовой базой <b>всегда</b>. Google подчеркивает несколько ключевых возможностей:</p><ul><li><b>Автоматическая документация.</b> Code Wiki описывает архитектуру, модули, классы, функции. Причем делает это регулярно, без участия разработчика.</li><li>Глубокий контекст. Встроенный чат на базе Gemini использует сгенерированную wiki как базу знаний. В итоге мы получаем не «общий» ИИ, а агента, который знает репозиторий целиком.</li><li><b>Навигация по коду.</b> Все элементы документации связаны гиперссылками с исходниками — можно сразу перейти от объяснения к конкретной строчке реализации.</li><li><b>Диаграммы.</b> Сервис автоматически рисует актуальные архитектурные, sequence- и class-диаграммы, которые меняются вместе с кодом.</li></ul><p>По задумке Google, новая система должна <b>сократить время входа в проект</b>: новичок сможет ориентироваться в большом репозитории <b>в первые часы</b>, а <b>не через неделю</b>.</p><figure><img src="https://media.tproger.ru/user-uploads/111041/2025-11-17/9d8cc7dc-157f-4645-8bf9-ae361ac3519d.jpeg" alt="" /></figure><h2>Что дальше</h2><p>Пока Code Wiki работает только <b>с публичными проектами</b>. Но Google уже делает CLI-расширение для Gemini, которое позволит генерировать документацию для закрытых, внутренних кодовых баз — <b>локально и без передачи данных в облако</b>.</p><p>Для компаний это может стать инструментом для работы с legacy-кодом: документация будет обновляться автоматически, даже если исходные авторы давно уволились.</p><h2>Зачем все это</h2><p>Google утверждает, что <b>эпоха написанных вручную устаревающих документов заканчивается</b>. Разработчики все чаще пишут код с ИИ-помощниками, но все еще тратят огромные усилия на чтение чужого.</p><p>Code Wiki должен закрыть этот пробел и превратить понимание кода в операцию, которая занимает минуты. Сервис <b>уже работает</b> в виде публичного превью на <a href="http://codewiki.google">codewiki.google</a>.</p>]]></content:encoded>
    </item>
    <item>
      <title>Лучшие агентства по разработке цифровых продуктов под ключ</title>
      <link>https://tproger.ru/articles/luchwie-agentstva-po-razrabotke-cifrovyh-produktov-pod-klyuch</link>
      <comments>https://tproger.ru/articles/luchwie-agentstva-po-razrabotke-cifrovyh-produktov-pod-klyuch?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Валерия Турчак]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/articles/luchwie-agentstva-po-razrabotke-cifrovyh-produktov-pod-klyuch</guid>
      <description><![CDATA[<p>Подборка проверенных агентств для разработки цифровых продуктов под ключ: от сложных legacy-проектов и высоконагруженных систем до AI-агентов и комплексного брендинга. Сравниваем специализацию, подходы и кейсы, чтобы помочь выбрать подрядчика под ваши задачи.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/articles/luchwie-agentstva-po-razrabotke-cifrovyh-produktov-pod-klyuch">Лучшие агентства по разработке цифровых продуктов под ключ</a>»</p>]]></description>
      <category><![CDATA[Инструменты]]></category>
      <category><![CDATA[Быстрый старт]]></category>
      <category><![CDATA[Работа]]></category>
      <category><![CDATA[Сервисы]]></category>
      <category><![CDATA[Аналитика]]></category>
      <category><![CDATA[Дизайн]]></category>
      <category><![CDATA[Бизнес]]></category>
      <category><![CDATA[Разработка]]></category>
      <category><![CDATA[Legacy]]></category>
      <category><![CDATA[Статьи]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Sat, 18 Oct 2025 08:00:00 GMT</pubDate>
      <content:encoded><![CDATA[<p>Когда компании нужно запустить продукт с нуля или модернизировать существующий, встаёт вопрос выбора подрядчика. Рынок предлагает разные варианты — от студий с узкой специализацией до агентств полного цикла.</p><p>Мы собрали подборку проверенных агентств, которые создают цифровые продукты под ключ — от MVP и корпоративных платформ до высоконагруженных систем, веб‑сервисов и решений с ИИ. В ней есть команды, которые помогают стартапам выйти на рынок, а крупным компаниям — масштабироваться и оцифровывать процессы.</p><h2>1. ТРИАДА: разработка и поддержка проектов в горящие сроки</h2><p>Компания <a href="https://triadasite.ru/?utm_source=tproger&amp;utm_medium=article">ТРИАДА</a> работает с высоконагруженными e-commerce проектами, корпоративными порталами, CRM-системами и мобильными приложениями с 2006 года — реализовали более 200 проектов для банков, страховых компаний, промышленных предприятий.</p><figure><img src="https://media.tproger.ru/user-uploads/102593/2025-10-17/792e2f42-b725-43dc-8224-6840b4d9742b.png" alt="" /></figure><p>Специализация — поддержка legacy-кода и запуск проектов в условиях жестких сроков, когда другие подрядчики не справились.</p><h3>Что делают</h3><p>Предлагают разработку под ключ: реализуют проекты с нуля, а также берут на поддержку и модернизацию уже существующие системы. Специализируются на сложных самописных решениях, так называемом «наследием предыдущих разработчиков», даже при отсутствии документации.</p><p><b>Полный цикл разработки включает:</b></p><ul><li>тщательный анализ требований</li><li>проектирование архитектуры</li><li>создание продуманного UI/UX-дизайна</li><li>разработку</li><li>тестирование</li></ul><p>После запуска обеспечивают проактивный мониторинг 24/7 с мгновенными оповещениями в Telegram и Mattermost. Система мониторинга обнаруживает потенциальные сбои до того, как они станут заметны пользователям.</p><p>Для удобства клиентов предлагают гибкие форматы оплаты: фиксированная ставка, «Time &amp; Materials» или постоплата с отсрочкой.</p><figure><img src="https://media.tproger.ru/user-uploads/99854/2025-10-20/f62fff6e-e42b-424d-b92f-87ac68377b76.png" alt="" /></figure><p>Выстраивают долгосрочные отношения — помогают с процессами разработки, консалтингом по архитектуре и инфраструктуре.</p><h3>Примеры проектов</h3><h4>1. Крупнейших интернет-магазин по версии Data Insight</h4><p>Обеспечили стабильную работу одного из крупнейших интернет-магазинов России с нагрузкой 1 млн посетителей в сутки. Интеллектуальная система балансировки дает скорость ответа 0,01 сек для гостей и персональную выдачу для авторизованных пользователей.</p><p>Команда из 30 экспертов внедрила строгую стандартизацию процессов и бесшовно интегрировала 20+ внешних систем. Результат: проект 4 года в топе Data Insight с бесперебойной работой и премиальным пользовательским опытом.</p><figure><img src="https://media.tproger.ru/user-uploads/99854/2025-10-20/340e6132-43a8-4854-87ad-975d7ae2e305.png" alt="" /></figure><h4>2. CRM для металлургического холдинга — импортозамещение за 3 месяца</h4><p>За 90 дней перенесли 5-летнюю кастомизацию американской CRM на Битрикс24. Команда из 8 специалистов сохранила всю бизнес-логику и улучшила процессы.</p><p>Реализовали безопасную синхронизацию между CRM в закрытом контуре без интернета, интегрировали SAP, развернули СЭД, чат-боты и BI-аналитику. Холдинг получил полную цифровую экосистему под российским контролем.</p><figure><img src="https://media.tproger.ru/user-uploads/99854/2025-10-20/9180817f-a41f-47fc-899e-c9ab17826f27.png" alt="" /></figure><h4>3. Корпоративный портал для цифровой трансформации завода</h4><p>Команда из 7 специалистов за год создала портал с системой навигации по бизнес-процессам. Реализован BPMN-редактор с версионностью и согласованиями, объединено управление проектами, клиентским сервисом и документооборотом. Настроена интеграция с 1С и другими корпоративными системами.</p><p>Результат: любой сотрудник компании за пару кликов получает информацию о регламентах и стандартах через интерактивные схемы вместо поиска по документам.</p><figure><img src="https://media.tproger.ru/user-uploads/99854/2025-10-20/399b146a-e3f2-4b50-966b-eeef1991093f.png" alt="" /></figure><h3>Как работают</h3><p>Методология по Agile, Scrum, Prince2 — в зависимости от процессов заказчика или предлагают собственные. Участвуют в митингах клиента, планировании спринтов, демо результатов. Команда доступна как in-house сотрудники, предоставляют прозрачные отчёты по времени в срезах задач и сотрудников.</p><p>Перед запуском составляют план коммуникации с периодичностью встреч и форматами. На каждой встрече фиксируют договоренности с ответственными и сроками — протокол резюмируется устно, затем отправляется письмом всем участникам. Используют собственные инструменты для проведения встреч и подготовки протоколов через локальный ИИ.</p><p>Задачи ставятся в Jira с доступом для клиентов. Проектная документация, функциональные требования и протоколы встреч фиксируются в паспорте проекта в Confluence. Регулярные статусные встречи служат формой отчетности — обсуждается выполнение протокола прошлой встречи и статусы задач за период.</p><p>Выстраивают DevOps-культуру с CI/CD-конвейером через Gitlab CI/CD, Jenkins — новые функции доставляются быстрее и чаще с минимальными рисками. Контейнерная архитектура на Docker, Kubernetes, Docker Swarm.</p><h3>Поддержка и мониторинг</h3><p>На серверах разворачивают систему мониторинга производительности, доступности и безопасности. Она отслеживает нагрузку CPU и RAM, работу Apache и Memcached, статус SSL‑сертификатов и бэкапов. Все показатели собраны в дашборде «Рабочий стол проекта».</p><p>При превышении допустимых параметров, например загрузке CPU свыше 80% более 5 минут, система автоматически отправляет уведомление специалистам с графиками метрик для быстрой диагностики. Время реакции и устранения инцидентов регламентировано SLA, а контроль круглосуточный.</p><h3>Технологии</h3><p>Команда работает с любыми технологиями: от PHP (Symfony, Laravel, Yii) и GO до современных фреймворков ReactJS и VueJS. Специалисты разбираются в legacy-коде и самописных движках. Мобильная разработка на Swift, Kotlin, знают ObjC и Java.</p><p>Ключевое преимущество — опыт интеграций с CRM (Битрикс24, AmoCRM, Salesforce), ERP (SAP, 1C), CDP, программами лояльности, логистическими сервисами, эквайрингом. Одними из первых в России построили сквозную BI-аналитику</p><h2>2. fuse8 — полный цикл от гипотезы до продакшена</h2><p><a href="https://fuse8.ru/?utm_source=tprogger&amp;utm_medium=article&amp;utm_campaign=rating">fuse8</a> — агентство, которая специализируется на комплексной разработке цифровых продуктов с акцентом на современные технологии. Работают по схеме «от идеи до масштабирования»: сначала проектирование с фиксацией целей и метрик, затем разработка короткими спринтами, после — поддержка и развитие.</p><p>Среди клиентов — футбольные клубы, премьер-лиги, финтех и ритейлеры с собственными технологическими ландшафтами.</p><h3>Что делают</h3><ul><li>Запускают новые продукты с нуля</li><li>Модернизируют существующие системы</li><li>Собирают выделенные команды под экосистему заказчика</li><li>Интегрируют платёжные системы, маркетплейсы, CRM и ERP — исключая привязку к коробочным решениям вроде 1С и Битрикс</li><li>Реализуют API и SDK под конкретные задачи продукта</li></ul><p>В проектах используют TypeScript, React, Next.js, Nest.js, Node.js и .NET.</p><p>Архитектуру подбирают под цели и ограничения проекта, без привязки к стандартным коробочным решениям.</p><h3>Как работают</h3><p>Процесс разбит на три этапа.</p><p>1 Этап. Проектирование занимает 5 недель: исследуют аудиторию, фиксируют метрики, описывают сценарии и интеграции, собирают user story map, приоритезируют MVP и готовят роадмап с первыми прототипами. Выбирают стек под экосистему и команду заказчика на этом же этапе.​</p><p>2 Этап. Разработка идет короткими спринтами с регулярными демо. Если проект с фиксированным бюджетом и сроками, управляют скопом через FFF (фиксированная цена, объем и бюджет), сохраняя качество MVP (подробнее — <a href="https://fuse8.ru/articles/fff?utm_source=tprogger&amp;utm_medium=article&amp;utm_campaign=october">в статье</a>). Заказчик погружен в процесс и видит артефакты на каждом шаге.​</p><p>3 Этап. После запуска настраивают наблюдаемость — метрики, логирование, мониторинг производительности. Планируют бэклог гипотез для развития продукта. Средний срок сотрудничества с клиентами — больше четырех лет.​</p><h3>Примеры проектов</h3><ul><li>FF Manager — платформа для молодежной футбольной лиги в Казахстане. База упражнений, планирование тренировок, оценка эффективности — все в одном интерфейсе. Проект получил награды G8, WDA и Tagline Awards. От идеи до первых дизайнов, роадмапа и выбора стека ушло 5 недель.​</li></ul><figure><img src="https://media.tproger.ru/user-uploads/102593/2025-10-17/7d371536-2c60-4abb-90d5-d2726de694a8.png" alt="" /></figure><ul><li>Личный кабинет поставщика для EMEX — автоматизация процессов, которые тормозили развитие продукта. Унифицировали стек, ускорили выпуск версий, повысили отказоустойчивость системы. Проект взял золото и серебро на Tagline Awards. До этого провели технический аудит портала, который не обновлялся 7 лет, и спроектировали новую архитектуру за 5 недель.​</li></ul><figure><img src="https://media.tproger.ru/user-uploads/102593/2025-10-17/58cdd104-24a2-42b3-937b-727fd989612e.png" alt="" /></figure><ul><li>Платформа для the Open — британский гольф-турнир с миллионами активных пользователей. Переработали устаревшее решение в highload-систему, которая выдержала нагрузку при десяти миллионах одновременных сессий. Билеты на турнир разошлись за 40 дней — рекорд для мероприятия.</li><li>ERP для бизнеса по взысканию долгов — индивидуальная система на .NET. Автоматизировали 80% ручного труда сотрудников, эффективность отдела выросла на 20% после запуска первой версии. Снизили регуляторные риски за счет автоматической генерации отчетов. Бронза Tagline Awards в категории финтех-проектов.​</li><li>Сервис онлайн-займов — начали работу с продуктом на этапе идеи стартапа и вместе с командой заказчика довели его до позиций лидера рынка. После запуска первой версии наращивали функциональность и развивали систему несколько лет.</li><li>Веб-платформа для Crystal Palace — фанатский сервис футбольного клуба. Расходы на серверные мощности сократили в 10 раз, доход от продажи членства вырос на 40%, количество веб-сессий увеличилось на 78%.​</li></ul><figure><img src="https://media.tproger.ru/user-uploads/102593/2025-10-17/abf47c45-6e03-49b2-8e57-d289c8d844c3.png" alt="" /></figure><ul><li>Сайт Уралпромбанк — переработали структуру главной, логику каталога продуктов, оптимизировали анкеты-заявки. Раскрытие информации о деятельности банка для акционеров и регуляторов стало полнее и удобнее. Бронза Tagline Awards в категории сайтов-сервисов.​</li><li>Складская система для EMEX — интерфейсы для десктопа и портативных устройств, автоматизация всех сценариев работы складских сотрудников. Интеграция с остальными системами компании для непрерывного логистического процесса.​</li></ul><h3>Для кого подходит</h3><p>Агентство предлагает не разрозненные технологические ресурсы, а сработанную команду с отраслевым опытом под интересы заказчика.</p><p>Формат подходит компаниям на разных стадиях роста: стартапам, которым нужно проверить гипотезу и безопасно вывести продукт на рынок, и зрелому бизнесу, который хочет расширить цифровое присутствие, оцифровать существующие процессы или модернизировать действующие системы.</p><p>Агентство помогает создавать сервисы для клиентов или сотрудников, настраивать процессы вокруг продукта, обеспечивать масштабирование и повышать производительность уже работающих решений. Реальные интерфейсы и детали проектов с иллюстрациями —<a href="https://fuse8.ru/projects?utm_source=tprogger&amp;utm_medium=article&amp;utm_campaign=october"> в портфолио на сайте.</a></p><h2>3. Бестранк: автоматизация как сервис</h2><p><a href="https://bestrank.ru">Агентство Бестранк </a>специализируется на цифровизации внутренних процессов среднего бизнеса — автоматизируют согласование договоров, интегрируют ИИ‑агентов и CRM, сопровождают проекты длительное время, по формату максимально близки к внутреннему IT-отделу.</p><h3>Чем занимается агентство</h3><p>Ключевые направления — автоматизация бизнес-процессов, создание и поддержка внутренних порталов, модулей для Bitrix24, интеграция нейросетей и запуск ИИ‑ассистентов. Форматы — разработка «под ключ», долгосрочное сопровождение, быстрый старт и мягкая адаптация решений под уже работающие системы, доработка и развитие существующих платформ.</p><p>Частые задачи: настройка CRM, автоматизация сбора и согласования данных, организация электронного документооборота, интеграция ИИ‑агентов для сокращения рутины, связка между корпоративными и государственными системами.</p><h3>Кейсы и сценарии</h3><ul><li>Автоматизация согласования договоров в ГК Симметрон. Проект делился на четыре этапа, внедрение происходило итерациями. Итог — стабильная работа процесса уже четыре года: ежедневно автоматизировано согласование до 10 документов.</li><li>Автоматизация заполнения карточек компании в CRM. Приходит новый запрос — система автоматом извлекает e‑mail, подтягивает ИНН, ОГРН, адрес, численность сотрудников, ОКВЭД, сайт. С помощью нейросетей анализируется содержимое сайта, уточняется сфера деятельности и основные направления. Все заносится в CRM без ручного ввода.</li></ul><h3>Особенности подхода</h3><p>Используют продуктовый подход: вместе с клиентом строят дорожную карту развития цифровой экосистемы — CRM, портала или ИИ-решений. Агентство нацелено на долгосрочные отношения, предпочитает клиентов с планами роста на 3+ года и заключает годовые, полугодовые контракты (100 часов в месяц по фиксированной цене). Работают по модели гибкой смены приоритетов: если бизнес меняет задачи, план переустраивается без дополнительных сложностей — близко по духу к внутреннему IT-отделу, но экономичнее.</p><p>Специализируются на компаниях среднего размера. Привыкли работать и без жестко формализованного ТЗ — обсуждают бизнес-требования на текущий период, решают задачи по факту их возникновения, при этом разрабатывают готовые модули, которые сотрудники смогут настраивать потом самостоятельно.</p><h3>Технологические детали</h3><p>В качестве базы — Bitrix24 и доработки для нее: собственные модули, сценарии, инструменты внедрения ИИ‑функций. Активно используют интеграции с Yandex.GPT, а также типовые и кастомные решения для синхронизации с корпоративными CRM, ERP, внешними API, платёжными и информационными сервисами.</p><h3>Управление проектом и поддержка</h3><p>Взаимодействуют через сервисы Bitrix24: если клиент использует аналогичный портал, настраивают автоматический обмен задачами между площадками. Если у клиента другая система — подстраиваются под существующий таск-трекер. Взаимодействие строится гибко: ключевое — прозрачность обмена задачами, отчетность, доступ к процессу работы. Работа с поддержкой включает технические работы, SLA и оперативную доработку, ориентированную на потребности бизнеса.</p><p>В результате клиент получает понятную, работающую автоматизацию, возможность донастроек своими силами и прозрачность по всем задачам на каждом этапе взаимодействия.</p><h2>4. WaiWai: ИИ-агенты, которые говорят на языке бизнеса</h2><p>Команда <a href="https://getwaiwai.com">WaiWai </a>разрабатывает и внедряет и AI‑агентов для продаж и рекрутмента. Компания помогает среднему и крупному бизнесу автоматизировать поиск лидов и коммуникацию с потенциальными клиентами.</p><p>Подход — инженерный, с измеримыми бизнес‑результатами. Частые участники рейтингов и премий на мировом уровне, поэтому награды отражают их реальный вклад в индустрию развития ИИ-технологий.</p><figure><img src="https://media.tproger.ru/user-uploads/102593/2025-10-17/73e34dca-4de7-4499-93b1-0ac7172fe62e.png" alt="" /></figure><h3>Чем занимается агентство</h3><p>WaiWai работает под ключ — от настройки среды и целей до развертывания готовой AI‑системы в продуктиве. Основное направление — разработка AI‑агентов для продаж и рекрутмента. Агентство создаёт кастомные интеграции с корпоративными CRM и маркетплейсами, разворачивает модели в контуре компании и обеспечивает техническое сопровождение.</p><h3>Кейсы и сценарии</h3><ul><li>АК Барс Банк — AI‑агент для рекрутмента. Система подключается к HeadHunter и другим площадкам, оценивает не только резюме, но и карьерный путь кандидатов, формирует персональные обращения. Благодаря этому автоматизируются массовые вакансии с тысячами откликов. Результат — 61% сокращение срока закрытия вакансий, 48% высвобожденного времени рекрутеров. Проект получил премию «AI Олимп» в номинации «Новая цифровая идея года».</li></ul><figure><img src="https://media.tproger.ru/user-uploads/102593/2025-10-17/d370d005-211b-4d75-8cef-c6851471d62e.png" alt="" /></figure><ul><li>Falcone — AI‑агент для продаж услуг доставки. После внедрения отклик клиентов вырос в 5,7 раза, а продажи — на 21%. Оборот компании удвоился, Falcone стал резидентом «Сколково» благодаря интеграции ИИ‑решений.</li></ul><figure><img src="https://media.tproger.ru/user-uploads/102593/2025-10-17/3fd3d45b-afe9-4fbe-859c-c27d02b2bd5e.png" alt="" /></figure><ul><li>Конференции Онтико — AI‑агент для продажи билетов. Агент подбирал разработчиков по профессиональным интересам и истории участия в мероприятиях, коммуницировал через Linkedin и email. Конверсия выросла в 2,4 раза.</li></ul><figure><img src="https://media.tproger.ru/user-uploads/102593/2025-10-17/57d35936-f95b-47eb-84c5-32e2dc73a026.png" alt="" /></figure><h3>Подход к работе</h3><p>Агентство работает спринтами, каждый проект начинается с пилота, результаты которого измеримы в метриках KPI. WaiWai придерживается принципа, что ИИ с первого дня должен приносить пользу бизнесу.</p><p>Решения развертываются безопасно, с изоляцией данных внутри инфраструктуры клиента. Для тестирования есть собственные SDK, IDE и Playground — среда, где заказчик может проверять сценарии AI‑агентов без риска утечек.</p><h3>Технологическая база</h3><p>WaiWai разворачивает LLM‑модели семейства Qwen и Gemma внутри инфраструктуры клиента, добиваясь безопасной работы с внутренними данными. Модели адаптированы к российскому контексту и требованиям 152‑ФЗ. Компания входит в «Сколково», Реестр отечественного ПО и реестр МТК.</p><p>Архитектура решений поддерживает интеграции с CRM, ERP и внешними API, а также подключение платёжных систем и marketplace‑функционала.</p><h3>Управление и поддержка</h3><p>Поддержка решений включает регулярный файнтюнинг и контроль согласованных метрик эффективности. После запуска каждый клиент получает полную документацию по настройке и обучению модели, мониторинг производительности и доступ к дашбордам метрик.</p><h2>5. Beavers Brothers: от брендинга до высоконагруженных игр</h2><p><a href="https://dabb.ru/?utm_source=tproger&amp;utm_medium=referral&amp;utm_campaign=dev_list">Beavers Brothers</a> работает с комплексными проектами — разрабатывает фирменный стиль, сайты, личные кабинеты, веб-игры и делает дизайн-поддержку  для IT-компаний и финансового сектора.</p><p>Среди клиентов — Microsoft, SAP, Schneider Electric, Яндекс, Лаборатория Касперского, 1С, Т1, Банк России.</p><h3>Что делают</h3><p>Основные направления — разработка сайтов (лендинги, промо-страницы, корпоративные порталы, веб-игры), сервисы и личные кабинеты, брендинг (логотип, фирменный стиль, бренд-платформа), дизайн-поддержка (motion, презентации, арты для соцсетей). Форматы работы — под ключ, разработка дизайна, поддержка и доработка с расширением функциональности.</p><p>Самые популярные задачи — продвижение продуктов через презентационные инструменты, улучшение пользовательского опыта существующих сервисов, создание визуальной упаковки для запуска новых решений на рынке.</p><h3>Примеры проектов</h3><ul><li>Игра для Мегамаркет — высоконагруженный проект для десктопа и мобильного приложения. Команда из 16 человек за 2 месяца разработала под ключ геймдизайн, интерфейс, код и развернула проект с пиковой нагрузкой 30 тысяч пользователей одновременно.</li></ul><figure><img src="https://media.tproger.ru/user-uploads/99854/2025-10-17/acebbab0-d376-4af3-86c4-2c0bb0edd5af.jpg" alt="" /></figure><ul><li>Мобильное приложение и десктоп-версия личного кабинета для Appeer — система денежных переводов с широкой целевой аудиторией. Задача — создать интерфейс, удобный для всех и соответствующий требованиям финансового регулятора. До этого команда разработала для клиента нейминг, бренд-платформу, логотип и фирменный стиль. Проект занял 4 месяца, команда — 6 человек. Функционал личного кабинета дополнялся по ходу работы, требовалась синхронизация с инхаус-разработчиками сайта.</li></ul><figure><img src="https://media.tproger.ru/user-uploads/99854/2025-10-17/1fc34411-ab0c-4aae-8a6c-c578d60b43b8.jpg" alt="" /></figure><ul><li>База знаний для ПИК-Комфорт — проект с бизнес-задачей снизить стоимость обучения сотрудников через оптимизацию процесса. Провели аналитику, изучили пользовательские сценарии, спроектировали интерфейс онлайн-базы и подготовили стандарты оформления образовательной документации. 2 месяца, команда из 6 человек.</li></ul><ul><li>Личный кабинет для интернет-магазина Ushatava — комплексный проект для улучшения UX и расширения функционала сайта. Выделили 8 пользовательских сценариев, разработали кликабельные прототипы и протестировали их на глубинных интервью с представителями целевой аудитории. Сделали дизайн в стиле существующего сайта и сверстали. 6 месяцев, команда из 6 человек.</li></ul><figure><img src="https://media.tproger.ru/user-uploads/99854/2025-10-17/ef6195b7-cccb-4239-a850-b9dd149bd575.jpg" alt="" /></figure><h3>Подход к работе</h3><p>Процесс разработки адаптируется под задачи и возможности клиента — используют практики Agile, спринты, конвейерную разработку и DevOps. Для качества и скорости проводят код-ревью, тестирование, ретроспективы, поддерживают кросс-функциональность команды.</p><p>Упор делается на комплексный подход — от разработки фирменного стиля и создания сайта до motion-контента и поддержки. На этапе агрегации требований аналитик разбирает бизнес-задачу, сценарии потребления продукта и продажи, проводит глубинные интервью с целевой аудиторией, экспертами заказчика и рынка. Так формируется список требований для проектирования.</p><p>Больший опыт проектов с IT-компаниями — международными, федеральными и стартапами, а также финансовым сектором — банками и финтех-проектами.</p><h3>Технологии</h3><p>React (Next), PHP (Symfony, Laravel), Kotlin/Java (Spring Framework, Spring Boot), Angular, Vue (Nuxt), NodeJS (NestJS). Базы данных — SQL, NoSQL (MongoDB, PostgreSQL). CMS — WordPress, Webflow, 1C-Битрикс.</p><p>Интеграции с CRM, платёжными системами, клиентскими API и базами данных.</p><h3>Управление и поддержка</h3><p>Взаимодействие строится по принципу одного окна — работа с одним контактным лицом, прямой доступ к команде по запросу. Для постановки и контроля задач используют таск-трекеры, регулярно готовят отчётность и проводят чекап-созвоны. Облачные инструменты для легаси проекта доступны в любое время с любого устройства.</p><p>Поддержка включает гарантийную техподдержку в течение 3 месяцев после сдачи проекта, DevOps-поддержку стабильной работы в период высокой нагрузки и доработки — добавление новых разделов, развитие функциональности, локализацию на иностранные языки.</p><h2>Кого в итоге выбрать?</h2><p>Выбор подрядчика зависит от конкретной задачи и стадии развития продукта.</p><ul><li>ТРИАДА — вариант для сложных проектов с legacy-кодом, горящими сроками и необходимостью в глубокой экспертизе по поддержке и интеграциям, особенно на базе 1С и Битрикс.</li><li>fuse8 — подойдёт для компаний, которым нужен партнёр полного цикла, способный быстро спроектировать и запустить MVP, а затем развивать его, опираясь на современные технологии без привязки к коробочным решениям.</li><li>Бестранк — специализируется на автоматизации внутренних процессов для среднего бизнеса, особенно на базе Bitrix24.</li><li>WaiWai — узкопрофильное агентство для тех, кому нужны AI-агенты для продаж и рекрутмента.</li><li>Beavers Brothers — работают в комплексных проектах, где нужна не только разработка, но и визуальная составляющая: брендинг, дизайн, 3D и motion-графика.</li></ul><p>В итоге, чтобы не ошибиться, стоит определить, что сейчас в приоритете: спасение legacy-проекта, быстрый запуск MVP, автоматизация внутренних процессов, внедрение ИИ для продаж или создание продукта с сильным визуальным образом.</p>]]></content:encoded>
    </item>
    <item>
      <title>Анонимные и стрелочные функции: как использовать их вместо create_function в PHP 8</title>
      <link>https://tproger.ru/articles/anonimnye-i-strelochnye-funkcii--kak-ispolzovat-ih-vmesto-create-function-v-php-8</link>
      <comments>https://tproger.ru/articles/anonimnye-i-strelochnye-funkcii--kak-ispolzovat-ih-vmesto-create-function-v-php-8?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Виталий Киреев]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/articles/anonimnye-i-strelochnye-funkcii--kak-ispolzovat-ih-vmesto-create-function-v-php-8</guid>
      <description><![CDATA[<p>Рассказал, как работают анонимные и стрелочные функции в PHP. А также, на что заменить create_function при переходе с PHP 7.4 на PHP 8.
</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/articles/anonimnye-i-strelochnye-funkcii--kak-ispolzovat-ih-vmesto-create-function-v-php-8">Анонимные и стрелочные функции: как использовать их вместо create_function в PHP 8</a>»</p>]]></description>
      <category><![CDATA[PHP]]></category>
      <category><![CDATA[Рефакторинг]]></category>
      <category><![CDATA[Legacy]]></category>
      <category><![CDATA[Статьи]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Sun, 03 Mar 2024 12:50:02 GMT</pubDate>
      <content:encoded><![CDATA[<p>PHP выкатывает крупные обновления почти каждый год. В новых версиях появляются фичи, позволяющие увеличить производительность, а иногда частично меняется синтаксис. С выходом обновления две предыдущие версии PHP поддерживаются разработчиками еще три года — они продолжают устранять ошибки и улучшать безопасность. Когда время проходит, за старыми версиями PHP перестают следить, и некоторые функции полностью перестают работать. Если вовремя не обновить код в проекте, начнут появляться ошибки.</p><p>Меня зовут Виталий Киреев, я руководитель отдела исследований и разработок хостинг-провайдера SpaceWeb. В статье расскажу, как мы с нашей командой проводили рефакторинг кода при переходе с PHP 7.4 на PHP 8 и на что заменили одну из самых популярных функций — create_function.</p><p>Статья будет полезна и тем, кто только погружается в язык PHP. На примере реальной задачи по рефакторингу подробно разберу, как использовать анонимные и стрелочные функции. И объясню, чем они отличаются.</p><h2>Контекст: когда стало ясно, что нужен рефакторинг</h2><p>В части проектов SpaceWeb много legacy-кода. Мы поддерживаем проекты с версии PHP 5.6, которая появилась в 2014 году. С некоторой периодичностью переходим на новые версии PHP, постоянно обновляя код.</p><p>Оставлять прежний код в старых версиях PHP — плохая идея, потому что в какой-то момент он может перестать работать. А еще в них могут быть уязвимости в разрезе безопасности. Обновленные версии PHP обычно включают исправления ошибок и новые языковые возможности, которые могут улучшить производительность сайтов и приложений.</p><p>Когда вышла версия PHP 7.4, функция create_function, которая часто использовалась в нашем коде, стала deprecated, то есть перестала поддерживаться и работать. Из-за этого стали появляться ошибки в коде. Тогда и стало ясно, что нужен рефакторинг.</p><p>Подсветить часть проблем в коде нам помогли статические анализаторы кода — PHP Code Style Fixer и PHPstan. Но большую часть кода мы проверяли и обновляли вручную. В первую очередь нужно было придумать, на что заменить  популярную create_function. Сперва начали переход на анонимную функцию и замыкание. А спустя время внедрили и стрелочные функции, чтобы повысить читаемость кода и решить дополнительные задачи.</p><h2>Анонимные функции: как работают и как применить замыкание</h2><p>Особенность анонимных функций в том, что они задают область видимости. Внутри этой области будут работать только те переменные, которые определены там же. Если мы пропишем переменные за пределами функции, код будет выдавать ошибку.</p><p>На самом деле, create_function, которую мы обычно использовали до PHP 8 — это классический пример использования анонимной функции. Ее часто применяли для обработки данных в массиве. Функция содержит два аргумента — массив аргументов функции и сам код.</p><p>Когда эта функция стала deprecated в PHP 8, мы начали рефакторинг кода. Анонимные функции стали выглядеть так:</p><p>Но что, если нам потребуется вызвать эту функцию в нескольких разных местах? Тогда можно использовать замыкание. Это позволит вызывать функцию, используя ее как переменную.</p><p>А как быть, если нам нужно использовать переменные из окружения, и значения переменных  будут меняться в процессе выполнения программы? Здесь нам помогут стрелочные функции.</p><h2>Стрелочные функции: в чем отличие от анонимных и где лучше использовать</h2><p>Стрелочные функции позволяют избежать постоянного использования use, потому что в них есть автоматический захват внешних переменных. Это позволяет сделать код более лаконичным. Еще стрелочные функции лучше подходят для работы с большим количеством переменных или с частой сменой переменных в процессе.</p><p>В этом примере была задача отфильтровать контракты и соотнести их с нужным ИНН. Если бы решали ее с помощью анонимных функций, то под каждый ИНН пришлось бы писать отдельную функцию. А еще везде использовать use.</p><p>С помощью стрелочных функций получилось решить задачу быстрее, потому что они позволяют получить доступ ко всей области видимости. Это уменьшает время на дальнейшую поддержку кода, а доступ к области видимости выше можно получить без дополнительных функций.</p><p>Важно отметить, что у стрелочных функций есть ограничение. Они не могут быть слишком сложными, у них компактный синтаксис. Если нам нужно разместить многострочный код, мы используем анонимные функции.</p><h2>Итоги</h2><p>Для замены create_function в PHP 8 можно использовать как анонимные, так и стрелочные функции.</p><p>Анонимные функции в PHP позволяют создавать функции, не имеющие определенных имен. Они работают в заданной области видимости и только с теми переменными, которые определены там же. Преимущество анонимных функций — в них можно разместить многострочный код, в отличие от стрелочных.</p><p>Стрелочные функции позволяют избежать постоянного использования use и упростить синтаксис. А еще они лучше подходят для работы с большим количеством переменных или с частой сменой в процессе.</p>]]></content:encoded>
    </item>
  </channel>
</rss>