Аналоговый город-рефакторинг: как зонировать кодовую базу по законам градостроительства, прежде чем добавить ещё одну фичу
Прежде чем прикрутить ещё одну фичу к легаси‑системе, посмотрите на кодовую базу как на город. Узнайте, как зонирование, планирование инфраструктуры и вовлечение «жителей» помогают делать безопасные, поэтапные рефакторинги, после которых система становится масштабируемой, тестируемой и поддерживаемой.
Аналоговый город-рефакторинг: как зонировать кодовую базу по законам градостроительства, прежде чем добавить ещё одну фичу
У разработчиков и градостроителей больше общего, чем кажется на первый взгляд.
И те и другие наследуют живые, хаотичные системы: города с беспорядочной застройкой и кодовые базы с десятилетними костылями. И те и другие постоянно слышат запрос «ну давайте просто ещё вот это добавим» — здесь новый торговый центр, там новый feature flag — даже когда базовая инфраструктура уже трещит по швам.
Вместо того чтобы слепо навешивать новые фичи, что если начать относиться к своей легаси‑кодовой базе как к городу, а к рефакторингу — как к градостроительству?
В этом посте разберём, как зонирование, инфраструктура и участие «жителей» помогают делать более безопасные, инкрементальные изменения, которые делают систему понятнее, тестируемее и поддерживаемее — ещё до того, как вы добавите следующий небоскрёб.
1. Ваша кодовая база — это город, а не головоломка
Мы часто говорим о коде так, будто это статическая головоломка: фиксированный набор деталей, из которых надо собрать единственно правильное решение. Но большинство зрелых систем ведут себя скорее как города:
- Они растут органически, со временем.
- Разные «районы» строили разные люди и по разным правилам.
- Есть обходные тропинки, «задние дворы» и странные тупики, про происхождение которых уже никто не помнит.
- Людям всё ещё нужно там жить и работать, пока вы всё это улучшаете.
Городская метафора помогает по‑другому смотреть на рефакторинг:
- Районы (districts): функциональные зоны, модули, сервисы.
- Улицы и магистрали: вызовы функций, очереди сообщений, API, data pipelines.
- Коммунальные службы: логирование, мониторинг, конфигурация, системы сборки, CI/CD‑пайплайны.
- Правила зонирования: архитектурные гайды, код‑стандарты, правила зависимостей.
Перед тем как построить ещё одно «здание» (фичу), спросите: где ему место в этом городе и какая инфраструктура ему понадобится?
2. Зонирование: обозначьте границы до того, как строить
Градостроители не начинают с расстановки отдельных зданий. Они начинают с зонирования: где будут жилые, коммерческие и промышленные зоны и что разрешено в каждом районе.
С кодовой базой можно сделать то же самое.
Определите районы в системе
Даже в запущенном легаси‑монолите можно обнаружить и обозначить фактические районы:
- Презентационный район: UI‑шаблоны, контроллеры, API‑обработчики.
- Доменный район: бизнес‑правила, ядро предметной области, сущности, value objects.
- Инфраструктурный район: доступ к базе данных, внешние API, очереди/сообщения, файловая система.
При этом легко обнаружить:
- Контроллеры, которые из произвольных мест напрямую ходят в базу.
- Бизнес‑логику, спрятанную во view‑слой.
- Утилитарные классы, которые используются как «многофункциональные небоскрёбы» под всё подряд.
Вместо Big Bang‑переписывания начните с границ зонирования:
- «Новая бизнес‑логика должна жить в доменном слое».
- «Контроллеры могут зависеть от доменных сервисов, но не ходят напрямую в базу».
- «Инфраструктурные детали не должны протекать в доменные объекты».
Это лёгкие правила — как строительные нормы — которые начинают ограничивать, куда можно класть новый код и от чего он может зависеть.
Зонирование — это про контроль, а не про идеал
Город не станет чистым и аккуратным мгновенно. Но зонирование даёт возможность:
- Сдерживать новый хаос в пределах понятных границ.
- Не позволять локальным изменениям расползаться по всей кодовой базе.
- Постепенно переформатировать планировку системы, продолжая при этом релизить.
Думайте о каждой границе как о звукоизолирующей стене: изменения в одном районе не должны заставлять перестраивать, перетестировать и переосмысливать все остальные.
3. Градостроительство междисциплинарно — таким же должен быть рефакторинг
Градостроительство — это не просто красивые карты. Оно соединяет в себе:
- Архитектуру (какими должны быть здания?)
- Строительство и инженерку (выдержат ли мосты?)
- Социологию (как люди реально используют город?)
- Политику и экономику (что мы можем себе позволить? кого это затронет?)
С рефакторингом кодовой базы всё так же:
- Архитектура: какие должны быть модульные границы и слоистость?
- Инженерия: что технически возможно при текущих зависимостях и ограничениях рантайма?
- Дизайн и UX: как изменения повлияют на пользовательские сценарии, юзабилити и паттерны дефектов?
- Социальные факторы: как работают ваши команды? кто за что отвечает? где ломаются передачи задач?
Если вы нарисуете «идеальную» архитектуру, игнорируя то, как реально работают разработчики, QA и ops/SRE, ваш план зонирования провалится. Люди начнут его обходить.
Вместо этого:
- Подключайте разработчиков к обсуждению границ модулей и зон ответственности в коде.
- Подключайте QA, чтобы определять границы тестирования и риски регрессий.
- Подключайте ops и SRE, чтобы продумывать деплой, наблюдаемость и домены отказа.
Относитесь к этим участникам как к жителям вашего кода‑города, а не как к пассивным получателям сверху спущенных планов.
4. Изучите уличную сеть, прежде чем перестраивать город
Планировщики не сносят магистраль «по ощущениям». Они анализируют трафик, использование земли и потоки пешеходов.
Ваш аналог — это граф зависимостей — «уличная сеть» вашего кода‑города.
Картографируйте зависимости
Минимально важно понимать:
- Какие модули зависят от каких других модулей?
- Какие сервисы вызывают какие API или пишут в какие топики/очереди?
- Где есть плотные циклические зависимости?
Инструменты (static analysis, архитектурные диаграммы, визуализаторы call graph’ов) помогают, но даже грубая схема, нарисованная вручную, лучше, чем чистая интуиция.
Ищите:
- Магистрали: базовые сервисы или библиотеки, в которые ходят все.
- Узкие места: классы или модули с огромным числом зависимых от них компонентов.
- Незаконные «срезы»: низкоуровневые модули, зависящие от высокоуровневых, пересекающие задуманную слоистость.
Используйте карту, чтобы направлять поэтапные изменения
Когда карта перед глазами, можно планировать как городской инженер:
- Снимать нагрузку с узких мест, вынося наружу стабильные интерфейсы.
- Создавать объездные дороги (facade’ы или anti‑corruption layers), которые изолируют «грязные» районы.
- Закрывать опасные сквозные проезды (запретить некоторые сквозные зависимости, добавить линтеры/проверки архитектуры).
Так вы постепенно рефакторите «городскую сетку»: добавляете новые маршруты, выводите из эксплуатации старые и меняете потоки трафика, не останавливая жизнь всего города.
5. Осторожно: современные build‑системы в разросшемся городе
Современные системы сборки похожи на продвинутую строительную технику. Они мощные, но могут и усилить уже существующие проблемы.
Если ваш граф зависимостей — переплетённый ком, добавление быстрой «умной» build‑системы не решит проблему — она просто сделает глобальные пересборки быстрее и болезненнее.
Корень проблемы не в том, что «кран медленный». В том, что при малейшем изменении балкона текущие «правила зонирования» заставляют вас переосвидетельствовать весь городской горизонт.
Как запутанные зависимости бьют по сборкам
Когда всё зависит от всего:
- Мелкие изменения в коде выглядят как затрагивающие огромную часть системы.
- Инструменты сборки по‑консервативному пересобирают колоссальные объёмы кода.
- Время CI растёт, и рефакторинг с эксперименатми становятся дорогими.
Вместо того чтобы винить build‑систему, исправляйте генплан города:
- Вводите чёткие границы модулей и слоёв.
- Минимизируйте перекрёстные вызовы между районами.
- Двигайтесь к чётким интерфейсам и инверсии зависимостей.
Только упростив планировку города, вы начнёте получать реальную отдачу от современных build‑систем: инкрементальные сборки, параллелизацию и надёжное кеширование.
6. Отдавайте предпочтение «ямочному ремонту» вместо героических бульдозеров
Мечта: перекрыть город, всё снести и построить идеальный, выверенный по линейке мегаполис.
В терминах софта: героический полный rewrite.
Реальность:
- Полные переписывания рискованны, дороги и часто не доходят до feature parity.
- Бизнес‑задачи не ставятся на паузу, пока вы рисуете новую карту.
- Теряется накопленная в легаси‑системе экспертиза и обработка редких краевых случаев.
Градостроители обычно работают вокруг уже существующего:
- Прокладывают новые улицы.
- Перезонируют отдельные кварталы.
- Меняют коммуникации квартал за кварталом.
С кодовой базой можно делать то же.
Паттерны поэтапного рефакторинга
- Strangler Fig pattern: оборачиваете старый функционал новым интерфейсом; часть трафика переводите на новую реализацию, постепенно расширяя её, пока старый код не станет ненужным.
- Anti‑corruption layer: ставите границу вокруг легаси‑модулей, переводя данные между старой и новой моделями, чтобы остальная система не заражалась легаси‑ограничениями.
- Правило бойскаута (Boy Scout Rule): при каждом касании файла оставляйте его чуть лучше: улучшите имена, выделите функцию, добавьте тест, переместите логику в правильный «район».
Думайте в категориях:
«Что я могу безопасно перезонировать на этом квартале сегодня?», а не «Как мне перестроить весь город?»
Мелкие, малорисковые шаги в сумме дают крупные, структурные изменения.
7. Вовлекайте жителей: общие правила, а не тайный мастер‑план
Генплан города, спрятанный в одном бумажном томе на полке, бесполезен. Так же и архитектурная диаграмма, которой никто не следует, — просто настенное украшение.
Чтобы рефакторинг прижился, вовлекайте «жителей» и закрепляйте привычки.
Сделайте правила зонирования явными
- Пишите короткие Architecture Decision Records (ADR) для ключевых границ: «UI зависит от домена, домен — чистый, инфраструктура — заменяемая».
- Создайте лёгкие чек‑листы для code review, подчёркивающие границы: «Соблюдает ли новый код слоистость?», «Не утекают ли инфраструктурные детали в домен?»
- Там, где возможно, добавьте линтеры и автоматические проверки модульных границ.
Советуйтесь с теми, кто делает работу
- Спросите разработчиков: Где изменения ощущаются куда рискованнее, чем должны быть? Это часто «плохие перекрёстки» или места, где не хватает границ.
- Спросите QA: Какие области особенно хрупкие и требуют тотальной регрессии? Это признаки того, что зонирование не работает и локальные изменения имеют глобальный эффект.
- Спросите ops/SRE: Какие сервисы или модули доставляют больше всего проблем в проде? Это ваши перегруженные коммуникации и хлипкие мосты.
Когда люди видят, что планы по рефакторингу соответствуют их реальному опыту работы с системой, они куда охотнее соблюдают новые «строительные нормы».
8. Сводим всё вместе, прежде чем добавить следующую фичу
Прежде чем добавить ещё одну фичу в свой легаси‑код‑город, на секунду притормозите и:
-
Нарисуйте карту города
- Определите основные районы (UI, домен, инфраструктура, кросс‑срезы и т.п.).
- Визуализируйте ключевые зависимости и пути вызовов.
-
Определите или уточните зонирование
- Решите, какой код где должен жить.
- Запишите простые, исполнимые правила для нового кода.
-
Спланируйте инфраструктурные улучшения
- Сначала разгребите самые жёсткие узкие места и запутанные развязки.
- Введите фасады или anti‑corruption layers вокруг особо грязных зон.
-
Релизьте фичи «дружественно городу»
- Размещайте новые фичи в подходящих районах, соблюдая границы.
- Используйте поэтапные паттерны (strangler, boy scout), улучшая то, к чему прикасаетесь.
-
Вовлекайте жителей
- Синхронизируйте рефакторинг с рабочими процессами команды, тестированием и эксплуатацией.
- Итеративно дорабатывайте план, пока город эволюционирует.
Заключение: постройте город, в котором можно жить
Вам не нужен идеальный, сияющий «умный» город. Вам нужен такой, в котором можно годами строить, поддерживать и безопасно развивать софт.
Относясь к легаси‑кодовой базе как к городу, а к рефакторингу — как к градостроительству, вы:
- Делаете структурные проблемы видимыми через повседневные образы (районы, улицы, инфраструктура).
- Ставите приоритет на границы и зонирование, а не на героические переписывания.
- Используете карты зависимостей, чтобы направлять точечные, поэтапные улучшения.
- Согласуете технические изменения с тем, как реально работает ваша команда.
В следующий раз, когда спросят: «Мы можем просто добавить ещё одну фичу?», вам не обязательно вздыхать и говорить «ну да».
Вы можете ответить: «Да — но давайте сначала посмотрим на карту зонирования».
Этот сдвиг в мышлении — то, что превращает хрупкий легаси‑самострой в устойчивый, пригодный для жизни код‑город.