Failure Of Cake PHP

5,505 views

Published on

Published in: Technology, Self Improvement
0 Comments
1 Like
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total views
5,505
On SlideShare
0
From Embeds
0
Number of Embeds
317
Actions
Shares
0
Downloads
35
Comments
0
Likes
1
Embeds 0
No embeds

No notes for slide

Failure Of Cake PHP

  1. 1. CakePHP の失敗談 増えたのは残業時間 株式会社ブルーオーシャン 岡田佳典 2008/6/27 BlueOcean
  2. 2. 自己紹介 <ul><li>株式会社ブルーオーシャン </li></ul><ul><ul><li>Web コンテンツの企画・開発・運営 </li></ul></ul><ul><ul><li>やっと事務所が借りられる </li></ul></ul><ul><li>岡田佳典 </li></ul><ul><ul><li>Web システム開発 </li></ul></ul><ul><ul><li>CakePHP 関連情報の執筆 </li></ul></ul>2008/6/27 BlueOcean
  3. 3. 発表の概要 <ul><li>CakePHP を使う中で遭遇した7つの失敗を次の観点から紹介します </li></ul><ul><ul><li>背景 </li></ul></ul><ul><ul><li>惨劇 </li></ul></ul><ul><ul><li>原因 </li></ul></ul><ul><ul><li>解決策 </li></ul></ul><ul><li>今後の開発にお役立てください </li></ul>2008/6/27 BlueOcean
  4. 4. 第1の失敗 <ul><li>AppController::beforeFilter() にログインチェックを書く </li></ul>2008/6/27 BlueOcean
  5. 5. 第1の失敗 - 背景 <ul><li>ログインが必要なアプリケーションを作る必要があった </li></ul><ul><li>ほとんどのアクションでログインチェックが必要なため、コントローラごとにログインチェックを書きたくなかった </li></ul>2008/6/27 BlueOcean
  6. 6. 第1の失敗 – 惨劇 <ul><li>ログインチェックが不要なアクションを指定できなければならなくなった </li></ul><ul><ul><li>たとえば PagesController の display アクションなど </li></ul></ul><ul><ul><li>しかも、頼りのコントローラ名とアクション名は空の場合がある </li></ul></ul><ul><li>派生クラスで beforeFilter() を実装する場合に parent::beforeFilter() を呼ぶ必要が生じる </li></ul>2008/6/27 BlueOcean
  7. 7. 第1の失敗 – 失敗の原因 <ul><li>AppController の beforeFilter() にログインチェックを書けば、すべての派生クラスでログインチェックを有効にできると手抜きをした </li></ul><ul><li>オブジェクト指向がもたらす効果がわかっていなかった </li></ul>2008/6/27 BlueOcean
  8. 8. 第1の失敗 – 解決策 <ul><li>CakePHP 1.2 の場合は Auth コンポーネントを使う </li></ul><ul><li>CakePHP 1.1 の場合でも同等のコンポーネントを作る </li></ul>2008/6/27 BlueOcean
  9. 9. 第1の失敗 – 解決策 – 効果 <ul><li>ログインチェックの有無をクラスの連携で設定できるようになる </li></ul><ul><li>意外とこのスタイルの方が保守しやすい </li></ul>2008/6/27 BlueOcean
  10. 10. 第2の失敗 <ul><li>関連するモデルにアソシエーションを動的設定する </li></ul>2008/6/27 BlueOcean
  11. 11. 第2の失敗 – 背景 <ul><li>多すぎるアソシエーションは重いという先入観から、必要に応じてアソシエーションを設定する方向性で開発していた </li></ul><ul><ul><li>bindModel() </li></ul></ul>2008/6/27 BlueOcean
  12. 12. 第2の失敗 – 惨劇 <ul><li>bindModel() を実行してもアソシエーションが変更されないという不具合に遭遇した </li></ul><ul><ul><li>User モデルが Review を hasMany している時、 Review と Vote を関連づけたい </li></ul></ul><ul><ul><li>×$this->Review->bindModel(“Vote”); </li></ul></ul><ul><li>原因究明に時間がかかった </li></ul>2008/6/27 BlueOcean
  13. 13. 第2の失敗 – 失敗の原因 <ul><li>CakePHP の仕様を理解していなかった </li></ul>2008/6/27 BlueOcean
  14. 14. 第2の失敗 – 解決策 <ul><li>$this->User->Review->bindModel(“Vote”) で解決した </li></ul>2008/6/27 BlueOcean
  15. 15. 第3の失敗 <ul><li>関連するモデルの取得順を動的に指定する </li></ul>2008/6/27 BlueOcean
  16. 16. 第3の失敗 – 背景 <ul><li>データは表示順の変更やフィルタリングすることを考えて、必要に応じて取得条件を設定する方針で開発を進めていた </li></ul>2008/6/27 BlueOcean
  17. 17. 第3の失敗 – 惨劇 <ul><li>関連しているモデルの取得順を動的に変更できなかった </li></ul><ul><ul><li>User モデルが Review を hasMany している場合 </li></ul></ul><ul><ul><li>×$this->User->Review->order = array(); </li></ul></ul><ul><ul><li>×$order = array(“Review.id DESC”);   $this->User->findAll($cond, null, $order); </li></ul></ul>2008/6/27 BlueOcean
  18. 18. 第3の失敗 – 失敗の原因 <ul><li>CakePHP の仕様を理解していなかった </li></ul><ul><li>bindModel() の用途が完全に見えていなかった </li></ul>2008/6/27 BlueOcean
  19. 19. 第3の失敗 – 解決策 <ul><li>bindModel() でアソシエーション設定を上書きすることで実現できた </li></ul><ul><li>bindModel() には「上書きする」という用途にも使える </li></ul><ul><ul><li>一度 find 系のメソッドを使えば元の設定に戻るため安心 </li></ul></ul>2008/6/27 BlueOcean
  20. 20. 第4の失敗 <ul><li>何も考えないで自作ビヘイビアの設定値をインスタンスへ保存する </li></ul>2008/6/27 BlueOcean
  21. 21. 第4の失敗 – 背景 <ul><li>CakePHP 1.2 の登場からモデルの振る舞いを共通化しようというムーブメントが起こった( in 自分) </li></ul>2008/6/27 BlueOcean
  22. 22. 第4の失敗 – 惨劇 <ul><li>同じビヘイビアをアタッチしているモデルで最後の設定しか反映されなくなった </li></ul><ul><ul><li>どうやらビヘイビアのインスタンスはアプリケーションでひとつらしい </li></ul></ul>2008/6/27 BlueOcean
  23. 23. 第4の失敗 – 失敗の原因 <ul><li>ビヘイビアはモデルインスタンスごとにインスタンス化されると誤解していた </li></ul>2008/6/27 BlueOcean
  24. 24. 第4の失敗 – 解決策 <ul><li>ビヘイビアの設定値をモデル名の要素の下に保存する </li></ul><ul><li>$this->__settings[$model->alias][ ~ ] </li></ul>2008/6/27 BlueOcean
  25. 25. 第5の失敗 <ul><li>コンポーネントのメンバ変数を startup() で初期化する </li></ul>2008/6/27 BlueOcean
  26. 26. 第5の失敗 – 背景 <ul><li>共通性の高いロジックを外部において再利用する手段としてコンポーネントが用意されていた </li></ul><ul><li>これを利用しない手はないと思った </li></ul>2008/6/27 BlueOcean
  27. 27. 第5の失敗 – 惨劇 <ul><li>startup() で初期化したはずのメンバ変数が未定義値に変わってしまった </li></ul><ul><li>原因究明に時間がかかった </li></ul>2008/6/27 BlueOcean
  28. 28. 第5の失敗 – 失敗の原因 <ul><li>startup() の用途を間違えていた </li></ul><ul><li>コンポーネントの設計意図を誤解していた </li></ul><ul><ul><li>C++ のトレイトや限定多重継承に近い使い方が正しいみたい </li></ul></ul><ul><li>オブジェクト指向の理解が不足していた(教えて詳しい人) </li></ul>2008/6/27 BlueOcean
  29. 29. 第5の失敗 – 解決策 <ul><li>メンバ変数は startup() やコンストラクタ以外の場所で初期化する </li></ul><ul><ul><li>↑ これらはクローンが実行するから </li></ul></ul>2008/6/27 BlueOcean
  30. 30. 第6の失敗 <ul><li>契約プログラミングを導入する </li></ul>2008/6/27 BlueOcean
  31. 31. 第6の失敗 – 背景 <ul><li>テストよりも導入しやすく、確実に品質を向上させる仕組みが必要だった </li></ul>2008/6/27 BlueOcean
  32. 32. 第6の失敗 – 惨劇 <ul><li>isset(), array_key_exists(), is_array(), is_string() を多用する羽目になり、かえって可読性が低下した </li></ul><ul><ul><li>特に Amazon との連携 </li></ul></ul><ul><li>assert() の中に式を書いてしまったために、どんな条件に違反したのかわからなくなった </li></ul>2008/6/27 BlueOcean
  33. 33. 第6の失敗 – 失敗の原因 <ul><li>assert() を書くコストを読み違えた </li></ul><ul><ul><li>PHP のビルトインコンテナが配列しかないことが一因 </li></ul></ul><ul><ul><li>PHP の配列は連想配列っぽい部分もあれば、そうでないっぽい部分がある </li></ul></ul><ul><li>assert() 関数の中に式を書いてしまった </li></ul><ul><ul><li>正しくは恒等式を文字列で渡す </li></ul></ul>2008/6/27 BlueOcean
  34. 34. 第6の失敗 – 解決策 <ul><li>テストを使う </li></ul><ul><li>Set クラスを使う </li></ul><ul><li>Set::check() で配列のパスを検証 </li></ul><ul><li>Set::extract() で深い配列から目的のデータリストを取得 </li></ul><ul><ul><li>ほか CakePHP guide 内で紹介予定 </li></ul></ul>2008/6/27 BlueOcean
  35. 35. 第6の失敗 – 解決策 – 効果 <ul><li>ソースコードの行数が3割近く減った </li></ul>2008/6/27 BlueOcean
  36. 36. 第7の失敗 <ul><li>車輪の再開発 </li></ul>2008/6/27 BlueOcean
  37. 37. 第7の失敗 – 背景 <ul><li>いわずもがな </li></ul>2008/6/27 BlueOcean
  38. 38. 第7の失敗 – 失敗の原因 <ul><li>いわずもがな </li></ul><ul><li>あえて言うなら想像力の欠如と調査不足 </li></ul>2008/6/27 BlueOcean
  39. 39. 第7の失敗 – 惨劇 <ul><li>弊社で再開発された主な車輪 </li></ul><ul><ul><li>レコードをスレッド形式で取得するメソッド </li></ul></ul><ul><ul><li>バリデーション機構 </li></ul></ul><ul><ul><li>国際化機構 </li></ul></ul><ul><ul><li>ログインチェックコンポーネント </li></ul></ul><ul><ul><li>HABTM 取得形式->保存形式の自動変換 </li></ul></ul>2008/6/27 BlueOcean
  40. 40. 第7の失敗 – 解決策 <ul><li>Model::findAllThreaded() を使用する </li></ul><ul><li>CakePHP 1.2 の新しいバリデーションを使用する </li></ul><ul><li>i18n, l10n 関連クラスを使用する </li></ul><ul><li>Auth コンポーネントを使用する </li></ul><ul><li>Set::extract() を使用する </li></ul>2008/6/27 BlueOcean
  41. 41. まとめ 2008/6/27 BlueOcean
  42. 42. 大切なこと <ul><li>新しい機能を調べるときには想像力を働かせる </li></ul><ul><li>面倒がらずに開発コードも読む </li></ul><ul><li>CakePHP を書いている人たちのことを想像する </li></ul><ul><li>近年の開発手法を勉強する(テストなど) </li></ul>2008/6/27 BlueOcean
  43. 43. おしまい <ul><li>ご清聴ありがとうございます </li></ul>2008/6/27 BlueOcean

×