JavaScript上級

上級 JavaScriptで学ぶクリーンアーキテクチャ|アンチパターン編

導入

クリーンアーキテクチャは、ソフトウェアの保守性や拡張性を高めるためのアプローチとして広く知られています。しかし、実際のプロジェクトでは、理論通りに実装することが難しい場合が多々あります。特に、アンチパターンに陥ることで、意図した通りにアーキテクチャが機能しなくなることがあります。本記事では、上級者向けに、クリーンアーキテクチャの実装における具体的なアンチパターンを取り上げ、それに対する改善策を考察します。

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

重要な概念の整理

クリーンアーキテクチャは、ソフトウェアの各層を明確に分離することによって、依存関係を逆転させ、ビジネスロジックを外部の影響から守ることを目的としています。これにより、テスト可能性や可読性が向上します。特に、ドメイン層とインフラ層の分離は、アプリケーションの堅牢性を高める鍵となります。

コード例(JavaScript)


// ユーザー情報を取得するサービス
class UserService {
    constructor(userRepository) {
        this.userRepository = userRepository;
    }

    async getUser(userId) {
        const user = await this.userRepository.findById(userId);
        if (!user) {
            throw new Error('User not found');
        }
        return user;
    }
}

// ユーザー情報を保存するリポジトリ
class UserRepository {
    constructor(database) {
        this.database = database;
    }

    async findById(userId) {
        return this.database.users.find(user => user.id === userId);
    }
}

コードの行ごとの解説

  1. UserServiceクラスは、ユーザー情報を取得するためのサービスです。リポジトリを依存性注入により受け取ります。
  2. getUserメソッドは、ユーザーIDを受け取り、リポジトリからユーザー情報を取得します。ユーザーが見つからない場合はエラーを投げます。
  3. UserRepositoryクラスは、データベースからユーザー情報を取得する役割を持ちます。
  4. リポジトリは、データベースの具体的な実装に依存せず、ビジネスロジックを維持します。

アンチパターン編

多くのプロジェクトで見られるアンチパターンの一つに、「リポジトリの責務が肥大化する」という問題があります。例えば、リポジトリがデータベースへのクエリを直接記述し、ビジネスロジックも混在してしまうケースです。以下のコードは、その典型的な例です。


// 複雑なロジックを含むリポジトリ
class UserRepository {
    constructor(database) {
        this.database = database;
    }

    async findUserWithDetails(userId) {
        const user = await this.database.users.find(user => user.id === userId);
        if (user) {
            user.details = await this.database.userDetails.find(details => details.userId === userId);
        }
        return user;
    }
}

このコードの問題は、リポジトリがユーザー情報の取得だけでなく、詳細情報の取得も担っている点です。これにより、リポジトリはビジネスロジックを持つことになり、再利用性が低下します。改善策としては、ユーザーの詳細情報を取得するための別のサービスを作成し、リポジトリは単一の責務に徹することが望ましいです。

まとめ

  • クリーンアーキテクチャでは、各層の責務を明確に分けることが重要です。
  • リポジトリの肥大化を防ぐために、ビジネスロジックはサービス層に移動させるべきです。
  • 依存性注入を活用し、テスト可能なコードを実現することが、クリーンな設計に寄与します。