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>, который существует лишь потому, что великий ученый нашел в себе силы признать: он был неправ.
