重要なドメイン概念にはValue Objectを活用する

Contents

Actively use Value Objects for variables representing important domain concepts. (重要なドメイン概念を表す変数には、Value Objectを積極的に使用する)

解説

プリミティブ型(文字列、数値など)だけでドメイン概念を表現すると、型安全性が失われ、無効な値の混入リスクが高まります。Value Objectを使用することで、ドメインルールをカプセル化し、型システムの力でバグを防止できます。重要なドメイン概念(メールアドレス、金額、ユーザーIDなど)をValue Objectとして定義することで、コードの表現力と安全性が向上します。

具体例

// 悪い例(プリミティブ型のみ使用)
type User struct {
    ID    string
    Email string
}

func CreateUser(id, email string) (*User, error) {
    // バリデーションが散在
    if id == "" || email == "" {
        return nil, errors.New("invalid input")
    }
    return &User{ID: id, Email: email}, nil
}

func SendEmail(email string) error {
    // emailの妥当性チェックが毎回必要
    if !strings.Contains(email, "@") {
        return errors.New("invalid email")
    }
    return emailClient.Send(email, "Hello")
}

// 良い例(Value Object使用)
type UserID struct {
    value string
}

func NewUserID(id string) (UserID, error) {
    if id == "" {
        return UserID{}, errors.New("user ID cannot be empty")
    }
    return UserID{value: id}, nil
}

func (u UserID) String() string {
    return u.value
}

type Email struct {
    value string
}

func NewEmail(email string) (Email, error) {
    if !strings.Contains(email, "@") {
        return Email{}, errors.New("invalid email format")
    }
    return Email{value: email}, nil
}

func (e Email) String() string {
    return e.value
}

type User struct {
    ID    UserID
    Email Email
}

func CreateUser(id UserID, email Email) *User {
    // Value Objectは既に検証済みなので追加チェック不要
    return &User{ID: id, Email: email}
}

func SendEmail(email Email) error {
    // Emailは既に妥当性が保証されている
    return emailClient.Send(email.String(), "Hello")
}

参考リンク

Show Text to Share
重要なドメイン概念にはValue Objectを活用する
https://www.tricrow.com/core/coding-standard/use-value-objects.html
この記事を書いた人
T.Nakamura
T.Nakamura
AIが大好きなクラウドエンジニア。IT業界歴10年以上。標準化と効率化を追求している。技術ネタを発信中。フォローお気軽にどうぞ!フォローはこちら

カテゴリ

タグ