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

Я называю это своей ошибкой на миллиард долларов. Это было изобретение нулевой ссылки в 1965 году. В то время я разрабатывал первую всеобъемлющую систему типов для ссылок в объектно-ориентированном языке («ALGOL W). Моя цель состояла в том, чтобы гарантировать, что любое использование ссылок должно быть абсолютно безопасным, с автоматической проверкой компилятором. Но я не мог устоять перед искушением добавить нулевую ссылку просто потому, что это было так легко реализовать. Это привело к бесчисленным ошибкам, уязвимостям и системным сбоям, которые, вероятно, причинили миллиарды долларов боли и ущерба за последние сорок лет». (Тони Хоар, Нулевые ссылки: ошибка на миллиард долларов, 2009 г.)

Так что же это за нулевая ссылка? Определения различаются. Некоторые утверждают, что нулевая ссылка является выражением ложности. Под ложностью понимается то, что хотя что-то не является явно истинным, оно также не является явно ложным. Это возможно.

Хотя приведенная выше попытка ввести «может быть» в сильно формализованные системы может показаться разумной на первый взгляд, более целенаправленный анализ показывает, что она совершенно неразумна. Хорошо структурированная формализованная система не должна напоминать швейцарский сыр тем, что содержит всевозможные дыры в своей логике. Другими словами, хорошо структурированная формализованная система должна быть четко сформулированной.

Когда мы заявляем, что что-то в разработанной нами системе является ложным, мы на самом деле говорим, что наша система невнятна. Мы признаем, что на самом деле не все продумали при проектировании и создании нашей системы. Такое небрежное проектирование приводит к ненадежным, ненадежным и неисправным системам и службам.

Как построить шарнирную систему?

Давайте рассмотрим обстоятельства, при которых у кого-то может возникнуть соблазн объявить null в своей системе:

  1. Значение, которое мы ожидаем найти в системе, не было предоставлено
  2. Значение, которое мы ожидаем найти в системе, неизвестно (на данный момент)
  3. Значение, которое мы ожидаем найти в системе, неизвестно (например, «есть ли начало времени?»)

Предположим, нам нужно знать, установлен ли диалог сеанса между пользователем и системой. Если пользователь вошел в систему, значение сеанса будет найдено в системе благодаря акту входа в систему. Но если пользователь не вошел в систему, значение сеанса не будет найдено в системе. В этот момент система спроектирована так, чтобы предоставлять нулевое значение запросу «дайте мне имя вошедшего в систему пользователя». Получив нулевое значение, запросчик вздрагивает, застигается врасплох, что часто приводит к сбоям системы.

Приведенный выше сценарий иллюстрирует обстоятельство, описанное выше в пункте 1 (Значение, которое мы ожидаем найти в системе, не было предоставлено). В таком случае следующим логическим вопросом будет «будет ли это значение предоставлено позже?», на который логическим ответом будет «не знаю» (или ноль). В обоих случаях наша система застревает в неоднозначном состоянии, что является верным признаком некачественной разработки.

Каким будет решение вышеуказанной проблемы? Если тот, кто использует систему, ожидает, что система предоставит определенную ценность, а если эта ценность не была предоставлена, такая договоренность всегда становится неприятным сюрпризом для потребителя. Ответственность всегда лежит на создателе системы, чтобы гарантировать наличие однозначного значения. В этом случае на вопрос, установлен ли диалог сеанса, система должна дать четкий ответ да или нет. Предоставление расплывчатого, двусмысленного «может быть» (в форме нулевого значения) — это дешевая отговорка, которая служит только для увековечивания печально известной ошибки в один миллиард долларов.

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

Как насчет проблемы, описанной в пункте 2 — Значение, которое мы ожидаем найти в системе, неизвестно (на данный момент)? Если мы, создатели системы, знаем, что есть вероятность того, что значение будет предоставлено позже, то давать нулевой ответ, маскирующийся под может быть, определенно неправильно. Вместо того, чтобы идти на еще одну дешевую отговорку, мы должны разработать нашу систему, чтобы предлагать так называемые будущее или обещания при ответе на такие вопросы. Предоставляя будущее или обещание запрашивающему клиенту, мы выпускаем вексель, говоря, что окончательный ответ придет в конце концов. Затем любознательный клиент должен решить, хотят ли они остаться и дождаться обещанного ответа или двигаться дальше. Но такой членораздельный ответ определенно не должен заставить их рухнуть и сгореть, как это часто бывает, когда их поражает невнятный ответ, который просто говорит ноль.

Наконец, пункт 3 — Значение, которое мы ожидаем найти в системе, неизвестно (например, «есть ли начало времени?»). Давать нулевой ответ на вопрос, на который, как мы знаем, нет ответа, очень небрежно. На такие неотвеченные вопросы, если их по какой-либо причине разрешено задавать нашей системе, всегда следует отвечать постоянным значением. Вместо того, чтобы отвечать нулевым значением (пожимая плечами и говоря: «Зачем спрашивать меня?»), мы должны просто признать отсутствие знаний, предоставив постоянное значение, что-то вроде «непознаваемого».

Вывод

При проектировании формальной системы, которая должна вести себя логично, совершенно неправильно строить основу структуры системы вокруг объектов. Если спроектированная нами система в первую очередь опирается на свои объекты для предоставления ответов на вопросы, которые ставят потребители услуг системы, то мы неизбежно будем делать в ней дыры, посредством которых будут возникать различные ситуации (временно вызванные или иным образом обусловленные). ), когда эти объекты могут присутствовать или отсутствовать для предоставления ответов. Когда объект отсутствует в системе (по какой-либо причине), а встроенная в систему логика для предоставления ответа полностью полагается на присутствие этого объекта, возникает проблема в виде ужасного нулевого значения.

Вместо того, чтобы строить на таком ошибочном фундаменте, рекомендуется сместить акцент и полностью полагаться на ценности. В нашей системе должна быть реализована надежная логика, управляющая отображением и преобразованием значений; это отображение должно быть строго формализовано, а логика отображения/преобразования должна гарантировать, что система никогда не попадет в неоднозначное состояние. Таким образом, система не полагается на наличие какого-либо объекта/роли, а вместо этого просто выдает значения, когда задаются некоторые вопросы. При таком раскладе невозможно когда-либо столкнуться с ситуацией, когда ответом, который выдает столь четко сформулированная система, будет этот постыдно невнятный, расплывчатый нуль.