Slide 1

Slide 1 text

コード構成素案 主にビジネスロジックの話 @amyroi

Slide 2

Slide 2 text

コード配置例 # 例 app/ ├ lib/ # もしくは lib/ 配下、autoload │ └ aiml/ # プロダクトコードに影響しないコンポーネン │ └ aws/ # プロダクトコードに影響しないコンポーネント │ └ nlu/ # gem 化想定 │ ├ models/ │ └ concerns/ # ActiveSupport::Concern │ └ user.rb # ActiveRelation 継承 │ └ validators/ # 独自validation クラス ├ behaviors/ │ └ user_search_form.rb # Form オブジェクト │ # | Service クラス │ # | Decorator クラス │ └ nlu_manage/ # プロジェクト内で行うNLU への │ # アクセス関するクラスをまとめるnamespace │ └ project.rb # 振る舞いのクラス │ └ bot.rb # 振る舞いのクラス 2

Slide 3

Slide 3 text

継承と結合をなくしていく module, callback, 継承の使用を極力さける 継承より委譲 密結合 → 疎結合へ lib配下のライブラリは対象外 3

Slide 4

Slide 4 text

メリット 振る舞いに合わせたオブジェクト設計 疎結合にすることによりユニットテストの見通しがよくなる デメリット デザインパターンの乱用 振る舞いにおけるファイル数増 4

Slide 5

Slide 5 text

継承 class A def save end end class B < A end b = B.new b.save 5

Slide 6

Slide 6 text

委譲 class A def initialize(object) end def save object.save end end class B # object を汚染しない end class C end a = A.new(B.new) a.save a = A.new(C.new) a.save 6

Slide 7

Slide 7 text

モジュール インスタンスを生成しない 例:helper グローバルでアクセスが可能。 moduleではなくclassにしていく。もしくはnamespaceとして使 う。 7

Slide 8

Slide 8 text

concernについて ActiveSupport::Concern 使用用途:ApplicationRecordに共通のクラスメソッド、インスタン スメソッドを追加する クラスのトップレベルの共通化。 使用頻度を少なく 8

Slide 9

Slide 9 text

クラス インスタンス化 メソッドのスコープを限定できる オブジェクト! models配下に振る舞いのクラスを生成していく ActiveModel、デザインパターン、委譲 transactionは明示的に行う 9

Slide 10

Slide 10 text

FormObject (ActiveModel) フォーム表示するための振る舞いを分離したクラス validationも配置可能 Serviceクラスでも可 10

Slide 11

Slide 11 text

モジュール module Seachable extend ActiveSupport::Concern def self.seach(params) end end class User include Seachable end # Usage User.search(params) 11

Slide 12

Slide 12 text

Formオブジェクト class UserSearchForm include ActiveModel::Model def self.search(search_params) end end class User # object を汚染しない end # Usage UserSearchForm.search(params) 12

Slide 13

Slide 13 text

Callback Railsのcallbackの影響 モデル同士の結合度の高さ 完結したユニットテストがかけない ActiveModel::Callbacksを使用 transactionは定義 Decoratorパターンで作成したクラスで処理を完結させる。 13

Slide 14

Slide 14 text

ActiveRecordのcallback class User before_create :join_project def join_project self.project = Project.create() end end user = User.new user.save 14

Slide 15

Slide 15 text

Decoratorパターンで役割を分離した例 class UserCreateDecorator include ActiveModel::Model attr_accessor :user define_model_callback :save before_save :set_project def save User.transaction do run_callbacks(:save) do @user.save end end end def set_project @user.project = Project.create end end user = UserCreateDecorator.new(User.new) user.save 15