заведён реестр префиксов, правила канона перенумерованы
- идентификатор правила теперь `<ПРЕФИКС>-<номер>` вместо `R<номер>`: префикс уникален по всему канону, поэтому ссылка больше не требует пути к файлу и не зависит от того, на какой оси файл лежит - префикс выбирается под файл, а не выводится по формуле, и хранится в conventions/prefixes.toml вместе с выбывшими; номера сохранены один в один вместе с дырами
This commit is contained in:
@@ -1,3 +1,7 @@
|
||||
---
|
||||
prefix: KEYS
|
||||
---
|
||||
|
||||
# Идентификаторы сущностей
|
||||
|
||||
Как выбираются и как выглядят первичные ключи сущностей. Форма записи —
|
||||
@@ -14,7 +18,7 @@
|
||||
|
||||
## Правила
|
||||
|
||||
### R1. Первичный ключ новой сущности — ULID
|
||||
### KEYS-1. Первичный ключ новой сущности — ULID
|
||||
|
||||
**ДОЛЖЕН.** Новая сущность получает сортируемый строковый идентификатор,
|
||||
который порождает приложение, — во **всех** таблицах, включая те, что
|
||||
@@ -31,12 +35,12 @@
|
||||
Второй довод дешевле, но важнее в быту: одна ментальная модель избавляет от
|
||||
спора при заведении каждой таблицы и делает идентификатор **глобальным** —
|
||||
уникальным across таблиц, а не только внутри своей. На этом держится
|
||||
корреляция по логам (R7).
|
||||
корреляция по логам (KEYS-7).
|
||||
|
||||
Правило про **сгенерированные суррогатные** ключи. Естественные и составные
|
||||
ключи у таблиц-деталей (R6) — третья категория, они допустимы всегда.
|
||||
ключи у таблиц-деталей (KEYS-6) — третья категория, они допустимы всегда.
|
||||
|
||||
### R2. Идентификатор генерирует приложение, а не база
|
||||
### KEYS-2. Идентификатор генерирует приложение, а не база
|
||||
|
||||
**ДОЛЖЕН.** Значение ключа известно до вставки строки.
|
||||
|
||||
@@ -46,26 +50,26 @@
|
||||
и достраивать связи вторым проходом, либо иметь два источника истины о
|
||||
моменте создания.
|
||||
|
||||
### R3. Генерация и разбор идентификаторов — в единственной точке
|
||||
### KEYS-3. Генерация и разбор идентификаторов — в единственной точке
|
||||
|
||||
**ДОЛЖЕН.** Один модуль порождает идентификаторы, он же их разбирает.
|
||||
Самодельных генераторов и парсеров в коде нет.
|
||||
|
||||
**Почему.** Нормализация регистра (R4) и проверка формата обязаны
|
||||
**Почему.** Нормализация регистра (KEYS-4) и проверка формата обязаны
|
||||
применяться ко всем идентификаторам без исключения. Любая вторая точка
|
||||
входа рано или поздно окажется той, где нормализацию забыли, — и дефект
|
||||
проявится не там, где создан.
|
||||
|
||||
### R4. Канонический вид — нижний регистр
|
||||
### KEYS-4. Канонический вид — нижний регистр
|
||||
|
||||
**ДОЛЖЕН.** Идентификаторы порождаются и хранятся в нижнем регистре.
|
||||
|
||||
**Почему.** Сравнение строк в базе обычно побайтовое, поэтому регистр — не
|
||||
косметика, а корректность поиска. Спецификация ULID канонизирует **верхний**
|
||||
регистр, и библиотеки по умолчанию отдают именно его: без единой точки (R3)
|
||||
регистр, и библиотеки по умолчанию отдают именно его: без единой точки (KEYS-3)
|
||||
разный регистр появится в базе сам собой.
|
||||
|
||||
### R5. Внешний идентификатор разбирается до обращения к базе
|
||||
### KEYS-5. Внешний идентификатор разбирается до обращения к базе
|
||||
|
||||
**ДОЛЖЕН.** Значение, пришедшее снаружи, проходит разбор и нормализацию
|
||||
раньше, чем по нему делается запрос. Реакция на неудачный разбор зависит от
|
||||
@@ -73,28 +77,28 @@
|
||||
|
||||
| № | Откуда пришёл | Разбор не удался → |
|
||||
|---|---|---|
|
||||
| R5.1 | путь или query URL | «не найдено» без обращения к хранилищу |
|
||||
| R5.2 | собственная форма, данные кнопки | «некорректный ввод» либо «элемент устарел» |
|
||||
| KEYS-5.1 | путь или query URL | «не найдено» без обращения к хранилищу |
|
||||
| KEYS-5.2 | собственная форма, данные кнопки | «некорректный ввод» либо «элемент устарел» |
|
||||
|
||||
**Почему.** Синтаксически невалидное значение не может соответствовать
|
||||
записи, поэтому поход в базу за ним — заведомо холостой; отсекая его на
|
||||
границе, мы дёшево снимаем целый класс мусорного трафика.
|
||||
|
||||
Разделение R5.1 и R5.2 нужно, потому что источники значат разное. Мусор в
|
||||
URL — это чужая или протухшая ссылка, и «не найдено» описывает ситуацию
|
||||
точно. Мусор из собственной формы — это баг интерфейса или устаревший
|
||||
экран; ответ «не найдено» здесь скрывает дефект и лишает диагностики
|
||||
единственный момент, когда он заметен.
|
||||
Разделение KEYS-5.1 и KEYS-5.2 нужно, потому что источники значат разное.
|
||||
Мусор в URL — это чужая или протухшая ссылка, и «не найдено» описывает
|
||||
ситуацию точно. Мусор из собственной формы — это баг интерфейса или
|
||||
устаревший экран; ответ «не найдено» здесь скрывает дефект и лишает
|
||||
диагностики единственный момент, когда он заметен.
|
||||
|
||||
Таблица перечисляет **внешние** источники — те, откуда значение приходит
|
||||
вместе с запросом, и правило говорит, что отдать в ответ. Идентификатор из
|
||||
конфигурации, из собственной базы или из фикстуры сюда не относится: он
|
||||
ничего не отдаёт наружу, а его невалидность означает, что сломано у нас.
|
||||
Формат идентификатора в конфигурации проверяется на старте
|
||||
(`arch/config.md` R18), невалидное значение в собственной базе — нарушенный
|
||||
инвариант единой точки (R3).
|
||||
(`CONF-18`), невалидное значение в собственной базе — нарушенный
|
||||
инвариант единой точки (KEYS-3).
|
||||
|
||||
### R6. У таблиц-деталей допустим естественный или составной ключ
|
||||
### KEYS-6. У таблиц-деталей допустим естественный или составной ключ
|
||||
|
||||
**ДОПУСКАЕТСЯ.** Когда ключ есть по природе данных, отдельный
|
||||
сгенерированный идентификатор не заводится.
|
||||
@@ -104,10 +108,10 @@ URL — это чужая или протухшая ссылка, и «не на
|
||||
лишний вопрос «по какому из них искать» на каждом запросе. Дополнительной
|
||||
информации он не несёт.
|
||||
|
||||
### R7. Прочие генерируемые идентификаторы — через ту же точку
|
||||
### KEYS-7. Прочие генерируемые идентификаторы — через ту же точку
|
||||
|
||||
**ДОЛЖЕН.** Идентификаторы, не являющиеся первичными ключами (батч,
|
||||
задание, корреляционный ключ), порождаются тем же модулем (R3) и в том же
|
||||
задание, корреляционный ключ), порождаются тем же модулем (KEYS-3) и в том же
|
||||
формате.
|
||||
|
||||
**Почему.** Единый формат делает работающим главный побочный эффект
|
||||
@@ -118,7 +122,7 @@ URL — это чужая или протухшая ссылка, и «не на
|
||||
|
||||
## Почему ULID, а не UUID
|
||||
|
||||
R1 требует **сортируемый** строковый идентификатор. UUIDv4 не
|
||||
KEYS-1 требует **сортируемый** строковый идентификатор. UUIDv4 не
|
||||
сортируется по времени вовсе. UUIDv7 (RFC 9562) сортируется — и против него
|
||||
остаются два довода: 36 символов против 26 и дефисы, из-за которых
|
||||
идентификатор не берётся ни двойным кликом, ни `grep`-ом как одно слово.
|
||||
|
||||
Reference in New Issue
Block a user