JavaScript上級

上級 JavaScriptで学ぶドメイン駆動設計|練習問題編

導入

ドメイン駆動設計(DDD)は、ソフトウェア開発における複雑なビジネスロジックを効果的に管理するためのアプローチです。特に、ビジネスドメインに基づいたモデルを構築することで、開発チームはより明確なコミュニケーションを図り、システムの理解を深めることができます。このセクションでは、JavaScriptを用いて具体的なケーススタディを通じて、DDDの実践的な側面を探求します。

教科書レベルの解説(ドメイン駆動設計)

重要な概念の整理

ドメイン駆動設計では、「エンティティ」「値オブジェクト」「集約」といった基本概念が重要です。エンティティは識別子を持ち、ライフサイクルを通じて変化します。値オブジェクトは属性の集合であり、識別子を持たず、イミュータブルであることが特徴です。集約は、関連するエンティティと値オブジェクトを一つの単位として扱い、一貫性を保つ役割を果たします。これらの概念を理解し、実際のビジネスケースに適用することで、システムの設計がより明確になります。

コード例(JavaScript)


// エンティティ: ユーザー
class User {
    constructor(id, name, email) {
        this.id = id;
        this.name = name;
        this.email = email;
    }

    changeEmail(newEmail) {
        this.email = newEmail;
    }
}

// 値オブジェクト: 住所
class Address {
    constructor(street, city, zipCode) {
        this.street = street;
        this.city = city;
        this.zipCode = zipCode;
    }
}

// 集約: ユーザーのプロフィール
class UserProfile {
    constructor(user, address) {
        this.user = user;
        this.address = address;
    }

    updateAddress(newAddress) {
        this.address = newAddress;
    }
}

// 使用例
const user = new User(1, 'Alice', 'alice@example.com');
const address = new Address('123 Main St', 'Anytown', '12345');
const userProfile = new UserProfile(user, address);

コードの行ごとの解説

  1. class User: ユーザーエンティティを定義します。識別子や属性を持ち、メールアドレスを変更するメソッドを持っています。
  2. class Address: 住所を表す値オブジェクトです。イミュータブルな特性を持ち、変更されることはありません。
  3. class UserProfile: ユーザーと住所を関連付けた集約です。ユーザーのプロフィールを一つの単位として扱います。
  4. updateAddress: ユーザーの住所を更新するメソッドです。集約の一貫性を保つために、住所の変更を管理します。

練習問題編

以下の練習問題に取り組み、ドメイン駆動設計の理解を深めてください。

  1. 問題1: ユーザーエンティティに「電話番号」を追加し、電話番号を変更するメソッドを実装してください。

    模範解答:

    
    class User {
        constructor(id, name, email, phone) {
            this.id = id;
            this.name = name;
            this.email = email;
            this.phone = phone;
        }
    
        changeEmail(newEmail) {
            this.email = newEmail;
        }
    
        changePhone(newPhone) {
            this.phone = newPhone;
        }
    }
    
  2. 問題2: 住所の変更時に、郵便番号が正しい形式かをチェックするバリデーションを追加してください。

    模範解答:

    
    class Address {
        constructor(street, city, zipCode) {
            this.street = street;
            this.city = city;
            this.setZipCode(zipCode);
        }
    
        setZipCode(zipCode) {
            const zipCodePattern = /^\d{5}$/; // 5桁の郵便番号
            if (!zipCodePattern.test(zipCode)) {
                throw new Error("Invalid zip code format");
            }
            this.zipCode = zipCode;
        }
    }
    
  3. 問題3: ユーザーのプロフィールを作成する際、ユーザーと住所の整合性を保つために、どのような設計が考えられますか?具体的なアイデアを述べてください。

    模範解答:

    ユーザーのプロフィールを作成する際、ユーザーと住所を同時に作成し、集約として扱うことで整合性を保つことができます。例えば、ユーザー作成時に住所も必須とし、両者を同時に初期化するコンストラクタを設計することが考えられます。

まとめ

  • エンティティ、値オブジェクト、集約の概念を正しく理解し、実装することが重要です。
  • 整合性を保つための設計は、ビジネスロジックの信頼性を向上させます。
  • 具体的なビジネスケースに基づいた設計を行うことで、より実践的なスキルを身につけることができます。