Самый частый вопрос от CTO про executable engineering standard: «это же просто SonarQube?». Нет. Но и не вместо. Эти инструменты живут на разных уровнях абстракции и дополняют друг друга, а не конкурируют.

Эта статья — таблица сравнения по 12 параметрам и разбор «когда что использовать».

Резюме за 30 секунд

  • SonarQube / ESLint / Detekt — для багов уровня кода и стиля. Регексы, AST-анализ, безопасность.
  • Code review глазами тимлида — для архитектуры и домена. Не масштабируется на команду 20+.
  • AI-скиллы с corpus правил — для архитектуры и домена. Масштабируется. Дополняют линтеры, не заменяют.

Все три должны работать одновременно в зрелой команде. Линтер ловит NPE, скилл ловит «событие зарегистрировано не в корне агрегата», человек смотрит на «правильно ли вообще выбрана граница агрегата».

Полная таблица сравнения

ПараметрSonarQube/ESLintТимлид-ревьюAI-скилл с corpus
Что проверяетстиль, security-баги, complexityархитектура, доменархитектура, домен
Глубина пониманиясинтаксис + ASTсемантика + контекстсемантика + контекст (через corpus)
Кто исполняетстатический анализаторчеловекLLM-агент
Кодифицированоплагины + конфигв головеmarkdown в репо
Citeable в обзорахда (java:S1234)нетда (R-AGG-X4)
Масштабируетсяданет (bottleneck)да
Latency обзорасекунды (CI)дни (тимлид reads)минуты (claude run)
False positivesсредне (~10–20%)низкосредне (~10–15%)
Понимает доменнетдада
Версионируетсярелиз плагинаустные правилаgit diff на corpus
Открытостьopen-source движокв головерепо команды
Lifecycle правилрелизы плагиновнеформальноgit, semantic diff

Где они НЕ конкурируют

Возьмём один и тот же PR — handler оплаты заказа:

public void handle(PayOrder cmd) {
    Order order = orders.findById(cmd.orderId()).get();
    order.setStatus(OrderStatus.PAID);
    order.setPaidAt(Instant.now());
    orders.save(order);
    events.publishEvent(new OrderPaid(order.id(), order.total()));
}

SonarQube скажет:

  • java:S3655Optional.get() без isPresent() — может бросить
  • java:S1192 — string literal "PAID" дублируется (если есть в других местах)

AI-скилл ucp-ddd-tactical-review скажет:

  • R-AGG-X4 — событие зарегистрировано не в корне агрегата
  • R-ENT-X3 — публичные сеттеры вместо бизнес-метода
  • R-EVT-X4events.publishEvent() без транзакционных гарантий

Тимлид скажет:

  • «Этот use case вообще должен быть Order.pay() или application service PaymentSaga? У нас же платёж асинхронный и приходит через webhook.»

Три уровня. Три инструмента. Все три нужны.

Когда что брать

Только линтер

  • Команда < 5 инженеров.
  • Простой CRUD-проект, не доменно-сложный.
  • Нет архитектурных стандартов в голове техлида.

Линтер + тимлид-ревью

  • Команда 5–10.
  • Есть техлид с устоявшейся архитектурой.
  • Архитектура держится на людях, не формализована.

Линтер + AI-скиллы + тимлид

  • Команда 10+.
  • Несколько сервисов, риск drift между ними.
  • Архитектурные паттерны достаточно устоялись, чтобы их кодифицировать.

Линтер + тимлид (без AI-скиллов)

  • MVP-этап, всё меняется еженедельно.
  • Команда не доверяет AI-обзорам.
  • Архитектура ещё не устоялась.

Что общего у всех трёх

Все три — это инструменты обзора, а не замены ответственности. Линтер не пишет код за вас. Тимлид не подписывает PR за разработчика. AI-скилл не принимает архитектурные решения. Все они — усилители, не подменители.

Качество ревью на любом из трёх уровней зависит от качества исходных стандартов:

  • ESLint без хорошей конфигурации — шум.
  • Тимлид без устоявшихся принципов — субъективные капризы.
  • AI-скилл без хорошего corpus правил — generic-обзор уровня «улучши читаемость».

Качественный corpus правил — то, что отличает зрелую команду от cargo-cult adoption.

Что AI-скиллы делают, чего не делают линтеры

Есть один класс правил, который традиционные линтеры принципиально не достанут:

  1. Правила про доменный слой. «Имя value object — существительное в единственном числе». Линтер не знает что такое value object и какое имя «доменное», а какое нет.
  2. Правила про границы. «Один use case изменяет один агрегат, остальные через события». Линтер не знает где проходят границы агрегатов в вашей доменной модели.
  3. Правила про намерение. «Имя класса соответствует доменному термину из ubiquitous language». Линтер не знает ubiquitous language.
  4. Правила про контекст. «На Tier B JSON-сериализация через jackson, на Tier C — через MapStruct». Линтер не знает Tier и не выбирает правила в зависимости от него.

LLM умеет всё это потому что читает прозу правил вместе с прозой кода. Для LLM «доменный термин» и «не доменный» — это вопрос контекста, а не AST-узла.

Что линтеры делают, чего не делают AI-скиллы

И обратное:

  1. Скорость. Линтер за 3 секунды просмотрит 100K строк. Скилл — десятки секунд на PR.
  2. Детерминированность. Линтер на одном и том же коде даст один и тот же результат. LLM — с вариациями.
  3. Низкоуровневые баги. NPE, deadlock, off-by-one. Это работа AST-анализатора.
  4. Security-сканирование. SQL injection, XSS, hardcoded secrets — паттерны более чёткие.

Дальше