はじめに―デフォルトの怖さについて
Railsは文字通り「レールに乗る」ときに最大の効率を発揮するフレームワークです。CoC(Convention over Configuration)は今やRailsのみならず各所で用いられる概念となっています。これはもちろん圧倒的な量のxml設定ファイルに比べれば進歩ですが、一方で気になることもあります。それはデフォルト設定の重みがさらに増しているということです。
多くの人はソフトウェアをあまりカスタマイズせずに使います。ほとんどのソフトウェアは設定項目を最低数個、多いものでは数百個持っていますが、デフォルトでも「ある程度」動くものがほとんどなため、カスタマイズの必要を感じない人が多いのかもしれません(個人的にはgitやtmuxなどは設定を工夫するとかなり便利になるのにやっていない人が多い印象)。
さて、RailsはそのCoCを強調する姿勢ゆえになおさらカスタマイズをする人が少ない、デフォルトの設定をそのまま使う人が多いフレームワークである、ということはできないでしょうか。そしてデフォルトの設定に不都合な点がある場合に、それが見過ごされる・軽視される可能性が高くなってしまうということもまた言えるのかもしれません。
今回はそんなRailsのデフォルト設定のうち、文字通りアプリケーションの中心となるapp
ディレクトリに焦点を当てたいと思います。
不満点
まず、特に何もせずにrails new
したときのapp
ディレクトリの構成は以下のようになっています。
- assets
- controllers
- helpers
- mailers
- models
- views
あえてそれぞれ説明はしませんが、個人的にはmailerがデフォルトで作られるのがやや印象的です。
この構成で最も不満だと(個人的に)思われるのが、オブジェクト指向的なデザインパターンで用いられるクラスの適切な置き場所がないことです。これは結果的に、models
ディレクトリ内に置かれたクラス=ActiveRecord::Base
を継承したクラスにすべてが置かれるという状況を引き起こしやすくなるでしょう。例えば、ここでも言及されているサービスクラスですが、本来はここに書くべき内容を「services
ディレクトリがないがゆえに」モデルに書いてしまうということは、将来的にメンテナンス性の低下をもたらすでしょう。
また、ビュー絡みの命名がやや不正確であるというのも問題です。上記のリンク先には「Railsのviews
ディレクトリ内にあるファイルは実際はtemplates
である」というようなことが書かれています。確かに、views
ディレクトリ内にあるのはすべてerbのファイルばかりでRubyのファイルはひとつもない場合がほとんどです。さらにそして、本当にviews
であるようなクラスを置きたい場合、どこに置けばいいのでしょうか?フォームオブジェクトは?
言うまでもないことですがこれらの不満は自分でディレクトリを作ってしまえば解消されます。しかし、それらのディレクトリがデフォルトで存在しないという事実が人々を適切なディレクトリ構成から遠ざけてしまいます。では、存在したほうが多くの人にとって救いとなるようなディレクトリは一体何でしょうか。
デフォルトでほしいディレクトリその1―services
個人的にサービスクラスはお気に入りです。いくつか解釈はあると思いますが、自分の場合は複数モデルにまたがるロジックや外部サービスと関連するようなロジックはサービスクラスに置くというルールで実装しています。複数モデルにまたがるロジックをコールバックで実装しようとすると、テストが難しくなったり変更に弱くなったりしてろくなことがない、というのが私の感想です。
サービスクラスはたいていのアプリケーションで必要になる類のものである、ゆえにデフォルトのディレクトリとすべきである、と私は思っているのですが、普通にmodels
ディレクトリに置けばいいと思っている人もいるでしょう。これは「モデル」という単語にどこまでロジックを含めるか、という問題に対する感覚の差の表れです。モデルをDBへの薄いラッパーであると考える人はサービスクラスを多用するでしょうし、データとロジックが一体となったものであると考える人は使わないか、使ってもモデルの一部として考えるでしょう。
デフォルトでほしいディレクトリその2―forms
Railsのaccepts_nested_attributes_for
はとんでもない代物です。あれを使うとほぼ間違いなく頭痛のたねになります。しかし、あれをいやいや使っている人は多いでしょう。それというのも、Railsはフォームをオブジェクトではなく単なるパーシャルとして扱ってしまうからです。
しかし、複数モデルを同時に利用するようなフォームの場合は明らかにパーシャルでは力不足です。このような場合にフォームオブジェクトが使われます(gemもreformなどがあります)。これは単純に説明すると、form_for
の引数にモデルを直接与えるのではなくそれをラップしたフォームオブジェクトを与え、そこでバリデーションその他を行うことによりモデルから複雑性を取り除こうとするパターンです。これらを置くのにforms
ディレクトリが必要となります。
デフォルトでほしいディレクトリその3―decorators
Railsのヘルパーは扱いづらいです。ネームスペースがないので命名に気を遣ったり、再利用性が低かったり…
そこで、Rails界隈ではヘルパーの代替としてデコレーターパターンが用いられることがあります(そのためのgemではDraperなんかが有名です)。これはモデルとビューコンテクストをどちらも参照することで、モデルのロジックをモデルから切り離しつつビューに適用しようとするパターンです(正確な説明かどうか自信ないです…)。これもディレクトリがないので(自製する場合は)作る、ということになりますね。
余談―橋渡しをすること
気がついた方も多いでしょうが、上に挙げられたものはどれも「複数の異なるもの同士を関連付ける」ために必要となるものです。オブジェクト指向は(もちろん)オブジェクトとメッセージ送信が中心なのですが、オブジェクトを点メッセージを線としたとき、線の引き方をオブジェクトで管理する必要があるのではないか、そうなるとそのオブジェクトが送信するメッセージの管理は…うわー、みたいなことを最近考えています。
まとめ
デフォルトがより良くなればみんなハッピー。でもデフォルトが変わらないなら、気にせず正しいプログラミングをしよう!