Badri Janakiraman 氏とのヘキサゴナル Rails に関する対談
最近、Kent Beck 氏や David Heinemeier Hansson 氏とTDD は死んだのかについて議論を重ねてきましたが、そこから多くの議論が派生しました。その一つが、Thoughtworks のシニア開発者である同僚の Badri Janakiraman 氏との意見交換です。Badri 氏は 10 年以上の経験を持ち、Ruby on Rails だけでなく、Java や .NET を使った開発スタックにも精通しています。過去 6 年間は、製品部門であるStudiosに所属し、長年 Rails プロジェクトとして稼働しているプロジェクトコラボレーションツールであるMingleに携わってきました。
私たちの議論は非常に興味深いものであったため、ビデオに記録することにしました。そこで、ビデオチャットの時間を設けました。これは、Ruby on Rails におけるヘキサゴナルアーキテクチャの役割についての興味深い視点、そして「TDD は死んだのか」という議論を補完する有益な情報となるでしょう。
1: アクティブレコード vs データマッパー
2014年6月5日
ヘキサゴナルアーキテクチャの概念を紹介し、Badri 氏はアクティブレコードを使用するかデータマッパーを使用してデータベースをヘキサゴンの外側に押し出すかのトレードオフについて説明します。
more…(続きを読む)
Minutes(議事録)
Badri 氏は、Alistair Cockburn 氏によって提唱されたヘキサゴナルアーキテクチャの概念を説明することから始めました。 このアーキテクチャの主要なアイデアは、ドメインが外部コンポーネントに依存しない自己完結型のエンティティであるということです。これにより、外部コンポーネントから独立してアプリケーションを推論し、テストすることができます。 これは、何が外部で何が内部なのかという疑問につながります。Rails におけるヘキサゴナルアーキテクチャの説明では、通常、データベースは外部と見なされますが、これは必ずしもそうとは限りません。 元の記事では、さまざまな形式の UI を介してアプリケーションを駆動することも検討されています。
Martin は、ヘキサゴナルアーキテクチャと階層型アーキテクチャの概念との関係を描きました。一般的な階層化は、UI、ドメイン、データソースのレイヤーを持ち、UI → ドメイン → データソースという依存関係を持つバリエーションです。ヘキサゴナルアーキテクチャは、ドメインとデータソース間の依存関係を変更し、UI → ドメイン ←︎ データソースという依存関係にします。 Martin がP of EAAを書いたとき、彼はこのアプローチをデータマッパーパターンとして説明しました。これは、ドメインをデータソースに結び付けるアクティブレコードとは対照的です。
Martin は Badri 氏に、データマッパーとアクティブレコードの違いをどのように特徴づけるかを尋ねました。彼は、それは構築する必要があるアプリケーションの種類によって決まると答えました。彼は初期のキャリアで、リースや保険などの複雑なビジネスロジックを持つアプリケーションを構築しました。ドメインにそのような複雑さがある場合、データベースの懸念事項から分離する必要があります。
過去 6 年ほど、彼は Rails を使用して、はるかに単純なドメインロジックを持つ製品アプリケーションに取り組んできました。たとえば、Mingleは、カードウォールのメタファーを使用してバックログを管理するのに役立つプロジェクトコラボレーションツールです。Thoughtworks の哲学は、ツールがチームのプロセスを制約すべきではないというものであるため、データには多くの柔軟性、つまりユーザー定義フィールドが必要です。ユーザー定義フィールドの通常のアプローチはあまりうまく機能しないため、カスタムフィールドを追加するためにリレーショナルスキーマを動的に変更します。これは非常にうまく機能し、ドメインオブジェクトをデータベースに結び付け、データベースをアプリケーションの中心に据えています。 Martin は、ここでのテーマは、ドメインモデルとデータソースを独立して進化させたい場合にデータマッパーを使用する必要があるということだとまとめました。
Badri 氏は、Rails 以前の仕事では、アプリケーション開発者がデータベース構造を完全に制御できないケースがあったと続けました。これにより、データマッパーの魅力が高まります。データマッパーはデータベースからの分離を強化しますが、完全な分離ではありません。特定のニーズに応じて、同じデータを異なるドメインモデルオブジェクトでロードするなど、データ管理の懸念事項を考慮する必要があります。
Badri 氏は、Mingle がいくつかの異なるデータベース(Postgres、Oracle、そしてかつては MySQL)でどのように動作するかを説明しました。ユニットテストがデータベースにヒットするという事実は、これらのデータベース間の移植性を大いに助けます。これは、分離が必要であるという一般的な概念とは反対です。
Martin は、データマッパーとアクティブレコードのトレードオフを、データベースを制御できない場合(たとえば、統合データベースを使用している場合)または複雑なドメインロジックがある場合は、データマッパーを使用する理由があると述べてまとめました。しかし、これらの力が作用していない場合は、アクティブレコードの方がシンプルです(したがって優れています)。データベースのサイズはここでは要因ではないことを指摘します。Mingle は 100 を超えるデータベーステーブルを持つ 50 KLOC のアプリですが、アクティブレコードでうまく機能します。
Martin は、テストの実行にどれくらいの時間がかかるかを尋ねました。Badri 氏は、複数のブラウザとデータベースで並列にテストを実行することで、テストは約 10 分で実行されると答えました。チームは、10 分のコミットスイートはフローを維持するのに十分な速さだと考えています。彼らはペンディングヘッドにコミットします。
2: Rails: プラットフォーム vs コンポーネント群
2014年6月12日
Ruby on Rails のようなリッチなフレームワークを使用する場合、プラットフォームとして扱うか、コンポーネント群として扱うことができます。Badri 氏はこれらの違いについて議論し、私たちはどのようなトレードオフが意思決定に付随するかについて議論します。
more…(続きを読む)
Minutes(議事録)
私たちは、Martin が Rails(およびその他の同様のフレームワーク)に対する態度をどうあるべきかを尋ねることからこの会話を始めました。欠点も含めて、プラットフォームとして受け入れるべきでしょうか?それとも、フレームワークの好きな部分を選んで、気に入らない部分は残すコンポーネント群として扱うべきでしょうか?Badri 氏は、Rails はよりモジュール化が進んでいるものの、現在ではコンポーネント全体を交換するよりも Rails のサブセット化の方が簡単だと答えました。たとえば、メールを送受信する必要がないアプリケーションでは、Action Mailer を省略できます。Action Support を標準の Ruby アプリケーションにプルインして、多くの便利なメソッドとコア拡張機能を利用できます。とはいえ、たとえば、Rails のリクエストレスポンスディスパッチサイクルを Node.js のようなイベントシステムに簡単に置き換えることはできません。これは、Rails が非常に特定の種類のアプリケーションをサポートするように構築されているためです。Martin は、Rails は Basecamp を構築するためのフレームワークであるという比喩を挙げて笑いました。
Badri 氏は、Rails のスイートスポットは、リレーショナルデータストアと通信する深くウェブ的なアプリケーションであると反論しました。言い換えれば、アプリケーションのユーザー数は限られており、Web UI を介してアプリケーションを使用する人間であろうと、REST API を介してアプリケーションと対話する他のマシンであろうと、Web は偶発的な要素ではありませんでした。 Badri 氏はさらに、問題は人々がフレームワークの採用を早すぎる段階で決定することにあるのではないかと推測しました。フレームワークは多くの利便性と引き換えに多くの設計オプションを奪います。つまり、おそらく、アプリケーションをどのように設計したいかを理解してから、最初にフレームワークを選択してシステムの設計方法を妨げるのではなく、それらの設計の選択肢を妨げないフレームワークを選択する必要があります。
Martin は、フレームワークを使用してアプリケーションをある方法で設計するという選択は、しばらく前にされた可能性があると答えました。とはいえ、フレームワークの設計者は別の道を選択する可能性があり、あなたは窮地に陥る可能性があります。Martin は、これまでの会話をまとめ、フレームワークのスイートスポットにいる場合は、将来の変更から身を守るために事前に努力するのではなく、プラットフォームとして受け入れる方が理にかなっていると述べました。 Badri 氏はこの要約に同意し、一部の人々は、彼らが追加したレイヤーが設計思考を導くのに有益であると感じていると述べました。とはいえ、彼個人は Rails をプラットフォームとして使用する側に傾いています。
フレームワークをプラットフォームとして使用するという彼の個人的な好みは、過去にフレームワークを回避しようとした経験から来ています。.NET のリッチクライアントフレームワークの例を使用して、彼は双方向データバインディングを使用しないように試みたアプリケーションに取り組んだ時のことを思い出しました。チームのメンバーの一部がアプリケーションをテストする方法を感じたため、彼らはデータバインディングメカニズムを使用しないことで謙虚なビューを作成しようとしました。これは、フレームワークがそのように使用されるように設計されていなかったため、かなりの混乱を招き、私たちは多すぎるコードを記述し、フレームワークの主要な部分を再発明することになりました。これは、フレームワークの趣旨に反して実行したいチームが理解する必要がある種類のコストです。おそらくコストに見合う価値がある場合もありますが、しばしば莫大なコストがかかるという事実は避けられません。彼は、チームがフレームワークに大きな変更を加えたい場合は、最高のライブラリを選んでアラカルトアプリケーションを構築することをお勧めすると付け加えました。 Martin は、重要なのは、ニーズによって、フレームワークをプラットフォームとして使用するかコンポーネントスイートとして使用するかを、どちらのアプローチのコストとメリットを考慮せずに、どちらのモードも盲目的に完全に受け入れることなく、情報に基づいた選択を行うことであると繰り返しました。
マーティンは、フレームワークが特定の設計 choices を行うことに価値があるかどうか、そしてそれがチームの新メンバーがより早く始めることを可能にするかどうかを尋ねました。 バドリは、Java の Spring など、フレームワーク全般の利点であると答えました。彼は、フレームワークを使用する際に人々が従う共通の使用パターンがより重要であると個人的に考えていると述べ、2001年頃のエンタープライズ Java の世界では、ほとんどすべてのアプリケーションがトランザクション境界の位置と実装方法について独自の実装を持っていたという例を挙げました。これは、彼が担当するすべてのアプリケーションで何度も繰り返し学ばなければならなかったことでした。一方、Rails では、すべてのリクエストとレスポンスのサイクルをラップするフィルターでトランザクションを開始し、ロールバックまたはコミットするという共通のパターンがあります。この種の学習は、ある Rails コードベースから次のコードベースに持ち越すのに役立ちます。
マーティンは、フレームワークを不得意な場所に押し込まないように呼びかけました。 バドリは、この点は完全に正しい一方で、Rails はフレームワークが意見を持たない場所では、あらゆる種類の設計 choices の余地を確実に残していると付け加えました。彼は、自分が関わったプロジェクトのいくつかの例を挙げて、これを説明しました。 最初の例は、バージョン管理システムからコミットデータを取得し、アプリケーション内の他のデータのコンテキストで表示できるようにしたものです。この機能なしでアプリケーションを動作させる必要があること、および複数のバージョン管理システムからのデータをすべてアプリケーションに取り込む必要があることから、彼らはシステムへのこの情報のエントリポイントを定義するポートを設計しました。このポートは、このポートに到着するあらゆる種類のデータに適切なアダプターを使用することで、すべての着信データを適合させるための単一ポイントとなりました。
2つ目の例は、双方向通信です。彼らは、作業中のストーリーに関連するチームチャットルームのメッセージを取得し、それらをバックログを管理するアプリケーションのストーリーにディスカッションスレッドとして添付する Jabber チャットルームボットを構築しました。この機能はアプリケーションの中核ではなく、個々のチームが必要に応じてこの機能をオンまたはオフにする必要があるため、チャットルームとコアアプリケーション間のすべての通信を処理するゲートウェイを実装しました。コアアプリケーションは、この機能が構成されているかどうかさえ認識していませんでした。これにより、ドメインロジックの中核部分を適切に隔離することができました。
マーティンは、これら2つの例を要約して、Rails を使用することは、分離を完全に回避することではないと述べました。プラットフォームから自分を隔離したくはないが、外部の要素からは隔離したいと強調しました。 アプリケーションのどの部分が外部であり、どの部分が内部であるかという区別は、Hexagonal Architecture パターンでチャットを開始した場所に私たちを完全に連れ戻します。
