search
LoginSignup
4

More than 1 year has passed since last update.

posted at

updated at

Organization

Goで書くDDDの仕様(Specification)パターン

この記事はドメイン駆動設計 Advent Calendar 2020 7日目の記事です。

DDDで紹介される戦術パターンの一つの仕様(Specification)パターンのGoでの実装を(自分へのメモ用と整理も兼ねて)2つ紹介します。

interfaceを利用

DDDはJavaで紹介されることが多いのですが、1つ目はこのJavaで紹介されるインターフェースを利用したものを素直に書いたパターンです。

例で見てみましょう。

// 仕様はRuleの集合で表現する
type Specification struct {
    rules []rule
}

// 検証を表すインターフェース
type rule interface {
    IsValid() bool
}

// 名前の長さのルール
type nameLengthRule struct {
    name string
}

func (n nameLengthRule) IsValid() bool {
    return len(n.name) < 20
}

// 有効な年齢のルール
type ageRangeRule struct {
    age int
}

func (a ageRangeRule) IsValid() bool {
    return 0 <= a.age && a.age < 200
}

func NewSpecification(name string, age int) Specification {
    return Specification{
        rules: []rule{
            nameLengthRule{name},
            ageRangeRule{age},
        },
    }
}

func (s Specification) Satisfied() bool {
    for _, rule := range s.rules {
        if !rule.IsValid() {
            return false
        }
    }
    return true
}

検証内容をruleとしてinterfaceに切り出すことで、今後検証内容が増えても既存の影響はSpecificationの生成だけになります。
ビジネスルールは比較的頻繁に変わるので、変更に強いプログラムになると言われています。
(とはいえ、このくらいの検証でやるのは過剰ですが。。)

typeを利用

もう一つはruleの関数自体を型にしてしまうものです。

これも例をみてみましょう。

type Specification struct {
    rules []rule
}

type rule func() bool

func nameLengthRule(name string) rule {
    return func() bool {
        return len(name) < 20
    }
}

func ageRangeRule(age int) rule {
    return func() bool {
        return 0 <= age && age < 200
    }
}

func NewSpecification(name string, age int) Specification {
    return Specification{
        rules: []rule{
            nameLengthRule(name),
            ageRangeRule(age),
        },
    }
}

func (s Specification) Satisfied() bool {
    for _, rule := range s.rules {
        if !rule() {
            return false
        }
    }
    return true
}

検証の内容は変わりませんが、structの宣言がなくなった分コードがスッキリします。
ポイントは関数のfunc() boolを型にしてしまうところです。
これによって関数宣言だけでルールが作れるので、シンプルな形になっています。

Goでは関数も型にできるので、うまく利用するとインターフェースを使うよりもシンプルな形で実装できるので、参考になれば幸いです。

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
What you can do with signing up
4