Информация
- В рейтинге
- 5 702-й
- Дата рождения
- Зарегистрирован
- Активность
Специализация
Архитектор программного обеспечения, ML разработчик
Ведущий
Python
Docker
Git
REST
Java
SQL
Многопоточность
Объектно-ориентированное проектирование
Разработка программного обеспечения
Алгоритмы и структуры данных

Второй раз по лбу Больно убираю грабли в сторону...
Ирония понятна, и скепсис по поводу маркетингового хайпа вокруг ИИ абсолютно оправдан. Но в четвертом пункте вы совершили классическую подмену понятий.
Никто не предлагает человеку вручную писать запросы в виде AST. Разработчик вообще не должен думать об узлах синтаксического дерева, ровно как автор кода на Python или Go не думает об опкодах виртуальной машины.
Всю черновую работу делает детерминированный тулинг, а не человек:
Разработчик пишет обычный код или делает обычный рефакторинг.
Tree-Sitter за пару миллисекунд снимает синтаксис в дерево, а префиксное дерево нормализует пути вызовов.
Анализатор математически проверяет, не разъехался ли контракт DTO на глубине стека.
Если контракт нарушен, система показывает точную точку отказа до деплоя, а не надеется на то, что стохастический RAG случайно угадает проблему.
Вы почему-то приписали мне цель убрать профессию кодера, хотя мой изначальный вывод был строго противоположным: нейросети никого не заменят, а инженерам придется только глубже понимать теорию компиляторов и архитектуру.
Это не костыли поверх ИИ. Это нормальная инженерная гигиена, которая загоняет вероятностные модели в жесткие рамки детерминированного контроля. Когда появился TypeScript, многие тоже ворчали, что компилятор заставляет нас явно описывать контракты вместо того, чтобы рантайм сам во всем разбирался. Время показало, что строгий контроль инвариантов всегда выигрывает у слепой веры в угадывание.
Если у вас под капотом уже есть Tree-Sitter и синтаксический граф — это отличная база. И сама идея Declared-графа требований абсолютно правильная. Но искренний архитектурный совет: не делайте мост между ТЗ и графом через комментарии внутри кода, вы сами себе закладываете мину на будущее.
Дело даже не в эстетике. В проде на 500k+ строк этот подход неизбежно развалится по двум сугубо инженерным причинам:
Хрупкость при рефакторинге. Для любого парсера комментарий — это мусорная trivia-нода, синтаксически не связанная с инструкциями. Банальный
Extract Method(человеком или агентом), вынос валидации в хелпер или перенос логики разорвет парные тегиSTART/END_BLOCK. Компилятор и линтер промолчат (комментарий же валиден), но ваш Declared-граф начнет молча ссылаться на пустое место. В коде начнется тихий семантический дрейф.Комбинаторный взрыв метаданных. Сегодня вы помечаете требования ТЗ. Завтра проект обяжут проверять утечки персональных данных по 152-ФЗ / PCI-DSS (taint-анализ), изолировать слои по Clean Architecture и контролировать дрейф DTO-схем. Если каждую политику зашивать тегами в исходники, код превратится в решето из служебной разметки, где за комментариями не видно бизнес-логики.
Как это сделать надежно, раз у вас уже есть AST:
Вынесите требования ТЗ в независимый слой поверх синтаксического графа. Tree-Sitter уже дает вам детерминированную систему координат — FQN (Fully Qualified Name) классов, методов, эндпоинтов и типов.
Связывайте Declared-граф с кодом через внешний декларативный манифест по FQN символов:
Код остается на 100% стерильным от служебных тегов.
Любой внутренний рефакторинг функции не трогает трассировку требований. Если метод переименовали — анализатор мгновенно видит не сошедшийся FQN в CI и подсвечивает расхождение, а не теряет куски разметки.
На этот же самый чистый AST-граф вы сможете параллельно навешивать любые другие модули (безопасность, проверку слоев, аудит контрактов), не трогая файлы исходников и не порождая конфликты слияния.
Раз уж у вас есть синтаксический граф — используйте его мощь на полную: проецируйте ТЗ на граф снаружи, а не вбивайте костыли внутрь самого кода.
Поймал, снимаю шляпу
Набросал на коленке свои мысли про то, как нас задолбали эти ИИ-галлюцинации в коде. Решил ускорить верстку черновика через сетку, а она навалила своего фирменного канцелярского пафоса с буллетами. Ирония судьбы в чистом виде: пытался выдать мысль против засилья LLM, а инструмент превратил её в рекламу самого себя.
А если смыть глянец, посыл-то был ровно в твоем ключе про схлопывание пузыря: нафиг кормить вендоров миллионами токенов и пихать стохастику в CI. Обычный синтаксический разбор на Tree-Sitter решает проблему контроля кода за миллисекунды, локально и абсолютно бесплатно — как старый добрый компилятор.
Боль описана предельно точно, но главная ловушка сейчас — в попытке лечить проблему тем же, что её породило. Когда на сгенерированный код натравливают ИИ-ревьюера или обмазывают его сгенерированными тестами, получается классический уроборос: одна стохастическая модель с confirmation bias подтверждает галлюцинации другой, а на выходе возникает иллюзия «зелёного пайплайна».
Вторая причина этого ада — инструмент контроля. Лиды пытаются инспектировать двухтысячестрочные простыни через обычный Git-дифф. Но в плоском диффе строк архитектуры не видно в принципе: там невозможно вовремя заметить расползание связности, тихо поплывшие контракты или нарушение изоляции.
Мы сами упёрлись ровно в эту стену, когда поток быстрой генерации начал физически вымывать архитектуру проекта. В итоге пришли к тому, что отдавать валидацию кода на откуп промптам, агентам и токенам — путь в тупик.
Сейчас как раз собираем под CI детерминированное ядро на AST-парсерах (на базе Tree-Sitter). Подход чисто инженерный: никакого анализа через LLM и никаких тяжелых рантаймов. В отличие от стандартных линтеров, запертых внутри одного языка, легковесный синтаксический анализ за пару секунд строит сквозной граф зависимостей системы и сразу рубит PR, если: — поплыли контракты DTO между бэкендом и клиентом или изменились сигнатуры эндпоинтов; — нарушены границы слоёв (зависимость потекла туда, куда архитектурно вход закрыт); — появились циклические зависимости или повисли мёртвые вызовы.
Если код ломает топологию системы — билд падает в CI за секунды, ещё до того, как тимлид или сеньор вообще открыли вкладку Files Changed.
Генерация кода может оставаться быстрой и вероятностной, но фильтр на входе в репозиторий обязан быть строго детерминированным и не зависеть от настроения нейросети. Иначе лиды неизбежно сгорят, работая биологическими компиляторами чужих промптов.
Главная проблема всей дискуссии вокруг лавины ИИ-патчей, «километровых автогенераций» и выгорания мейнтейнеров — это попытка проверять вероятностный код вероятностными же инструментами.
Когда 2000 строк сгенерированного диффа пытаются скормить обратно в LLM, бездумно заталкивая в промпт окружающий монолит на сотни тысяч токенов (в надежде на бездонные 1–2M контекстные окна), получают классическое тушение пожара керосином. На выходе: дикий чек за инференс, задержки в CI и неизбежный Lost in the Middle, когда модель в середине контекста теряет фокус и пропускает рассинхрон типов. А сваливать ревью всего этого спагетти на уставшие глаза сеньоров — верный путь к параличу релизов.
Линус абсолютно прав: ИИ — это просто генератор, как компилятор. Но коду нужен детерминированный синтаксический шлюз верификации, работающий вообще без участия нейросетей.
Архитектурно эта задача закрывается жестким разделением на детерминированное ядро и подключаемые модули анализа:
1. Детерминированное синтаксическое ядро (Zero-LLM Gate)
Входной точкой в CI/CD ставится инкрементальный CST/AST-парсер (например, на Tree-Sitter). Он крутится в изолированном контейнере с
--network none, за миллисекунды разбирает синтаксические деревья полиглотного проекта, нормализует сетевые маршруты через сжатые префиксные деревья (Radix-Trie) с поиском за $O(k)$ и строит строгий граф зависимостей.Результат ядра: точный математический слепок системы с нулевым расходом токенов, абсолютной воспроизводимостью в CI и нулевой вероятностью галлюцинаций.
2. Модульная экосистема аудита поверх графа
Когда в памяти есть точный граф синтаксиса и связей, на него как плагины навешиваются проверки прикладных болей:
Breaking Change Sentinel: мгновенный type-diff между ветками — отлавливает удаление или переименование полей в контрактах до запуска тяжелых тестов.
Security & Taint-анализ: легковесный внутрипроцедурный DFA/Taint-трекинг по синтаксическому графу, блокирующий утечки секретов и персональных данных в логгеры без отправки кода во внешние SAST-облака.
Layer Violation Guard: контроль границ архитектурных слоев (DDD / Clean Architecture) и мгновенный отлов циклических импортов алгоритмом Тарьяна ($O(V+E)$).
Dead Code Pruner: сквозное сопоставление вызовов фронтенда с роутерами бэкенда для выявления мертвого легаси.
3. Хирургический мост к LLM: контекстный срез вместо гигабайтов промптов
И вот только когда синтаксический граф верифицирован, подключается нейросеть (если генерация вообще требуется). Но ей передается не весь репозиторий и не стохастическая каша из RAG-векторов.
AST-ядро выполняет два раздельных действия:
Для контрактов: собирает полное транзитивное замыкание типов (BFS по графу DTO до листьев с контролем циклов).
Для логики: делает хирургический срез вызовов строго на глубину 1–2 хопов вокруг целевого метода.
Вместо «простыни» на 50 000 токенов агент получает изолированную математическую выжимку на 400–600 токенов интерфейсов и типов. Модель физически лишается пространства для галлюцинаций, а стоимость инференса падает на 90%+.
Генерация кода может оставаться быстрой и вероятностной. Но топология системы, контракты интерфейсов и входной фильтр верификации обязаны опираться на строгую, детерминированную математику компиляторов. Только тогда поток автогенераций перестает сжигать мейнтейнеров и превращается в управляемый конвейер.
Хорошая, честная статья. Переход на SQLite WAL для локального агента — абсолютно верный шаг, но раз уж вы открыли дискуссию про грабли квитанций и конкурентности, подкину четыре прикладных решения из нашего продакшна, которые сэкономят вам пару месяцев отладки.
1. Как гарантированно закрыть проблему разрастания WAL (Checkpoint Starvation) В Go-сервисе фатально использовать общий пул соединений для записи и чтения SQLite. Агенты шлют отчёты каждые 500 мс (непрерывный поток
INSERT), а пользователь в это время открывает тяжелый суточный график. Долгая читающая транзакция держит старый read mark и намертво блокирует сброс страниц из WAL в основной файл.Решение: жёстко разделите коннекты. На запись держите строго одно постоянное соединение на весь процесс (
SetMaxOpenConns(1)) сPRAGMA busy_timeout = 5000;. Чтение выносите в отдельный пул сPRAGMA query_only = ON;.На все HTTP-хэндлеры чтения графиков обязательно вешайте контекстный таймаут (
context.WithTimeout(ctx, 2*time.Second)), чтобы зависший ридер принудительно обрывался и не держал snapshot.2. Квитанции vs Стейт-машина (Reconciliation Loop) Вы абсолютно верно заметили в комментариях, что 200 OK от Docker API не гарантирует, что контейнер реально поднялся. Логика «не повторять, если исход неизвестен» хороша, но без проверки состояния она оставляет систему слепой.
Решение: паттерн Transactional Outbox + стейт-машина внутри SQLite. Действие переходит по статусам:
PENDING→DISPATCHED→VERIFYING→COMPLETED / FAILED.При отправке команды агент не закрывает задачу, а переводит её в
VERIFYING, ждёт grace-период (3–5 сек) и делает идемпотентный опрос реального рантайма (docker inspectна healthcheck). Панель же при ретраях стучится по уникальномуcommand_uuid— и вместо повторного рестарта просто получает текущий статус из стейт-машины агента.3. Гарантированная зачистка зомби-процессов модулей на уровне ядра Если агент упал или модуль отстрелили по таймауту, фоновые дочерние процессы останутся в памяти. Полагаться на логи здесь бесполезно — нужно заставлять ядро ОС делать зачистку:
В Linux: при сборке команды через
exec.Commandвыставляйте вSysProcAttr:Setpgid: true— обособляет модуль в собственную группу процессов. Убивать при таймауте нужно не PID, а всю группу отрицательным сигналом:syscall.Kill(-pgid, syscall.SIGKILL).Pdeathsig: syscall.SIGKILLчерезprctl(PR_SET_PDEATHSIG)— если сам процесс агента внезапно падает (OOM, panic), ядро автоматически прибивает все дочерние бинарники модулей.В Windows: аналогично закрывается через Windows Job Objects с флагом
JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE.4. Даунсэмплинг телеметрии (Rollup) При интервале 500 мс даже десяток серверов сгенерирует миллионы строк в сутки. Рендерить такой объем в браузере через Next.js — смерть для фронтенда и диска. Разделите хранилище: горячий сырой слой (500 мс) держите в SQLite с TTL в 2–3 часа для real-time дебага, а фоновым воркером раз в минуту складывайте предрассчитанные бакеты (avg/p95/max) в аналитическую таблицу. Суточные графики должны смотреть только в бакеты.
Мы ровно через эти грабли проходили, когда проектировали отказоустойчивые интеграционные шлюзы на связке SQLite WAL + FastAPI: решали проблемы гонок токенов, рейтлимитов и гарантированной доставки событий.
В треде наметилась занятная бинарная ловушка: либо затаскивать стохастический RAG, либо заставлять разработчиков уродовать кодовую базу килограммами комментариев-якорей. Ни то, ни другое в реальном энтерпрайзе на 500k+ LOC не живет.
1. Про адептов RAG/GraphRAG в коде Кодовая база — это не корпус текстов на естественном языке. Векторный поиск оперирует косинусным сходством эмбеддингов в семантическом пространстве. Для архитектуры это смерть: косинусная близость понятия не имеет о границах модулей, транзитивности вызовов, циклическом импорте и контрактах DTO. Когда на монолите в полмиллиона строк нужно отследить смену поля в контракте на глубине 5 хопов (контроллер → сервис → фасад → адаптер → база), RAG выдает стохастический шум и ловит classic Lost in the Middle, скармливая модели куски с похожими названиями функций, но из совершенно других контекстов. Использовать RAG как основу CI-гейта — это сознательно строить нестабильный пайплайн, где один и тот же PR сегодня собирается, а завтра валится из-за флуктуации выборки.
2. Автору статьи: вектор верный, реализация через якоря — тупик Идея положить declared и computed графы в репозиторий и детектировать дрейф архитектурных контрактов до слияния — абсолютно зрелая. Выносить контекст из чатов в Git — единственный способ перестать платить налог на забывчивость моделей.
Но попытка сделать код читаемым для агента через разметку:
// START_MODULE_CONTRACT// SCOPE: src/...// LINKS: M-AUTH-VALIDATE// START_BLOCK_DECODE_JWT— это перекладывание архитектурной лени тулинга на плечи разработчиков. Превращать продакшн-код в расчерченную зебру из служебных тегов — верный путь к тому, что на третьем мерж-конфликте разметка разъедется, парные комменты потеряются, а линтер начнет блокировать деплой из-за съехавшего текстового якоря. Если для понимания границ модуля агенту требуются подсказки в комментариях, значит, анализатор просто не умеет работать с кодом как с синтаксическим деревом.
3. Как это решается через строгую математику графов Зачем вручную писать то, что компилятор и парсер знают детерминированно из коробки?
Границы и контракты без единой строчки комментов: Инкрементальный парсер на базе CST/AST (например, Tree-Sitter) на лету за миллисекунды снимает байтовые координаты
FunctionDeclaration,ExportNamedDeclaration, сигнатуры типов и точки вызовов (CallExpression). Код остается стерильным — AST уже содержит в себе всю семантику, ему не нужны псевдо-якоря.Трассировка контрактов: Маршруты и вызовы мапятся через сжатое префиксное дерево (Radix-Trie) с O(k)O(k)O(k) сложностью поиска по сегментам путей, а схема зависимостей DTO вычисляется строгим BFS-обходом с отсечением циклических ссылок (visited set) до глубины 12–15 уровней. Никакой RAG и близко не даст такой детерминированной полноты среза.
Арбитраж дрейфа: Когда computed-граф расходится с declared, дрейф разрешается не эвристиками и не верой модели, а расчетом радиуса поражения (blast radius). Мы, например, вешаем на топологический срез расширенную метрику Генри — Кафура:
HK=LOC×(fan_in×fan_out)2×2−distanceHK = LOC \times (fan\_in \times fan\_out)^2 \times 2^{-distance}HK=LOC×(fan_in×fan_out)2×2−distance
где узел с минимальным весом топологически обязан стать точкой адаптации интерфейса, чтобы не ломать зависимые сервисы.
Итог простой: автор совершенно прав в том, что знание должно быть в репозитории в виде графа. Но графу не нужны человеческие комменты внутри функций — ему нужны точный AST-анализ синтаксиса и строгая теория графов. Тогда CI-чек на расхождение замысла и факта отрабатывает за 2 секунды в изолированном контейнере с
--network noneс нулевым расходом токенов, а LLM вызывается ровно один раз — наложить точечный патч на строго локализованный математический срез, где она физически не сможет нагаллюцинировать.Статья поднимает правильный вопрос о трансформации роли разработчика, но развернувшаяся дискуссия снова поляризовалась на две привычные крайности: либо «ИИ со дня на день заменит всех специалистов», либо «модели не способны ни на что сложнее типовых сниппетов и шаблонных скриптов».
Оба этих полюса упускают главное: нейросети действительно со временем заберут колоссальный объем прикладного кодинга, но это не уничтожает профессию, а резко расширяет угол обзора самого разработчика.
Сегодня нейросеть способна выдавать стабильный инженерный результат только при одном условии: ее нужно жестко загонять в детерминированные рамки.
Пока модели пытаются скармливать задачи на естественном языке в надежде на «магию», на выходе получается стохастический шум, расползание архитектуры и скрытый техдолг. Модель начинает работать надежно только тогда, когда вокруг нее выстроен жесткий внешний каркас:
Изолированные синтаксические срезы. Агент не должен вариться во всем проекте сразу — контекст жестко ограничивается конкретным контрактом, интерфейсом и точкой изменения.
Внешний контроль инвариантов. Проверка типов, обратная совместимость API и целостность связей валидируются не рассуждениями модели, а компилятором, статическим анализом и тестами.
Автоматические тестовые полигоны. Любой сгенерированный фрагмент проверяется детерминированным рантаймом до того, как попадет в кодовую базу.
Этот контур автоматических ограничений будет только расти и усложняться. В результате фокус разработчика неизбежно смещается: от ручного набора конструкций языка к проектированию архитектурных рамок, спецификаций и систем сквозной верификации.
Парадокс эпохи ИИ заключается в том, что инженеру теперь приходится учиться не меньше, а кратно больше и глубже. Если раньше можно было годами оставаться востребованным, просто зная синтаксис популярного фреймворка, то теперь требуется фундаментальное понимание теории компиляторов, графов зависимостей, распределенных систем и архитектурных инвариантов. ИИ берет на себя рутину, но правила игры и границы допустимого по-прежнему задает системный архитектор.
Проблема с «противоречием между страницей 10 и 345» — точный диагноз, но попытка скормить эту задачу в RAG и надеяться на контекстное окно LLM изначально обречена.
Векторный поиск по эмбеддингам семантически слеп: он находит похожие по смыслу фрагменты текста, но в упор не видит топологию связей, транзитивные зависимости и строгие контракты данных. Загонять сотни тысяч строк кода или сотни страниц документации в окно модели — это рулетка: сегодня механизм внимания сработает, а завтра из-за сдвига контекста (Lost in the Middle) пропустит критический рассинхрон прямо в прод.
Поиск логических противоречий и контроль инвариантов — задача не для вероятностной LLM, а для детерминированного статического анализа (Zero-LLM):
Синтаксический граф вместо эмбеддингов. Polyglot-парсер на Tree-Sitter разбирает кодовую базу в AST за секунды, а эндпоинты и маршруты нормализуются в префиксное дерево (Radix-Trie) со сложностью поиска $O(k)$.
Математическая верификация контрактов. Граф вызовов и цепочки DTO обходятся строгим детерминированным алгоритмом (BFS) с контролем циклов. Если контракт на одном конце системы ожидает поле, которое изменили или удалили на другом, конфликт фиксируется математически за миллисекунды — без токенов, галлюцинаций и сетевых запросов.
Локализация контекста. LLM подключается только в самом конце — на изолированном, предварительно выверенном синтаксическом срезе (context slice) конкретного метода или функции, где объем контекста минимален, а границы инвариантов уже зафиксированы ядром.
Нейросети никого не заменят, пока их пытаются использовать как всемогущий черный ящик. Разработчикам придется учиться еще серьезнее: глубоко разбираться в теории компиляторов, графах зависимостей и синтаксическом анализе, чтобы проектировать детерминированные контуры контроля, внутри которых ИИ сможет безопасно генерировать код.