TGTGInsightаналитика telegramLIVE / telegram public index
← Системный сдвиг
Системный сдвиг avatar

TGINSIGHT POST

Post #792

@systemswing

Системный сдвиг

Просмотры4,130Количество просмотров
Опубликован13 авг.13.08.2025, 11:34
Содержимое поста

Содержимое

Про типизацию в разных схемах я тут уже писал, а вот вам про null-ы. С ними вообще чудеса: каждый подходит со своей логикой. Вообще, можно найти довольно много статей под заголовком "Null considered harmful", Гугл сходу выдает штук 10. Страниц выдачи. Сам Чарльз Энтони Ричард Хоар, изобретатель null reference, говорит, что это его "ошибка на миллиард долларов". Говорит, невозможно было удержаться, но "this has led to innumerable errors, vulnerabilities, and system crashes, which have probably caused a billion dollars of pain and damage in the last forty years". В чем проблема с Null? Основная проблема в том, что это семантическая черная дыра. Что конкретно означает Null каждый раз, когда он появляется, непонятно. То ли это ошибка, то ли это пропущенное значение (например, при объединении двух таблиц), то ли пустое значение, то ли элемента нет в списке, то ли есть элемент с пустым значением, и т.д. Наличие в языке значения Null подрывает всю идею статической типизации — когда мы можем проверить типы без исполнения программы. Теперь не можем, потому что всё может быть Null. Это приводит к защитному стилю программирования — каждый раз нам нужно проверять значение на Null. В некоторых языках ещё и на пустое значение, потому что они разные. Получаются конструкции типа string.IsNullOrEmpty(str). Пустое или Null. Бинарная логика становится тернарной: True, False и Null. Или даже 4-арной (я не знаю, как это читается): True, False, Null и Empty (Undefined). Во многих случаях нам нужно это различать: аватар пользователя Null потому, что мы не можем его прямо сейчас извлечь из хранилища/кэша, или пользователь его не установил (Empty) и нужно показать дефолтный? В случае интеграций всё ещё больше запутывается, когда мы используем разные языки (в некоторых null == 0, в некоторых нет, а со сравнениями вообще чудеса происходят). Удивительно, что каждый формат решает это по-своему. В XML никаких Null'ов нет, зато есть вариант с пустым тегом (<avatar/>) или просто исключение тега, когда его нет в документе. Что какая семантика означает — решать вам! Будет пустой тег пустой строкой или Null'ом? Когда как. Я видел дичь, когда <string></string> дает пустую строку, а <string/> — Empty. Впрочем, у пустого тега можно ещё поставить атрибут xsi:nil="true", но некоторые парсеры на этом ломаются. В JSON всё ещё хуже: есть отдельное значение null, и получается 6 вариантов: null, "", 0, [], {}, пропущенное значение. Все они разные и не равны друг другу. Зато в Protobuf вообще нет Null! Вот я понимаю — концептуальная целостность! Выкручивайтесь как хотите. Зато там есть значения по умолчанию для типов (0, "", false), и механизм для явного указания пропущенных полей. Помним, что protobuf бинарный и стремится к уменьшению размера сообщения, а для передачи null нужно было бы накручивать дополнительную семантику. А вот в Avro есть отдельный тип null, который ни с каким другим типом не совместим, так что нужно его в схеме явно указывать: это поле может иметь два типа — int и null. Зато в GraphQL Null'ы резвятся вовсю: все типы по умолчанию nullable, и нужно специально указывать, если вы хотите это отключить. Null в GraphQL — в первую очередь признак ошибки (значение этого поля по какой-то причине не удалось предоставить). Потому что GraphQL пытается отправить хоть какую-то информацию, пусть даже неполную. Это же позволяет гибко управлять доступом (вернем null в тех полях, которые недоступны этому клиенту) и допускает эволюцию схемы без изменения старых клиентов (мы выкинули какое-то поле, а клиент его запрашивает? Ну просто вернем ему null!). Кстати, вопрос про эволюцию схемы данных можно смело задавать на собеседовании, ещё один в копилочку :) Ну а про null'ы — если нужно зачем-то кандидата засыпать 🥴