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.

マジックビーンズ

19,944 views

Published on

SQLアンチパターン読書会でマジックビーンズについて発表しました。

Published in: Technology
  • Be the first to comment

マジックビーンズ

  1. 1. マジックビーンズ Twitter: @a_suenami Github: a-suenami id: a_suenami
  2. 2. 自己紹介 • 末並晃(すえなみあきら) • @a_suenami • 髪切りました / 痩せました • RubyとかPHPとかJavaScriptとか • いわゆる”Web系”エンジニア • どちらかというと自然キー/複合キー容認派 • どちらかというとNULL撲滅したい派
  3. 3. マジックビーンズとは MVC アーキテクチャにおいて、 M ( モデル ) の設計や実装を単純化するために、 すべてのモデルをアクティブレコードの 継承クラスにするというアンチパターン
  4. 4. アクティブレコードとは データベーステーブルあるいはビューの1行が1つのクラスにラップさ れ、オブジェクトのインスタンスがそのデータベースの1つの行に結合 される。このクラスはデータベースアクセスのカプセル化も行う。オブ ジェクトの生成後は、保存メソッドで新しい行がデータベースに追加 される。 オブジェクトが更新されると、データベースの対応する行も また更新される。 出典: http://ja.wikipedia.org/wiki/Active_Record
  5. 5. アクティブレコードとは # 1 件取得 bug = Bug.find(1234) # SELECT * FROM bugs ! # 新規作成 bug = new Bug.new bug.summary = ‘保存時にクラッシュが発生’ bug.save # INSERT INTO bugs (summary) VALUES (‘保存時にクラッシュが発生’) ! # 更新 bug = Bug.find(1234) # SELECT * FROM bugs bug.summary = ‘保存時にクラッシュが発生’ bug.save # UPDATE bugs SET summary = ‘保存時にクラッシュが発生’ WHERE id = 1234 ! # 削除 bug = Bug.find(1234) # SELECT * FROM bugs bug.delete # DELETE FROM bugs WHERE id = 1234
  6. 6. 弊害1: モデルがデータベーススキーマに依存する • アクティブレコードを用いると、n 個のテーブルがある場合、n 個の モデルクラスが必要になる。 • データベースをリファクタリングする際にモデルクラスだけでなく、 それを使う側のコードまで変更する必要がある。
  7. 7. 弊害2: CRUD 機能を公開してしまう • アクティブレコードを用いると find, create, update, delete などの メソッドを公開メソッドとして直接呼び出せてしまう。 • ビジネスロジックとして実装されたメソッドを利用せず、公開 CRUD メソッドを利用できてしまう結果、要件を満たさないコード が書かれる可能性がある。 • 書籍中ではバグ担当者をアサインしたらメール通知するはずだが、 メール通知が迂回されてしまうという例で紹介されている。 • 仮に要件を満たせたとしても、公開 CRUD メソッドの利用はビジネ スロジックがアプリケーション層まで流出する結果になる。また、 複数箇所に同じロジックが重複する可能性がある。
  8. 8. 弊害3: ドメインモデル貧血症をもたらす • モデルがデータアクセスオブジェクトとしてしか利用されず、ビジ ネスロジックの多くがアプリケーション層にあるコントローラーオ ブジェクトやサービスオブジェクトに記述されている状態を「ドメ インモデル貧血症」という。 • 参考: http://capsctrl.que.jp/kdmsnr/wiki/bliki/? AnemicDomainModel • CRUD メソッドを公開してしまった結果として起こりやすい。 • ビジネスロジックを持たないモデルと巨大で手続き的なサービスオ ブジェクトで構成されることになり保守性が低下する。オブジェク ト指向のカプセル化の考え方に完全に違反している。
  9. 9. 弊害4: ユニットテストが困難 • モデル、ビュー、コントローラ、すべてのレイヤーにおいてユニット テストが困難になる。 • モデル: データベースと密結合になるため、本番と同等のデータベー ススキーマを準備して実際に接続する必要がある。 • ビュー: モデルが単なるデータコンテナとして使われると表示処理に も複雑なロジックが生じるため、実際のレスポンスとして返される HTML を生成し、それに対してテストする必要がある。 • コントローラ: ビジネスロジックがアプリケーション層に漏れだして いるため、ビジネスロジックのテストのために HTTP リクエストとレ スポンスをエミュレートする必要があり煩雑になる。
  10. 10. “Railsの”アクティブレコードのさらなる弊害 Rails のアクティブレコードの場合、データベースに加えてフォームと も密結合になる。 <%= form_for(@bug) do |f| %> <div class="field"> <%= f.label :summary %><br> <%= f.text_field :summary %> </div> <div class="field"> <%= f.label :description %><br> <%= f.text_area :description %> </div> <div class="actions"> <%= f.submit %> </div> <% end %>
  11. 11. “Railsの”アクティブレコードのさらなる弊害 • テーブルとフォームが綺麗に対応しない場合にはモデルにフォーム 由来の実装が現れる。 • (例) メールアドレスの確認入力 • (例) 「利用規約に同意する」チェックボックス • バリデーションルールやエラーメッセージの管理もモデルの責務とし て実装される。 • Rails でアンチパターンに陥ると、モデルにはバリデーションルール のみがあり、ビジネスロジックはコントローラに流出してしまう。
  12. 12. アンチパターンの見つけ方 • 「モデルにカスタム SQL クエリを渡すにはどうすればいい?」 • モデルにカスタム SQL を渡す必要はない。クエリをカプセル化し、アプリ ケーション層から隠ぺいする。 • 「複雑なモデル操作をすべてのコントローラにコピーすればいいのだろうか、 それとも、親の抽象コント ローラクラスに 1 回だけコーディングすればいいの だろうか」 • どちらの方法でも安定性や保守性は得られない。複雑な手続きがあるのであ ればモデルのメソッドとして公開する必要がある。 • 「モデルのユニットテストを行うために、データベースフィクスチャをもっと書 かなければならない」 • モデルのテストではなくデータアクセスのテストをしている可能性がある。
  13. 13. アンチパターンを用いてもよい場合 • アクティブレコードそのものは優れたデータアクセスパターンであ り、それ自体はアンチパターンではない。 • テーブルの各行に対してシンプルな CRUD 操作ができるだけで十分 なアプリケーションも多く、その場合には DAO とモデルを同一の ものにすることで設計を単純化できる。 • プロトタイプ作成においては作業省力化の役に立つ。
  14. 14. http://a-suenami.hatenablog.com/entry/2014/11/12/221805 “何が必要か/本当に必要かがわかるまでは開発しないか最低限の開発で検証を 重ねるのがいいと思いますし、その結果コアドメインが姿を表したらユビキタ ス言語を構築してモデリングをするべきでしょう。逆にノンコアドメインにつ いてはフレームワークや既存のパターンを使って低コストに済ませてしまうの がよいと思います。”
  15. 15. 解決策 • モデルがアクティブレコードを「持つ」ようにする • モデルを理解する • ドメインモデルの使用 • プレーンなオブジェクトのテスト • 現実的に考える
  16. 16. レイヤー化アーキテクチャ • 「エリックエヴァンスのドメイン駆動設計」で紹介されているアー キテクチャパターン。 • ある層の要素は同じ層の別の要素か、より下の層の要素にしか依存 しないことを原則とする。 ユーザ・インターフェース層ユーザへの情報の表示、ユーザからの入力の解釈を責務 として負う。 アプリケーション層 ソフトウェアがやるべき仕事を定義し、問題を解決でき るようにドメインオブジェクト間の調整をする。ドメイ ンに対する知識を持たず、薄く保たれる層。 ドメイン層ビジネス上の概念やビジネスルールを表す責務を負う。 インフラストラクチャ層上位のレイヤを支える技術的機能を提供することを責務 とする。
  17. 17. オブジェクトの責務の割当てパターン ( GRASP ) • 情報エキスパート ( Information Expert ) • 生成者 ( Creator ) • 疎結合性(Low Coupling) • 高凝集性(High Cohesion)
  18. 18. ドメインモデル • ドメインモデルについては「エリック・ エヴァンスのドメイン駆動設計」で詳し く述べられている。 • ドメインモデルとは対象ドメインに関心 事をアプリケーションで表現したもので あり、MVC アーキテクチャにおける本来 の「モデル」もそうであるべきである。 • エリック・エヴァンスの書籍では永続化 層とドメイン層の仲介役としてリポジト リパターンが紹介されている。
  19. 19. プレーンオブジェクト • データベースの構造に依存しないプレーンなオブジェクトはテストしや すく、またテストの実行速度も速い。 • 特に実装言語が Java の場合、それが特定のフレームワークやアーキテ クチャに依存してないことを強調するために POJO ( Plain Old Java Object ) と呼ばれる。 • 他の言語でも同様に POXO ( X は言語の頭文字 ) と呼ぶケースはあ る。 • ドメインモデルを正しく設計してビジネスロジックをそこに隠蔽すると、 コントローラやビューのテストではそれらのモデルをモックやスタブに 差し替えることができ、数多くの分岐をテストしなくてよくなる。
  20. 20. Before & After 出典: 『SQLアンチパターン』P269, P276
  21. 21. ちなみに… 若干古い書籍ですが、「エンタープライズ Rails」という書籍に models/physical と models/logical を作成して、同様のことを 実現する方法が紹介されているのでご興味 ある人はぜひ。 ※まわし者ではありません。 ※時間なくて詳細を資料に盛り込めません でした、すいません。
  22. 22. 最後にちょっと小話。 Rails を使ってる場合の現実的な 落とし所について。
  23. 23. 公開メソッドについて • モジュールの include で見た目の複雑性を下げる。 • コードレビューによるチェックで基底クラスの公開メソッドを使わ ないようにする。
  24. 24. フォーム / サービスオブジェクトの利用 http://a-suenami.hatenablog.com/entry/2013/12/06/092146
  25. 25. まとめ データベースとモデルは区別しましょう。 ! DOA の人とモデルの人は殴りあってないで もっと仲良くしましょう。(マジで)

×