У меня 12 лет опыта в Go. И я больше не имею права назвать себя программистом: мой код не пройдёт ту планку качества, которую я выставил для своих агентов. Хотя честнее так: они сами её выставили, я лишь ставил цели.
Заявление громкое, но у меня есть график. Красная пунктирная линия на нём: уровень моего лучшего рукописного кода. Синяя кривая: код, который пишут агенты. В апреле 2026 кривая ушла под красную линию и продолжает падать.
Меня зовут Александр, я удалённый разработчик в финтех-стартапе. С мая 2025 года я в одиночку веду закрытый финтех-продукт, и код в нём с первого дня пишут ИИ-агенты. С февраля 2026 добавился второй проект, платёжный. Дальше покажу, как получился этот график. Модель делает главную работу, но планку качества держит набор проверок вокруг неё. И этим проверкам всё равно, кто написал код: модель, я или коллеги. Инструмент открыт, свою кривую вы сможете построить сами.
Истоки нейрослопа
Весна 2025-го. Anthropic выпустил Claude Code, и завертелось. За несколько месяцев нейронка родила нейрослопище. К осени кодовая база разъелась до 224К строк, из которых изрядная часть была дублями, брошенными ветками (не гита — кода) и забытыми экспериментами.
Знаковое число того периода: на срезе октября 2025-го 105 пакетов проекта не проходили проверку типов. Я коммитил часто, чтобы не терять изменения по дороге к рабочему состоянию, и код ехал быстрее, чем сходилась сборка. Сейчас такой пакет один, а все коммиты собираются. Но это сейчас.
Обычные линтеры сработали наполовину
go vet, staticcheck, golangci-lint я подключил почти сразу, и они дали эффект. Проблема оказалась в другом: они рассчитаны на людей, а нейронка совершала совсем другие ошибки, на которые люди, естественно, и не думали писать линтеры.
Ошибки агента растут из короткого контекста. Человек обычно помнит, что он делал 15 минут назад. Модель — нет. Отсюда бесконечные дубли одного и того же, галлюцинации, ненужные неиспользуемые ветки. И отдельный, самый опасный для финтеха класс: маскировка непонимания. Модель, не разобравшись в ситуации, могла тихо вернуть что-нибудь правдоподобное вместо ошибки. Пустую структуру. false из функции, которая вовсе не предикат. Сконструированный объект с nil-зависимостью внутри, о которой она честно написала в лог и пошла дальше.
Под этот класс у меня постепенно выросла целая группа проверок: error-masking, fallback-return, log-and-return-zero, empty-struct-return, constructor-swallows-nil-dep. Ни одна из них не нужна против человека: люди так не ошибаются. Против агентов они срабатывают до сих пор.
50 велосипедов
Схема была простая: заметил класс проблем — пишу анализатор. Анализаторы жили внутри проекта, и к январю 2026 их накопилось 50.
В январе я понял, что это надо вынести в отдельный инструмент и применять ко всем своим проектам, а заодно и к нему самому. За день появился каркас с первым десятком правил, через неделю один коммит выкинул все 50 проектных анализаторов. Универсальные правила уехали в общий линтер, продуктовая специфика — в отдельный проектный. Общий называется glint, он открыт под MIT, и всё, что дальше в статье, посчитано им.
Тогда же случилась большая чистка: за две недели из проекта ушло 140К строк мёртвого кода, дублей и протухших инструментов. На графике это первый обрыв.
Как баг стал правилом
Цикл, который крутится с тех пор:
-
Вижу или получаю репорт о баге.
-
Агент исследует и находит причину.
-
Я подозреваю, что проблема не единичная, и даю задачу найти подобные по всему коду.
-
По результатам решаем, получится ли из этого правило.
-
Правило гоняется по кодовой базе и нередко вскрывает ещё несколько скрытых случаев.
Контур замкнут: модель находит баги, пишет правило, сама читает выхлоп правила и сама его дотачивает. Моего участия тут на пару решений.
Вот пример правила, которое невозможно положить в универсальный линтер. В платёжном проекте есть проверка: команда платёжному провайдеру не должна уходить раньше, чем в собственном хранилище появилась durable-запись о намерении её отправить. Если процесс упадёт между отправкой денег и записью об этом, деньги ушли, а следа нет: нечего повторить, нечего сверить, нечего показать пользователю. Оба вызова по отдельности абсолютно корректны, типы сходятся, ошибки обработаны. Дефектом является их порядок. Чтобы это поймать, надо знать, как в этом конкретном проекте называются провайдеры и хранилища и что вызов SendPayout не откатывается defer-ом. Это знание о предметной области, и оно не может оказаться в staticcheck по построению.
Таких доменных правил за июль добавилось несколько десятков, тремя волнами. На графике это предпоследний спуск.
Вся история в числах
Дальше мне стало интересно посмотреть на всю историю проекта в числах. Методика: срезы каждые две недели через всю git-историю, на каждом срезе прогон сегодняшним набором правил, полным, без единого проектного исключения. Один и тот же прибор на все точки, заведомо строже того, что существовало тогда. Тяжёлыми дальше называю находки двух верхних уровней серьёзности: за ними потенциальная потеря денег, сломанная логика или падение в рантайме. Пропущенный комментарий или кривое имя переменной сюда не попадают. Нормировка на тысячу нетестовых строк Go.
Кривая на обложке ступенчатая: плато, обрыв, плато, обрыв. Каждый обрыв объясняется конкретным событием: январская замена 50 анализаторов и чистка, апрельский разбор god-object-ов, июльские волны доменных правил, августовское снятие старых исключений. Между событиями кривая почти не движется. Качество не улучшается от того, что модели становятся умнее. Оно улучшается, когда контур проверок дотягивается до новых мест.
Тот же прогон можно разрезать по классам ошибок, и этот срез мне кажется самым красноречивым. Мёртвый код был самым массовым классом на старте и умер первым: его берут даже обычные линтеры. Типобезопасность обвалилась осенью 2025-го. Паттерны вроде маскировки ошибок продержались весь 2025 год и сдались только доменным правилам. А документация единственная светится до сих пор. Ни один класс не умер сам: у каждого своя дата смерти и свой убийца.
Сразу о том, что эта кривая НЕ доказывает. Правила писались, глядя на этот код, и код чинился под правила. Кривая показывает, что контур приводит код к своему стандарту. Независимой оценкой качества она не является.
Второй проект, платёжный, начинался уже с контуром. Его кривая короче и круче: 3.18 в марте, 0.30 в августе, при том что кода стало в 6,6 раза больше.
Заповедник багов
Летом замер выживаемости показал: почти половина строк большого проекта не менялась с 2025 года. Я был уверен, что это хлам, до которого просто не дошли руки. Проверка показала другое: выживший код лежал ровно в тех каталогах, которые я сам когда-то исключил из проверок: вспомогательные утилиты, генераторы, тестовые хелперы. У каждого исключения было разумное на тот момент обоснование, которое к июлю никто уже не помнил, включая меня.
Внутри заповедника сохранилось всё, что контур давно вычистил из остального проекта. Жемчужина коллекции: 6 тестов вида require.True(t, true, «архитектурные принципы должны соблюдаться»). Они зелёные всегда, числятся покрытием и не проверяют ничего. Агент производит такое как законченную работу: формально задача «покрыть тестами» закрыта.
Можно сделать вывод: старый код консервируется вместе со своими дефектами там, куда не дотянуты проверки, а исключения в конфиге линтера складываются в карту этих мест. В августе я снял старые исключения и две недели разгребал найденное: это последний обрыв кривой, с 0.70 до 0.38. Кстати, разница между штатным прогоном и прогоном без исключений у меня измерялась тысячами находок. Любопытно, какая она у вас.
Контрольная группа
Кривая большого проекта во многом показывает уборку, и по ней трудно судить, предотвращает ли контур новые проблемы. Здесь мне повезло: у эксперимента нашлась контрольная группа. Третий проект, тоже закрытый, писался агентами в те же месяцы 2025 года, теми же моделями. Одно отличие: из проверок там был только go vet.
Плотность тяжёлых находок в нём росла: 3.25 летом 2025-го, 6.95 к осени. Тот же я, те же модели, кривая идёт в другую сторону. Потом проект стоял 9 месяцев. В конце июля 2026 я вернулся к нему уже с линтером: 12 волн чистки за полторы недели, минус 34К строк, на выходе 0.65.
Красная черта
Оставался вопрос: а как хорошо я писал без агентов?
У меня нашёлся подходящий проект для ответа. Крипто-бот 2024 года, 31К строк Go, последнее, что я делал действительно без агентов: модели тогда могли максимум написать функцию по шаблону, и ту приходилось чистить. Это код на максимуме моего опыта и мотивации, потому что проект торговал моими собственными деньгами. Реально торговал и приносил прибыль. Цена ошибки: весь капитал. Ошибка в числе нулей при свопе стейблов, и ты кому-то подарил всё своё бабло, без возможности отката.
Прогнал по нему тот же прибор. 2.32 тяжёлых находки на тысячу строк. 21 небезопасный type-assertion. 12 замаскированных ошибок. И 8 раз деньги во float в JSON-контракте: в коде, где я больше всего боялся ошибки в числе нулей.
Это и есть красная линия на первом графике. Агентный код прошёл под неё в апреле 2026, а сейчас он по этой метрике в шесть раз чище моего. Не потому что агенты пишут лучше меня. Потому что я никогда не гонял по своему коду 130 правил перед каждым коммитом.
Кто первым узнаёт о баге
Замеры по git-истории имеют слепое пятно: всё, что контур поймал до коммита, в историю не попадает. Я это пятно измерил по логам агентных сессий, там вся работа линтера видна.
Только за май по большому проекту линтер срабатывал с находками 132 раза. За последние две недели в логах 203 эпизода одного и того же сюжета: агент заканчивает фичу, идёт коммитить, линтер находит проблему, агент правит, прогон становится зелёным, коммит уходит. Я видел это глазами почти каждый день, теперь у меня есть число.
Отсюда получается метрика зрелости процесса, применимая к любой команде: кто первым узнаёт о дефекте, проверка или клиент? Критические баги у меня находятся практически каждый день. При этом прод стабилен и жалоб почти нет. В старой рамке первое означало бы катастрофу. В новой это признак работающего контура: дефекты гибнут до того, как их кто-то увидел.
Где линтер не спасает
Ранние правила шумели безбожно. magic-number в первой версии дал 478 находок, из которых полезными были 18. context-first судил по имени функции вместо поведения и был переписан дважды. silent-error прошёл семь итераций за один день, каждая учила его отличать легитимную практику от проглоченной ошибки. Ложные срабатывания я чиню в правиле, подавления в проекте запрещены, поэтому каждое правило проходит эту дорогу целиком.
Точечная метрика «поймал бы линтер этот исторический баг» даёт скромные цифры. На выборке из 566 старых fix-коммитов тяжёлая находка совпала с местом правки в 6.4% случаев, а ручная проверка показала, что часть совпадений случайна: находка рядом с багом, но о другом. Работает не отдельное правило на отдельном баге, а контур целиком, что и видно на кривой.
К примеру, свежий пропущенный баг: после рефакторинга логики вывода деньги у пользователя списывались, но на паре страниц показывалась сумма как до вывода. Три слоя защиты промолчали разом: запрет на разные источники истины, финансовые правила, тесты. Идеальных инструментов нет, работа над качеством никогда не заканчивается.
И одна категория находок у меня растёт с 2025 года: документация. Мне на эти находки давно пофиг: правила documentation я добавил в самом начале, отчасти подражая классическим линтерам. Теперь их растущий график скорее сам документирует, что документация уже никому не нужна: вопросы задают модели, а она ищет ответ в коде. Но это тема отдельного разговора.
Выводы
Качество перестало быть свойством того, кто пишет код, и стало свойством контура, в котором код пишется. Агенту не нужно быть безошибочным: ему не нужно держать в голове 130 правил, он имеет право совершать типовые машинные ошибки, потому что до коммита они не доживают. По той же причине контуру безразлично, кто автор. В июле пару тикетов в платёжном проекте писал живой разработчик, я с моделью модерировал: его код прошёл через те же проверки, что и агентный. Спор «пишет ли ИИ лучше человека» в этой рамке теряет смысл.
Как это выглядит в моей ежедневной работе. Статанализ гоняется перед каждым коммитом, полный, за секунды. Каждый разобранный баг: кандидат в правило, а дешевле всего правило пишется, пока разбор свеж. Ложные срабатывания чинятся в самом правиле. Исключения в конфиге периодически пересматриваются, теперь уже с пониманием, во что они превращаются за год.
Инструмент открыт, в нём есть режим прогона по некомпилируемой истории и скрипт замера в tools/history. Кривую по своему репозиторию можно построить за вечер.
12 лет опыта никуда не делись. Просто теперь они уходят на то, чтобы ставить цели и строить планку, а держит её машина. Меня это устраивает: планку моего рукописного кода она уже преодолела.
ссылка на оригинал статьи https://habr.com/ru/articles/1068920/