Что такое статический анализ?

Статический анализ — это автоматизированная проверка исходного кода без его выполнения. Инструменты сканируют код, выявляя паттерны, указывающие на баги, уязвимости безопасности, нарушения стиля и проблемы сложности.

Если ручные ревью (из Урока 2.29) опираются на человеческое суждение, инструменты статического анализа применяют тысячи правил единообразно к каждой строке кода за секунды. Они не устают, не пропускают известные паттерны и работают одинаково каждый раз.

Думайте о статическом анализе как о проверке орфографии для кода. Проверка орфографии не скажет, хорош ли аргумент вашего эссе (для этого нужен человек), но она мгновенно находит опечатки и грамматические ошибки.

Статический анализ vs. Ручное ревью

АспектСтатический анализ (инструменты)Ручное ревью (люди)
СкоростьСекунды — минутыЧасы — дни
Согласованность100%Зависит от рецензента
ПокрытиеКаждый файл, каждая строкаФокус на изменённом коде
Что находитИзвестные паттерны, нарушения правилДефекты дизайна, ошибки логики
Что пропускаетНовые баги, ошибки бизнес-логикиИзвестные паттерны (если рецензент устал)
СтоимостьЛицензия + время CIВремя разработчика

Лучшая практика: используйте оба. Статический анализ ловит рутинные проблемы, освобождая людей для анализа дизайна и логики.

Популярные инструменты статического анализа

ИнструментЯзыкиФокус
SonarQube/SonarCloud30+ языковКомплексный: баги, уязвимости, smells, покрытие
ESLintJavaScript/TypeScriptСтиль, паттерны, потенциальные ошибки
Pylint / RuffPythonКачество, стиль, ошибки
PMDJava, Apex и др.Паттерны, сложность
SpotBugsJavaПаттерны багов в байткоде
RuboCopRubyСтиль, паттерны, сложность
golangci-lintGoМета-линтер, объединяющий несколько инструментов
SemgrepМульти-язычныйПоиск паттернов с фокусом на безопасность

Обзор SonarQube

SonarQube — отраслевой стандарт непрерывной инспекции качества кода. Предоставляет централизованный дашборд для мониторинга качества кода по проектам, отслеживания технического долга и применения стандартов.

Типы Issues

Bugs — Код, который доказуемо неверен или может вызвать неожиданное поведение при выполнении. Примеры: разыменование null, выход за границы массива, утечки ресурсов.

Vulnerabilities — Код, который может быть эксплуатирован атакующими. Примеры: SQL injection, XSS, захардкоженные учётные данные.

Code Smells — Код, который не является неверным, но затрудняет поддержку кодовой базы. Примеры: дублирование кода, чрезмерно сложные методы, неиспользуемые переменные.

Уровни серьёзности

СерьёзностьОписаниеПример
BlockerВызовет краш или потерю данныхРазыменование null в продакшн-пути
CriticalВероятно вызовет серьёзную проблемуУязвимость SQL injection
MajorМожет вызвать незначительную проблему или существенную деградациюМетод с цикломатической сложностью 50
MinorПроблема качества с низким влияниемНеиспользуемый import
InfoНе проблема, лишь предложениеРассмотрите использование StringBuilder

Quality Gates

Quality Gate — набор условий, которым новый код должен соответствовать. Это барьер между разработкой и деплоем.

Quality Gate по умолчанию («Sonar Way»):

  • Нет новых багов
  • Нет новых уязвимостей
  • Покрытие нового кода ≥ 80%
  • Дублирование нового кода ≤ 3%

Команды настраивают Quality Gates под свои стандарты.

Технический долг

SonarQube измеряет технический долг как оценочное время для исправления всех code smells. Отображается как временная оценка: «5 дней технического долга.»

Ratio технического долга = (стоимость исправления smells) / (стоимость переписывания с нуля). Ratio ниже 5% считается управляемым.

graph LR subgraph Дашборд SonarQube B[Bugs: 12] V[Уязвимости: 3] CS[Code Smells: 245] COV[Покрытие: 72%] DUP[Дублирование: 4.2%] TD[Тех. долг: 8 дней] QG{Quality Gate} end QG -->|Пройден| DEPLOY[Деплой] QG -->|Не пройден| FIX[Исправление] style QG fill:#f97316,color:#000 style DEPLOY fill:#22c55e,color:#000 style FIX fill:#ef4444,color:#fff

Настройка SonarQube

Локальная установка (Docker)

# Запуск SonarQube
docker run -d --name sonarqube -p 9000:9000 sonarqube:community

# Доступ по http://localhost:9000 (логин: admin/admin)

Сканирование проекта

sonar-scanner \
  -Dsonar.projectKey=my-project \
  -Dsonar.sources=src \
  -Dsonar.host.url=http://localhost:9000 \
  -Dsonar.token=ваш-токен

Интеграция с CI/CD

# Пример GitHub Actions
- name: SonarQube Scan
  uses: sonarqube/sonarcloud-github-action@v2
  env:
    SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
    SONAR_HOST_URL: ${{ secrets.SONAR_HOST_URL }}

Pipeline падает, если Quality Gate не пройден, предотвращая интеграцию некачественного кода.

Интерпретация отчётов SonarQube

При просмотре отчёта следуйте порядку приоритетов:

  1. Статус Quality Gate — Пройден или нет?
  2. Новые баги и уязвимости — Высший приоритет. Исправить все blockers и criticals.
  3. Security hotspots — Код, отмеченный как потенциально уязвимый, требующий человеческой проверки.
  4. Покрытие нового кода — Адекватно ли протестирован? Ниже 80% указывает на пробелы.
  5. Code smells в новом коде — Низкий приоритет, но отслеживайте тренд.
  6. Общие метрики — Проект улучшается или ухудшается со временем?

Упражнение: Интерпретируйте отчёт SonarQube

Вы — QA Lead, проверяющий отчёт SonarQube для PR с новой функцией регистрации пользователей:

Анализ нового кода:

  • Bugs: 2 (1 Critical, 1 Major)
  • Уязвимости: 1 (Critical)
  • Code Smells: 8 (2 Major, 6 Minor)
  • Покрытие: 65%
  • Дублирование: 1.2%

Детали багов:

  • CRITICAL: Разыменование null в UserService.register()
  • MAJOR: UserController.handleRegistration() ловит общий Exception

Детали уязвимости:

  • CRITICAL: SQL injection в UserRepository.findByEmail() — email конкатенируется прямо в SQL-запрос

Quality Gate: НЕ ПРОЙДЕН (покрытие < 80%, критическая уязвимость)

Часть 1: Приоритизируйте находки. Что нужно исправить до merge?

Часть 2: Для уязвимости SQL injection опишите исправление и тест-кейсы.

Часть 3: Разработчик утверждает, что 65% покрытия «достаточно». Напишите ваш ответ.

Часть 4: Какие улучшения процесса вы бы рекомендовали?

ПодсказкаДля Части 1 учитывайте серьёзность и тип issue. Уязвимости, особенно SQL injection, всегда должны исправляться до merge. Для Части 3 подумайте, чего должны достигать цели покрытия.
Решение

Часть 1: Приоритизация

Обязательно исправить до merge:

  1. CRITICAL уязвимость: SQL injection — риск утечки данных.
  2. CRITICAL баг: Разыменование null — вызовет краши в продакшне.

Настоятельно рекомендуется исправить: 3. MAJOR баг: Перехват общего Exception. 4. Покрытие: 65% → нужно больше тестов.

Можно отложить: 5. 8 code smells — создать тикет на следующий спринт.

Часть 2: Исправление SQL Injection

Уязвимый код:

String query = "SELECT * FROM users WHERE email = '" + email + "'";

Исправленный код:

@Query("SELECT u FROM User u WHERE u.email = :email")
Optional<User> findByEmail(@Param("email") String email);

Тест-кейсы: обычный email, попытка SQL injection (admin'; DROP TABLE users;--), спецсимволы, пустой email, null email.

Часть 3: Сохранить порог 80%, потому что: 65% покрытия на потоке регистрации рискованно, порог применяется только к новому коду, снижение планки создаёт прецедент, а настоящий вопрос — почему покрытие низкое.

Часть 4: Интеграция SonarLint в IDE, pre-commit hooks с правилами безопасности, обучение по OWASP Top 10, чеклист в шаблоне PR, интеграционные тесты для dependency injection.

Ключевые выводы

  • Статический анализ автоматизирует инспекцию кода, находя баги, уязвимости и code smells без выполнения кода
  • SonarQube классифицирует issues на bugs (надёжность), vulnerabilities (безопасность) и code smells (поддерживаемость)
  • Quality Gates устанавливают пороговые условия для нового кода
  • Технический долг измеряется как оценочное время для исправления всех code smells
  • Статический анализ дополняет ручные ревью — инструменты ловят паттерны, люди — логику и дизайн
  • Интеграция с CI/CD обеспечивает анализ каждого изменения
  • Наибольшую ценность даёт исправление issues в новом коде (shift-left), а не ремедиация legacy-кода