Appearance
Runtime
Time, Async, and Cancellation
[Required]アプリ内のDateTimeは、特別な要件がない限りUTCに統一する。[Required]現在時刻はTimeProvider.GetUtcNow()を使う。[Required]DB に保存するDateTimeはDateTimeKind.Utcにする。[Required]外部入力から受けたDateTimeがKind == Unspecifiedのまま DB に入らないよう、境界で validation または正規化する。[Required]表示のための local time 変換は UI / 表示層に閉じる。[Required]日付だけを扱う値はDateOnly、または UTC 日付境界のDateTimeのどちらかに揃え、混在させない。[Required]DateTimeOffsetを使う領域は永続化境界で必要な保存形式へ明示的に変換し、offset 情報を失う暗黙変換を経由しない。[Required]I/O を伴う処理は async にする。[Required]async method 名はAsyncsuffix を付ける。[Required]CancellationToken ctを最後の引数に置く。[Required]repository / provider SDK / 外部 API 呼び出しにはctを渡す。[Required]sync over async (.Result、.Wait()) は禁止する。[Recommended]fire-and-forget は原則禁止する。必要な場合は background service として設計する。
DI
[Required]DI registration は area 単位のIServiceCollectionextension にまとめ、Program.csから呼び出す。use case 固有の登録は area extension の private method に分ける。
csharp
public static class CustomerServiceCollectionExtensions
{
public static IServiceCollection AddCustomerFeatures(this IServiceCollection services)
{
services.AddCustomerSignupFeature();
return services;
}
private static IServiceCollection AddCustomerSignupFeature(this IServiceCollection services)
{
services.AddScoped<CustomerSignupHandler>();
services.AddScoped<ICustomerSignupRepository, CustomerSignupRepository>();
return services;
}
}[Required]Program.csから呼ぶ公開 extension はAdd{Area}Features()にする。[Required]use case 固有の DI 登録は area extension 内のAdd{Area}{UseCase}Feature()private method にまとめる。[Required]Program.csに handler / repository の個別登録を増やさない。[Required]use case を切り出したら handler と use case port の登録も同じ private method に移す。[Required]Handler と repository は scoped にする。[Required]TimeProvider.Systemは singleton にする。