«Ошибка на миллиард»: как один человек в 1965 году внедрил null и изменил IT-индустрию навсегда

5 марта 2026 года в кругу семьи тихо ушел из жизни человек, чей программный код вы наверняка затрагивали на этой неделе. Не исключено, что именно из-за него сегодня «упал» ваш продакшн.

Этого человека звали сэр Чарльз Энтони Ричард Хоар. Близкие называли его Тони, а поколения студентов знают его как C. A. R. Hoare — гения, который в 26 лет изобрел алгоритм быстрой сортировки, выиграв спор у своего начальника на шесть пенсов. Он лауреат премии Тьюринга 1980 года, автор логики Хоара и концепции CSP, ставшей фундаментом для современной теории параллельных вычислений. Его карьера была монументальной, впечатляющей и практически безупречной.

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

Речь о null.

Существует популярный миф, будто IT-индустрия наполнена багами, с которыми героически сражаются инженеры. Это звучит красиво, но не имеет отношения к реальности. Самый дорогостоящий баг в истории разработки был допущен не злодеем или неопытным новичком, а одним из самых светлых умов в истории computer science.

Давайте разберемся, как это случилось.


Человек, нашедший в себе силы извиниться спустя 44 года

В 2009 году на конференции QCon в Лондоне Хоар совершил поступок, немыслимый для легенды его масштаба: он вышел к аудитории и открыто признал свою неправоту.

Он назвал свое изобретение «ошибкой на миллиард долларов» (my billion-dollar mistake). И это касалось не великого Quicksort или стройных логических систем, а простой null-ссылки, которую он единолично ввел в 1965-м.

Зал погрузился в тишину. Каждый присутствующий инженер понимал, о чем идет речь — ведь за ту неделю многие из них столкнулись с NullPointerException.


1965-й: как это стало возможным

Важно понимать контекст, иначе весь трагизм этой истории ускользнет.

В то время Хоар проектировал систему типов для ALGOL W — по сути, первую полноценную систему типов для объектно-ориентированного программирования. Его амбициозная цель граничила с утопией: он хотел сделать обращение по ссылке абсолютно безопасным. Он стремился к тому, чтобы компилятор автоматически исключал любую возможность обращения к несуществующему объекту.

Представьте: человек возводил крепость, главная задача которой — сделать «выстрел в ногу» физически невозможным. А потом сам же проделал в этой стене брешь.

Почему? Хоар объяснил это обезоруживающе честно: добавление null-ссылки было простым решением. Буквально пара строчек кода. Соблазн оказался сильнее принципов. Он осознавал, что это разрушает всю концепцию безопасности, но все равно сделал это.

«Так проще» — фраза, которая обошлась индустрии дороже, чем любые кибератаки, ошибки новичков или провальные технологии.


Во сколько обходится «простота»

Давайте оценим масштаб ущерба от этой бреши в системе безопасности.

null — это значение, которое одновременно утверждает «здесь ничего нет» и притворяется полноценным объектом. Тип переменной заявляет: «я строка», но внутри — пустота. И в тот миг, когда программа пытается обратиться к этой пустоте как к строке, она рушится.

Мы знаем это под разными масками:

  • В Java — NullPointerException (NPE), кошмар любого, кто хоть раз выкладывал код на прод.

  • В C и C++ — segmentation fault; программа не просто падает с ошибкой, а умирает на месте, порой прихватывая с собой данные.

  • В JavaScript — легендарное «Cannot read properties of undefined», ставшее и мемом, и стилем жизни разработчика.

  • В Go, Python, C#, PHP — названия разные, а боль от «неожиданного нуля» одна и та же.

Это не просто «ошибка джуна», это системный порок. OWASP годами включает null dereference в списки критических уязвимостей, через которые взламывают сервисы. Оценка «миллиард долларов», данная Хоаром в 2009-м, сегодня выглядит крайне скромной. С учетом всех падений, ночных дежурств и CVE-уязвимостей, реальный ущерб выше на порядки.


«Но ведь null — это удобно и необходимо»

Этот аргумент кажется логичным, но он воспроизводит ту самую ошибку 1965 года.

Безусловно, концепция отсутствия значения важна: поиск не дал результатов, параметр не задан, поле не заполнено. Проблема не в самой идее, а в реализации Хоара: он сделал null невидимым для системы типов.

Язык «знает», что значения может не быть, но не обязывает вас это учитывать. «Здесь может быть пусто» и «здесь гарантированно есть данные» выглядят в коде идентично. Вся ноша ответственности ложится на плечи разработчика, который должен помнить о потенциальной пустоте в каждой строке. А человек, как известно, не склонен к идеальной памяти, особенно работая с чужим кодом на сотни тысяч строк.

В этом и заключается «ошибка на миллиард». Не в существовании null, а в том, что компилятор игнорирует его присутствие.


Как индустрия провела работу над ошибками

После выступления Хоара в 2009 году многие современные языки начали избавляться от этой уязвимости. Общий вектор прост: факт отсутствия значения должен быть зафиксирован в типе данных, чтобы компилятор принудительно заставил вас его обработать.

В Haskell это Maybe. В Rust — Option<T>, где сырых null-указателей не существует в принципе.

Разница колоссальна. В Java компилятор молчит, и вы узнаете о проблеме только на проде. В Rust программа просто не соберется, пока вы явно не ответите на вопрос: «что делать, если тут пусто?». Брешь в стене наконец заделали на этапе компиляции.

Этот путь с разной степенью успеха прошли Swift (optionals), Kotlin (nullable-типы и оператор ?.), C# (nullable reference types) и TypeScript (strictNullChecks). Все они воплощают ту самую изначальную мечту Хоара из 1965 года — сделать каждое обращение безопасным. Просто на полвека позже.


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

Хоар не был недалеким человеком. Напротив, он был воплощением академической строгости и одержимости корректностью программного обеспечения. Он создал математический аппарат для доказательства правильности кода. И даже он не устоял перед соблазном «добавить маленькую удобную фичу, я же контролирую ситуацию».

Мы делаем подобный выбор ежедневно: захардкодить значение, пропустить написание теста, проигнорировать проверку, потому что «сюда null точно не придет», оставить комментарий `// TODO: исправить позже`. Это и есть маленькие null’ы нашего времени. Большинство из них не вызовут катастрофы. Но какой-то один переживет нас и будет обрушивать продакшн в 2086 году.

И последнее. Настоящее величие Хоара — не в том, что он ошибся. А в том, что он нашел мужество признать это перед всем миром. Именно это признание подтолкнуло индустрию к созданию более надежных механизмов вроде Option и Maybe. Он дал нам шанс исправить его ошибку.

Чарльз Хоар ушел, но его Quicksort навсегда останется в учебниках, логика Хоара — в основах верификации, а его признание ошибки на миллиард долларов живет в каждом современном типе Option<T>, который существует лишь потому, что великий ученый нашел в себе силы признать: он был неправ.

 

Источник

Читайте также