(訳者注: 原文は https://rubyonrails.org/doctrine/ です。しばらく寝かして問題なさそうであれば本家に投げようかと思っています。おかしいところがあればコメント・編集リクエストをお待ちしております。)
The Rails Doctrine
By David Heinemeier Hansson in January, 2016
Ruby on Railsの驚異的な台頭は、斬新な技術とタイミングによるところが少なからずあります。しかし、技術的な優位性は時間の経過とともに失われていきますし、タイミングの良さだけでは長期にわたってムーブメントを維持できません。そのため、Railsがどのようにして現役であり続けることができたのかだけでなく、どのようにしてそのインパクトとコミュニティを成長させてきたのかについて、より広範な説明が求められています。私が提唱するのは、永続的な実現要因は、今も昔も物議を醸しているドクトリン(信条)にあるということです。
このドクトリンは過去10年の間に進化してきましたが、その最も強力な柱のほとんどは開発当初からのものでもあります。私はこれらの考え方の根本的なオリジナリティを主張していません。Railsの主な成果は、プログラミングとプログラマーの本質についての異端的な考えを手広く集めたものを中心に、強力な部族を団結させ、育成したことです。
以上のことを踏まえて、Railsのドクトリンとして最も重要な9つの柱を以下に紹介します。
- プログラマーの幸せへの最適化 Optimize for programmer happiness
- 設定より規約 Convention over Configuration
- メニューは「おまかせ」 The menu is omakase
- 唯一のパラダイムはない No one paradigm
- 美しいコードの称賛 Exalt beautiful code
- 鋭利なナイフの提供 Provide sharp knives
- 統合されたシステムであることを重視 Value integrated systems
- 安定性よりも進歩 Progress over stability
- 大きな傘を広げる Push up a big tent
プログラマーの幸せへの最適化 Optimize for programmer happiness
RubyなしではRailsは存在しません。そのため、最初の信条の柱がRubyを作る動機の核心から直接導き出されたものであることは当然のことです。
Rubyの独特な特徴は、プログラマーの幸せを台座に据えたことでした。それ以前のプログラミング言語やエコシステムを牽引してきた他の多くの競合する有効な懸念事項よりも優先して、です。
Pythonが「何かをするための方法は一つしかない」を長所として掲げるのに対し、Rubyは表現力と繊細さを追求してきました。Javaがプログラマーを自分たちから強制的に保護することを主張していたのに対し、Rubyは初学者向けキットに鋭利なナイフ一式を入れていました。Smalltalkがメッセージパッシングの純粋さを追求していたのに対し、Rubyはキーワードやコンストラクトを貪欲に蓄積していきました。
Rubyが他の言語と異なっていたのは、Rubyが異なるものを大切にしていたからです。そして、それらの多くはプログラマーの幸せを追求することにつながりました。Rubyのポリシーは、他の多くのプログラミング環境から見て異質だっただけでなく、プログラマーとはどのような人間で、どのように振る舞うものなのかという常識的な感覚からもかけ離れていました。
Rubyはプログラマーの気持ちというものを認識しただけでなく、その気持ちを汲み取り、高めようとしました。それが不完全であろうと、気まぐれであろうと、喜びであろうと。Matzは、驚くほど複雑な実装のハードルを飛び越えて、機械がパートナーである人間にこっそり微笑みかけたり、気の利いたセリフを話したりするかのように感じられるようにしました。Rubyはイリュージョンに満ちており、私たちの心の目にはシンプルで明確で美しく見えていても、実際には床下配線がアクロバットのように渦巻いていたりします。これらの選択は容易に達成されたものではありませんでした(この魔法のオルゴールをリバースエンジニアリングしようとしたことについてはJRubyのクルーに尋ねてみましょう!)。そしてそれこそが、賞賛に値する理由です。
私のRubyへの恋心を決定づけたのは、プログラミングとプログラマーのための新たなビジョンへの真摯な姿勢でした。それは単に使いやすさだけではありません。ブロックの美学だけでもありません。また一つの技術的な成果でもありません。それはビジョンでした。カウンターカルチャーでした。既存のプロのプログラミングの型にはまらない人たちが、同じような心を持った人たちと仲間になるための場所でした。
私は以前、このRubyの発見を、自分の脳に完璧にフィットする魔法の手袋を見つけたと表現したことがあります。それまで自分に合った手袋として期待していたあらゆる想像を上回るものでした。しかし、それ以上のものでした。「プログラムが必要だったからプログラミングする」から、「知的なエクササイズと表現の手段としてのプログラミングが気に入ったからプログラミングする」へと、私自身の変化を示す出来事だったのです。それは、フローの源泉を見つけて、それを自由にオンにすることができるようになったことでした。チクセントミハイの仕事をよく知っている人にとっては、このインパクトは言い過ぎではないでしょう。
Rubyは私を変え、私のライフワークへの道を切り開いてくれたと言っても過言ではありません。それほど深い啓示でした。それは私にMatzの創造物に奉仕して宣教活動をするという召命を吹き込みました。この深遠な創造とその恩恵を広める手助けをするために。
皆さんの多くが信じられずに首を振っているのは想像できます。私はあなたを責めるつもりはありません。もし私がまだ「プログラミングはただの道具」というパラダイムの下で生きていたときに、誰かが上記の経験を説明してくれたら、私も首を横に振っていたでしょう。そして、宗教的な言葉を使った大げさな表現には笑っていたでしょう。しかし、これが真実であるためには、一部の人やほとんどの人が不快に思うようなことであっても、正直でなければなりません。
それはさておき、このことはRailsにとって何を意味し、この原則はどのように進化の指針となり続けるのでしょうか? その問いに答えるためには、初期の頃にRubyを説明するのによく使われていた別の原則、「驚き最小の原則」を見てみるのが有益だと思います。Rubyはあなたが期待するように振る舞うべきです。これはPythonとの対比で簡単に説明できます。
$ irb
irb(main):001:0> exit
$ irb
irb(main):001:0> quit
$ python
>>> exit
Use exit() or Ctrl-D (i.e. EOF) to exit
Ruby は exit
と quit
の両方を受け入れ、プログラマが対話型コンソールを終了したいという明らかな欲求に対応しています。一方、Python は、(エラーメッセージを表示しているため) 何を意味しているのか明らかに分かっているにもかかわらず、要求されたことを適切に行う方法をプログラマに指示します。これは、小さいとはいえ、「驚き最小の原則」のかなり明確な例です。
「驚き最小の原則」が Ruby コミュニティの支持を得られなくなった理由は、この原則が本質的に主観に基づいているからです。誰にとって驚きが最小なのでしょうか? まあ、Matzにとってですね。そして、彼と同じように驚いている人たちです。Ruby コミュニティが成長し、Matz とは異なることに驚く人の割合が増えていくと、この原則はメーリングリストでたびたび実りのない「自転車置き場の議論」の火種になりました。そこで、「XさんがYという挙動に驚いたかどうか」という出口のない議論をこれ以上増やさないために、この原則は背景に消えていったのです。
では、繰り返しになりますが、これがRailsと何の関係があるのでしょうか。まあ、Railsは「(Matzにとっての)驚き最小の原則」と似たような原理で設計されています。「(DHHにとっての)微笑み最大の原則」という原則は、まさにブリキに書いてある通りです。私をもっともっと広く笑顔にしてくれるようなものに細心の注意を払って設計されたAPIです。このように書き出すと、ほとんどコミカルなナルシストのように聞こえますし、私でさえ、その第一印象に反論するのは難しいと思います。
しかし、RubyやRailsのようなものを作るということは、少なくともその最初の段階では、深く自己愛的な献身の賜物なのです。どちらのプロジェクトも、一人のクリエイターの頭の中から生まれたものです。しかし、私がここでMatzに自分の動機を投影しているのかもしれないので、私が知っていることに絞って述べることにしましょう。私がRailsを作ったのは、私自身のためです。何よりも、私が笑顔になるためです。Railsの実用性の多くは、私がもっと楽しく生きるためにRailsに与えた能力に伴って生まれたものです。Web情報システムへの要件やリクエストをこなす日々の労苦を豊かにするためです。
Matzのように、私も時折、自分の主義主張を貫くためにふざけたことをしました。その一例がInflectorで、PersonクラスをPeopleテーブルに、AnalysisクラスをAnalysesに、そしてCommentクラスをCommentsにマッピングするのに十分な英語の活用形パターンと不規則活用を理解しているクラスです。この動作は現在ではRailsの疑う余地のない要素として受け入れられていますが、まだドクトリンとその重要性が固まっていなかった初期のRailsで論争を巻き起こしました。
そこまで実装に手間取らなかったものの、ほぼ同じくらいの騒動を引き起こした別の例が、Array#second
〜 #fifth
(および誰かが食いつくのを期待した#forty_two
)です。これらのエイリアスアクセサは声の大きいユーザーを著しく刺激し、Array#[1]
、Array#[2]
(およびArray[41]
)のように書けば済むものを肥大化させた(しまいには「文明の終焉が近づいた」)と非難されました。
しかし、この二つの決定は今でも私に笑顔をもたらしてくれます。テストケースやコンソールでpeople.third
と書く楽しさを満喫しています。もちろん、この楽しさは論理的でも効率的でもなく、病的とすら言えるかもしれません。しかしそのおかげで私は笑顔でいられ、それによって例の原則も満たされ、私の人生も豊かになり、私が12年間面倒を見てきたRailsに今後も関わり続けようと思えてくるのです。
パフォーマンスの最適化とは異なり、幸福度の最適化を測定するのは困難です。そのため、幸せを追求する努力の多くは本質的に非科学的で、つらい作業とまではいかなくても重要度が下がりがちです。プログラマーは、測定可能なものを議論し、征服することを教わります。つまり、結論が明確で、AがBよりも優れていると断言できるものです。
幸せの追求はミクロレベルでは測定が困難ですが、マクロレベルで観察するとはるかに明確になります。Ruby on Railsコミュニティには、まさにそうした点を追求するために来た人たちが大勢集まっていて、仕事人生が改善され充実したことを誇っています。そうした感情が集結する場を観察すれば、勝利は明らかです。
というわけで、結論です。幸せのために最適化することは、おそらくRuby on Railsが形成されるうえで最も重要な鍵であり、今後もそうあり続けるでしょう。
設定より規約 Convention over Configuration
初期のRailsにおける生産性のモットーの1つに、「あなたは世界でただ一つの美しいひとひらの雪ではない」というものがありました。意味のない個性重視をやめることで、平凡な意思決定を繰り返す煩わしさから解放され、本当に重要な分野で進歩を速められるという主張です。
データベースの主キーがどのような形式で記述されているかなんて誰が気にするでしょうか? それが "id"、"postId"、"posts_id"、または "pid"であるかどうかは本当に重要でしょうか? これは繰り返し審議する価値のある決定なのでしょうか? いいえ、そうではありません。
Railsの使命の一つは、Web情報システム開発者の目の前で鬱蒼と広がり続ける「意思決定の繰り返し」というジャングルに大なたを振るうことです。このような意思決定が必要な項目は何千もありますが、本来は一度決めれば済むことであり、誰かが代わりにやってくれれば、それに越したことはありません。
設定重視から規約重視に移行することで、私たちは意思決定の悩みから解放されるだけでなく、より深い抽象化を育てやすい豊かな地盤も提供できるようになります。Person
クラスが people
テーブルへマッピングされることが期待できるなら、同様の活用形で Person
クラスへマッピングされることを期待して has_many :people
というアソシエーションを宣言できます。優れた規約には、このように幅広い方面で活用できる強みがあります。
しかし、エキスパートの生産性向上だけでなく、初心者の参入障壁を下げることもできます。Railsには、初心者が知らなくても恩恵を受けられるような規約がたくさんあります。すべてのものがなぜそのようになっているのかを知らなくても、素晴らしいアプリケーションを作ることは可能です。
フレームワークが単なる分厚い教科書で、新しいアプリケーションが何も書かれていないただの白紙だとしたら、そんなことは不可能です。どこからどう手を付けたらよいかを把握するだけで途方もない努力が必要になり、作業の半分はとっかかりを見つけることに費やされてしまうでしょう。
すべてのピースがどのように組み合わされているのかを理解している場合も、同じことが言えます。それぞれの変更について次に何をするかが明白であればこそ、過去に経験したあらゆるアプリケーションと同じ部分や似通った部分の多くを早足で駆け抜けることができるようになります。あらゆるものに置き場所が定められ、あらゆるものが正しい場所に置かれるようになります。制約は、最も有能なマインドをも解放するのです。
しかし、何事もそうですが、慣習の力には危険がないわけではありません。Railsが多くのことをあまりにもあっさりこなすのを見ていると、アプリケーションのあらゆる側面は既成のテンプレートで作れるのではないかと思われがちです。しかし、構築する価値のあるアプリケーションには、ほとんどの場合、何らかの形で取り替えのきかない独自の要素があるものです。そうした要素は全体の5%や1%に過ぎないかもしれませんが、確かに存在します。
難しいのは、どんなときに規約から逸脱してよいかを見極めることです。独自の方法に逸脱して遠くまで進むことが、十分正当化できるほど重要な意味を持つのはどんなときでしょうか?私に言わせれば、世界にただ一つの美しいひとひらの雪でありたいという衝動は、ほとんどの場合検討が不十分で、Railsから外れるコストを過小評価していると思いますが、そうでない場合も十分ありうるので、その場合はあらゆる点を慎重に検討する必要があるでしょう。
メニューは「おまかせ」 The menu is omakase
何が美味しいか分からないのに、レストランで何を注文すればいいのか、どうやってわかるのでしょうか? そうですね、シェフに選んでもらえば、何が「美味しいもの」かわからないうちから、たぶん「美味しいもの」にありつけます。それが「おまかせ」です。料理の達人でなくても、目をつぶって運任せで選ばなくても、美味しいものを食べるための方法なのです。
プログラミングにとって、他の人にスタックの組み立てを任せるというこのプラクティスの利点は、「設定より規約を重視する(CoC: Convention over Configuration)」から得られるものと似ていますが、さらに高いレベルでのものです。CoCが個々のフレームワークをどのように使うのがベストなのかということで占められているのに対し、おまかせは「どの」フレームワークをどのように組み合わせて使うかに重点を置きます。
これは、利用可能なあらゆるツールを自由に選択可能にして、個々のプログラマにツールを決定する特権を(そして負担も)与える、という崇高なプログラミングの伝統と相反するものです。
「道具は自分の仕事に最適なものを使え」という言葉を聞いたことがあるでしょうし、うなずいたこともあるでしょう。これは議論の余地がないほど基本的な話のように思えますが、実際に「最適な道具」を選べるかどうかは、自信を持って「最適」を決める根拠があるかどうかにかかっています。これは見た目よりもずっと難しいことです。
これは、レストランでのディナーの問題に似ています。レストランでコースを選べば8品の料理もおのずと決まるのと同じように、Railsでは個別のライブラリやフレームワークを別途選ぶ作業は発生しません。どちらの場合も、ディナーやシステム全体を考慮することが目的です。
そこでRailsでは、ツールボックスの中から好きなツールを個別に選べるというプログラマー個人の善き特権を一つ減らし、代わりにより大きな善、すなわち「万人向けのより良いツールボックス」を増やすことに決めました。これによって以下のような多くのメリットを得られました。
-
数は安心感につながる: ほとんどの人が同じデフォルトの方法でRailsを使っていれば、皆が同じ経験を共有できます。このような共通基盤があると、教育やサポートが格段にやりやすくなりますし、そこから先へのアプローチを議論するときの基盤にもなります。昨日の夜7時にみんなで同じ番組を見ていれば、翌日その番組を話題にできるようになります。これによってコミュニティでつながる感覚がいっそう育まれます。
-
みんなで同じ基本ツールボックスを完成させる: フルスタックフレームワークであるRailsには多くの可動部品があり、それらを連携して動かす方法は、部品単体の動作と同じくらい重要です。ソフトウェアの痛みの多くは、個々のコンポーネントではなく、その相互作用から生じます。同じように構成され、同じように失敗するコンポーネントの共通の痛みを和らげることに全員で取り組めば、痛みを経験することは少なくなります。
-
置き換え可能だが、置き換えなくともよい: Railsはおまかせスタックですが、特定のフレームワークやライブラリを他のもので置き換えることも可能です。ただし置き換えは必須ではありません。つまり、自分の中で「ここは別のものを使いたい」といった明確な好みが固まるまでは、そのような決定を先延ばしにできるということです。
Railsを使い始めて今でも使い続けている、最も経験豊富な熟練プログラマーでさえ、Railsが用意したメニューのすべてに反対しているわけではありません(もしそうであれば、おそらくRailsに留まっていなかったでしょう)。熟練プログラマーたちは、代替部品を選ぶときは真剣に吟味し、後は他の人々と同様に精選された技術スタックの残りの部分を楽しむようにしています。
唯一のパラダイムはない No one paradigm
中心となるただ一つのアイデアを掲げて、そこから論理的帰結としてアーキテクチャのさまざまな基盤を導き出そうという主張には、強く感情に訴える魅力があります。このような規律には純粋さがあるため、プログラマーがこの眩しい光に自然と惹き寄せられるのは明らかです。
Railsはそうではありません。Railsは一枚の完全無欠な布地ではなく、さまざまな布地を縫い合わせたキルトです。Railsはさまざまな異なるアイデアやパラダイムの複合体であり、その多くは、一つ一つを単独で見比べると互いに相容れないように見えます。しかし、私たちがRailsでやろうとしているのはそのような対立ではありません。Railsは、勝者がただ一人でなければならないような優秀アイデア選手権の場ではないのです。
Rails MVCのうち、ビューを構築しているテンプレートを見てみましょう。これらのテンプレートからコードを抽出したヘルパーは、デフォルトではどれも大鍋に放り込まれた関数にすぎません! 名前空間すら一つにまとめられています。なんと衝撃的で恐ろしいことでしょう、まるで昔ながらのPHPのスープのようです!
しかしここで申し上げたいのは、ビューテンプレートの多くの抽象化がそうであるように、相互作用をほとんど必要としない個々の関数を提示する方法についてはPHPが正しかったということです。そして、単一の名前空間とメソッドの大鍋は、その目的のための合理的な選択であるだけでなく、優れた選択でもあります。
だからといって、ビューを構築する際に、よりオブジェクト指向的なものに手を伸ばしたくなることもないわけではありません。プレゼンターのコンセプトは、相互に依存している多くのメソッドとその下にあるデータをラップすることで、依存関係によって酸っぱくなってしまったメソッドのスープの完璧な解毒剤になることがあります。しかし、プレセンターがうまく適合することはめったになく、一般的ではないことが示されています。
一方、MVCという3層のケーキに含まれるモデルについては、オブジェクト指向の素晴らしさを発揮する重要な砦として扱うのが一般的です。オブジェクトにふさわしい名前を見つけ、凝集度を高め、癒着を削ぎ落とすことがドメインモデリングの醍醐味です。モデルはビューとは全く違うレイヤーなので、私たちは別のアプローチをとっています。
しかし、ここでも私たちはシングルパラダイムというドグマを支持していません。Railsのconcernsは、Rubyのミックスインの特殊版で、個々のモデルに非常に広大な拡張を与えるためによく使われています。アクティブレコードパターンでは、concernsのメソッドが相互作用するデータやストレージに直接アクセスできるようにすることで、うまく調和します。
しかし、このActive Recordフレームワークの基礎ですら、一部の純粋主義者にとっては目ざわりな部分です。私たちは、データベースと直接連動するために必要なロジックを、ビジネスドメインのロジックと混ぜています。「境界の侵犯だ!」はい、おっしゃる通りです。このようにする理由は、何らかのデータベースと事実上常に通信してドメインモデルを永続化するウェブアプリを実現するには、この方法が実用的であることが明らかになったためです。
Railsが思想的に柔軟だからこそ、このようなさまざまな問題に対処することが可能になるのです。個別のパラダイムは、問題空間の特定の範囲内ではほとんどの場合非常にうまく機能しますが、自然な範囲を超えて適用されると厄介で融通の利かないものになります。私たちは、たくさんのパラダイムを重複して適用することで側面をカバーし、背面をガードします。最終的なフレームワークは、個々のパラダイムだけで実現可能なものよりもはるかに強力で有能なものになります。
さて、このようにプログラミングに関する多くのパラダイムと節操なく関係を結ぶようになると、それと引き換えに概念上のオーバーヘッドが生じます。オブジェクト指向プログラミングを知っているだけではRailsを楽しむことはできません。手続き型プログラミングや関数型プログラミングの経験も十分に積んでいる方が望ましいでしょう。
同じことがRailsの多くのサブ言語にも当てはまります。私たちがやろうとしているのは、少なくとも、ビューで使うJavaScriptや、たまに複雑なクエリで使うSQLなどの奥義を極めるほど徹底的に学ばなくても開発できるようにすることであり、それらをほとんど学ばなくても済むようにすることではありません。
こうした学習の負担をある程度軽減するには、Railsを手軽に始められるようにすることです。そうすることで、フレームワークのあらゆる側面を完全に理解する前の段階でも本物の価値を生み出せるようになります。Railsがハローワールドを大急ぎで用意する理由はこのためです。テーブルはすでに準備されていて、前菜も並んでいます。
私たちが考えているのは、Railsを学ぶ早い段階で、本当に価値のあるものを提供し、それによって学習者が短期間でレベルアップできるようにすることです。Railsを学ぶ旅を障害物競走にせず、快適な旅行になるように考えましょう。
美しいコードの称賛 Exalt beautiful code
私たちがコードを書くのは、コンピュータや他のプログラマーに理解されるためだけではなく、心地よく美しい光を浴びるためでもあります。美的に優れたコードはそれ自体が価値であり、精力的に追求されるべきものです。美しいコードが常に他の何ものにも勝るというわけではありませんが、優先順位表から外すべきではありません。
では、美しいコードとは何でしょうか? Rubyではたいていの場合、ネイティブのRubyイディオムと各ドメイン固有言語の力との間のどこかにあります。美しさの基準は曖昧ですが、取り組んでみる価値は十分にあります。
以下はActive Recordの簡単な例です。
class Project < ApplicationRecord
belongs_to :account
has_many :participants, class_name: 'Person'
validates_presence_of :name
end
これは DSL のように見えますが、実際にはただのクラス定義で、シンボルとオプションを取る 3 つのクラスメソッドを呼び出しています。華々しいことは何もしていませんが、確かに見事です。確かにシンプルです。この数少ない宣言から、膨大な量のパワーと柔軟性を得ることができます。
この美しさの一部は、これらの呼び出しが上述の原則を尊重していることから来ています。belongs_to :account
を呼び出すとき、外部キーは account_id
と呼ばれ、それが projects
テーブルにあることを前提としています。participantsアソシエーションの役割の指定としてclass_name
にPerson
を必要とする場合、必要なのはそのクラス名の定義だけです。私たちは、そこから外部キーと他の設定ポイントを再び導出できるようになります。
データベースマイグレーションシステムの別の例を見てみましょう。
class CreateAccounts < ActiveRecord::Migration
def change
create_table :accounts do |t|
t.integer :queenbee_id
t.timestamps
end
end
end
これがフレームワークの力の本質です。プログラマは、たとえば #change
を実装した ActiveRecord::Migration
のサブクラスのように、特定の規約に従ってクラスを宣言します。フレームワークはその周りのすべての配線をつなげ、これが呼び出すべきメソッドであることを知ることができます。
こうして、プログラマの書くべきコードは非常に少なくなります。マイグレーションの場合、rails db:migrate
を呼び出してデータベースをアップグレードして新しいテーブルを追加するだけでなく、別の呼び出しでこのテーブルを削除することもできます。これは、プログラマーが同様のことを実現するために、自分自身で呼び出すライブラリを使ってワークフローをつなぎ合わせるのとは大きく異なります。
しかし、コードの美しさはもっと微細な部分に現れることもあります。コードを可能な限り短く書いたり強力にしたりすることよりも、宣言の流れをリズミカルにすることの方が重要なのです。
以下の2つの文は、どちらも同じ動作です。
if people.include? person
…
if person.in? people
しかし、フローと着目点は微妙に異なっています。1つ目の文ではコレクションに注目しているので、主語は people
です。2つ目の文の主語は、明らかに person
です。2つのステートメントの長さはそれほど違いませんが、personについての条件で使う場合は2つ目のステートメントの方がはるかに美しいと思います。そういう場所で私がこのコードを目にしたら、きっと笑顔になるでしょう。
鋭利なナイフの提供 Provide sharp knives
Rubyは、機能の引き出しの中に切れ味のよいナイフをたくさん揃えています。これは偶然ではなく、そのように設計されたのです。最も有名なナイフは、既存のクラスやメソッドを変更するモンキーパッチです。
モンキーパッチの力は、人間のプログラマーが扱うには危険すぎると揶揄されることがよくあります。Rubyよりも制約が多い環境から来た人たちは、ユーザーにこんな機能を与えるのはユーザーを信じすぎている、きっとRubyでさまざまな破滅的災難が起きるだろうと想像したものです。
どんなものでも変更できるのであれば、String#capitalize
を上書きして "something bold".capitalize
が "Something bold"
ではなく "Something Bold"
を返すようにすることを止める仕組みがあるでしょうか? このような変更はローカルアプリケーションではうまくいくかもしれませんが、元の実装に依存するさまざまな補助コードを壊してしまう可能性があります。
これについては「止める仕組みはない」が答えです。よく切れるナイフをむやみに振り回す人を制止するプログラム的な仕組みは、Rubyにはありません。私たちはそうした行動を慣習によって、互いに注意を呼びかけあうことによって、そして教育によって自制し、良識を保っているのです。キッチンから鋭いナイフをすべて撤去したり、トマトはスプーンで切らなければならないというルールを押し付けたりするような方法ではありません。
その理由は、モンキーパッチが2.day.ago
(現在から2日前の日付を返す)のような驚異的な機能を実現できる力を秘めているからです。この取引が割りに合わないと思う人もいるでしょう。2.days.ago
が使えなくなってもいいからString#capitalize
を上書きできないようにしたいと思うかもしれません。そのようなスタンスであれば、あなたはRubyには向いていないかもしれません。
しかし、自由と引き換えにもっと安全が欲しい人たちであっても、コアクラスやメソッドを変更する能力によって言語としてのRubyが破滅したと主張するのは難しいでしょう。それどころか、Rubyが繁栄したのは、この言語がプログラマーの役割について従来と大きく異なる急進的な視点を提供したからこそなのです。すなわち、プログラマーを信頼して鋭いナイフを渡すということです。
そしてRubyは、単にプログラマーを信頼するだけでなく、そのような強力なツールの使い方を学べる人々であるとみなしたのです。ほとんどのプログラマーは、指を切らずに鋭いナイフをもっと使いこなせる優秀なプログラマーになりたいと望むものであると仮定すれば、業界全体の向上が期待できるということです。このアイデアは信じられないほど野心的であり、多くのプログラマーが他のプログラマーに対して抱く直感に反しています。
なぜなら、鋭利なナイフの価値についての論争は、常に自分以外の他のプログラマーたちがどう使うかが争点になるからです。プログラマーが自分から手を挙げて「この力を使いこなせる自信がない、だからこの力を自分が使えないようにしてくれ!」などと発言するのを私は一度も聞いたことがありません。実際に耳にするのは「他のプログラマーはこれを乱用するだろう」と相場が決まっています。私は、誰かに保護を求める父権主義的な路線に魅力を感じたことはありません。
そこでRailsの話になります。このフレームワークが提供するナイフは、言語で提供されるナイフほど鋭くはないものの、切れ味のよいものがいくつもあります。Railsがこのようなツールをキットに含めて提供していることについて謝罪するつもりはありません。むしろ、仲間のプログラマたちの志を信じ、あえてそれを信頼したことを祝うべきでしょう。
Railsの多くの機能は、時とともに「自由度が高すぎる」という論争になりました。しかし、ちょうど現在話題になっているconcerns機能を例にとってみましょう。concernsは、Rubyの組み込み機能であるモジュールにシンタックスシュガーの薄い層を加えたもので、互いに関連しながらも独立して理解される複数の関心事(concernsの名前の由来です)を1つのクラスにカプセル化できるように設計されています。
concerns
は、オブジェクトを肥大化させがちなプログラマーに、雑多なものを詰め込む新しい引き出しセットを提供してしまっている、という批判があります。それはその通りで、concerns
は確かにそのように使うことも可能です。
しかしconcerns
は、概念をわかりやすく細部に分割するスキルさえあれば、控えめに使うだけで至福のアーキテクチャに通じる道をプログラマーに示してくれるのですから、これほどの機能を提供しないのは大いなる誤りです。キッチンシンクがconcerns
で溢れかえらないように整理整頓できないうちは、道のはるか遠くに光り輝くエレガントな設計にたどり着くことはおそらくできないでしょう。
プログラマーが鋭いナイフの使いこなし方を学んでいないうちは、まだメレンゲを作ることはできません。ここで重要なのは「まだ」という言葉です。私は、どんなプログラマーにも、一人前の有能なプログラマーになれる道が開かれていると信じています(なれる権利があるとまではいかなくても)。ここで言う「有能」とは、引き出しの中にあるさまざまなツールや危険なツールをいつ・どのように使いこなすかを知りつくしているという意味です。
だからといって、プログラマーがその境地にたどり着けるよう支援しなくてもよいということにはなりません。言語とフレームワークは、誰もが専門家になれるように手を差し伸べ、辛抱強く導くチューターでなければなりません。そうした支援が重要なのはもちろんですが、有能なプログラマーになれる唯一の確かな道は、「ミスだらけの道」を恐れずに最後まで通り抜けることです。ツールの使い方を間違えれば、時には血や汗や涙を流すこともあるでしょう。しかし他に確実な道はありません。
Ruby on Railsは、シェフになりたい人とシェフになった人のための環境です。最初は皿洗いから始めるかもしれませんが、精進を重ねていけばいつの日か厨房を任されるようになるでしょう。修行中に、業界最高のツールを使わせるほどあなたを信頼できないなどと誰にも言わせないようにしましょう。
統合されたシステムであることを重視 Value integrated systems
Railsはさまざまな文脈で利用できますが、初恋の相手としてふさわしいのは、統合システムの構築、すなわち問題全体に対処できるシステム全体を作ることです(マジェスティックモノリス!)。つまりRailsは、ライブアップデートを行うために必要なフロントエンドのJavaScriptから、本番でデータベースをどのようにバージョン間で移行するかまで、あらゆるものに関わっているということです。
これまで議論してきたように、これは非常に広い範囲ですが、一人の人間が理解するのが現実的ではないというほどではありません。Railsは特に、ジェネラリストの個人が独力で完結したシステムを作れるようにすることを目指しています。永続的な価値のあるものを構築するために、さまざまなニッチ分野のみを担当するスペシャリストを集めた本格的なチーム編成を必要とするようなものは、Railsの目的ではありません。
この統合システムでは、個人に力を与えることに重点を置きます。そのような統合システムでこそ、たくさんの不必要な抽象化を削減し、レイヤー間の重複(サーバーとクライアントの両方にテンプレートを配置するなど)を減らし、何よりも、本当に必要になるまでシステムの分散化を避けられるようになります。
AとBの間の呼び出し方法を制限する新しい境界を導入すると、多くの場合システムが複雑になります。オブジェクト間のメソッド呼び出しは単純ですが、マイクロサービス間のリモートプロシージャコールはそれよりもずっと複雑です。分散という巣窟に足を踏み入れれば、失敗状態や待ち時間の問題、依存関係の更新スケジュールなど、まったく見知らぬ苦痛の世界が待ち構えています。
もちろん、分散がどうしても必要になる場合もあります。HTTP呼び出し可能なAPIをWebアプリケーションに追加して、誰でも呼び出せるようにしたければ、苦痛に耐えながらそうした問題の多くに対処しなければなりません(リクエストを外部に送信する処理は複雑です。外部からリクエストを受信する処理の方がはるかに簡単ですが、自分のところでダウンタイムが発生すると、即座に他のところで障害状態として現れることになります!)。しかし、これは少なくとも、あなた自身の個人的な開発経験がある程度ダメージを受けることになるでしょう。
もっと深刻なのは、システム統合の成熟度がまだ低い段階なのに、システムがサービスや(下手をすると)マイクロサービスに分断されてしまうことです。このような状況は多くの場合、モダンなインターネットアプリケーションを作りたければシステムを何回も構築するしかない、という誤解が元になっています。サーバ側で1回、JavaScriptクライアント側で1回、ネイティブモバイルアプリケーションごとに1回ずつ構築しなければならない、といった具合です。これは自然の法則に則ったことではなく、そのようにする必要はありません。
アプリケーション全体の大きなチャンク(塊)を複数のアプリやアクセスにまたがって共有することは、十分に可能です。ネイティブモバイルアプリに埋め込まれたものと同じコントローラとビューのしくみをデスクトップウェブで利用することも、同様に可能です。壮麗にそびえ立つマジェスティックモノリスの内部に、可能な限りあらゆるものを集中させる、これがこの統合システムなのです。
この統合システムのスピードやユーザーエクスペリエンスといったどの要素にも、開発者が早まって分散化したくなるような要素はほとんど見当たりません。
これこそが、私たちが求めている「ほぼすべてを兼ね備える」ことなのです。念入りにチューンアップされた分散アプリケーションと同じパワーを、使いやすく理解しやすい単一の統合システムによって実現しています。
安定性よりも進歩 Progress over stability
Railsのように10年以上前から存在しているシステムでは、自然と硬直化に向かう傾向があります。どんな変更でも、過去の挙動に依存していた誰かにとって、問題になる可能性はいくらでもありえます。そして、実際にそれが当てはまる当人にとっては公平な理由です。
しかし、あまり保守的な声に耳を傾けすぎてしまうと、その反対側に何があるかが見えなくなってしまいます。私たちは、進化と成長のために、時にはあえて壊したり、やり方を変えたりしなければなりません。この進化こそが、これからの(数?)十年にわたってRailsが生存と繁栄に適した状態を維持することになるのです。
これは論理的には理解しやすいですが、これを受け入れて実践するのははるかに難しいことです。特に、Railsのメジャーバージョンでの下位互換性のない変更が原因で、自分のアプリケーションが壊れてしまった場合はなおさらです。そのようなときこそ、私たちは安定性よりも進歩を大切にし、壊れたものをデバッグして、それを解明し、時代とともに歩んでいく強さを与えてくれる、この価値を覚えておく必要があるのです。
これは、必要のない、あるいは過剰なダメージをいたずらに与えてもよいということではありません。2.xから3への大規模なRailsの移行は、その当時の関係者の多くに傷跡として今でも残っています。実に大変なことでした。深刻な大変動により、多くの人たちが3へ移行できず2.xに長い間取り残され、納得できないほど不快な思いをしました。しかし、大局的には、やはり実行する価値のあることでした。
これは、私たちがこれからも続けていかなければならない厳しい交渉です。今日行った変更によって、5年後のRailsはより良い状態になっているでしょうか? ジョブキューやWebSocketsのような別の問題領域を採用したほうが、数年後のRailsの利益になるのでしょうか? もしそうだとしたら、それを取り入れて作業しようではありませんか。
この作業はRails自体だけでなく、より大きなRubyコミュニティでも行われる必要があります。Railsは、Rubyコミュニティの人々がより新しいバージョンを採用するように促すことで、Rubyの進歩を支援する最前線に立つべきです。
これまでのところ、私たちはこの点では非常によくやっています。私が始めたときから、Ruby 1.6、1.8、1.9、2.0、2.1、2.2、2.3、2.4、2.5、そして現在は2.6へと移行してきました。この間、多くの大きな変更がありましたが、RailsはRubyの後ろ盾となり、誰もがより速くプログラムを利用できるようにするために存在していました。これは、RailsがRubyの主要な普及者としての特権と義務の一部です。
これは補助ツールチェーンにも当てはまります。Bundlerはかつて物議をかもしたアイデアでしたが、未来を共有するための礎となるものだとRailsが主張したことで、今日では当たり前のように使われるようになりました。アセットパイプラインや、永続的なコマンドプロセスであるSpringなどについても同じことが言えます。これら3つはいずれも、成長の痛みを経験したか、あるいは今も経験していますが、長期的に見て価値があることが明らかであるため、私たちはそれを押し通してきました。
進歩とは、最終的にはほとんどの場合、変化を推し進めようとする人々と、その意欲にかかっているのです。Rails CoreやRails Committersのようなグループに終身の席がないのはこのためです。どちらのグループも、フレームワークの進歩に積極的に取り組んでいる人たちのためのものです。ある人にとっては、そのような進歩への関与はわずか数年で終わり、私たちは彼らのサービスに永遠に感謝するでしょうが、他の人にとっては何十年も続くかもしれません。
同様に、このことはコミュニティの新しいメンバーを歓迎し、奨励し続けることが非常に重要な理由でもあります。私たちは、より良い進歩を遂げるために、新鮮な血と新鮮なアイデアを必要としています。
大きな傘を広げる Push up a big tent
多くの物議を醸すアイデアを持つRailsは、すべての人に常にすべての信条を完全に尊重することを求めれば、すぐに偏った思想の隠者による孤立した集団になる可能性があります。だから私たちはそうしません!
私たちには意見の相違が必要です。方言が必要です。思想や人物の多様性が必要です。このアイデアのるつぼの中にこそ最高の共有物があるのです。多くの人々が、コードや考察に基づく議論を通じて、協力しています。
このように、このドクトリンでは理想化された形を説明していますが、日常の現実はもっと繊細な(そして興味深い)ものです。Railsがこのような大規模なコミュニティを一つの傘のもとで支えることができるのは、リトマス試験がない(あったとしてもほとんどない)からです。
私がしばしば重大な不満を表明してきたテスト用DSLであるRSpecの継続的な成功は、完璧な証拠です。私はなぜこれではいけないと思うのか、顔を真っ赤にしてわめき散らすことができますが、にも関わらずRSpecは依然として花を咲かせ、繁栄することができます。その点の方が遥かに重要なのです!
APIとしてのRailsの到来についても同じことが言えます。私の個人的な焦点とこだわりは、ビューを含む統合システムにありますが、クライアントとサーバを分割したいと考えている人にも、Railsがうまくいく余地があることは間違いありません。私たちはこれを二次的なミッションとして共存できる限り受け入れるべきであり、それは確実に可能だと信じています。
大きな傘を広げるということは、すべての人に万能であろうとすることではありません。すべての人を歓迎し、自分の飲み物を持ってくることを許可するということです。他の人にも参加してもらうことで、私たちの魂や価値観を失う必要はありませんし、おいしい飲み物の新しい混ぜ方も学べるかもしれません。
これはタダではできません。歓迎するための努力が必要です。特に、あなたの目標が、すでにコミュニティの一部になっている人たちと同じような人たちをより多く集めることだけではないのであれば、なおさらです。参入障壁を下げることは、常に真剣に取り組むべき仕事です。
ドキュメントのスペルミスの修正を始めた人が、次の素晴らしい機能を実装することにいつなるかは誰にもわかりません。しかし、あなたが微笑んで、どんな小さな貢献にも感謝を示すことで、モチベーションを高めさせ、その可能性も生まれるかもしれません。