Cleanroom software engineering process IBM обеспечил 0,1 defect на тысячу строк кода. Промышленный средний показатель в то время колебался между 10 и 50. Процесс был задокументирован, реплицирован и независимо верифицирован на множестве проектов и языков. Затем он исчез.

Не потому, что его заменил лучший метод. Zero-defect engineering исчез, потому что изменились экономические условия, которые делали его ценным, а условия, которые делали его возможным, так и не распространились за пределы горстки government contractors.

Проблема: дефекты закладывались с самого начала

Большинство software создаётся на основе неявного предположения, что bugs неизбежны. Вы пишете code, запускаете его, находите проблемы, исправляете. Цикл кажется продуктивным. Это также уступка тому, что ваш process производит defects как нормальный output.

Cleanroom полностью отверг это предположение. Разработанный Харланом Миллсом в IBM в 1970-х, метод рассматривал software как производство полупроводников. Вы не тестируете качество в chip после изготовления. Вы предотвращаете условия, создающие defects изначально.

Метод включал три взаимосвязанные практики. Incremental development под statistical process control. Function-theoretic design с использованием структур black-box, state-box и clear-box. И правило, которое сломало больше всего мозгов: люди, написавшие code, были запрещены от его выполнения.

Это не был садизм. Это была forcing function. Если вы не можете запустить свой code, чтобы увидеть, работает ли он, вы должны рассуждать о корректности до того, как начнёте печатать.

Цифры не были случайностью

IBM Federal Systems Division применила Cleanroom к системе управления спутником NASA и измерила 0,1 defect на KLOC в финальном тесте. Система выставления счетов на COBOL достигла 0,3. Система реального времени на Ada достигла 0,4. Результаты сохранялись в разных командах, доменах применения и языках программирования.

Процесс также сжимал schedules. Промышленные данные того времени показывали, что 50–70 процентов усилий по software уходило на testing и debugging. Команды Cleanroom тратили это время на design вместо этого. Code работал с первой попытки компиляции.

Почему рабочий процесс был заброшен

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

Краткий ответ: экономика software инвертировалась между 1990 и 2010 годами. Полный ответ: zero-defect engineering был оптимизирован для мира, который перестал существовать.

В 1970-х и 1980-х software поставлялся на физических носителях. Bug в production требовал recall, patch-диска или выездного техника. Стоимость defect была огромной. Zero-defect engineering был дорогим, но один предотвращённый recall окупал весь process.

Web изменил cost function. Сегодня мы deploy по проводам. Bug попадает в production, мы делаем rollback за минуты, patch за часы. Стоимость одного defect упала на порядки. Стоимость zero-defect engineering не упала вообще. Он всё ещё требует formal verification, statistical process control и того, чтобы разработчики не запускали свой собственный code. Эти практики потребляют время, которое modern product development отказывается тратить.

Ловушка взаимозависимости

Cleanroom — это не меню. Вы не можете адаптировать только понравившиеся части.

Statistical process control работает только если вы измеряете каждый increment и останавливаетесь, когда defect targets пропущены. Box structures работают только если вы верифицируете каждый уровень перед написанием следующего. No-execution rule работает только если она абсолютна. Разработчик, который «просто быстро проверит, компилируется ли это», разрушает forcing function.

Частичное внедрение даёт вам ни одного из benefits и весь overhead. Команда не может попробовать Cleanroom на один sprint. Они должны реструктурировать весь свой cycle, переподготовить каждого разработчика и собирать данные process в течение месяцев. Большинство manager, столкнувшихся с этим proposal, нанимают вместо этого ещё одного QA engineer.

Velocity premium убил quality premium

Современный software конкурирует на time-to-market. Преимущество first mover в consumer software стоит дороже, чем стоимость исправления bugs после запуска. Инвесторы вознаграждают growth curves, а не метрики defect density.

Zero-defect engineering оптимизирован для другого scoreboard. Он предполагает, что корректность — это primary constraint, а давление schedule — вторичное. Это было верно для систем управления спутниками NASA. Это не верно для startup, пытающегося ship раньше конкурента.

Культурное несоответствие уходит глубже. Разработчикам нравится запускать code. Немедленный цикл обратной связи write-run-fix приносит удовлетворение. Cleanroom просит вас отложить это удовлетворение до тех пор, пока вы не обдумаете каждый edge case.

Промышленность выбрала другой social contract. Мы терпим bugs в обмен на speed, и патчим их в обмен на continuous feedback. Это рациональный trade. Это также причина, по которой среднее web application имеет defect rate, ближе к среднему показателю 1980-х, чем к цифрам Cleanroom IBM.

На что мы его променяли

Заменой стал набор практик, отдающих приоритет iteration над корректностью.

Continuous integration ускорило нахождение bugs, но не сделало code correct by construction. Agile сократил feedback loops, но также сократил design phases. Test-driven development всё ещё предполагает loop write-test-fix, который Cleanroom отверг.

Ни одна из этих практик не плоха. Современный stack оптимизирован для выяснения, чего хотят пользователи. Zero-defect engineering оптимизировал корректную реализацию известной specification.

Что можно украсть, не внедряя всю систему

Вероятно, вы не сможете внедрить полный Cleanroom в своей компании. Но лежащие в основе principles переносятся, и некоторые современные tools аппроксимируют строгость метода без его overhead.

Пишите contracts, а не только comments. Определяйте preconditions и postconditions явно и enforce их в code.

from dataclasses import dataclass
from decimal import Decimal

@dataclass(frozen=True)
class Transfer:
    from_balance: Decimal
    to_balance: Decimal
    amount: Decimal

    def execute(self) -> tuple[Decimal, Decimal]:
        # Preconditions stated and checked
        assert self.amount > 0, "transfer amount must be positive"
        assert self.from_balance >= self.amount, "insufficient funds"

        new_from = self.from_balance - self.amount
        new_to = self.to_balance + self.amount

        # Postcondition: total value is conserved
        assert new_from + new_to == self.from_balance + self.to_balance
        return new_from, new_to

Кодируя предположения как executable checks, вы превращаете неявное reasoning в явные guards, заставляющие вас продумывать edge cases во время development.

Используйте property-based testing как statistical process control. Cleanroom использовал statistical testing на основе usage profiles. Современные инструменты property-based testing делают нечто аналогичное, генерируя random inputs и верифицируя invariants.

from hypothesis import given, strategies as st
from datetime import datetime, timedelta

@given(
    start=st.datetimes(min_value=datetime(2000, 1, 1)),
    delta=st.timedeltas(min_value=timedelta(0), max_value=timedelta(days=365))
)
def test_duration_roundtrips(start, delta):
    """Adding then subtracting the same duration must return the original."""
    assert start + delta - delta == start

Этот test assert-ит mathematical property на огромном input space. Когда он находит контрпример, он shrink-ается к minimal failing case. Вы проверяете структуру computation, а не конкретные примеры.

Делайте invalid states unrepresentable. Box structure methodology Cleanroom заключался в определении поведения на возрастающих уровнях детализации. Современный эквивалент — использование static types для предотвращения незаконных состояний.

from typing import NewType

UserId = NewType("UserId", int)
OrderId = NewType("OrderId", int)

def fetch_order(order_id: OrderId) -> dict:
    ...

# This will not compile in a typed codebase:
# fetch_order(UserId(42))  # type error: expected OrderId, got UserId

Type checker становится verification layer, запускающейся до любого test. Вы не можете передать user ID туда, где ожидается order ID, потому что type system делает эту ошибку структурно невозможной.

Где это всё ещё важно

Zero-defect engineering не стал неправильным. Он стал niche.

Он всё ещё используется в safety-critical доменах, где один bug убивает людей. Medical devices, avionics и nuclear control systems по-прежнему используют процессы, производные от Cleanroom, потому что стоимость defect остаётся астрономической. Стандарты FDA и DO-178C сохраняют многие из тех же идей под другими именами.

Для остальных из нас bug в web application стоит support ticket и один deploy. Bug в pacemaker стоит жизни. Метод не перестал работать. Мы перестали нуждаться в нём.

Неприятная правда

Zero-defect engineering исчез не потому, что потерпел неудачу, а потому, что промышленность переопределила success. Цель сместилась от «ship software, работающее с первого раза» к «ship software достаточно быстро, чтобы сломанные версии были заменены до того, как пользователи заметят».

Это оправданный trade. Он построил современный internet. Это также означает, что большинство software строится процессами, математически гарантированными оставлять defects, и мы принимаем это, потому что исправлять их позже теперь достаточно дёшево.

Вам не нужно внедрять Cleanroom, чтобы писать лучший code. Начните с одной function. Напишите её contract до body. Запустите property-based tests против ваших invariants. Используйте types, чтобы сделать illegal states недостижимыми. Отслеживайте, откуда приходят ваши bugs, и исправляйте process, их производящий.

Zero defects на KLOC, вероятно, не ваша цель. Но понимание, почему метод работал и почему мы перестали заботиться, говорит о чём-то важном относительно того, что ваш process реально оптимизирует. Большинство команд никогда явно не делали этого выбора. Они унаследовали его от промышленности, которая десятилетия назад выбрала velocity вместо correctness, и так и не оглянулась назад.