Ruby/Railsのプロ開発者としての5年間を振り返る(翻訳)|TechRacho(テックラッチョ)〜エンジニアの「?」を「!」に〜|BPS株式会社エンジニアの「?」を「!」に。原著者の許諾を得て翻訳・公開いたします。Galanciak先日のTechRacho記事「DHHのYouTube動画を辛口レビュー」とある意味好一対をなしているように思いました。Ruby/Railsのプロ開発者としての5年間を振り返る(翻訳)自分でもちょっと信じられないのですが、RubyとRailsのプロとしての経験年数が早くも5年を超えていました。その間のRailsに対する私の姿勢は、盲目的な愛から容赦ない批判(ActiveRecord、あんたのことだよ)の間で大きく揺れ動き、ようやっとバランスが取れてきたところですが、今でも前向きに取り組んでいることは間違いありません。このぐらい年月を経れば、何らかのフレームワークを用いた開発経験を有意義に総括するには十分でしょう。そこで、特に私自身の振り返りを中心に据えつつ、Railsについて少しばかり語ってみたいと思います。ActiveRecordとモデル層Railsで最も重要な部分を占めるのがActiveRecordであることは言うまでもありません。ActiveRecordはそれ自身もかなり複雑ですが、「コントローラを薄く、モデルを厚くすべし」というお題目に従っていると、ActiveRecord::Baseをextendするモデルがみるみる膨れ上がり、事実上アプリの大半を占めてしまうことがちょくちょくあります。この(モデル)層について、この5年間の経験でどんな知見を得ることができたでしょうか。Way」に素直に従いました。ロジックをコントローラからモデルに移動し、ビジネスロジック全体をモデルのクラス内で扱い、永続化にからむロジックのコールバックをあちこちに追加していたのです。当初は素晴らしい手応えでした!Railsでのまともな経験がろくになかったにもかかわらず、どんな機能でも進捗は極めて良好でした。深刻な問題にいくつも直面するようになったのです。条件にまみれたロジックの大半を、コンテキストに応じて使い分けなければならなくなりました。レコード作成のロジックとレコード更新のロジックの両方を担当するメソッドがあると、両者の違いはほとんどないも同然であるにもかかわらず、さらに条件が上乗せされます。バリデーションロジックはたちまち複雑怪奇の様相を呈し、ついに条件付きバリデーションに手を出さざるを得なくなります。ある日のこと、とあるデータマイグレーションでupdate_columnsの代わりにupdate_attributesを使ったところ、何やら通知のコールバックをつっついてしまい、通知メールが怒涛の勢いで多数のユーザーに飛んでしまったのです。そのときの私は、アプリのロジックをまともに制御できる状態ではありませんでした。update呼び出しやsave呼び出しのような基本的な操作で何が起きるかわかったものではなかったからです。その日を境に、モデルに関する私のデフォルトポリシーは「コールバック使うな、絶対」「条件付きバリデーション使うな、絶対」「ロジックがひとかけらもないのが理想」に変わりました。envy)の「コードの臭い」が何度か発生するという事態になってしまいました。model)」アプローチが期待どおりの成果を出してくれていないようです。あるときは、何が何でもコールバックを避けようとするあまり、コールバックでモデルと結合していたgemを引っぺがそうとしてシャレにならない時間を使ってしまいました。「純潔を守る」という意味では間違っていなかったのでしょうが、ビジネス上の決定としてはとても褒められたものではありません。コードは、ビジネスを支えて必要な機能を提供するのが目的であり、けがれを知らない乙女のように一点の汚れもないソリューションを目指すのが目的ではありません。メンテナンスのしやすさももちろん重要ですが、混じりけのない美しい設計を実現したところでビジネス上の価値が高まるとも限らず、むしろ時間ばかりかかってしまうようでは、それを目指したところでほとんどのアプリがすぐにも採算割れしてしまうでしょう。そんなこんなで、ActiveRecordやモデル層への取り組み方もだいぶバランスを取り戻しました。Wayのメリットがどれほど大きいか、痛いほどわかります。私はモデルに関係のあるロジックをモデルに置く傾向もあるのですが、さてここで問題です。いうことをしているとファットモデルになりやすいでしょうか?モデルのコードが200〜300行にも達する大規模アプリなら、「イエス」の場合もあります。ロジックの凝集度が高く、コンテキストにそれほど癒着していないのであれば、大した問題にはなりませんでした。明確さが落ちることもほとんどありませんでしたし、メンテナンス性に負の影響が生じたわけでもありませんでした。重要なのは、一般的なドメインモデルロジックだけをモデルに配置することです。理想は、そのロジックが永続性そのものとは無関係であることです。このアプローチに沿うようにしたことで、私にとってはだいぶうまくいくようになりましたし、ActiveRecordに本気で頭にくることもなくなりました。Mapperパターンなどの方が上かもしれません。他にも、update_attributeやupdate_columnsといったメソッドは、十分な理由なしに用いると深刻な混乱を呼び起こす可能性がありますし、ActiveRecord.suppressのような見慣れない機能をうかつに使うとコードが理解不能すれすれになる可能性もあります。それでもActiveRecordを使いつつモデルをきれいに保つことは可能ですし、深刻な害をもたらす可能性があることがわかっているからといって、必ずしも絶対に使ってはならないということにはなりません。その部分の責任は、問題をスマートに解決して長期間メンテ可能になるよう、ツールや設計を選ぶ開発者にあります。ObjectやOperationクラスなどを提供するミニフレームワークです)。Railsのこの選択は必ずしも悪いものではないと私は思っています。モデルやコントローラの一般性は十分高いので、ほとんどのアプリは多かれ少なかれ似通ったものになります。Objectを実装したり層を追加したりするgemはいろいろありますが、そのほとんどは互いに著しく異なっています。Objectを追加するだけで極上の設計になるなどということはまずありません。Object、はたまた他の抽象化の構造のあるべき理想の姿をどうやって知ればよいのでしょうか?ほとんどのRails開発者が満足できるソリューションを見いだすのはおそらく死ぬほど困難でしょうし、Railsにそうした層を追加することで結果的に実装の詳細やインターフェイスが競合してしまうようでは、本当に生産的であるとは言えないでしょう。私見では、既存の層を対象とする現在のアプローチこそが正解であり、十分経験を積み重ねた開発者なら、どのようなアーキテクチャを用いるアプローチがアプリに最適であるかを見極められるはずです。ActiveSupportActiveSupportが、特にモンキーパッチ周りで多くの開発者に問題視されている層であることは確かでしょう。私自身はモンキーパッチを偏愛しているわけでもありませんし、使うこともまずありませんが、ActiveSupportが提供するコア拡張機能は実に有用かつ便利極まると思いますし、ActiveSupportで大きな問題に突き当たった覚えもありません。純粋さという意味では「エレガントな」ソリューションからはほど遠いであろうという点については同意しますが、長期的にはアプリでこれといった問題を引き起こすでもなく、着々黙々と仕事をやり遂げてくれています。突き詰めれば、これこそがソフトウェアエンジニアリングにおいて最も肝心な点ではありませんか。ActiveSupportに対する批判は総じて少々無理筋気味で、ActiveSupportがもたらす恩恵など取るに足らないものと決めてかかっているフシがありますが、ActiveSupportには多くの利点があることを見過ごす訳にはいきません。他のフレームワークはどうよ?この5年間で、Rails以外のフレームワークについてもいくつか試す機会に恵まれました。その中にはDjango(Python)もあればPlay(Java)もあればPhoenix(Elixir)もあればMeteor(JavaScript)もありましたし、Ruby製の他のフレームワークとしてはSinatraやHanamiも試しました。これらのフレームワークではそれなりに楽しく作業できましたが、生産性や開発の楽しさという点ではRailsでの経験を超えるほどではありませんでした。これについては明らかに(Railsの)エコシステムが成熟してきていることが大きな役割を果たしていますし、だからこそ新しいフレームワークたちの一部がRailsと互角に戦おうとして四苦八苦しているわけですが、gemを追加していない素っ裸のRailsですら、その生産性は他のフレームワークと比べて著しく上回っています。将来について少なくとも一般的なWeb開発向け以外の用途であれば、私にとってRailsをここしばらく置き換えるに足るであろうフレームワークは今のところ見当たりません。Phoenixはある意味でRailsに似ている面がありますし、もしかすると一番近いのかもしれませんが、私にすればElixir言語や関数型パラダイムの学習は、Rubyやオブジェクト指向プログラミングを学ぶよりずっとつらいものです。Railsの方がコミュニティもずっと大きく成熟しており、総合的な開発しやすさでも遥かに上です。Phoenixは、RubyやRailsと比較して速度やコンカレンシーといった点において明らかに上回っているにもかかわらず、この境地に達するにはかなり時間を要するかもしれません。Railsは、間違いなく私のプロ人生を素晴らしいものにしてくれましたし、これまで関わる機会のあったどのアプリを開発しているときにも計り知れない喜びを味わいました。本気で頭にきたことも一度や二度ではなかったにもかかわらず、です。至らない点はそれなりにあるものの、それでもRailsは私にとってほとんどの場合真っ先に選ぶフレームワークであり、これに取って代わるものは今のところ心当たりがありません。コボラー、ITコンサル、ローカライズ業界、Rails開発を経てTechRachoの編集・記事作成を担当。チュートリアル第2版の監修および半分程度を翻訳、Railsガイドの初期翻訳ではほぼすべてを翻訳。その後も折に触れて更新翻訳中。enno.jpを運営。実は最近Go言語が好きで、Goで書かれたRubyライクなGoby言語のメンテナーでもある。仕事に関係ないすっとこブログ「あけてくれ」は2000年頃から多少の中断をはさんで継続、現在はnote.muに移転。Storageを使ってはいけない(翻訳)#Tags#会社紹介#自社サービス#勉強会#Rails#PHP#デザイン#実績#週刊RailsウオッチCONTACTお気軽にご相談ください。(翻訳)CONTACTTechRachoでは、パートナーシップをご検討いただける方からのご連絡をお待ちしております。お気軽にご意見・ご相談ください。