ADR-0045: C# Language Standards
Статус
Принято.
Контекст
Pin — это fintech/gambling платформа, работающая с деньгами, PII и регуляторными данными. Код пишется командой и поддерживается годами. Без явных language standards возникают несогласованные паттерны: где-то nullable annotations, где-то нет; где-то records, где-то mutable classes; отсутствие guard clauses в aggregates; throw вместо Result.Fail в handlers.
Необходим единый язык, который исключает целые классы ошибок на уровне компилятора.
Решение
Nullability
#nullable enable + <WarningsAsErrors>nullable</WarningsAsErrors> во всех проектах. Nullable warnings превращаются в ошибки компилятора — PR с null-небезопасным кодом не компилируется в CI. null! запрещён в domain/application без обоснованного комментария.
Records Для Immutable Data
- Value objects:
readonly record struct— нет boxing, value equality из коробки. - DTO, commands, queries, results, events:
sealed record— immutable после создания. - Aggregates:
sealed classсprivate setи domain methods.
Sealed By Default
Все классы sealed если не проектировались для наследования. Снимается только для явных base classes (AggregateRoot<T>, PinHubBase<T>).
Required + Init
required keyword для обязательных полей команд и DTO — compile-time enforcement вместо runtime NullReferenceException.
Pattern Matching
switch expressions для exhaustive state mapping. _ case с throw new UnreachableException(...) — гарантия что неизвестный enum не проходит молча.
Exception Strategy
- Ожидаемые бизнес-ошибки →
Result.Fail(new TypedError(...)). - Нарушение инварианта домена →
DomainExceptionв aggregate/guard. - Unreachable code →
UnreachableException. - Системные ошибки → пробрасываются, ловятся в middleware.
Async/Await
CancellationTokenво всех I/O методах.- Нет
.Result/.Wait()в async контексте. ConfigureAwait(false)в infrastructure.- Собственные методы без суффикса
Async.
Последствия
- CI ломается на nullable warnings — нельзя смержить null-небезопасный PR.
- Все бизнес-ошибки типизированы — нет неожиданных exceptions в handlers.
- Immutable records исключают случайную мутацию DTO между слоями.
- Pattern matching exhaustive — добавление нового enum значения сломает компиляцию в switch без явного обработчика.
Ссылки
Обратные ссылки
Автоссылки: где используется этот документ.
- 13-code-quality-and-typing.md (1): Code Quality И Strong Typing — Enterprise .NET 10 Standards