TypeScript上級

上級 TypeScriptで学ぶクリーンアーキテクチャ|解説編

導入

クリーンアーキテクチャは、ソフトウェア設計の原則を体系化したもので、可読性や保守性を高めるための強力な手法です。本記事では、上級 TypeScriptエンジニアがクリーンアーキテクチャを実践する際に直面する具体的なシナリオを通じて、設計のポイントや落とし穴を探ります。

教科書レベルの解説(クリーンアーキテクチャ)

重要な概念の整理

クリーンアーキテクチャの中心には、依存関係の逆転原則があります。これにより、ビジネスロジックはインフラストラクチャから独立し、テストや変更が容易になります。さらに、層を分けることで、責任を明確にし、再利用性を高めることができます。

コード例(TypeScript)


interface User {
    id: string;
    name: string;
}

interface UserRepository {
    findById(id: string): Promise;
}

class InMemoryUserRepository implements UserRepository {
    private users: User[] = [];

    constructor(users: User[]) {
        this.users = users;
    }

    async findById(id: string): Promise {
        return this.users.find(user => user.id === id) || null;
    }
}

class UserService {
    private userRepository: UserRepository;

    constructor(userRepository: UserRepository) {
        this.userRepository = userRepository;
    }

    async getUser(id: string): Promise {
        return this.userRepository.findById(id);
    }
}

コードの行ごとの解説

  1. interface User { ... } – ユーザー情報を表すインターフェースを定義します。
  2. interface UserRepository { ... } – ユーザーを取得するためのリポジトリインターフェースです。これにより、実装の詳細を隠蔽します。
  3. class InMemoryUserRepository implements UserRepository { ... } – メモリ内のユーザー情報を管理するリポジトリの実装です。
  4. async findById(id: string): Promise { ... } – 指定したIDのユーザーを非同期に取得します。
  5. class UserService { ... } – ユーザーに関連するビジネスロジックを提供するサービスクラスです。
  6. async getUser(id: string): Promise { ... } – ユーザーリポジトリを使用してユーザーを取得するメソッドです。

解説編

このコード例では、クリーンアーキテクチャの原則に従い、ビジネスロジックとデータアクセスを分離しています。しかし、この設計の落とし穴として、依存性の注入を適切に行わないと、テストが難しくなる可能性があります。特に、リポジトリの実装を変更した場合、サービスクラスの再利用性が低下することがあります。これを避けるために、依存関係を外部から注入することが推奨されます。

まとめ

  • クリーンアーキテクチャは、ソフトウェアの可読性と保守性を向上させるための強力な手法です。
  • 依存関係の逆転原則を理解し、実装に活かすことで、ビジネスロジックをインフラから独立させることができます。