Типы данных и справочники
Мелочи, которые стоят дорого: обязательное отчество, статус свободным текстом, время в локальной зоне. Спрашивают про них именно потому, что здесь сразу видно, разгребал ли человек последствия таких решений.
Стержень: тип и ограничение выбирают из смысла данных и будущих запросов к ним, а не из удобства ввода в текущей форме.
// Формулировки: «в каком типе хранить сумму?», «зачем справочник вместо текста?», «чем пустое значение отличается от пустой строки?»
Деньги, время, перечисления
Деньги хранят в десятичном типе с фиксированной точностью и обязательно рядом валюту. Плавающая точка тут не годится: 0.1 не представима в двоичной системе точно, погрешность накапливается, и первой её замечает бухгалтерия на сверке.
Момент времени хранят в универсальном времени, а часовой пояс события держат отдельным полем, если он нужен для отображения. Хранение в локальном времени сервера обесценивается при переезде инфраструктуры и рвётся на переходах на летнее время, где один и тот же час случается дважды.
Статус свободным текстом гарантированно даёт «Новый», «новый», «НОВЫЙ» и «Новая» в одной колонке - причём все четыре введут разные люди с полной уверенностью в своей правоте. Любая группировка после этого врёт, и отчёт показывает четыре статуса вместо одного.
// Справочник решает это дважды. Он фиксирует перечень допустимых значений на входе и позволяет потом переименовать отображаемое название, не трогая накопленные данные: код остался прежним, подпись поменялась.
Обязательность и пустое значение
Обязательным делают то, что универсально, а не то, что типично. Обязательное отчество ломается на иностранцах и на части граждан, и пользователи начинают вписывать прочерк, точку или слово «нет» - данные засоряются именно из-за требования их заполнить.
Разница между пустым значением и пустой строкой не педантизм: пустое значение означает «неизвестно», пустая строка - «известно, и оно пустое». Это разные факты о мире.
И у пустого значения есть свойство, которое ломает отчёты. Оно не проходит ни условие равенства, ни его отрицание. Запрос «клиенты, у которых менеджер номер пять» его не вернёт, что логично. Но и запрос «клиенты, у которых менеджер не пятый» его тоже не вернёт - хотя человек, который писал этот запрос, наверняка имел в виду и клиентов вовсе без менеджера. Строки просто исчезают из обоих отчётов, и никто не замечает.
// Поэтому в требованиях полезно явно написать, что означает незаполненное поле и должно ли оно попадать в такие выборки. Одна строка текста экономит расследование расхождений в отчётах.
Когда уместно полуструктурированное хранение
Хранение в виде документа со свободным набором полей спасает в одном случае: когда состав атрибутов задаёт не разработчик, а клиент, или когда он различается от объекта к объекту. Характеристики товаров в разных категориях, пользовательские настройки, параметры интеграции с конкретным партнёром.
Плата понятная - слабая проверка типов на входе и неудобные запросы на выходе. Пока по этим полям только показывают, всё хорошо. Как только по атрибуту начинают регулярно отчитываться или фильтровать, его выносят в обычную колонку со своим типом.
// Ограничения длины полей берут не из головы, а из реальных данных: смотрят, что пишут сейчас, и закладывают запас. Слишком тесное поле пользователи обходят изобретательно - сокращают, переносят хвост в соседнее поле, пишут в комментарий. Данные от этого страдают сильнее, чем от лишних символов в базе.
Как отвечать: «Как хранить время в системе с пользователями из разных часовых поясов?»
Абсолютный момент в универсальном времени, а часовой пояс события - отдельным полем, если он нужен для отображения или отчётности. Тогда сравнение и сортировка работают всегда и одинаково, а перевод в местное время делается на выводе, под конкретного пользователя. Хранение в локальном времени сервера обесценивается при переезде инфраструктуры, а хранение в локальном времени пользователя делает невозможным сравнение записей разных людей - непонятно, что было раньше. Отдельно оговорю дату рождения и подобные величины: это календарная дата без момента времени, и часовой пояс к ней применять нельзя вообще, иначе при первом же переводе она уедет на сутки и человек помолодеет на день.
Кандидат даёт правило, объясняет, почему обе альтернативы хуже, и сам поднимает пограничный случай календарной даты - ошибку, которую совершают чаще всего именно те, кто твёрдо выучил правило про универсальное время.
На чём валятся
- −− Делают обязательными поля, отражающие частный случай, - например отчество.
- −− Хранят время в локальной зоне сервера и теряют его смысл при переезде.
- −− Заводят статус свободным текстом вместо справочника.
- −− Не различают пустое значение и пустую строку, из-за чего отчёты тихо теряют строки.
- −− Задают ограничение длины из головы, а не по реальным данным.
Проверьте себя
Пять вопросов из банка по этой подтеме. Всего их 13, остальные разбираются в тренажёре.
- Зачем справочник вместо текстового поля со статусом?A)Чтобы поле занимало меньше местаB)Чтобы разрешить пустые значения статусаC)Чтобы ускорить вставку новых записейD)Чтобы значения не расползались по написанию
показать ответ и разбор
+D)Чтобы значения не расползались по написанию// разбор: Свободный текст неизбежно даёт «Новый», «новый», «НОВЫЙ» и «Новая» — группировка ломается, отчёты врут. Справочник фиксирует перечень допустимых значений, даёт им коды и позволяет переименовать отображаемое название, не трогая данные и логику.
- В каком виде хранить момент времени в системе с пользователями из разных часовых поясов?A)В локальном времени сервераB)В локальном времени пользователяC)В UTC с отдельным полем зоныD)Строкой в формате, привычном пользователю
показать ответ и разбор
+C)В UTC с отдельным полем зоны// разбор: Хранят абсолютный момент в UTC, а часовой пояс события держат отдельно, если он нужен для отображения или отчётности. Тогда сравнение и сортировка работают всегда, а перевод в местное время делается на выводе. Хранение в локальном времени рвётся на переходах и при переезде сервера.
- Аналитик задал полю «Комментарий» ограничение в 50 символов. Что стоит проверить?A)Поддерживает ли СУБД такую длинуB)Хватит ли этого в реальных сценарияхC)Кратна ли длина степени двойкиD)Не занято ли это имя другим полем
показать ответ и разбор
+B)Хватит ли этого в реальных сценариях// разбор: Ограничения длины приходят не из головы, а из практики: посмотреть, что пишут в аналогичное поле сейчас, и заложить запас. Слишком тесное поле пользователи обходят сокращениями и переносом смысла в соседние поля. Слишком широкое, впрочем, тоже вредно — оно приглашает складывать туда всё подряд.
- Что не так с обязательным полем «Отчество»?A)Оно избыточно при наличии полного имениB)Оно замедляет поиск по таблице клиентовC)Отчество есть не у всех людейD)Оно дублирует данные из паспорта
показать ответ и разбор
+C)Отчество есть не у всех людей// разбор: Обязательность отчества ломается на иностранцах и на части граждан, у которых его нет. Пользователи начинают вписывать прочерк или точку, и данные засоряются. Это общий класс ошибок: обязательными делают поля, отражающие частный случай, а не универсальное правило.
- Когда для гибких атрибутов оправдано хранение в JSON-поле?A)Когда нужна строгая проверка значенийB)Когда по этим атрибутам строят отчётыC)Когда атрибутов больше двадцатиD)Когда набор атрибутов заранее неизвестен
показать ответ и разбор
+D)Когда набор атрибутов заранее неизвестен// разбор: Полуструктурированное хранение спасает, когда состав полей задаёт клиент или он различается от объекта к объекту: характеристики товаров в разных категориях, настройки. Плата — слабая проверка типов и неудобные запросы. Как только по атрибуту начинают отчитываться регулярно, его выносят в обычную колонку.
дальше
Теорию прочитали. Навык ставится повторением
В Сеньорчике эта подтема идёт в ежедневных сессиях: движок возвращает её, пока ответы не станут уверенными, и ведёт прогресс отдельно по каждой подтеме. Теория внутри тоже бесплатна, лимит только на количество вопросов в день.