ссылки между конвенциями переписаны на темы и идентификаторы
- 41 ссылка вида `lang/go/logging.md` заменена на «конвенция `logging`», идентификатор правила или «базовый слой» для своей же темы - MIGR-8 больше не отсылает за форматом меток времени, а называет его; MIGR-11 перенёс ссылку на KEYS-1/KEYS-2 из нормы в «Почему»
This commit is contained in:
@@ -5,7 +5,7 @@ extends: arch/config.md
|
||||
|
||||
# Конфигурация: реализация на Go
|
||||
|
||||
Как `arch/config.md` выглядит в Go-приложении: формат, загрузчик, границы
|
||||
Как базовый слой выглядит в Go-приложении: формат, загрузчик, границы
|
||||
запрета на окружение. Форма записи — `LANGUAGE.md`.
|
||||
|
||||
Секретов Go-специфика не касается: они приходят из деплоя уже в файле, а
|
||||
@@ -224,8 +224,8 @@ zoneinfo, а сообщение указывает не на ту причину
|
||||
|
||||
## Связано
|
||||
|
||||
- `lang/go/time.md` — зона отображения и формат времени.
|
||||
- `lang/go/logging.md` — `slog`, которым падает невалидный конфиг.
|
||||
- конвенция `time` — зона отображения и формат времени.
|
||||
- конвенция `logging` — `slog`, которым падает невалидный конфиг.
|
||||
|
||||
<!-- local:связано -->
|
||||
<!-- /local -->
|
||||
|
||||
@@ -5,7 +5,7 @@ extends: arch/db-identifiers.md
|
||||
|
||||
# Идентификаторы: реализация на Go
|
||||
|
||||
Как `arch/db-identifiers.md` выглядит в Go-приложении. Форма записи —
|
||||
Как базовый слой выглядит в Go-приложении. Форма записи —
|
||||
`LANGUAGE.md`.
|
||||
|
||||
Единая точка из `KEYS-3` — пакет `internal/ident`: он
|
||||
@@ -118,8 +118,8 @@ HTTP-кодов. В случае GKEY-8.1 снаружи это неотличи
|
||||
**НЕ ДОЛЖЕН.** Обработчик не конструирует доменный sentinel (например
|
||||
`ErrNotFound`), чтобы тут же сопоставить его со своим ответом.
|
||||
|
||||
**Почему.** Инверсия правила «трансляция у источника» из
|
||||
`lang/go/errors.md`. Sentinel — сообщение от слоя, который знает факт:
|
||||
**Почему.** Инверсия правила «трансляция у источника» из конвенции
|
||||
`errors`. Sentinel — сообщение от слоя, который знает факт:
|
||||
строка не найдена, потому что store её искал. Сфабрикованный транспортом,
|
||||
он утверждает непроверенное, и по типу ошибки перестаёт быть видно, был ли
|
||||
вообще поход в хранилище — а на этом держится вся диагностика по ошибкам.
|
||||
|
||||
@@ -119,14 +119,15 @@ down останавливает сразу и заставляет пересо
|
||||
таблицы соответствия, которую пришлось бы держать в голове для числового
|
||||
кода.
|
||||
|
||||
### MIGR-8. Метки времени — `TEXT` в формате из `arch/time.md`
|
||||
### MIGR-8. Метки времени — `TEXT` в каноническом формате
|
||||
|
||||
**ДОЛЖЕН.** Колонка с меткой времени объявляется как `TEXT`, значения
|
||||
пишутся в формате из `arch/time.md`.
|
||||
пишутся как RFC 3339 в UTC с суффиксом `Z` и фиксированной шириной.
|
||||
|
||||
**Почему.** Типа даты в SQLite нет, поэтому единственное, что делает
|
||||
значения сравнимыми, — договорённость о формате. Текст в формате из
|
||||
`arch/time.md` сортируется лексикографически в том же порядке, что и
|
||||
значения сравнимыми, — договорённость о формате; сам формат выбран не
|
||||
здесь, а конвенцией `time` (`TIME-1`, `TIME-2`). Текст в нём сортируется
|
||||
лексикографически в том же порядке, что и
|
||||
хронологически: `ORDER BY` и диапазонные условия работают без функций
|
||||
преобразования, а значит и без потери индекса. Соседство двух форматов в
|
||||
одной колонке ломает и сравнение, и разбор на стороне Go.
|
||||
@@ -159,12 +160,12 @@ down останавливает сразу и заставляет пересо
|
||||
### MIGR-11. Первичный ключ новой таблицы — TEXT ULID
|
||||
|
||||
**ДОЛЖЕН.** Колонка ключа объявляется как `TEXT`, значение приходит из
|
||||
приложения (`KEYS-1`, `KEYS-2`).
|
||||
приложения.
|
||||
|
||||
**Почему.** Здесь конвенция схемы ничего не решает — она реализует решение,
|
||||
принятое в `arch/db-identifiers.md`. Повторить там ветвление или условие
|
||||
значило бы завести второй источник правды, и соседние таблицы разъехались бы
|
||||
по разным ответам на один вопрос.
|
||||
принятое конвенцией `db-identifiers` (`KEYS-1`, `KEYS-2`). Повторить там
|
||||
ветвление или условие значило бы завести второй источник правды, и соседние
|
||||
таблицы разъехались бы по разным ответам на один вопрос.
|
||||
|
||||
`AUTOINCREMENT` в такой таблице невозможен: SQLite разрешает его только на
|
||||
`INTEGER PRIMARY KEY`. То есть для новых таблиц запрещать нечего.
|
||||
@@ -192,9 +193,9 @@ down останавливает сразу и заставляет пересо
|
||||
|
||||
## Связано
|
||||
|
||||
- `arch/time.md` — формат меток времени.
|
||||
- `arch/db-identifiers.md` — выбор первичных ключей.
|
||||
- `lang/go/errors.md` — граничные ошибки `database/sql` транслируются в
|
||||
- конвенция `time` — формат меток времени.
|
||||
- конвенция `db-identifiers` — выбор первичных ключей.
|
||||
- конвенция `errors` — граничные ошибки `database/sql` транслируются в
|
||||
доменные у источника, в слое store.
|
||||
|
||||
<!-- local:связано -->
|
||||
|
||||
@@ -5,8 +5,8 @@ prefix: GERR
|
||||
# Ошибки
|
||||
|
||||
Как ошибки строятся, оборачиваются и проверяются. Форма записи —
|
||||
`LANGUAGE.md`. Где и когда ошибку **логировать** — в
|
||||
`lang/go/logging.md` (коротко: лог один раз на доменной границе).
|
||||
`LANGUAGE.md`. Где и когда ошибку **логировать** — в конвенции `logging`
|
||||
(коротко: лог один раз на доменной границе).
|
||||
|
||||
Две границы, о которых говорят правила ниже:
|
||||
|
||||
@@ -169,7 +169,7 @@ HTTP-клиентов, файловой системы, внешних SDK.
|
||||
### GERR-12. Полная ошибка идёт в приватный канал
|
||||
|
||||
**ДОЛЖЕН.** В лог уходит вся цепочка `%w` с контекстом; где и когда именно
|
||||
— `lang/go/logging.md`.
|
||||
— конвенция `logging`.
|
||||
|
||||
**Почему.** Цепочка — единственный носитель диагностики (GERR-1), и
|
||||
единственный канал, где её можно показать целиком, — тот, который видит
|
||||
@@ -231,7 +231,7 @@ HTTP-клиентов, файловой системы, внешних SDK.
|
||||
|
||||
**Почему.** Непокрытая ошибка — не класс отказа, а дефект: ветвь забыли
|
||||
завести вопреки GERR-16. Адресат у неё владелец в смысле «надо чинить», отсюда
|
||||
`ERROR` — уровень выбирается по адресату (`lang/go/logging.md`). Статус
|
||||
`ERROR` — уровень выбирается по адресату (конвенция `logging`). Статус
|
||||
тоже не выбирается: известное пользовательское состояние лежало бы в
|
||||
маппинге, а про неизвестное сказать пользователю нечего, поэтому 4xx
|
||||
отпадает.
|
||||
@@ -385,9 +385,8 @@ HTTP-клиентов, файловой системы, внешних SDK.
|
||||
|
||||
## Связано
|
||||
|
||||
- `lang/go/logging.md` — где и когда ошибка попадает в лог.
|
||||
- `KEYS-7` (`arch/db-identifiers.md`) — формат корреляционного ключа
|
||||
из `GERR-14`.
|
||||
- конвенция `logging` — где и когда ошибка попадает в лог.
|
||||
- `KEYS-7` — формат корреляционного ключа из `GERR-14`.
|
||||
|
||||
<!-- local:механизировано -->
|
||||
<!-- /local -->
|
||||
|
||||
@@ -44,7 +44,7 @@ dev-выводом перестаёшь ежедневно гонять собс
|
||||
### SLOG-3. Время записи — UTC
|
||||
|
||||
**ДОЛЖЕН.** `time` приводится к UTC через `ReplaceAttr` по `slog.TimeKey`
|
||||
(см. `lang/go/time.md`).
|
||||
(см. конвенцию `time`).
|
||||
|
||||
**Почему.** По умолчанию UTC не получится: встроенные хендлеры пишут время
|
||||
в зоне самого `time.Time`, то есть в локальной зоне процесса. Записи одного
|
||||
@@ -54,8 +54,8 @@ dev-выводом перестаёшь ежедневно гонять собс
|
||||
событий.
|
||||
|
||||
Точность `JSONHandler` — миллисекунды фиксированной ширины; это другая
|
||||
точность, чем в БД, и по `arch/time.md` так и должно быть: ширина
|
||||
фиксируется на носитель.
|
||||
точность, чем в БД, и по `TIME-2` так и должно быть: ширина фиксируется
|
||||
на носитель.
|
||||
|
||||
## Сообщение
|
||||
|
||||
@@ -243,7 +243,7 @@ dev-выводом перестаёшь ежедневно гонять собс
|
||||
|
||||
**НЕ СЛЕДУЕТ.** Отдельный случайный `trace_id` не заводится, если у
|
||||
сущностей есть стабильные уникальные идентификаторы. (Как их выбирают —
|
||||
`arch/db-identifiers.md`, если конвенция взята.)
|
||||
конвенция `db-identifiers`, если взята.)
|
||||
|
||||
**Почему.** Идентификатор сущности уже существует, стабилен между
|
||||
процессами и во времени — по нему собираются записи не одного прохода, а
|
||||
@@ -347,7 +347,7 @@ ctx = logctx.With(ctx, log) // достаём логгер из ctx в кажд
|
||||
|
||||
Нарушение инварианта в собственном коде — паника, недостижимая ветка — в
|
||||
таблицу не входит: это не доменный отказ, и логирует его recover-граница
|
||||
вместе со стеком (`lang/go/errors.md`). Искать его класс здесь не нужно.
|
||||
вместе со стеком (конвенция `errors`). Искать его класс здесь не нужно.
|
||||
|
||||
Мимо таблицы идёт и доменная ошибка, которой нет в маппинге: класса у неё
|
||||
нет, потому что её просто забыли завести. Она логируется `ERROR` с
|
||||
@@ -505,7 +505,7 @@ API-ключи и токены, `Authorization`-заголовки, аутент
|
||||
### SLOG-37. `*url.Error` санитизируется на границе клиента
|
||||
|
||||
**ДОЛЖЕН.** Ошибка разворачивается в первопричину **до** лога и до
|
||||
обёртки — раньше трансляции в доменную (`lang/go/errors.md`).
|
||||
обёртки — раньше трансляции в доменную (конвенция `errors`).
|
||||
|
||||
**Почему.** `*url.Error` встраивает полный URL запроса, а секрет живёт
|
||||
прямо в нём: токен в пути, `api_key` в query. Go редактирует только пароль
|
||||
@@ -553,11 +553,11 @@ API-ключи и токены, `Authorization`-заголовки, аутент
|
||||
|
||||
## Связано
|
||||
|
||||
- `arch/time.md` — точность и зона меток времени фиксируются на носитель.
|
||||
- `lang/go/time.md` — как ставится UTC в `ReplaceAttr` (SLOG-3).
|
||||
- `lang/go/errors.md` — трансляция ошибки в доменную, порядок относительно
|
||||
- конвенция `time` — точность и зона меток времени фиксируются на носитель;
|
||||
как ставится UTC в `ReplaceAttr` (SLOG-3).
|
||||
- конвенция `errors` — трансляция ошибки в доменную, порядок относительно
|
||||
санитизации (SLOG-37).
|
||||
- `arch/db-identifiers.md` — откуда берутся стабильные идентификаторы,
|
||||
- конвенция `db-identifiers` — откуда берутся стабильные идентификаторы,
|
||||
на которых держится корреляция (SLOG-18).
|
||||
|
||||
<!-- local:механизировано -->
|
||||
|
||||
@@ -5,7 +5,7 @@ extends: arch/time.md
|
||||
|
||||
# Время: реализация на Go
|
||||
|
||||
Как требования `arch/time.md` выполняются в Go-коде: откуда берётся
|
||||
Как требования базового слоя выполняются в Go-коде: откуда берётся
|
||||
«сейчас», в каком виде время попадает в базу и в логи, что делать с зонами.
|
||||
Форма записи — `LANGUAGE.md`.
|
||||
|
||||
@@ -178,13 +178,13 @@ func utcTime(_ []string, a slog.Attr) slog.Attr {
|
||||
суток у того, что давно посчитано и сохранено.
|
||||
|
||||
Календарные вычисления бизнес-логики берут зону явно — как описано в
|
||||
`arch/time.md`.
|
||||
базовом слое.
|
||||
|
||||
<!-- local:механизировано -->
|
||||
<!-- /local -->
|
||||
|
||||
## Связано
|
||||
|
||||
- `arch/time.md` — базовая конвенция: UTC как формат хранения, нормализация
|
||||
чужого входа, явная зона в календарных вычислениях.
|
||||
- `lang/go/config.md` — валидация зоны отображения загрузчиком конфига.
|
||||
- базовый слой — UTC как формат хранения, нормализация чужого входа, явная
|
||||
зона в календарных вычислениях.
|
||||
- конвенция `config` — валидация зоны отображения загрузчиком конфига.
|
||||
|
||||
Reference in New Issue
Block a user