Самый эффективный процесс обеспечения качества, которым никто не пользуется

В 1976 году Майкл Фаган опубликовал статью в IBM Systems Journal, в которой описал процесс ревью настолько эффективный, что он стал золотым стандартом качества ПО. Fagan Inspections выявляли от 60 до 90 процентов всех дефектов до запуска хотя бы одного теста. Исследование NASA 2002 года показало, что каждый час, потраченный на инспекцию, в среднем предотвращал 33 часа сопровождительных работ в будущем.

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

Сегодня им почти никто не пользуется.

Вопрос не в том, работали ли Fagan Inspections. Они работали почти слишком хорошо. Вопрос в том, почему процесс с такой репутацией исчез из мейнстрим-разработки, и не потеряли ли мы что-то важное, заменив его.

Как на самом деле выглядели Fagan Inspections

Фаган не изобрёл code review. Он изобрёл специфический, жёстко структурированный ритуал поиска дефектов.

Процесс состоял из шести неукоснительных фаз:

  1. Planning: Модератор выбирал участников и проверял, что материал соответствует критериям входа.
  2. Overview: Автор объяснял контекст. Это была постановка контекста, а не ревью.
  3. Preparation: Каждый участник независимо изучал материал со скоростью примерно 150 строк в час, составляя личный список предполагаемых дефектов.
  4. Inspection Meeting: Команда собиралась не более чем на два часа. Reader вслух излагал логику. Recorder фиксировал дефекты. Модератор следил за тем, чтобы встреча была сосредоточена на поиске дефектов, а не на их устранении.
  5. Rework: Автор исправлял каждый зафиксированный дефект.
  6. Follow-up: Модератор проверял, что исправления внесены и новые дефекты не появились.

Роли были чётко определены и не пересекались. Модератор вёл процесс, но не был техническим авторитетом. Reader излагал код, но не защищал его. Автор присутствовал, но ему запрещалось объяснять замысел во время встречи. Цель была не в сотрудничестве. Целью была холодная, систематическая детекция дефектов.

Именно это позволяло процессу работать. Социальная динамика обычных инженерных встреч была исключена по замыслу.

Почему цифры были такими хорошими

Уровень обнаружения дефектов был не случайностью. Он вытекал из нескольких сознательных проектных решений.

Независимая подготовка означала, что шесть человек изолированно изучали один и тот же код до того, как групповое обсуждение могло на них повлиять. Пересечение их списков показывало, насколько очевиден дефект. Пункты, которые нашёл только один человек, часто были наиболее ценными.

Жёсткий лимит в два часа предотвращал разрушение суждений усталостью. Фаган знал, что эффективность инспекции резко падает примерно после двух часов. Скорость 150 строк в час также была выбрана осознанно. Если двигаться быстрее, вы начинаете видеть то, что ожидаете увидеть, а не то, что есть на самом деле.

Правило «без решений» удерживало встречи в фокусе. Ничто не разрушает инспекцию быстрее, чем комната, полная инженеров, проектирующих исправление для дефекта, который они ещё не до конца охарактеризовали.

Эти ограничения не были бюрократическим overhead. Они были механизмом. Убери их — получишь что-то более дружелюбное, но менее эффективное.

Что погубило Fagan Inspections

Если процесс был таким эффективным, почему же он исчез?

Короткий ответ: он был дорогим именно так, как отказывается терпеть современная разработка ПО.

Одна Fagan Inspection поглощала от 15 до 20 процентов усилий, затраченных на написание рецензируемого кода. В одном задокументированном случае 348 строк потребовали 27,3 человеко-часов инспекции. Это соотношение немыслимо, когда команды деплоят несколько раз в день.

Одно лишь планирование было работой на полную ставку. Требовалось собрать пять или шесть человек в комнате на два часа, плюс подготовка, плюс follow-up. В крупной организации поиск двухчасового слота, в котором модератор, reader, два reviewer, recorder и автор были бы все свободны, мог занимать дни.

Жёсткая структура ролей также не масштабировалась. Fagan Inspections предполагали стабильную команду с достаточным числом людей для заполнения всех ролей. В стартапе пятичеловеческая команда может не располагать кем-то, кто мог бы выступить выделенным модератором, не разрушив velocity.

Самый большой фактор был культурным. Fagan Inspections были преднамеренно неудобными. Автор молча сидел, пока коллеги вслух излагали его код и фиксировали его дефекты. Не было места для фразы «это всего лишь черновик». Процесс исходил из предположения, что дефекты дороги, а социальное трение дёшево. Современная инженерия опирается на противоположное предположение.

Чем мы их заменили

Индустрия не отказалась от структурированного ревью. Она заменила его pull requests.

Ревью pull request — асинхронное, с минимумом церемоний, встроенное непосредственно в development workflow. Reviewer может посмотреть diff между встречами, на телефоне или пока ждёт завершения CI. Нет назначенных ролей. Автор и reviewer зачастую — один и тот же человек, которому просто нужен ещё один approval, чтобы сделать merge.

Это колоссальное улучшение в доступности, скорости и developer experience. Это также колоссальная регрессия в обнаружении дефектов.

Несколько исследований показали, что неформальное ревью выявляет примерно половину дефектов, которые выявляет структурированная инспекция. Эксперимент 2009 года Басили и др. сравнивал инспекцию в стиле Fagan с lightweight review и обнаружил, что более лёгкий процесс выявил значительно меньше дефектов на том же материале.

Проблема не в том, что reviewer ленивы. Процесс не предназначен для поиска дефектов. Он предназначен для того, чтобы люди могли отгружать код, на который посмотрели вторые глаза, а это не одно и то же.

Что мы на самом деле потеряли

Ревью pull request оптимизирует throughput. Инспекция Fagan оптимизировала тщательность. Это принципиально разные цели, и ни одна из них не ошибочна. Ошибка заключается в том, чтобы считать, что более лёгкий процесс — строгое надмножество более тяжёлого.

Вот что исчезло:

Независимая подготовка. В pull request reviewer видит diff холодно. Он не потратил час на чтение окружающего контекста, прослеживание потока данных и построение ментальной модели. Он реагирует на уведомление. Глубина изучения несопоставима.

Роль reader. Когда кто-то вслух излагает код, он заставляет группу двигаться в темпе, который может выдержать самый медленный участник. Это обнажает допущения, которые скрывает тихое чтение. Diff на экране позволяет глазам пропускать скучные места. Reader не пропускает.

Фокус только на дефектах. Комментарии к pull request уходят в стилистические и архитектурные мнения. Они ценны, но это не детекция дефектов. Каждая минута, потраченная на споры об отступах, — это минута, не потраченная на поиск null dereference.

Измеримые данные процесса. Fagan Inspections давали твёрдые цифры: дефектов в час, время подготовки, время доработки, defect density по модулям. Современные инструменты ревью считают комментарии и approvals, которые почти ничего не говорят о качестве ревью.

Практический компромисс

Вы не станете проводить полноценные Fagan Inspections в современной среде continuous deployment. Но можно позаимствовать те части, которые имеют значение.

Самая важная переносимая идея — структурированная независимая подготовка. Перед глубоким async-ревью требуйте, чтобы reviewer проводили время с материалом в одиночестве. Не быстрый просмотр. Настоящая подготовка.

Вместо генерического «LGTM» введите lightweight-чеклист, имитирующий дисциплину, которую Фаган заложил в роли и правила:

from dataclasses import dataclass, field
from typing import List, Optional
from enum import Enum

class DefectSeverity(Enum):
    MINOR = "minor"
    MAJOR = "major"
    CRITICAL = "critical"

@dataclass
class ReviewEntry:
    line_number: Optional[int]
    category: str
    severity: DefectSeverity
    description: str

@dataclass
class InspectionReport:
    reviewer: str
    prep_time_minutes: int
    entries: List[ReviewEntry] = field(default_factory=list)

    def defect_count(self) -> int:
        return len(self.entries)

def run_inspection_checklist(
    code: str,
    reviewer: str,
    prep_time_minutes: int
) -> InspectionReport:
    """Structured prep produces structured output.

    Mimics the Fagan prep phase: reviewer spends focused
    time with the material, then logs findings against a
    consistent taxonomy instead of ad hoc comments.
    """
    report = InspectionReport(
        reviewer=reviewer,
        prep_time_minutes=prep_time_minutes
    )

    # Example: check for missing null handling
    if "->" in code and "null" not in code.lower():
        report.entries.append(ReviewEntry(
            line_number=None,
            category="null-safety",
            severity=DefectSeverity.MAJOR,
            description="No explicit null handling in pointer function"
        ))

    return report

Это не Fagan Inspection. Это способ вернуть одно из её важнейших свойств: вывод ревью должен быть структурированным, измеримым и сфокусированным на категориях дефектов, а не на мнениях.

Ещё одна переносимая идея — time-boxed глубокое ревью. Выбирайте один критический модуль на спринт. Планируйте 90-минутное сфокусированное ревью с независимой подготовкой. Фиксируйте только дефекты. Без решений, без стилистических споров, без архитектурных дискуссий.

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

Неудобная правда

Fagan Inspections не провалились. Они были отвергнуты, потому что строгость, которую они требовали, была несовместима со скоростью, которую приоритизировала индустрия.

Этот компромисс имел смысл для многих программных продуктов. Опечатка на кнопке landing page не нуждается в пятиглавой формальной инспекции. Но культура, заменившая Fagan Inspections, относится ко всему коду одинаково, и именно здесь скрывается цена.

Самые дорогие дефекты находятся в коде, который выглядит правильным, проходит тесты и падает в продакшене способами, которые стоят реальных денег. Это именно тот код, который больше всего выигрывает от процесса, предназначенного для поиска дефектов, а не от процесса, предназначенного для одобрения diffs.

Ревью pull request останется с нами, и это нормально. Но притворяться, что оно заменяет структурированную инспекцию, — не нормально. Это другой инструмент для другой задачи, и команды, которым доступен лишь один из них, будут и дальше находить дорогие баги, которые лучший процесс поймал бы до деплоя.

FAQ

Что такое Fagan Inspection?

Структурированный многофазный процесс ревью для поиска дефектов в программных артефактах, разработанный Майклом Фаганом в IBM в 1970-х годах. Он включает шесть фаз (Planning, Overview, Preparation, Inspection Meeting, Rework, Follow-up) с чёткими ролями участников. Встреча сосредоточена исключительно на фиксации дефектов, а не на их устранении.

Насколько эффективными были Fagan Inspections?

IBM сообщала о показателях устранения дефектов свыше 90 процентов. Исследование NASA 2002 года показало, что каждый час инспекции в среднем предотвращал 33 часа сопровождения. Независимые исследования последовательно обнаруживали, что структурированная инспекция находит примерно вдвое больше дефектов, чем неформальное ревью.

Почему команды перестали использовать Fagan Inspections?

Процесс поглощал от 15 до 20 процентов общих трудозатрат проекта, требовал сложного планирования участия нескольких людей и был культурно жёстким. По мере того как команды переходили к более коротким циклам релизов, overhead стал неподъёмным. Ревью pull request заменило его по умолчанию, потому что оно быстрее и проще интегрируется в обычный workflow, хотя и находит меньше дефектов.

Могут ли современные команды по-прежнему извлечь пользу из Fagan Inspections?

Не в оригинальной форме. Полный шестифазный процесс с назначенными ролями не подходит для continuous deployment. Но ключевые идеи — независимая подготовка, time-boxed сфокусированное ревью, структурированная регистрация дефектов и разделение поиска дефектов и проектирования решений — могут быть адаптированы. Команды, которые избирательно применяют их к критичному коду, получают большую часть выгоды без overhead.