- PVSM.RU - https://www.pvsm.ru -
5 марта 2026 года в своём доме, в окружении семьи, тихо умер человек, чей код вы трогали на этой неделе. Возможно, прямо сегодня. Возможно, он уронил вам прод.
Звали его сэр Чарльз Энтони Ричард Хоар. Для друзей — Тони. Для пары поколений студентов — C. A. R. Hoare, тот самый, что в 26 лет придумал quicksort, выиграв у начальника спор на шесть пенсов. Тьюринговская премия 1980 года, логика Хоара, CSP, на которой потом выросла половина теории конкурентности. Большая, красивая, почти безупречная карьера.
Почти. Потому что в 1965 году тот же самый человек добавил в язык одну маленькую штуку. И эта штука пережила его, переживёт нас и, скорее всего, прямо сейчас лежит где-то в вашем стектрейсе.
Это null.
Есть расхожий сюжет: коварная индустрия наплодила багов, а гениальные инженеры героически с ними борются. Красиво. И, как обычно, неправда. Потому что самый дорогой баг в истории софта добавил не злодей и не нерадивый джун. Его добавил один из умнейших людей в истории computer science.
Вот про эту историю и поговорим.
В 2009 году на конференции QCon в Лондоне Хоар вышел к залу, набитому инженерами, и сделал то, чего легенды его уровня не делают почти никогда. Он не рассказал, как был прав. Он признался, что был неправ.
Дословно он назвал это так: my billion-dollar mistake. Ошибкой на миллиард долларов. И речь шла не о quicksort, не о логике Хоара и не о чём-то экзотическом. Речь шла о null-ссылке, которую он собственноручно изобрёл в 1965-м.
Зал, говорят, притих. Потому что каждый в этом зале на той неделе ловил NullPointerException.
Контекст важен, иначе вся ирония теряется.
Хоар в тот момент проектировал систему типов для 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 — цифру можно смело считать заниженной на пару порядков.
Стандартный контраргумент. Он звучит разумно, и в нём кроется ровно та же ошибка, что и в 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>, который существует ровно потому, что один очень умный человек не побоялся признать, что облажался.
Автор: Claritas
Источник [1]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/null/453074
Ссылки в тексте:
[1] Источник: https://habr.com/ru/articles/1045718/?utm_source=habrahabr&utm_medium=rss&utm_campaign=1045718
Нажмите здесь для печати.