Среднее значение по индустрии программного обеспечения в 1980-х годах составляло от 30 до 60 дефектов на тысячу строк кода. Команда Cleanroom в IBM поставила инкремент компилятора объёмом 20 000 строк, в котором при тестировании было найдено 53 дефекта. Это 2,6 на KLOC. Некоторые отдельные инкременты объёмом 10 000 строк прошли системное тестирование без обнаруженных дефектов.

Самая странная часть? Программистам было запрещено запускать собственный код.

Что на самом деле означает Cleanroom software engineering

Cleanroom software engineering, разработанная математиком Харланом Миллсом в IBM в 1980-х годах, — это процесс, основанный на теории, который опирается на formal specification, structured design и mathematical correctness verification вместо Unit Testing и debugging. Название пришло из производства полупроводников. На чиповом заводе ты не вносишь пыль, чтобы потом её стереть. Ты предотвращаешь загрязнение изначально.

В Cleanroom разработчики не проводят Unit Testing. Они не дебажат. Они верифицируют.

Процесс разбивает ПО на инкременты, обычно от 5 000 до 15 000 строк кода. Каждый инкремент специфицируется, проектируется, верифицируется, а затем статистически тестируется как законченная единица. Разработчики пишут код, но им не разрешается компилировать или выполнять его в процессе разработки. Первый раз код запускается во время формального системного тестирования.

Как box structure verification заменяет debugging

Ключевой механизм — box structure specification. Каждый компонент определяется на трёх уровнях.

black box специфицирует внешнее поведение. Она определяет стимулы и отклики, не упоминая внутреннее состояние.

state box добавляет внутренние переменные состояния и функцию перехода состояний.

clear box — это непосредственная реализация, которая должна быть структурированным уточнением state box.

Эта иерархия важна, потому что она позволяет верифицировать корректность на каждом уровне независимо. Ты доказываешь, что state box реализует black box, и что clear box реализует state box.

Вот как это выглядит на практике для функции с нетривиальным correctness argument:

from typing import Optional

def binary_search(arr: list[int], target: int) -> Optional[int]:
    """
    Black box spec:
      Pre:  arr is sorted in non-decreasing order.
      Post: Returns index i such that arr[i] == target,
            or None if target is not present.
    """
    low, high = 0, len(arr) - 1

    while low <= high:
        mid = (low + high) // 2

        if arr[mid] == target:
            return mid
        elif arr[mid] < target:
            low = mid + 1
        else:
            high = mid - 1

    return None

verification argument для цикла — это то, что имеет значение. Команда совместно просматривает его и подтверждает три факта. Во-первых, если arr[mid] == target, postcondition выполняется немедленно. Во-вторых, если arr[mid] < target, target может существовать только по индексам больше mid, поэтому установка low = mid + 1 сохраняет invariant, что target находится в arr[low:high+1], если он вообще существует. В-третьих, если arr[mid] > target, симметричный аргумент справедлив для high = mid - 1.

Это не Code Review, где кто-то спрашивает, подумал ли ты о пустых массивах. Это структурированное групповое доказательство, что любой возможный вход производит специфицированный выход.

Цифры IBM за zero-defect заявлением

IBM применяла Cleanroom к трём крупным проектам в конце 1980-х и начале 1990-х годов: COBOL Structuring Facility (40 000 строк), программа полёта вертолёта ВВС (35 000 строк) и система планирования космических перевозок NASA (45 000 строк).

Данные COBOL/SF — наиболее подробные. Первый инкремент объёмом 20 000 строк был разработан с formal specifications, box structure design и групповой correctness verification. Разработчикам не разрешалось компилировать или запускать свои модули в процессе разработки. Код сразу попадал в системное тестирование.

Результат: 53 дефекта найдено во время тестирования. Более 90 % всех дефектов были пойманы на фазе верификации до того, как код был выполнен.

Для сравнения, на обычных проектах IBM того времени находили около 60 % дефектов до выполнения. Cleanroom перевернул это соотношение.

Некоторые инкременты, особенно меньшие — менее 10 000 строк, показали ноль дефектов, найденных при системном тестировании. Отсюда происходит заявление о «10 000 строках с нулевым количеством дефектов». Это действительно случилось. Это было не универсально, но достаточно воспроизводимо, чтобы IBM сделала это стандартным бенчмарком.

Почему отказ от запуска собственного кода даёт меньше багов

Это та часть, которая взрывает мозг разработчикам. Как может отсутствие тестирования давать лучший код?

Ответ когнитивный, а не технический. Когда ты знаешь, что не можешь запустить код, чтобы проверить свою работу, ты проектируешь внимательнее. Ты пишешь меньшие функции. Ты думаешь о крайних случаях до того, как начать печатать. Ты опираешься на Type System и структурное программирование, потому что у тебя нет страховочной сети.

Это та же причина, по которой хирурги используют чек-листы. Ограничение заставляет переключиться на другой ментальный режим.

Также существует слой статистического контроля качества. Cleanroom использует statistical usage testing на основе operational profile. Тестовые случаи выбираются из вероятностного распределения реального поведения пользователя, а не из догадок разработчика о том, где находятся баги. Это означает, что ты измеряешь надёжность, а не просто охотишься на баги.

Trade-offs, которые удержали Cleanroom в нише

Cleanroom не захватила мир. Есть причины.

Во-первых, барьер обучения высок. Тебе нужны команды, которые умеют писать formal specifications и строить mathematical correctness arguments. Большинство выпускников CS в 2025 году никогда не делали формального доказательства для нетривиальной функции.

Во-вторых, upfront затраты на проектирование высоки. IBM сообщала, что текст specification превышал текст design в четыре раза на проекте COBOL/SF. Ты обмениваешь время проектирования на время тестирования. Это работает для компиляторов и flight software. Это не работает для CRUD-приложения с еженедельными требованиями к pivot.

В-третьих, zero-defect заявление относится к defect density, а не к отсутствию всех багов. Инкремент Cleanroom всё ещё может содержать specification errors. Если black box неверна, верифицированная clear box тоже неверна, просто по построению.

Как украсть дисциплину Cleanroom без бюрократии

Ты, вероятно, не можешь внедрить полный Cleanroom. Твой Product Manager не будет ждать соотношения specification-к-коду четыре к одному. Но ты можешь украсть ценные части.

1. Пиши contract до реализации.

Используй preconditions, postconditions и invariants для определения своей black box. Даже неформальные комментарии заставляют тебя думать о границах до оптимизации.

from typing import List, Tuple

def partition(nums: List[int], pivot: int) -> Tuple[List[int], List[int]]:
    """
    Black box spec:
      Pre:  True (any list of integers is valid).
      Post: left contains exactly the elements of nums where x <= pivot.
            right contains exactly the elements of nums where x > pivot.
            len(left) + len(right) == len(nums).
    """
    left = [x for x in nums if x <= pivot]
    right = [x for x in nums if x > pivot]

    # Runtime checks act as lightweight verification witnesses.
    assert all(x <= pivot for x in left)
    assert all(x > pivot for x in right)
    assert len(left) + len(right) == len(nums)

    return left, right

2. Замени некоторые Unit Tests на verification arguments.

Прежде чем писать тест, напиши одно предложение-аргумент, почему код корректен. Если ты не можешь построить это предложение, дизайн слишком сложен. Это самая эффективная практика Cleanroom для современных команд.

3. Используй property-based testing как statistical usage testing.

Инструменты вроде Hypothesis в Python или fast-check в JavaScript генерируют входные данные из распределения. Это духовно ближе к statistical testing Cleanroom, чем примерные Unit Tests.

4. Отделяй компиляцию от верификации.

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

FAQ

Используется ли Cleanroom сегодня?

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

Могу ли я действительно поставлять код без Unit Testing?

Только если ты заменишь его чем-то столь же строгим. Команды Cleanroom тратили больше часов на верификацию, чем большинство команд на testing. Время не исчезло. Оно сдвинулось влево.

Гарантирует ли Cleanroom ноль багов?

Нет. Она гарантирует, что implementation соответствует specification с высокой вероятностью. Если specification неверна, баг сохраняется идеально.

Каково было влияние на продуктивность?

IBM сообщала о продуктивности более 400 строк кода на человеко-месяц на проекте COBOL/SF, во многом потому, что резко сокращённое время тестирования компенсировало увеличенные затраты на проектирование.

Итог

В следующий раз, когда кто-то заявит, что методология обеспечивает zero-defect ПО, потребуй данные проекта. Цифры Cleanroom IBM реальны, но они пришли из конкретного контекста: опытные команды, формальное обучение, инкрементальная поставка и готовность верифицировать вместо того, чтобы дебажить.

Инкремент объёмом 10 000 строк с нулевым количеством дефектов достижим. Это просто стоит большего предвидения, чем большинство организаций готовы заплатить.