Skip to content

Runtime

Time, Async, and Cancellation

  • [Required] アプリ内の DateTime は、特別な要件がない限りUTCに統一する。

  • [Required] 現在時刻は TimeProvider.GetUtcNow() を使う。

  • [Required] DB に保存する DateTimeDateTimeKind.Utc にする。

  • [Required] 外部入力から受けた DateTimeKind == Unspecified のまま DB に入らないよう、境界で validation または正規化する。

  • [Required] 表示のための local time 変換は UI / 表示層に閉じる。

  • [Required] 日付だけを扱う値は DateOnly、または UTC 日付境界の DateTime のどちらかに揃え、混在させない。

  • [Required] DateTimeOffset を使う領域は永続化境界で必要な保存形式へ明示的に変換し、offset 情報を失う暗黙変換を経由しない。

  • [Required] I/O を伴う処理は async にする。

  • [Required] async method 名は Async suffix を付ける。

  • [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 単位の IServiceCollection extension にまとめ、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 にする。