クリーンアーキテクチャ は何をしますか?
Robert C. Martin氏の著書『Clean Architecture』に基づく、クリーンアーキテクチャの原則とベストプラクティス。このスキルは、ソフトウェアシステムの設計、コード構造のレビュー、アプリケーションのリファクタリングにおいて、より良い関心の分離を実現するために活用されるべきです。レイヤー、境界、依存関係の方向性、エンティティ、ユースケース、システムアーキテクチャに関わるタスクで発動します。
主要原則
依存関係のルール
- ソースコードの依存関係は、内側のレイヤー(抽象度の高いもの)のみを指すこと
- 外側のレイヤーが内側のレイヤーに依存してはならない
- 内側のレイヤーは、外側のレイヤーについて一切知らないこと
レイヤー構造(外側から内側へ)
-
フレームワーク&ドライバー
- データベース、Webフレームワーク、UIなど
- 最も外側のレイヤー
- 詳細はここに置く
-
インターフェースアダプター
- コントローラー、プレゼンター、ゲートウェイ
- 外側のフォーマットと内側のフォーマットを変換する
-
アプリケーションビジネスルール(ユースケース)
- アプリケーション固有のビジネスルール
- システムのすべてのユースケースを調整
-
エンタープライズビジネスルール(エンティティ)
- 最も内側のレイヤー
- エンタープライズ全体のビジネスルール
- 最も安定した要素
実装パターン
依存関係逆転の原則 (DIP)
- インターフェースを通じて依存関係を逆転させる
- 具象クラスは外側のレイヤーで定義する
境界を越える方法
- 境界を越えるデータは、単純なデータ構造であること
- 内側のレイヤーのインターフェースを、外側のレイヤーが実装する
使用例
// エンティティ(内側)
interface UserEntity {
id: string;
name: string;
email: string;
}
// ユースケース(中間)
interface UserRepository {
findById(id: string): Promise<UserEntity>;
}
class GetUserUseCase {
constructor(private userRepository: UserRepository) {}
async execute(id: string): Promise<UserEntity> {
return this.userRepository.findById(id);
}
}
// アダプター(外側)
class PostgresUserRepository implements UserRepository {
async findById(id: string): Promise<UserEntity> {
// データベース接続ロジック
}
}
テスト戦略
- 内側のレイヤーは、外側のレイヤーをモックしてテストする
- エンティティは依存関係がないため、単体テストが容易
- ユースケースは、リポジトリインターフェースをモックしてテストする
よくある間違い
- エンティティにビジネスルール以外のロジックを含める
- ユースケースがフレームワークに依存する
- 境界を無視した依存関係の注入
- 過剰な抽象化