【ITニュース解説】Clean Architecture for .NET API + Blazor Server: A Practical, Testable Template
2025年09月22日に「Dev.to」が公開したITニュース「Clean Architecture for .NET API + Blazor Server: A Practical, Testable Template」について初心者にもわかりやすく解説しています。
ITニュース概要
Clean Architectureは、アプリのUI、ビジネスロジック、インフラを分離し、大規模システムの保守性・テスト容易性を高める設計手法だ。.NET APIとBlazor Serverを用いた実践的なテンプレートを解説。テストしやすく、変更に強いシステム構築に役立つ。
ITニュース解説
大規模なソフトウェア開発において、アプリケーションが複雑化し、将来的な変更や拡張が困難になることはよくある問題である。Clean Architecture(クリーンアーキテクチャ)は、このような課題を解決し、アプリケーションを長期間にわたって保守しやすくするための設計手法である。このアーキテクチャは、ユーザーインターフェース(UI)、ビジネスルール、そしてデータへのアクセスや外部サービスとの連携といったインフラストラクチャの間に明確な境界線を設けることで、各部分が互いに過度に依存し合うことを防ぐ。
Clean Architectureを採用する主な理由は、システムの保守性、テストのしやすさ、そして柔軟性を高めることにある。例えば、UIの見た目や操作方法が変更されても、アプリケーションの核となるビジネスロジックには影響が及ばない。また、データベースの種類を変更したり、外部サービスとの連携方法を変えたりする際にも、ビジネスロジックを修正することなく対応できるため、システムの進化が容易になる。この分離された構造は、開発チームがそれぞれの担当領域に集中して作業を進めることを可能にし、結果として開発速度の向上にもつながる。
このアーキテクチャでは、アプリケーションがいくつかの層に分けられ、それぞれが特定の役割を持つ。主な層は「Presentation(プレゼンテーション)」「Application(アプリケーション)」「Infrastructure(インフラストラクチャ)」の三つである。Presentation層はユーザーインターフェースやAPIエンドポイントなど、ユーザーとの直接的な接点となる部分を扱う。Application層は、ビジネスの要件を満たすための具体的な処理手順、つまり「ユースケース」と、他の層との連携に必要な「ポート」(抽象的なインターフェース)を定義する。Infrastructure層は、データベースへのアクセス、外部APIとの通信、ファイル操作など、具体的な技術的な実装を担当する。
これらの層の間には厳格な依存関係のルールがある。内側の層は外側の層について何も知らないという「依存性逆転の原則」が適用される。具体的には、Presentation層はApplication層に依存し、Application層はInfrastructure層で定義されたインターフェース(ポート)に依存する。そして、Infrastructure層がそのインターフェースを具体的に実装する「アダプター」の役割を果たす。この構造により、Application層は特定のデータベースや外部サービスの実装に縛られず、純粋なビジネスロジックに集中できる。アプリケーションの実行時には、Infrastructure層で実装された具体的なサービスがApplication層に注入(インジェクション)されて利用される。
Clean Architectureを適用したプロジェクトのファイル構造は、この層の考え方を反映している。例えば、最上位のフォルダとして「Portal」があり、その中にAPIのコントローラーやアプリケーションの起動設定を置く「API」フォルダが配置される。ビジネスロジックの中核である「Application」フォルダには、データ転送オブジェクト(DTOs)、インターフェース(ポート)、具体的なユースケースの実装が含まれる。必要に応じて、ビジネスエンティティ(実体)を定義する「Domain」フォルダも設けることができる。「Infrastructure」フォルダには、データサービスの実装、HTTPクライアント、データベースコンテキストなどが配置され、これらはApplication層のインターフェースを具体的に満たすものとなる。さらに、コードの品質を保証するための「Tests」フォルダも用意され、単体テストや結合テストが格納される。
各層の役割をさらに具体的に見ると、Presentation層は、ユーザーからの入力(APIリクエストやUI操作)を受け取り、それをApplication層のユースケースに渡し、ユースケースから返された結果をユーザーに返すことに専念する。この層にはビジネスロジックは一切含まない。Application層は、純粋なビジネスルールとユースケースのオーケストレーション(調整・制御)を行う。ここには特定の技術実装の詳細(例えば、HTTP通信やデータベースアクセス)は含まれず、抽象的なインターフェースのみに依存する。Infrastructure層は、Application層で定義されたインターフェース(ポート)を具体的なサービスとして実装し、外部システムとのやり取りを担当する。
具体的な例として、「日付ごとのストライキ参加率を照会する」というユースケースを考えてみよう。Application層では、まず「日付を指定してストライキ参加率を取得する」というインターフェースを定義し、そのインターフェースを実装するユースケースクラスを作成する。このユースケースは、データ取得のための別の抽象インターフェース(例: IStrikeParticipationService)に依存する。この段階では、データがどこから来るか(データベースか、外部APIか)は気にしない。次に、Infrastructure層で、このIStrikeParticipationServiceインターフェースを具体的に実装する。もしデータが外部APIから取得されるのであれば、HTTPクライアントを使ってAPIを呼び出し、その結果をApplication層が理解できる形に変換する。もしデータベースから取得されるのであれば、データベースクエリを実行する。そして、API層(Presentation層の一部)では、HTTPリクエストを受け取り、Application層のユースケースを呼び出し、その結果をHTTPレスポンスとして返す。ここでも、API層はビジネスロジックを持たず、ただ仲介役を果たすだけである。
Blazor Serverアプリケーションをこのアーキテクチャに組み込む場合、BlazorのページやコンポーネントはPresentation層に位置する。これらのコンポーネントは、APIエンドポイントを呼び出すことでApplication層のユースケースを実行するか、もしBlazorアプリケーションとAPIが同じプロセス内でホストされている場合は、HTTP通信を介さずに直接ユースケースを呼び出すことも可能である。Blazorのコンポーネントは、状態を表示し、ユーザーの操作に応じてイベントを発生させ、そのイベントをユースケースに伝えるだけの「愚かな」存在に保つことが推奨される。これにより、UIの変更がビジネスロジックに影響を与えるのを防ぐ。
テスト戦略もこの層の分離から大きな恩恵を受ける。Application層の単体テストでは、依存するInfrastructure層のサービスをモック(偽物)に置き換えることで、ビジネスロジックが意図通りに機能するかを高速かつ確定的に検証できる。APIの結合テストでは、WebApplicationFactoryのようなツールを使用して実際のAPIエンドポイントを起動し、必要に応じてインフラの実装をフェイクに置き換えることで、エンドツーエンドのフローをテストする。さらに、外部サービスとの連携部分には、そのサービスとの契約が守られているかを検証する契約テストを実施することもある。
このClean Architectureテンプレートは、将来的な拡張や変化にも強い。新しいユースケースはApplication層に追加するだけでよく、既存のコントローラー(APIのエンドポイント)を変更する必要はほとんどない。また、データベースや外部APIの実装を変更する必要が生じても、Infrastructure層のアダプターを交換するだけで済み、ビジネスロジックを持つApplication層には手を加える必要がない。キャッシュ機能やCQRS(Command Query Responsibility Segregation)のような高度なパターンも、特定の層に影響を与えることなく導入できる。
開発を進める上でのベストプラクティスとして、Presentation層にはビジネスロジックを含めず、Application層はインフラの詳細を知らず、Infrastructure層はUIを知らないという原則を徹底することが重要である。また、コンストラクタインジェクションを活用して依存関係を明確にし、小さな単位のサービスを組み合わせて使うこと、そしてエラーハンドリングや結果の返し方を統一することで、一貫性のある堅牢なアプリケーションを構築できる。
このように、Clean Architectureは、.NET APIとBlazor Serverを組み合わせたアプリケーションにおいて、明確な設計規約と層の分離を通じて、保守性、テストのしやすさ、柔軟性の高い骨格を提供する。ユースケース中心の設計によりビジネスロジックが明確になり、インターフェースに基づいたインフラの管理により依存関係が整理され、APIは薄く信頼性の高いものとなる。