5 марта 2026 года в своём доме, в окружении семьи, тихо умер человек, чей код вы трогали на этой неделе. Возможно, прямо сегодня. Возможно, он уронил вам прод.
Звали его сэр Чарльз Энтони Ричард Хоар. Для друзей — Тони. Для пары поколений студентов — C. A. R. Hoare, тот самый, что в 26 лет придумал quicksort, выиграв у начальника спор на шесть пенсов. Тьюринговская премия 1980 года, логика Хоара, CSP, на которой потом выросла половина теории конкурентности. Большая, красивая, почти безупречная карьера.
Почти. Потому что в 1965 году тот же самый человек добавил в язык одну маленькую штуку. И эта штука пережила его, переживёт нас и, скорее всего, прямо сейчас лежит где-то в вашем стектрейсе.
Это null.
Есть расхожий сюжет: коварная индустрия наплодила багов, а гениальные инженеры героически с ними борются. Красиво. И, как обычно, неправда. Потому что самый дорогой баг в истории софта добавил не злодей и не нерадивый джун. Его добавил один из умнейших людей в истории 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-м. Это была вежливая оценка. К 2026-му, с учётом всех NPE, всех сегфолтов, всех ночных дежурств и всех CVE — цифру можно смело считать заниженной на пару порядков.
«Но ведь null удобен и вообще нужен»
Стандартный контраргумент. Он звучит разумно, и в нём кроется ровно та же ошибка, что и в 1965-м.
Да, понятие «значения нет» — нужно. Запрос ничего не нашёл, поля нет, опциональный параметр не передали — это нормальные, законные ситуации. Проблема не в идее «отсутствующего значения». Проблема в том, как именно Хоар её реализовал: он сделал null невидимым для системы типов.
То есть язык знает, что значение может отсутствовать, но никак тебя об этом не предупреждает и ничего не требует. «Тут может быть пусто» и «тут гарантированно есть значение» выглядят в коде абсолютно одинаково. Вся ответственность — на человеке, который должен помнить про каждую дырку вручную. А человек, сюрприз, не помнит. Никогда. Особенно в чужом коде на 200 тысяч строк.
Это и есть billion-dollar mistake. Не сам null. А null, который компилятор молча пропускает.
Как это в итоге починили
Самое интересное началось как раз после того доклада 2009 года. Языки, которые проектировали уже с оглядкой на признание Хоара, эту дырку начали заделывать — каждый по-своему, но в одну сторону: отсутствие значения должно быть видно в типе, и компилятор должен заставить тебя его обработать.
В Haskell это Maybe. В Rust — Option<T>, и raw-null там просто нет как класса
Разница принципиальная. В Java компилятор молчал, и ты узнавал о проблеме в проде. В Rust компилятор не даёт собрать программу, пока ты явно не ответишь на вопрос «а если тут пусто?». Дырку в стене вернули обратно в чертёж — и заварили на этапе компиляции.
То же самое, разными путями, сделали и остальные, кто учился на чужих граблях: Swift с его optionals и синтаксисом String?, Kotlin с nullable-типами и оператором ?., C# с nullable reference types, TypeScript со strictNullChecks. Все они, по сути, реализуют ту самую исходную мечту Хоара из 1965-го — «любое обращение по ссылке безопасно». Просто на 50 лет позже и уже зная, чем заканчивается соблазн «так проще».
Тут полагается мораль про важность хороших систем типов. Она верная, но скучная, и вы её и так знаете.
Хоар не был дураком. Он был ровно противоположностью дурака — один из самых строгих, формальных, помешанных на корректности умов в истории дисциплины. Человек, который буквально придумал математический аппарат для доказательства правильности программ. И даже он не устоял перед «давай добавим вот эту маленькую удобную штуку, я же знаю, что делаю».
Каждый из нас принимает такое решение по десять раз на дню. Захардкодить. Не покрыть тестом. Пропустить проверку, «потому что сюда null никогда не придёт». Оставить `// TODO: обработать позже». Это всё — маленькие null’ы 1965 года. Большинство из них не выстрелит. Какой-то один — переживёт вас и будет ронять чей-то прод в 2086-м.
И вот ещё что. Настоящее наследие Хоара — не в том, что он ошибся. А в том, что он встал перед полным залом и сказал вслух: я был неправ, и вот сколько это стоило. Именно это признание, а не сама ошибка, в итоге родило Option, Maybe и optionals. Индустрия чинит null до сих пор — но чинить начала только после того, как автор набрался смелости назвать вещи своими именами.
Он умер 5 марта. Quicksort останется в учебниках. Логика Хоара — в курсах по верификации. А его «ошибка на миллиард долларов» останется в каждом Option<T>, который существует ровно потому, что один очень умный человек не побоялся признать, что облажался.
ссылка на оригинал статьи https://habr.com/ru/articles/1045718/