Files
dev-conventions/lang/go/db-identifiers.md
T
av 4a59c71737 заведён канон общих конвенций для личных проектов
- 13 конвенций по осям arch / lang / stack / common; репозитории берут
  оттуда копии в свой docs/conventions/ и коммитят их у себя
- conv — синхронизация копий: add / status / diff / pull / push, локальные
  регионы исключены из сравнения, поэтому расхождение не даёт шума
2026-07-25 18:18:18 +03:00

3.0 KiB

status, extends
status extends
рекомендуемая arch/db-identifiers.md

Идентификаторы: реализация на Go

Как arch/db-identifiers.md выглядит в Go-приложении, выбравшем ULID.

Единая точка — internal/ident

  • ident.NewID() — генерация. PK сущности генерируется в Create-методах слоя store. Прочие идентификаторы (батч, задание, корреляционный ключ) генерируются там, где начинается операция, — но тоже только через ident.
  • ident.NewIDAt(t) — генерация с заданным временем, для бэкфилла в Go-миграциях: сортировка id тогда сохраняет историческую хронологию, а не момент прогона миграции.
  • ident.Parse() — разбор и нормализация; зовётся на входных границах (HTTP-роут, форма, callback бота), до обращения к store.
  • Других генераторов и парсеров id в коде нет. Это то самое «единая точка» из базовой конвенции; без него нормализация регистра неизбежно где-нибудь пропускается.

Типы

В структурах store и домена id — обычный string. Отдельный тип ID заводим, только если появится вторая семья идентификаторов, которую можно перепутать; до этого он даёт конверсии без выгоды. От перепутывания двух id одной семьи в сигнатуре он всё равно не спасает — там помогают имена параметров.

Невалидный id на границе

Разбор не удался — дальше зависит от того, откуда id пришёл:

  • из пути или query URL — сразу 404, без обращения к store и без фабрикации доменной ошибки: снаружи это неотличимо от несуществующей записи, и хорошо;
  • из собственной формы или callback-данных кнопки — 400 либо понятное сообщение («кнопка устарела»): это баг интерфейса или протухший экран, и под «не найдено» его маскировать нельзя.

Транспорт не создаёт доменные sentinel'ы, чтобы тут же их сматчить, — это инверсия правила «трансляция у источника» из lang/go/errors.md.