2021年5月6日木曜日

なんちゃって Ruby で DDD 超入門

なんちゃって Ruby で DDD 超入門

概要

DDD は設計手法なので実装するとなるとまた話は別ですが実際に作ってみないとイメージが全くわかないので超簡単なサンプルを作ってみました

環境

  • macOS 11.2.3
  • Ruby 3.0.0

登場人物

  • リポジトリ ・・・ DB の扱うレイヤ、DB の処理はここだけしか行えない
  • エンティティ ・・・ 属性の管理を行うモデル、DB からデータ取得、追加など DB への操作はこのモデルのクラスのオブジェクトを渡すことで行う
  • ドメインサービス ・・・ モデルとなるクラスのオブジェクトのユーティリティクラス、今回は重複チェックをしてもらう
  • メイン ・・・ エンティティとドメインサービスを使ってメインの関数などを提供するクラス

とりあえずこんな感じで実装してみます

リポジトリ

  • vim user_repository.rb
# coding: utf-8
# DB に関する処理をまとめて書く
# ここで ActiveRecord などを使う
class UserRepository
  @@user_repo = {
    "hawk" => 10,
    "snowlog" => 20
  }

  def search_age(user)
    @@user_repo[user.name.value]
  end

  def save(user)
    @@user_repo.store(user.name.value, user.age.value)
  end

  def all
    @@user_repo
  end
end

エンティティ

  • vim user_entity.rb
# coding: utf-8
# User の属性を管理する
# UserName, UserAge は immutable
class UserName
  def initialize(value)
    @value = value
  end

  attr_reader :value
end

class UserAge
  def initialize(value)
    @value = value
  end

  attr_reader :value
end

class User
  def initialize(name, age)
    @name = name
    @age = age
  end

  attr_accessor :name, :age
end

ドメインサービス

  • vim user_service.rb
# coding: utf-8
# User に関するユーティリティ機能を提供する
# UserRepositry を扱うことができる
require './user_repository.rb'

class UserService
  def initialize(user)
    @user = user
  end

  def duplicate?
    ur = UserRepository.new
    return false if ur.search_age(@user).nil?
    return true
  end
end

メイン

  • vim main.rb
# coding: utf-8
# メインの処理を書くクラス
# UserEntiry と UserService を使って実装する
require './user_repository.rb'
require './user_service.rb'
require './user_entity.rb'

class Main
  def create_user(val_name, val_age)
    name = UserName.new(val_name)
    age = UserAge.new(val_age)
    user = User.new(name, age)
    us = UserService.new(user)
    return if us.duplicate?
    ur = UserRepository.new
    ur.save(user)
    p ur.all
  end
end

main = Main.new
main.create_user("hawksnowlog", 30)

ポイント

何をドメインとして切り出すかがポイントかなと思います
今回で言えば User がそれに当たります
User の属性を管理する「エンティティ」、User のデータ永続化を管理する「リポジトリ」、User の重複チェックなどを行う「ドメインサービス」と言った具合に User を主体に様々なクラスを作成しています

あくまでも一例ですが、こんな感じでドメインとして扱うオブジェクトというかモデルを抽出してそれを主体にコーディングしていく感じになります

また各ドメイン間での結合度を下げてることも重要で DI や引数などを使ってドメイン間やクラス間での依存性を下げる意識を持ったほうが良いかなと思います
(例えばサンプルだと UserService はメンバーである必要はないので引数にするとか)

最後に

DDD は設計手法なのでプロダクトの製品や使われているフレームワークなどにも大きく影響するものかなと思っているので一概に実装の正解はないかなと思っています

あと簡単すぎるので自分で書いていますが実践的ではないあまり良いサンプルではないかと思うので実際はもっと複雑になるかなと思います

参考サイト

0 件のコメント:

コメントを投稿