gemをあまり使わずにFat Modelを整理するための本「Growing Rails Applications in Practice」
タイトルの通りで、 Growing Rails Applications in Practiceを読みました。
Fat controllerやFat modelに代表されるように、少し気を抜くとカオスになりがちなRailsアプリケーションの整理方法についての本です。
表紙とか目次も含めてPDFで88ページしかなくて比較的読みやすかったです。*1
全体的な構成
章立ては次のようになっています。
- Introduction
- Beautiful controllers
- Relearning ActiveRecord
- User interactions without a database
- Dealing with fat models
- A home for interaction-specific code
- Extracting service objects
- Organizing large codebases with namespaces
- Taming stylesheets
- On following fashions
- Surviving the upgrade pace of Rails
- Owning your stack
- The value of tests
- Closing thoughts
このうち、2章から4章が「New rules for Rails」、5章から9章が「Creating a system for growth」、10章から14章が「Building applications to last」という節に含められています。
各章について
各章の内容について簡単に触れてみます。
1. Introduction
基本的に https://leanpub.com/growing-rails に書かれている「About the Book」の内容です。 ここでDCI、CQRS、SOAなどに一瞬触れられていますが、その後の本文中で対比されることはありませんでした。
2. Beautiful controllers
はじめに「Controllerでいろんなことをせずに他のオブジェクトに適切に委譲しよう、Skinny controllerだ!」みたいなことを言った上で、そのための新しいルールを紹介してサンプルコードが提示されるんですが、そのサンプルコードが独特で面食らいます。 このときはちょっとした違和感を覚えるくらいでしたが、この独特なコードが第4章で思わぬ形で再登場します。
3. Relearning ActiveRecord
ActiveRecord継承モデルが仕事をしすぎている話が語られます。
ARモデルはupdate_attributes
やhoge=
のようなメソッドでいろいろなところからattributeを変更されうるので、attributeや他のモデルとの関係の整合性が損なわれる可能性に触れて、validationとcallbackを使って整合性を保つ方法が紹介されます。
4. User interactions without a database
ログイン画面を例にとって、ActiveTypeを使ったフォームが紹介されます。
validationをフォームに切り出すというのはオーソドックスで良いと思うのですが、入力されたメールアドレスとパスワードが正しいかどうかを検証するために@sign_in.save
するというインターフェイスになっていて、saveとはなんだったのかみたいな気持ちになりました。
あと、本筋とは関係ないですがログイン失敗時に「User not found」とか「Incorrect password」といったエラーを返していてセキュリティ的に厳しい気持ちにもなりました。
5. Dealing with fat models
Fat modelが生まれる理由について語られます。
いろいろなコンテキストにおいてUser
クラスに求められる責務が例示され、その責務を分割していくという方針が語られます。
例として挙がっているUser
クラスの責務が具体的で「なるほど。たしかにこれはFatにならざるを得ない……」みたいな気持ちになれるのでオススメです。
6. A home for interaction-specific code
ARモデルが持つべき責務を
- データ整合性担保のためのvalidation
- associationの管理
- レコードを探したり操作するための汎用的なメソッド
のみであるとし、それ以外のユーザーとやりとりするためのロジックをform modelに抽出しなければならないとのこと。
そのためのモデルとして、User
を継承してUser::AsSignUp
を作るという考えが紹介され、そのままだとクラス名が変わったことによりform_for
などが動かなくなるため、User
ではなくActiveType[User]
を継承する方法なども紹介されます。
これは便利そうな気がすると同時に、どこが引っかかっているのかはわかりませんが、ちょっとびみょい感じもしています。
7. Extracting service objects
controllerにベタで書いているロジックをservice objectに切り出そうという話がされます。テストしやすくなる点などにも触れられている。
「ロジックを別の場所に移しただけだよね?「うんそうだよ」的なことが書かれていて良い。
8. Organizing large codebases with namespaces
Invoice
の子リソースであるItem
をInvoice::Item
にするといった感じで、app/models/
直下を整理する試みが実例とともに語られます。
昔、自分でやってみていろいろハマった記憶があるんですが、ちゃんとやればうまくできるものなんだろうか……というのが正直な感想。 (試してみたのがかなり前なので僕がRailsをよくわかってなかっただけという説もある)
9. Taming stylesheets
アプリケーションコードだけではなく(もっとカオスになりがちな)CSSを整理する方法についても触れています。
といっても、基本的にはBEMを紹介しているだけなので、ここは飛ばしてWebを漁っても良さそう。
10. On following fashions
流行っているgemを採用するかどうかの基準について。
導入に際して書き換えるコードが多いgemは捨てるときにもコストがいるし、銀の弾丸はないんだから簡単に飛びつかないように注意が必要とのこと。
また、イケてるgemは裏でごにょごにょやってたりしてつらみを生むこともあるし、開発者が飽きてメンテされなくなることも多いから気をつけないといけないといったことも語られている。
11. Surviving the upgrade pace of Rails
Railsのバージョンを上げていくときに、gemが意外と足を引っ張るから注意してねといった話。
12. Owning your stack
gemを採用するならちゃんと責任をもってやれよといった内容。
言っていることは至極真っ当だとは思うんですが、前の2章と合わせて若干くどいというか目の敵にしすぎな感じが否めません。
13. The value of tests
UnitテストとIntegrationテストを書こうという話。
コードベースを改善していく上でテストがあるメリットは計り知れないので重要な話ではあるが、この本に必要かと問われると微妙なところ。*2
14. Closing thoughts
「thought」と書いてあるから著者の深淵なる考えでも書かれているのかと思いきや、連絡先の記載や拡散の依頼など事務連絡的なことが書かれている1ページ未満の章。
さいごに
サクッと読めて、問題点の整理ができるという点は非常に良い本だった。
一方、問題に対する解決策については良いと思う点があった一方で、首をかしげるところも多かったのでそのまま使うかどうかは検討する必要がありそう。
排他的リソースに対するスケジュールの重複判定をSQLでシュッとやる
突然ですが、排他的にしか利用できないリソースに対するスケジュールの重複判定の問題を考えてみようと思います。 典型的には「ある会議室では同時に複数の会議を開催できない」というようなスケジューリングの問題です。
ある既存のスケジュールを下の図のピンクで示します。
すると、そこに対して新規にスケジュールを追加するときのパターンは既存のスケジュールの始点と終点のまたぎ方によって分けられ、黄色と青色を合わせて全部で6パターンあります。 *1
このうち、黄色はピンクと重複している部分があるもの(invalidなスケジュール)、青色は重複していないもの(validなスケジュール)です。
新規に追加するスケジュールがinvaidな黄色の場合にエラーを返したいのですが、4パターンもあって場合分けが大変そうです。
というわけで、青色のパターンから考えます。
青色になる条件
黄色と違って、青色になる条件は比較的簡単です。
- 新規追加するスケジュールの終点が既存のスケジュールの始点よりも前にある
- 新規追加するスケジュールの始点が既存のスケジュールの終点よりも後にある
のいずれかですね。
したがって、新規追加するスケジュールの始点と終点をそれぞれSn
, En
、既存のスケジュールの始点と終点をそれぞれSe
, Ee
とすると、青色になる条件はEn < Se OR Sn > Ee
となります。
黄色になる条件
青色になる条件がわかったので、元々求めたかった黄色になる条件を求めます。
新規追加するスケジュールは黄色か青色のいずれかになるので、青色にならなければ黄色です。
したがって、さっき調べた青色になる条件を使うとNOT (En < Se OR Sn > Ee)
と書けます。
ド・モルガンの法則を使って変形するとNOT (En < Se) AND NOT(Sn > Ee)
。
もう一歩整理してEn > Se AND Sn < Ee
です。
シンプルになりました。
SQLで
この条件を使って、これから挿入しようとするスケジュールが既存のスケジュールと重複していないかどうか調べるSQLを書くことができます。 *2
select * from rooms inner join events on rooms.id = events.room_id where roooms.id = ROOM_ID and En > events.start_at and Sn < events.end_at ;
さいごに
このような重複判定をApp側で複雑に場合分けしてバリデーションしていたコードがあったのでこのエントリを書きました。
手続きで温かみある感じではなく、スパッと宣言的に判定していきたい気持ちです。
MIX PENLa-PRO のカスタム色設定 / Color-circle MIX PenLa-Pro
ミックスペンラプロといえば全国のP御用達のペンライトですが、このペンライトは色の並びがよくわからない感じになっています。
参考:TurnON | 唯一のペンライトメーカー:1,500万本販売実績
MIX PENLa力が低いと、「あの色どこだっけ?」とか「あ、このピンクじゃない! もう少し淡い色が欲しい!」みたいなことがよくあります。
そこで、カスタム色設定機能を使って、色相環的に色が並ぶようにしました。 直感的に色を探すことができるようになったことによって、ガールズの応援に集中することができます。
順序 / Order | 色番号 / Color number | 色名 / Color name |
---|---|---|
1 | 1 | レッド / Red |
2 | 2 | エンジレッド / Enji Red |
3 | 3 | ローズ / Rose |
4 | 18 | ピンク / Pink |
5 | 19 | ピーチ / Peach |
6 | 20 | サクラピンク / Sakura Pink |
7 | 23 | ラベンダーパープル / Lavender Purple |
8 | 22 | パープル / Purple |
9 | 21 | バイオレット / Violet |
10 | 4 | ブルー / Blue |
11 | 7 | アクアブルー / Aqua Blue |
12 | 5 | ライトブルー / Light Blue |
13 | 6 | アイスブルー / Ice Blue |
14 | 24 | ホワイト / White |
15 | 17 | エメラルドグリーン / Emerald Green |
16 | 16 | ペパーミントグリーン / Peppermint Green |
17 | 13 | グリーン / Green |
18 | 15 | ライトグリーン / Light Green |
19 | 14 | イエローグリーン / Yellow Green |
20 | 8 | イエロー / Yellow |
21 | 9 | ライトイエロー / Light Yellow |
22 | 12 | ヤマブキオレンジ / Yamabuki Orange |
23 | 11 | パッションオレンジ / Passion Orange |
24 | 10 | オレンジ / Orange |
なお、私は TurnON MIX PENLa-PRO 24c Decoスティック キラキラ ワイド Mタイプ を使っています。