Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

Skinny Controllers, Skinny Models

4,778 views

Published on

7 つの実装パターンと Code Climate を使った実際のリファクタリング実践の紹介です。

Published in: Technology
  • Be the first to comment

Skinny Controllers, Skinny Models

  1. 1. Skinny Controllers, Skinny Models M3 Tech Talk #m3dev Kazuhiro Sera @seratch
  2. 2. RubyKaigi 2013 •  LT しました(rspec-kickstarter) •  席に戻ったら Gemfile に追加! •  今日は Refactoring Fat Models with Patterns という講演の内容とその実践に ついて紹介します •  興味を持った方は、動画が公開されている ので後で観てみてください https://vimeo.com/68611168
  3. 3. @brynary •  Bryan Helmkamp •  Code Climate 創業者 •  顧客の Ruby コードを解析して品質・セ キュリティ改善を支援するサービス •  OSS なら無料、以下は Gistub の例 •  https://codeclimate.com/github/ seratch/gistub/
  4. 4. Code Climate: Rating
  5. 5. Code Climate: Code Smell
  6. 6. Code Climate: Classes
  7. 7. ブログエントリ •  7 Patterns to Refactor Fat ActiveRecord Models •  http://blog.codeclimate.com/blog/ 2012/10/17/7-ways-to-decompose-fat- activerecord-models/ •  さらに改善されたコード例を GitHub で公開 している(RubyKaigi での発表で使用) •  https://github.com/codeclimate/ refactoring-fat-models
  8. 8. Rails ActiveRecord •  Pro: シンプルさ •  Con: DB のテーブルと 1:1 を強いられる
  9. 9. Rails アプリでの失敗例 •  適切にデザインされたオブジェクト指向の コードはラビオリに例えられる •  時折、カルゾーネみたいに一カ所に詰め込 んだ Rails コードを見かける・・
  10. 10. Skinny Models •  Fat Models とよく言われるが Model も Skinny であるべきなんでは?
  11. 11. Fat Models との戦い •  Controller が肥大化するよりはマシ? •  既存の AR(ActiveRecord) model に責 務を持たせていくとどんどん肥大化 •  最悪のケースは神オブジェクトが誕生 •  @brynary は、定番の実装パターンをうま く Rails の model のリファクタリングに 適用する方法を提案している
  12. 12. アンチパターン •  ただし、安易に mixin として module に 切り出すのはアンチパターン •  mixin は形を変えた継承 •  がらくたを突っ込む引き出し(コードを module に移して include するだけ) •  たくさん mixin された class だとどんな オブジェクトか把握するのが大変になる
  13. 13. 7 つの実装パターン •  Value Objects •  Service Objects •  Form Objects •  Query Objects •  View Objects •  Policy Objects •  Decorators
  14. 14. Value Objects •  おなじみ Value Object •  immutable な値を保持するクラス •  保持する値によって比較可能 •  何らかのロジックを持つ attribute(また はその小さな集合)が適している •  具体例:PhoneNumber、Money、 Ratingなど
  15. 15. Service Objects •  複数の model を利用する場合 •  外部のサービス、API と連携する場合 •  複雑なロジックを実装する場合 •  既存の model の主たる責務でない場合 •  Strategy パターンを適用したい場合 •  普通 ActiveModel ではない
  16. 16. Form Objects •  一つのフォームで複数の AR model を更 新したい場合に有効 •  ActiveModel にする •  Form の save の内部で複数の AR model の save を呼び出す •  標準の accepts_nested_attributes_for は @brynary 的には非推奨 •  複雑になったら永続化処理を Service に
  17. 17. Query Objects •  バッチ用 or 複雑な条件の SQL を AR の scope やクラスメソッドにせず Query Object として分離 •  初期化時に AR::Relation オブジェクトを 渡すようにすると合成可能になる •  TrialQuery.new(Account.where(…)).fin d_each do ¦e¦ … end
  18. 18. View Objects •  View のためのロジックを AR model に 書かない(エラーメッセージ生成など) •  AR model を保持するクラスを定義し render にはこちらを渡すようにする •  helper に AR model を渡す実装よりも、 リファクタリングが促進される •  多様な UI に対応する場合にも有効
  19. 19. Policy Objects •  AR model を参照はするが主たるドメイ ンではないロジック(分析のための判定 など)を分離する •  例:メール配信対象?アクティブユーザ? •  AR model を保持するクラスとして定義 •  他との違い:Policy は read な処理だけ Service は write も含む、Query は SQL 実行と result set を yield に渡すだけ
  20. 20. Decorators •  Decorator パターンを適用して callback 地獄を回避する •  例:save メソッドを数珠つなぎにする (AR の Order#save で orders テーブル に insert -> DHW に通知 -> 受付完了 メールを送信)
  21. 21. 実践してみた •  実際にパターンを使って Gistub のリファ クタリングをしてみた
  22. 22. パターンを実践する前
  23. 23. パターンを実践した後
  24. 24. やったこと •  使ったパターンは Service Objects だけ •  単に Controller から Service に切り出し ただけだと、今度はその新しい Service のスコアが悪かった(当たり前) •  複雑度の高すぎるメソッドを名前を付け られる単位に分割 •  コードの重複を共通化
  25. 25. 改善の過程
  26. 26. 今日から出来ること •  盲目的に AR のクラスメソッドにしない •  AR でないモデルもどんどんつくる •  Controller に AR model 呼び出しをズラ ズラ書くより Service にする •  複雑なフォームは Form を導入する •  AR に表示用ロジックを持たず View Object でラップして表示処理に渡す
  27. 27. まとめ •  既に実践されているものも多いが、パター ンに名前がついて言語化されることは大事 •  最初はシンプルでよい(パターンのやりす ぎは over engineering) •  アプリが育っていく中で規模に応じたリ ファクタリングは必要になっていく •  ただし、十分なコードカバレッジは必須
  28. 28. アプリ規模とアーキテクチャ
  29. 29. Q&A M3 Tech Talk #m3dev Kazuhiro Sera @seratch Any Question?

×