За двадцать лет в профессии я успел поработать тестировщиком, разработчиком, DevOps-инженером, руководителем команд и целых направлений. Видел взлет agile, расцвет облаков, приход микросервисов и десятки других «революций», каждая из которых обещала навсегда изменить разработку. Недавно, готовясь к выступлению на конференции, я поймал себя на неожиданной мысли: на этот раз все действительно иначе. Возможно, впервые за всю мою карьеру меняется не способ писать код, а сама экономика качества. Иронично, что именно в этот момент пригодился инвайт на Хабр, пролежавший без дела больше десяти лет. Потому что разговор пойдет не о том, как повысить качество разработки, а о том как не сдеградировать и не упасть на дно при использовании AI в ваших проектах.
И так ... AI сделал нас быстрее, сильно быстрее, но у этого момента есть побочный эффект. Наверно многим, кто уже столкнулся в вайбкодингом в своих проектах, знакомо такое чувство когда радуешься от того, что фичи делаются быстро и потом в какой-то момент ты понимаешь, что система деградировала настолько, что новое впиливается все сложнее и сложнее, и даже агент уже справляется с трудом, кол-во багов растет, тех долг накапливается и кажется, что проще все снести и переписать. И никто не может сказать, когда именно это началось, потому что каждый MR вроде как ок, но система в целом - нет.
И даже если ты сам понимаешь, что нужно сделать и как исправить ситуацию в конкретном git проекте, то как это поставить на поток, остается загадкой и кажется, что вайбкодинг - зло, да и вообще это все дорого, за токены надо платить, давайте опять наймем много разработчиков и лучше будем писать, как раньше. Но на самом деле если мы посадим джунов / мидлов и загрузим их задачами без контроля, то получим примерно такой же эффект, через пол года-год нам захочется все выкинуть и переписать. В эпоху AI этот процесс просто ускорился.
Мы ускорились и не заметили, что потеряли
AI дал нам ощущение, которого раньше почти не было в разработке - лёгкость: фичи появляются быстро, задачи закрываются легко, код пишется почти без трения. И первое время это похоже на магию. Ты смотришь на velocity и думаешь: «Вот теперь-то мы действительно ускорились». Но магия всегда что-то забирает взамен. Она забрала сопротивление, то самое, которое раньше заставляло остановиться и подумать: «А точно ли так стоит делать?». Теперь код появляется быстрее, чем успевает сформироваться сомнение, система начинает меняться, не резко, почти незаметно она становится… тяжелее.
Это не ломается, это «оседает»
Самое коварное в деградации кода - в том, что она не выглядит как проблема. Нет падений, нет алертов, CI зелёный, каждое изменение - само по себе разумно. Но если смотреть не на изменения, а на систему целиком - она как будто начинает «оседать», как здание, у которого чуть-чуть повело фундамент. Сначала - ничего страшного, потом - двери начинают закрываться хуже, потом - появляются трещины и однажды ты понимаешь: «Я не хочу здесь ничего менять».
Мы задаём вопрос, на который нет смысла отвечать
Долгое время индустрия задавала себе один и тот же вопрос: «Насколько хороший у нас код?». В этом вопросе есть одна проблема, он предполагает, что код - это состояние, что его можно измерить и зафиксировать, но код - это не состояние, код - это движение, код живет от фичи к фиче и от релиза к релизу. Он не бывает «хорошим» или «плохим» сам по себе, он либо становится лучше, либо становится хуже. И правильный вопрос звучит иначе: «Куда он движется прямо сейчас?».
Две силы, которые мы не замечаем
Если долго смотреть на разные проекты, начинаешь замечать странную вещь. Проблемы почти всегда выглядят по-разному, но причина - одна и та же. Внутри любой системы есть два невидимых вектора: один тянет её в сторону усложнения, другой - в сторону структуры. Первый проявляется как тяжёлый код, когда функция выглядит как клубок логики, который нужно распутывать. Второй - как избыточная архитектура, когда за простой логикой стоит лабиринт абстракций. И самое важное, что это не разные проблемы, это две грани одной и той же проблемы.
Ты открываешь функцию, сначала всё понятно, потом появляется ещё одно условие, потом ещё одно.. Ты читаешь дальше - и вдруг ловишь себя на том, что перестал держать всё в голове. Не потому что сложно, а потому что слишком «плотно».
Есть код, который длинный, но читается легко, а есть код, который короткий - но «давит» и не даёт «дышать».
def get_user_name(user): if user: if user.profile: if user.profile.first: if user.profile.last: return f"{user.profile.first} {user.profile.last}" return "Unknown"
Такой код не обязательно плохой, но он вызывает ощущение хрупкости. Как будто одно неосторожное движение - и всё рассыпется. И ты переписываешь его не потому что «надо красиво», а потому что хочешь вернуть контроль.
def get_user_name(user): profile = user and user.profile if not profile: return "Unknown" return format_name(profile.first, profile.last)
И вдруг становится легче, как будто в комнате открыли окно.
Но есть и другая крайность. Ты открываешь код - и он выглядит правильным: аккуратные классы, наследование, методы.. И всё равно что-то не так. Ты идёшь по цепочке вызовов: один файл, второй, третий.. И в какой-то момент забываешь, зачем вообще сюда пришёл. Это не сложность, это потеря локальности. Код перестаёт быть местом, где живёт логика. И становится картой, по которой нужно путешествовать.
Баланс, который нельзя почувствовать на скорости
Интересно, что команды обычно чувствуют момент, когда что-то идёт не так, но чувствуют постфактум.
Когда:
изменения начинают занимать больше времени
баги становятся страннее
обсуждения длиннее
Проблема в том, что при высокой скорости разработки это ощущение приходит слишком поздно. AI не делает плохой код, он делает много нормального кода подряд и именно это разрушает систему быстрее всего.
Нам не хватает зрения
В какой-то момент становится понятно: проблема не в том, чтобы писать лучше код, проблема в том, чтобы видеть, что происходит с системой и иметь контроль над деградацией и балансом.
Но раз мы понимаем проблему, то почему бы не попробовать ее решить.
До этого момента мы говорили про ощущения:
«код тяжёлый»
«архитектура мешает»
Но если оставить это на уровне ощущений - ничего не изменится.
Хорошая новость в том, что обе силы можно описать вполне инженерно и измерить, назовем их - Refactoring Pressure (RP), и Overengineering Pressure (OP).
Refactoring Pressure (RP): давление сложности
RP отвечает на вопрос:
насколько код давит на разработчика, когда его нужно менять?
Наивно можно было бы считать только цикломатическую сложность. Но это плохо работает: одна сложная функция в маленьком проекте и десятки сложных функций в большом проекте - разные ситуации.
Поэтому RP состоит из двух частей:
RP = 0.6 × Peak(max, p90, loc) + 0.4 × Base(density, loc)
Peak - это давление от самых сложных мест, он смотрит не только на max_complexity, но и на p90_complexity.
combined = max_complexity × 0.6 + p90_complexity × 0.4Peak = 100 × (1 - e^(-0.08 × combined)) × scale
Почему здесь max и p90? Потому что один монстр на complexity 40 - это плохо, но если p90 тоже высокий, значит проблема уже не локальная. Это не одна больная функция, а стиль всей кодовой базы.
Base - это фоновое давление системы:
Base = 100 × (1 - e^(-0.02 × density × scale))
А density считается как:
density = (total_complexity / loc) × 100
Тут важно уточнить, что LOC (lines of code) - это чистые строчки кода, без учета визуального форматирования.
Почему же важна density, представьте две функции:
Первая:
200 строк
10 условий
Вторая:
20 строк
те же 10 условий
Формально - одинаковая сложность, но читаешь ты их совершенно по-разному. Во второй функции логика «сжата» и мозг от этого устаёт.
То есть RP учитывает не просто «сложность», а концентрацию сложности и масштаб проекта. В маленьком проекте один тяжёлый кусок кода ещё может быть случайностью. В большом - это уже сигнал состояния системы.
Overengineering Pressure (OP): давление архитектуры
OP отвечает на другой вопрос:
насколько архитектура стала источником сложности?
Сначала считается score на уровне класса / структуры:
class_score = ( 0.35 × fan_out_norm + 0.25 × fan_in_norm + 0.25 × depth_norm + 0.15 × centrality_norm ) × 100
Здесь веса важны.
fan_out весит больше всего — 35%, потому что класс, который зависит от многих других, трудно понимать и тестировать изолированно.
fan_in — 25%. Если от класса зависит много других классов, его страшно менять.
depth — ещё 25%. Глубокие цепочки превращают чтение кода в путешествие по графу.
centrality — 15%. Это сигнал появления объектов, через которые проходит слишком много путей. Такие классы постепенно становятся «центром мира».
После этого OP считается уже на уровне проекта:
OP = ( 0.4 × coupling_norm + 0.6 × avg_class_score_norm ) × 100
То есть общий coupling важен, но не доминирует. Главный вклад - 60% - дают средние class-level scores. Это логично: проект может иметь умеренную связанность в среднем, но при этом содержать несколько архитектурных узлов, которые делают изменения болезненными.
Как связаны OP и RP
Чтобы визуализировать разницу и лучше уловить суть, давайте посмотрим на пример, конечно он будет надуманным, но поможет ощутить разницу
class PremiumPolicy(OrdersPolicy): def calculate(self, user): if user.is_premium: return 0.15 return super().calculate(user)
На первый взгляд всё нормально, но если посмотреть на граф связей:
PremiumPolicy → OrdersPolicy → DiscountPolicy
depth = 3
есть зависимость от родителя
логика размазана
Попробуем упростить
def premium_discount(user): if user.is_premium: return 0.15 def orders_discount(user): if user.orders > 10: return 0.10
depth ≈ 1
связи минимальны
логика локальна
В итоге OP уменьшается, но:
если бороться с OP - можно увеличить RP
если сильно снижать RP - можно вырастить OP
Поэтому цель не минимизировать каждую метрику отдельно, а держать баланс.
Теперь наглядно понятно, что нельзя просто взять сложить обе метрики или взять какое-то среднее значение чтобы оценить здоровье проекта, но давайте визуализируем это в цифрах.
Представим два проекта:
A: RP = 20, OP = 20 B: RP = 5, OP = 35
Формально:
Total(A) = 40 Total(B) = 40
Но это разные системы.
В первом - баланс
Во втором - сильный перекос в архитектуру
И второй вариант на практике будет ощущаться хуже.
Итоговый score. Ключевая идея: штраф за дисбаланс.
Теперь когда мы понимаем насколько значим баланс, становится понятно, что итоговый score должен строится не только на сумме метрик, но и на разнице между RP и OP.
В упрощённом виде:
Score = (RP + OP) + k × |RP - OP|
где:
первая часть - общее давление
вторая - штраф за перекос
Как это читается
если RP ≈ OP - система сбалансирована
если один сильно выше - появляется штраф
Например:
A: RP = 20, OP = 20 → Score = 40 B: RP = 5, OP = 35 → Score = 40 + penalty → хуже
Система редко «умирает» от одного фактора. Она умирает от того, что либо логика становится слишком плотной, либо структура становится слишком тяжёлой, но чаще - от того, что эти вещи разъезжаются и создают дисбаланс. Обычно видя такие проекты мы говорим "у Васи там весь проект сплошная вермишель" и это сильный перекос в RP или "у Феди там такой оверинжиниринг, что потеряться можно" и это сильный перекос в OP.
И что же дальше?
Когда вся эта история только начиналась, я не собирался создавать новый инструмент. Я просто искал решение проблемы и мне хотелось проверить гипотезу. Поэтому появился небольшой скрипт на GitHub: один файл, несколько формул и много попыток понять, можно ли измерять деградацию кода, а не спорить о ней.
Постепенно экспериментов становилось больше, данных тоже. Скрипт разросся в полноценный проект, который сегодня называется strictacode. Сейчас без него не обходится практически ни один наш проект, разрабатываемый с помощью AI. Мы используем его для контроля метрик в CI, формирования планов улучшений, как инструмент который помогает AI-агентам принимать более осознанные решения для рефакторинга (в комплекте есть skill для агента который поможет сделать анализ).
Я не утверждаю, что наш подход идеален. Но на практике он оказался на удивление эффективным. Поэтому хочу поделиться этой находкой с вами.
Если тема вам близка - попробуйте strictacode, покрутите цифры, покритикуйте идеи и поделитесь своим опытом. Возможно, у вас есть более удачные способы борьбы с этой проблемой. А мне будет очень интересно их обсудить.
Так же буду рад вас видеть в нашем тг канале QAriumCommunity возможно вас заинтересуют вещи которые мы туда выкладываем.
И да, спасибо, что дочитали мою первую статью до конца. Похоже, инвайт на Хабр, который ждал своего часа больше десяти лет, наконец-то его дождался. Дальше планирую написать цикл статей про промпт инжинирию, управление контекстом и гайд по тому, как писать хорошие скиллы для агентов, так что подписывайтесь, надеюсь - будет интересно :)
Комментарии (13)

i-netay
17.06.2026 12:52Интересно, а при помощи такого инструмента возможно научиться видеть, что кто-то начал вайб-кодить по самому коду, ловя быстро за руку на первом-втором коммите? Сильно метрики меняются, когда человек только начинает использовать агентов, резкая деградация?

bugfixing Автор
17.06.2026 12:52На 100% сказать сложно, но ИИ-ку обычно тянет RP перекос, большинство проектов которые мне доводилось видеть, которые написаны нейронкой, даже если используется какой-нибудь speckit или superpowers, то там обычно этот симптом вылезает. Попробуйте последить за этим показателем, возможно получится если не на 100% задетектить, но хотя бы заподозрить.
А если быть до конца честным, то в целом какая разница пишут нейронками или нет, если проект здоров =)

PickaPickaMan
17.06.2026 12:52По одному коммиту ничего не поймешь. Вайбкодинг убивает архитектуру постепенно, когда добавляется сотый костыль сбоку.
Проще настроить хуки в гите, которые будут блокировать коммиты с резким скачком цикломатической сложности, это остановит генерацию лапшекода на корню

zizop
17.06.2026 12:52Скажите пожалуйста, если проект на TypeScript, есть ли смысл на него strictacode натравливать?

bugfixing Автор
17.06.2026 12:52У нас есть фронт на js который полностью навайбкожен и мы работам по алгоритму — сделали несколько фич, запускаем скилл strictacode и делаем план улучшений. И пока ребятам такой подход очень нравится, говорят, что он предлагает достаточно хорошие планы и результат нравится. Возможно вам тоже поможет, попробуйте, будет интересно получить обратную связь ;)

titan_pc
17.06.2026 12:52Не ну было такое. Что код давит. Ну там 10 лет назад, когда первый хеллоу ворлд писал. Потом когда дочитал нужное количество книг - стало пофигу кто и как код писал. Научился читать его и выполнять в своей голове без отладчика. Были сомнения если - включал отладчик. Потом навык чтения развился на столько, что любой код - понятный. Даже если в нём есть классы хелперы и переменные названы х1, х2. Всегда есть опция - читать код двумя полушариями - как человек и как машина.
Потом да, надоело что все пишут "плохо" - стандарты начал внедрять. Сначала парочку, потом ещё, потом ещё. Но действительно - для ускорения внедрения фич. Чтобы ревью проводить быстрее, изменения контроллировать лучше. Порог входа в проект конечно выростал, но окупалось такое деяние примерно сразу. Хоп и новая фича залетает за день, потому что она копия вон той, для который есть шаблон.
Шаблоны - да. Паттерны проектирования. Страшные монстры абстракции, когда лень вникать в них. Но стоит потратить день другой - и получаешь ускорение, контроль. А главное код, который менять легко. А код он такой да - для него в первый день всё оверинжениринг и лишние детали. А через неделю - блин, вот если бы начал с шаблона Х, не хныкал бы сейчас, что рефакторишь уже два дня, а фичи новой ещё нет.
Фреймворки - отдельное людям за них спасибо. Вот где был настоящий борщ из всего. Если в руках фреймворк - то весь мир это гвоздь. И вместо создания новых концепций - ну напихивали в коробку кучу всего. Как майкрософт офис - на планете нет человека, который знает всё что там есть на 100%. Но при первом приближении - продукт хороший, и даже понятный. Как и хороший фреймворк - не требует от тебя знать все его 100% деталий и слепо следовать всем им. В итоге ещё одним стандартом команды становится - мы используем для задачи такой то - фреймворк такой то.
Итого, и до мира нейронок были все описанные проблемы в статье. Решали из просто стандартами в рамках команды. Чтобы всем было понятно, зачем мы делаем фичу х так, а не вот так. Просто убираешь вариативность реализации у задач - и всё едет с бустом х1000%.
Финальный стандарт - чистая архитектура. Штука уже древняя, но надёжная как Швейцарские часы. Есть порог входа, но после его преодоления - вечный покой. Твой код теперь масштабируется до бесконечности без головной боли. В один репозиторий можно засунуть не один микросервис и даже не 10, а скажем м×н проектов и систем - настоящая революция. Изменения влетают в изолированные друг от друга участки, влетают быстро, тестируются изолированно и без боли. Микросервисов собирай сколько хочешь и как хочешь. У нас конечно свой вариант Роберта Мартина - потому что совсем классике слепо следовать - как минимум скучно. Но самое полезное забрать - забрали.
Ну и вот пришёл ИИ. Что он поменял? Да ничего. Мы просто его в стандарты вогнали - и он вайбкодит по нашему. Всё что он пишет - понятно, масштабируется, легко меняется. Потому что его спеки и правила по рукам бьют. Да, это ИИ и он не следует всему, что ему сказали и бывает борщит. Ну просто носом его тык в борщ - и он не спервого, так со второго раза нормально сделает.
По итогу - ИИ это множитель того, что у Вас есть. А если для вас всё ещё не знаю - фабрика функций - оверсложность - ну вот и получите умножение - весь код будет с глубиной 1. И супер простой. Потом кароче через 3 дня оно пойдёт его менять и скажет извините, но 1 млн токенов не хватает вместить весь контекст зависимостей, чтобы внести фичу х. Откуда зависимимости ? Ну везде же глубина 1, значит кругом горы импортов. Но я же не так хотел - и тут ИИ сама говорит - а может паттерн проектирования?

bugfixing Автор
17.06.2026 12:52Спасибо, что не поленились и написали такой развернутый коммент! Когда пишешь первую статью, то вообще не ожидаешь, что кто-то потратит силы и напишет подробный комментарий, да еще и с которым не поспоришь.
Я полностью согласен, что если у тебя опыта вагон и за ним еще целый состав, то в целом проблем нет, сиди себе и пинай агента в спеки пока контекстное окно не закончится. Но я столкнулся с проблемой когда у людей не такая мощная инженерная база, команды в биг техах, как правило, разнородны, многие вообще отрицают новые подходы, да и с точки зрения опыта последнего года у меня были случаи когда пускали людей с агентами в репозиторий в котором идет очень интенсивная разработка и они буквально уничтожали репос агентами за пару месяцев и приходилось полностью откатываться и все переписывать и там было такое состояние проекта, что и strictacode бы не помог уже, а были случаи когда все достаточно гладко шло, потому, что репозиторий небольшой, работает в нем полтора человека и в целом следят за тем, что там агент делает. Но меня сейчас больше занимает вопрос того, как стабилизировать качество и получить контроль за деградацией с учетом того, что в биг техах очень интенсивная разработка, разнородные команды, многим разработчкам очень сложно читать спеки и выхлоп от агента, когда они привыкли уже мыслить трассировкой и держать в голове графовидную структуру взаимодействий, а им тут спеки подсунули, люди ломаются и либо забивают на то, что агент пишет и просто соглашаются и либо идут опять руками писать, и хорошо если второе, а вот если первое, то тут уже метрики могут помочь.

PickaPickaMan
17.06.2026 12:52Стандарты работают, когда команда стабильна, а при текущей текучке кадров любое соглашение о кодировании превращается в тыкву за полгода

bugfixing Автор
17.06.2026 12:52Все так, поэтому больше хочется quality gates, а не стандарты, но не бессмысленно трешхолды ставить которые душат, а более осмысленно это делать не мешая работе. Сейчас у нас достаточно прикольно получается, трешхолды в CI по рукам ударили в ветке, в агенте скилл запустил, план улучшений посмотрел, сделал небольшой рефкторинг сразу им же, не дал деградации усилиться. Вроде и не сложно, тк метрика по рукам ударила, но есть инструмент который сразу и поправить поможет, но и полезно, не дает на дно упасть. Хочется конечно дальше пойти, это не идеал, скорее просто старт, посмотрим куда приведет.

PickaPickaMan
17.06.2026 12:52Код давит не когда в нем много условий. Он давит когда абстракции текут, а документация устарела еще два года назад при переходе на микросервисы
maxxsalov
Интересная математика!
Подскажи, Java планируется добавить в strictacode?
bugfixing Автор
Если быть до конца честным, то я сам последний раз писал на java лет 15 назад и сейчас мы уже давно не используем его на проектах, kotlin встречается, а вот java нет. А добавлять язык для галочки, не понимая как это в реальной жизни работает просто нет ни времени, ни сил. Но если вы поможете проекту и добавите поддержку java, то мы не будем противиться pull request-у ;)
PickaPickaMan
Разумный подход, лучше поддерживать один язык, но глубоко, чем написать парсеры для десяти языков, которые будут выдавать погоду на Марсе