This commit is contained in:
2026-10-03 01:44:27 +07:00
parent 96edb0937e
commit 1375ec9218
+30 -8
View File
@@ -204,18 +204,40 @@ SQL держи рядом с методом, которому он нужен.
## 8. Ошибки и context
- Возвращай ошибки, не паникуй в обработке пользовательского ввода, БД,
файлов, сети и внешних сервисов.
- Для ожидаемых веток объявляй sentinel-ошибку в пакете, который владеет
смыслом ошибки; проверяй её через `errors.Is`.
файлов, сети и внешних сервисов. `panic` допустим только для невозможного
нарушения внутреннего инварианта при старте или в коде, который не имеет
осмысленного способа продолжить работу.
- Ошибкой владеет пакет, которому принадлежит её смысл. Ожидаемые состояния
объявляй как sentinel-ошибки (`var Err... = errors.New(...)`) в сервисе,
repository или module; не дублируй одну смысловую ошибку в разных слоях.
- Repository переводит ошибки драйвера и ограничения БД в свои предметные
ошибки. Service переводит их в ошибки use case. `app` не меняет бизнес-смысл
ошибки, а только преобразует её в транспортный ответ.
- Для ожидаемых веток проверяй цепочку через `errors.Is`; для ошибок с данными
используй `errors.As`. Текст ошибки не сравнивай.
- Оборачивай ошибку с контекстом через `%w`, например
`fmt.Errorf("загрузить сценарий %d: %w", id, err)`.
- Не сравнивай текст ошибки и не теряй исходную ошибку без причины.
`fmt.Errorf("загрузить сценарий %d: %w", id, err)`. Не теряй исходную ошибку
без причины и не оборачивай её повторно пустым или одинаковым сообщением.
- `status.Error` и `status.Errorf` используй только на транспортной границе
(`internal/app` или gRPC middleware). Services, repositories и modules не
возвращают gRPC-ошибки.
- Преобразование ошибок use case в gRPC-коды держи в `*_errors.go` рядом с
handler-ом. Для неизвестной ошибки возвращай `codes.Internal` с безопасным
общим сообщением; детали причины сохраняй в цепочке и логируй на внешней
границе.
- Клиенту нельзя отдавать SQL, пути файлов, адреса внешних сервисов, stack
trace, токены, пароли или персональные данные. Ошибки валидации могут
содержать только безопасные сведения, необходимые клиенту.
- Логируй ошибку один раз на границе, которая принимает решение о внешнем
ответе; нижние слои добавляют контекст через `%w`, но не дублируют лог.
- Каждый внешний вызов получает переданный `context.Context`; timeout нужен на
границе долгой операции или фонового worker-а.
границе долгой операции или фонового worker-а. Отмену контекста не скрывай:
возвращай `ctx.Err()` или оборачивай её через `%w`.
- Не помещай обязательные параметры операции в context. В context допустимы
только request-scoped данные, уже принятые проектным middleware.
- Не логируй пароли, токены, персональные данные и содержимое пользовательских
файлов.
- Для каждой новой ветки бизнес-ошибки тестируй `errors.Is` и итоговый
транспортный код; для неизвестной ошибки проверяй, что наружу уходит
`codes.Internal` без внутренних деталей.
## 9. SQL и транзакции