Анализ5 мин чтения2026-03-06

Code linters: почему ваш код всё ещё падает на ревью и как это исправить

Прошлый год. Понедельник. Утро. Открываю MR — там 47 комментариев. Утечка памяти, неиспользуемые переменные, забытые console.log. И это от опытного разработчика

Прошлый год. Понедельник. Утро. Открываю MR — там 47 комментариев. Утечка памяти, неиспользуемые переменные, забытые console.log. И это от опытного разработчика. Знакомая картина? Если вы сейчас кивнули — значит, у вас нет нормальной системы статического анализа. Или есть, но она не работает.

Code linters — это первый рубеж обороны. Не серебряная пуля, но инструмент, который экономит часы ревью и спасает от глупых багов в проде. Давайте разберёмся, как они работают, какие бывают и почему одна команда тратит на code review 20 минут, а другая — два дня.

Статический vs динамический анализ: в чём разница

Статический анализ смотрит код, не запуская его. Linter парсит исходник, строит AST (абстрактное синтаксическое дерево) и проверяет узлы по набору правил. Просто, быстро, работает до компиляции.

Динамический анализ требует запуска. Тестируем код на реальных данных, смотрим поведение в рантайме. Профилировщики, санитайзеры, фаззеры — всё это про динамический анализ.

Хорошая команда использует оба подхода. Но начинают всегда со статического — он дешевле и даёт быстрые результаты.

Статический анализ ловит:

Динамический находит то, что статический не видит:

На одном проекте мы внедрили Pylint и сразу нашли 200+ проблем. Но вот race condition в асинхронном коде Pylint не увидел — потребовалось писать тесты с ThreadSanitizer. Вывод? Инструменты дополняют друг друга.

Какие code linters выбрать в 2024 году

Рынок огромный. Давайте по языкам, без лишней воды.

Python: Pylint, Flake8, Ruff. Ruff сейчас рвёт всех — написан на Rust, работает в 10-100 раз быстрее Flake8. Я перевёл все проекты на него год назад и не жалею. Конфигурация проще, плагины не нужны.

JavaScript/TypeScript: ESLint. Стандарт де-факто. Для TypeScript — включаете @typescript-eslint/parser и получаете типобезопасные правила. Можно прикрутить Prettier для форматирования, но многие команды сейчас переходят на Biome — быстрее, меньше настроек.

Go: Прямо в тулчейне. go fmt, go vet. Для глубже — staticcheck. Go вообще идеально спроектирован в плане стандартов — споров о форматировании нет.

Java: Checkstyle, SpotBugs, PMD. Checkstyle — про стиль, SpotBugs — про баги, PMD — про сложность кода. Обычно используют вместе. SonarQube объединяет все проверки в одном месте.

PHP: PHP_CodeSniffer, PHPMD. Для современных проектов — Laravel Pint, если на Laravel.

Честно? Большинство команд берут дефолтный конфиг и успокаиваются. Ошибка. Дефолт — это база. На одном стартапе мы потратили неделю на тюнинг ESLint под специфику проекта. Результат? Количество ложных срабатываний упало с 30% до 5%. Разработчики перестали игнорировать варнинги.

Как внедрить линтеры в CI/CD

Начнём с простого примера. Вот как это выглядит в GitHub Actions:

name: Lint

on: [push, pull_request]

jobs:
  eslint:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: '20'
          cache: 'npm'
      - run: npm ci
      - run: npm run lint

Для GitLab CI:

lint:
  image: node:20
  stage: test
  script:
    - npm ci
    - npm run lint
  only:
    - merge_requests

Но это база. По-хорошему, нужно добавить кеширование, распараллелить проверки, настроить артефакты. Вот более реалистичный пример:

lint:
  image: python:3.11
  stage: test
  cache:
    key: ${CI_COMMIT_REF_SLUG}
    paths:
      - .cache/pip
      - .venv/
  before_script:
    - pip install ruff mypy
  script:
    - ruff check . --output-format=gitlab > ruff-report.json
    - mypy . --json-report mypy-report.json
  artifacts:
    reports:
      codequality: ruff-report.json
    expire_in: 1 week
  only:
    - merge_requests

Теперь про стратегию внедрения. Нельзя просто включить линтер на весь проект и сломать билд. Вернее, можно, но команда вас возненавидит.

Правильный подход:

  1. Настройте линтер локально
  2. Запустите на кодовой базе
  3. Отключите или переведите в warning правила с большим количеством срабатываний
  4. Включите в CI только для новых файлов
  5. Постепенно чините старый код

Для этого в ESLint есть опция --rule, в Ruff — --select и --ignore. В большинстве линтеров можно указать --warn вместо --error для конкретных правил.

# pyproject.toml для Ruff
[tool.ruff]
select = ["E", "F", "I"]  # базовые правила
ignore = ["E501"]  # длина строки — не критично

[tool.ruff.per-file-ignores]
"tests/*" = ["F401"]  # в тестах неиспользуемые импорты ок

Ложные срабатывания и как с ними жить

Если честно, это главная проблема линтеров. Пишешь код, всё работает, а линтер кричит. Разработчики начинают игнорировать варнинги. Потом игнорируют реальные баги.

Решения:

Инлайн-игнорирование. Но с осторожностью. Не так:

# pylint: disable=all  # BAD

А так:

# pylint: disable=too-many-arguments  # Legacy API, не трогать без рефакторинга

Файлы-исключения. .eslintignore, .gitignore-стиль. Удобно для сгенерированного кода.

Гранулярные настройки. Отключайте конкретные правила для конкретных паттернов. В ESLint:

rules: {
  'no-console': ['error', { allow: ['warn', 'error'] }],
}

На проекте в Яндексе мы ввели правило: каждое игнорирование должно иметь тикет в комментарии. Раз в квартал пробегались по тикетам и чинили. Работает.

AI-powered анализ: новая эра

Традиционные линтеры работают по фиксированным правилам. X — ошибка, Y — нормально. Но иногда X — это нормально, если понимать контекст.

AI-анализаторы смотрят на код шире. Они понимают семантику, находят логические ошибки, которые не описать правилом. Например:

def calculate_discount(price, is_premium):
    if is_premium:
        return price * 0.8
    return price * 0.9

# AI заметит: "А что если price отрицательный? Скидка увеличит сумму."

Традиционный линтер такое не поймёт. AI — поймёт.

Мы в Distiq как раз делаем такой инструмент. Бот интегрируется в GitLab, GitHub или GitVerse, анализирует каждый MR и оставляет инлайн-комментарии. Находит баги, уязвимости, проблемы с производительностью. Понимает контекст — не орёт на каждое "неправильное" место, а даёт релевантные советы.

Если устали от ревью с десятками nitpick-комментариев — попробуйте. Настройка занимает минуты, а результат виден сразу. Российский сервис, данные не уходят за рубеж — для многих компаний это критично.

Попробуйте Distiq для автоматического code review

AI-бот анализирует каждый MR/PR и оставляет комментарии с замечаниями. Интеграция за 2 минуты.

Попробовать бесплатно

Похожие статьи