オフィシャルで出ているDotnetrocks #364 Transcriptの拙訳です。
別の拙訳のS.O.L.I.Dの話で参照されてたので、ついでにこちらも訳しました。
2008年7月24日放送。まだDependency InjectionとかInversion of Controlが.Netのコミュニティで当り前ではなかった頃なので、
CarlとRichardが少し懐疑的な質問をしてます。おもしろい。
使ったもの(tools used):Express Scribe & Music to Code by
翻訳にあたってCarl Franklin氏の了承は頂きました。
リスナーの投稿とか、CarlとRichardのBetter Know Frameworkは飛ばして、ゲストインタビューのみ。
Carl Franklin (以下C) リチャード、今日のお客さんはJames Kovacだ。Jamesはシステムアーキテクト会社の経営者で、開発者で、教育者でつまり何でもできる。特に.Netにおけるアジャイル開発が専門で、テスト駆動、単体テスト、オブジェクト関係マッピング、依存性注入、リファクタリング、継続的インテグレーションなどを利用してのシステム開発者が柔軟性のあるシステムを作ることに関しては助力を惜しまない。彼はMSDNカナダのラジオステーションと提携している。Plumbers at work ポッドキャストの創始者でもあるよ。わ、すごいな。これについても話そうよ!
(Jamesさんのバイオについては飛ばします。2008年放送時からアップデートしていると思いますので。詳細はこちら)
C:ソフトウェア開発の新しくてカッコいい技術をよく知ってるって感じ?
James Kovac(以下J):いや、そういうのがカッコいいと思われる前から僕は飛びついてたよ。価値があると思ってたからね。最近どんどんたくさんのコミュニティが、そういうのに注目してきてて嬉しいよ。面白いのは、新しくてカッコいい、こういう考え方は、実は古くからあって、Javaのコミュニティから来たものなんだ。
C:そうだね。今日は制御の逆転(Inversion of Control)と、アスペクト指向プログラミングについて話すつもりだけどどう?
J:うん。そのつもりだよ。
Richard Campbell(以下R):あとね、先だって僕たちはHamiltonとCastle Windsorについて話したんだよ。でも、設備の問題でレコーディング取れなかったんだ。ムカつくわー。いいショウだったのに。
C:そうだね。あれは良いショウだったのにね。
R:でね。あのショウをやったあと気付いたんだけど、もしかしたらWindsorの基盤になっている考え方をもう少しやった方がいいと思ったんだ。James、君もWindsorが好きだろ?だからInversion of Controlからはじめて、できればCastleがどうそれに関わっているのかも話したいな。
Dependency Inversion(依存性の逆転)って何?
C:うん、まずは基礎から話してみようか。
J:そうだね。基礎はソフトウェアの構造をちゃんと見るところからだ。今までは、きっちりと秩序だった構造だった。つまり、あるコンポーネントが、もう一つのコンポーネントとやりとりするという。たとえば、顧客サービスは、データアクセスのコンポーネントとやりとりするという。
ただこの方法だと、この2つのコンポーネントが独立して変更することがすごく難しいんだ。例えば、違うデータベースに変えたいとき、とか、ログを取り入れたいときとか、何かを変更するとき、すべてを変えないといけない。
C:そうだね。
J:で、それに対する考え方として、依存の逆転というのがある。Robert C Martinがうまくまとめたものだけど、「高レベルのモジュールは、低レベルモジュールに依存してはいけない。しかし両社とも、抽象化されたものに依存するべきだ」
つまり具体的にいうと、顧客サービスがデータ層に依存する今の状況より、両者とも、インターフェイスか、何らかの抽象的クラスに依存するべきだということだ。ICustomerレポジトリで、レポジトリがデータ層、みたいなものにね。こうすると、この二つのコンポーネントを分離されて、顧客サービスクラスは、ただIRepositoryクラスとかIComponentクラスにとやり取りしているだけになる。そうすると、実行時に自由になり、何か別のものと代替することもできる、という柔軟性が出てくる。
C:うん。そうなんだよね。変更は必ず起こるから、作るものはフレキシブルじゃないといけない。僕が思うにあまりに多くの開発者が、未来に起こりうることを予測しようとして、それを構築に組み込もうとして失敗していると思う。一方でこれ(IoC) はただ柔軟であることが目的で、未知のことや、現在わからないことはわからないままで良くて、で、起こったら起こったで素早く適用できる、と。
J:そうそう、Carl。そこを狙っているんだ。コンポーネントの間に柔軟性を持たせた構築性ね。長い間そのことばっかり仲間内で話してて、ここ(DI)が落ち着くところだという結論になった。
じゃ、Dependency Injection(依存性の注入)って何?
C:で、それが(依存逆転)Dependency Inversionだね。で、依存性注入って何?(Dependency Injection)
J:依存性注入はね、依存逆転が起こったあと、高レベルのコンポーネントがインターフェースに依存している状況になったと。これを実行時に代入できるようにしたらどうだろう。依存性注入を使うことによって、コンストラクタからコンポーネントの依存を提供することができるんだ。まとまったやりかたでできるよ。例えばどうやってやるかというと、「New 顧客サービス」ってやったとたん、新しい依存性は「顧客レポジトリ」ができるってこと。
C:依存性をただの、オブジェクトのライフスパンの中の1コンポーネントにしてしまうと。
J:そう。ただのソフトウェアに使われる1コンポーネントなんだ。この例ではサービスとして。
C:で、コンストラクタによって提供されるってだけのものなの?
J:そうだよ。よく使われる、違う方法では、サービス・ロケーターってのもある。例えば顧客サービスなら、コンストラクタ内でファクトリに「ねえ、依存性ちょうだい」っていうっていう。
C:うん。
J:これも一つの方法だよ。ただ、これだとあまりテストやりやすいとは言えない。依存性はサービスの中に閉じ込められちゃってるからね。データベースから隔離された状態でのテストやほかのすべてのテストが難しくなる。それでもいいんだけど、テストは難しくなる。
一つ一つの依存性にコンストラクタへの注入をしてもらえば、モックのフレームワークやそのインターフェースを適用してデフォルトの状態のテストを、データベースと切り離した状態でテストすることができる。ログとったり観察(Audit)したりすることはしないけど、完全に独立した単体テストすることができる。
C:そうだね。
J:で、これのいいところは何かっていうと、大抵のソフトウェアが使われるとき、たぶん大抵は一つのことに、柔軟性もなく、一つの目的のために使われるんだけど、もしそれが2つのところで使われるようになったら、この柔軟性がうまくいい役をこなすんだ。
たとえば、2つのうち、一つがテストで一つが本番だとする。そうなると、これ(DI)のおかげでデザインするときに考え方まで柔軟性が持てる。じゃあどうやってテストしようか、という場面では、一つ一つの依存性にコンストラクタへの注入をしてもらえば、テストでモックやスタブを、自分の手で作った偽オブジェクトで作ることができるじゃないか、ってね。もちろん本番のコードは本番の環境に置いといたままで。
Inversion Control Container(制御の逆転コンテナ)って誰?
C:で、もう一つのコンセプト、Inversion of ControlとかInversion of Control Containerとかの話は、さっき最初の方で話したけど、まだちょっとわからない感じでもある。できたら制御の逆転コンテナを、簡単に短く、定義してくれるとうれしいな。
J:そうだね、IoCコンテナについてだけど、うん、依存性注入がそうやっていいことだってことは今言った通りで、これやると依存性の鎖ができてしまうんだ。たとえばUIコンポーネントがサービスコンポーネントを構築してそのサービスコンポーネントがデータレイヤコンポーネントが必要で、その一つ一つがその都度、依存性をもつ。そんな状況でその連綿とした鎖をたどるのに、それらの依存性を注入するレポジトリが必要になる。サービスを作って、そのリポジトリに注入するんだ。でも、その依存性の鎖のままUIまでたどっていくと、UIがデータアクセスコンポーネントやログコンポーネントや、Audit観察のコンポーネントやらのことを知っていなければならない。こんなたくさんのアーキテクチャなんて、UIでやるべきことじゃないだろ。
C:そこでやっちゃだめだよね。
J:UIは一番離れてるべきことだよ。
C:そうだね。
J:こういうロジックとかはUIに入れちゃいけない。
C:まったくだ。
J:どうやってそんな状況から逃れるか。そこでInversion of Controlコンテナを使う。コンテナはただのコンポーネントのファクトリだよ。
C:つまり、一つ一つ依存性を注入するために、ほかのコンテナを作って依存性をそこで生成し、UIに渡す、と。そうすればUIが依存性の鎖の最後にたどりつくところになれる。そういうこと?
J:そうそう!難しく聞こえるけど、そうでもないよ。君がコンテナに向かって「ねえ、ICostomerServiceちょうだい!」というと、コンテナ君は「あ、ICostomerServiceはこのカスタマサービスのクラスで、そいつはICostomer レポジトリも必要だよ」って返す。そいつはSQLのCostomerレポジトリだったりするし、Auditコンポーネントが必要だったりする。そうやって依存の鎖を読解して、逆方向から構築してから、出来上がったものを実行時に君に渡す。だから、ただのコンポーネント工場なんだ。
C:それってすごく理屈に合うことだよ。Windows Forms使ったことがある人ならわかると思うけど、あれってモジュールから始めるだろ。サブメインからはじまってフォームを作ってから、ハイ見せるよってやつ。いろいろなオブジェクト使ってではやってないけど、あれも一種のInversion of Controlだよね。フォームから始めてないってところが。
ほんとはIoCコンテナ、地味で質素なんですよ。
J:そうだね。基本的には実行時にオブジェクトを構築しているからね。依存注入コンテナはさまざまなサービスをオブジェクト構築に先んじて、すごく質素なレベルで提供している。けっこう、「やー。3rdパーティのコンポーネントはうちでは使えないよー」なんて話も聞く。Castle WidndsorとかStructureMapなんて大きなもの、使えないよ!・・・なーんて人もいるけど、実際、もしたくさんの依存性でてんてこまいしている状況だったら、自分で依存注入のコンテナを作っちゃえばいいんだ。24行程度だよ。これは僕の記事でも書いたから、[Loosen Upの記事読んで]
(http://jameskovacs.com/2008/03/13/loosen-up-tame-your-software-dependencies-for-more-flexible-apps/)。
R:シンプルなの出すってのはいいアイデアだよね。だって大抵の人はこれ、複雑すぎて敬遠しがちだもの。
C:そうだね。
J:本当に2ダース程度(24行)のコードなんだ。基本的に何がその中にいるかというと、ハッシュテーブルで、そのハッシュはインターフェイスとタイプを持ってる。だからシンプルなコンテナをつくりたかったら、自分用に作れるんだ。サブメインや、もしC#でやるならパブリックスタティックのメインからすべてのタイプを構築して、それをハッシュに投げ込んで、「ICostomerServiceちょうだい!」とお願いすれば、コンテナはハッシュを調べて、返してくれる。もっと機能の多いコンテナもあって、それらは依存の鎖をさかのぼってくれたりもするけど、コンテナが返す90%のものは、ほぼ各々が書いてしまえるもので、結構わかりやすいものだったりもする。
R:とても速く書けるものだね。
J:それがわかったら、コンテナのことをもっと知りたくなり、「Spring.Netがいいかな、Windsorがいいか、StructureMapかな? Unity? どのIoCコンテナがいいかな?ってすぐにいろいろ見てみたくなるよ。
C:たぶん聴衆は今、聞きなれない商品名を聞いて混乱したと思うよ。まず初めに、どうしようか、君が最初に話したいのから。今言ったフレームワークを一つ一つ見ていこうか。
IoCコンテナ、よりどりみどり。
J:今言ったのは みな制御逆転コンテナだよ。Sprint.Netは Javaから来たSpring Frameworkの一部で、Springを制御逆転につかっている。NHibernateオブジェクト関係マッピングに使うのはよく使われる構築法だよ。同じことを.Netでもできるんだ。
R:去年Mark Pollackをゲストに迎えたとき、そのSpring.Netの話ししたよ。
J:Springはコンテナで、他のコンテナでCastle Windsorってのもあって、これはCastleプロジェクトの一部なんだ。僕はこれが個人的に一番好きだ。WindsorがSpringよりいいなと思うのは設定にいろいろ柔軟性を持たせてあるところだよ。
Springはどうも多すぎるXMLセットアップがあってね。それは僕が去年っから使ってなくて、もう変わったかもしれないけど。今まではずっとXMLでいっぱいだった。XMLファイルをずっと追っかけてって、すべてのタイプがどうつながるか設定しないといけないんだ。
一方、Windsorではそうやる方法もあるけど、ほかの方法もたくさんあって、たとえばスクリプト言語やコードの中から設定することもできる。Craig Neuwirtがなかなか読みやすい(Fluent Interface)インターフェイスを作ったから、Stringを最新のCastleビルドの一部になってるよ。
読みやすいFluentインターフェイスの考え方は、Jeremy MillerとStructureMapから来ているんだ。Jeremyは、XMLや設定をXMLの中に入れとくのではなく、設定をオブジェクトに直接実装しようとしてた。そうするとGenericを使ってコンポーネントの設計をすることになる。そうなると、一つ一つのコンポーネントが制御逆転コンテナをもつことになるんだ。子コンポーネントは概して大きなものの一部になりやすい。WindsorはCastle Mono RailとCastle Active RecordとほかのCastleプロジェクトの一部だし。Springはそれ自体がアプリケーションだね。だから利用者がどう使うかにもよるんだ。もし軽く小さく使いたいなら、StructureMapがいいと思うよ。Jaremyのいいアイデアがつまっている。
UnityはMicrosoftがやっているね。Object Builderってのは皆も聞いたことあると思うけど、これはオブジェクト構築のためのFrameworkで、制御逆転はない。UnityはObject Builderの上位レイヤで制御逆転を提供している。
R:面白いね。これってCodePlexのPattern and Practiceチームがやってんだっけね。
J:そう。Pattern and PracticeチームでChris Tavaresがリーダーだね。すごい人だよ。UnityはWindsorとはちょっと違うやりかたでなんだけど、基本的には同じで、依存の構造を実行時に見つけくれるんだ。フレキシブルにね。これがどうしていいかっていうと、たとえばデータアクセスのコンポーネントがあるとして、データーベースに用があるときに必ずチェックしたいとする。手動でログとりのコンポーネントをくっつけたり、ほかのやり方もできる。けど、新しくログ取りのデータアクセスコンポーネントを加えるって方法もある。本物のデータが中に入るんだけど、実際にはただのIDataのAccessだよ。
制御逆転のコンテナを使うと、これをただWrap(包み込む)だけなんだ。Decoratorパターンを使って、IData アクセスコンポーネントを呼び出すときに、Audit観察データ、もしくはロギングデータアクセスコンポーネントをもってきて、それにログを取らせて、それを実際のデータアクセスコンポーネントにDelegateする。そうするとログとりを実装しつつ、もともとのデータアクセスコンポーネントを変更しなくてもいい。
**もとのコードを変更しないから、バグを新たに取り入れてしまう可能性もぐんと下がるよね。
これは閉鎖/開放の条項の考え方にもとづいてる。**クラスは拡張できるようにしつつ、変更はできないように作らないといけない。コードファイルはいちいちひらきたくないけど、コードは拡張したいよね。継承するか、組み合わせて新しい機能をつけるかで、新しい機能をシステムに取り入れるときは、今動いている機能を変更してはいけないっていう。
アスペクト志向プログラミング
C:それって、AOP、アスペクト志向プログラミングが主眼に置いているものだよね。やっかいなものは横に分けといて、自由にビジネスロジックを組み合わせられるようにしようよ、っていう。
J:そう。アスペクト志向プログラミングはちょっと違うんだ。Orthogonalityで、考え方同士が直角に交わってて、ロギングとデータアクセスを別個にする。
C:その難しい言葉を、まず定義していい?(笑)
J:Orthogonalityとか、何かがOrthogonalってのは、直角ってことで、二つのものが完全に隔離した関係ってことで・・・
C:直角?
J:直角。何かがアクセスするとき、他のアクセスに影響を与えない。(訳注:たぶんAxisの書き取り違いじゃないかな?Accessじゃなくて、Axis…?)XY座標があるとして、Y軸を上下させてもX軸に影響しないという。
C:つまり、完全に非結合(Decouple)しているってこと?
J:コードの非結合だよ。アスペクト志向プログラミングの考え方は、Auditのコンポーネントを実装するのに、顧客Auditのコンポーネントや、オーダーAuditのコンポーネントやナンチャラAuditのコンポーネントを実装させなきゃいけないのではなく、たった一つのコンポーネントを実装したら、それがすべての呼び出しにそのつど決定を下し対応する。アスペクトく志向プログラミングのフレームワークもあるよ。制御逆転コンテナはよくその一要素として使われるね。制御逆転を使うのに、アスペクト志向を使わなくてもいいし、全然別のものだけど、深くかかわりあってはいるよね。
イラッとする。ログ取り以外のとりえは?
R:ジェームス、この技術でイラっとすることがあるんだ。この技術に関する大抵の例のすべてがログとりに関してなんだけど、もうちょっと複雑な、たとえば、どうやったらこの技術で僕の作ったアプリケーションの難しい課題を治せるか?っていう例が見たいんだけど。
J:僕の作ったアプリケーションが例になるよ。入力確認ルールが必要だったから、サービスコンポーネントがたくさんの入力確認ルールを使ってどれが有効な注文か、チェックしなければならなかった。
R:うん。
J:今までは、IfやThenやSwitchを使って厄介なほど大きなブロックを作ってた。新しいルールができるたびに、ここに追加しなきゃいけないっていう。
R:でそれをテストするのってすごく難しくって、でっかいSwitchブロックをテストするのに沢山のテストをつくってた。
J:そのとおり。さまざまなIfとSwitchとやりとりしているうちに、管理できなくなってきてしまう。
R:うん。
J:そういうやりかたでなく、僕のサービスコンポーネントは、入力確認コンポーネントの行列に依存している。入力確認コンポーネントはの依存注入が実行時に起こるんだね。だから僕の設定では、入力確認コンポーネントの単純なリストがあるんだ。たとえば、購入には日付があるか?とか、購入量はある一定値より超えてないか?とか、この購入は、特別な顧客からのものからか?とか、なにが有効な購入かの単純なルールだよ。これらは、独立して簡単にテストできる。サービス側は、そのリストをループでIterateするだけだ。
R:で、たぶん何かのデータ構造をつかって、どのルールを実装するかを判断しているよね。
J:そう、だから新しいルールを追加する必要があったら、IValidationルールを作って、制御反転コンテナの中で設定するんだ。で、次にアプリケーションが上がった時には、勝手に実行される。僕自身がすべての厄介なテストをして、すべての条件の下で、枝ロジックの下で正常に働いているってチェックする必要はない。こうすれば、現在動いているものを壊さないでいい。もし、何かの理由で現在うごいている入力確認に問題を発見したり、プロモーション用に一定時にしかつかわないのがあれば、単にそれを無効にすればいい。コメントアウトするだけだからね。これはXMLの設定ファイルでできるんだ。まったく別のアセンブリでやるとか、他にもいろいろやり方はあるよ。全体の構造に影響を与えずに、その都度の実行時に追加したり削除したりするのはとても簡単なんだよ。
R:君に「これってルール・エンジンじゃない?」って聞こうと思ったんだけど、でも、考えて聞かないでもわかったよ。僕がルールエンジンで引っかかっているところだ。君が言っているのは、コードを書かずに、ルールの創造に集中して、やっかいなSwitchでテストすることに気をとられずに、いやコードも書いてもいいんだけど、システムにこの構造を注入することによって、現行システムを危険にさらさずに、それでも変更できるってことだよね。
J:全くその通りだよ。リチャード。これって、どうアプリケーションを見るかってことなんだ。誰がユーザーになるかってことで。よくあるのは、プログラマがルールを書いて、テストするだろ。まあ、君が好きなC#とかで、単体テストを書くと。これをビジネス側のユーザーにあげちゃって、彼らが設定してルールを書く。この例だと販売ルール・エンジンだね。これがフロントエンドのエディタをもたせてね、君がやることはアプリケーションをみて、どうやればエンドユーザーにとっていいか、を考えるけど、いくつかの入力確認があるからとか、どう設定させるかとかのために大きなルールエンジンをいじる必要はない。
読みにくいよ!
R:そうだね。大きなものをバラバラにしなくてもいいってのは、いいよね。もうひとつあって、これっていいんだけど、コード読みづらくならない?たとえば新しい人が参加したときに、コードの流れが判りづらい。
J:どうだろう、どちらともいえるね。読みにくくなるのは、線的な流れではないうえ、見たことないからかもしれない。でも慣れてくれば反射的にすぐに読めるよ。サービスコンポーネントの中の一ブロックが、「注入された各入力確認ルールの集合を取り出して確認せよ」って言ってても簡単に読み解ける。次にやることはIValidationルールを実装したすべてをみつけだすことだ。Test Driven開発をやってる多くの人がResharperを使っているしね。1キーで、このインターフェースの実装をみつけて、とか、他の機能もある。けっこう皆、フレキシブルじゃないシステムを使いだして、実装を見つけて、継承したタイプみつけてコードベースの中を動き回るまで、Resharperみたいなツールの良さってわからないかもしれない。
R:それさ、ツールのことだけど、前はこういった話もってきたとき、「この機能をすべてのクラスにつけたい!」って場合、僕が最初に考えたのは「よし、Findといっしょにサーチがんばるぞ!」ってことだったんだけど、君ならオブジェクトを俯瞰してみながら、同じタスクやるよね。
J:そう。一面で、実行時にこういうことをしたいから、オブジェクトを使ってコードを構築する。もう一面では、プログラマとして、効率的にコード内を動き回って何が起こっているかを理解したい。この注入されたルールは何だ?Interfaceの実装者はどこだ?誰がこのメソッドをオーバーライドしてる?ってね。Reshaperはこういうときに、とても価値のあるツールでこういった疑問に効率的に答えてくれる。
(ここでTelerikの広告)
習うより24行書いてみよう!
C:Windsorのこと、もうちょっと突っ込んで話せるかな。Micro kernelのこととか。Windsorを使ってどうだった?とか、これってプロジェクトの最初に入れるものなの?とか。使用する際のプロセスについて教えてくれるかな。
J:うん。でも、全機能のそろった制御逆転コンテナを最初から使い出すのは、けっこう難しいかもしれない。おすすめするのは、これは僕がやった方法だけど、シンプルで、小さな制御逆転コンテナをつくって、自分でハッシュテーブルを作るといいよ。コアとなる考え方をすぐに身につけることができる。で、後から、全機能のそろった制御逆転コンテナをつかうといい。Windsorとかね。自分で書いたものから簡単に変更できるのがいいところだよね。
C:じゃ、自分でIoCコンテナ書くのがいちばんいいってこと?
J:そうだね。たとえば Orin Elniのブログあたりから参考にするかな?いくつか、簡単な制御逆転コンテナのコードサンプルを出してるよ。CastleとかSpringのフレームワークを試してみる前にやるのにちょうどいいかも。
C:実際にやっているコードが見えるようになるから?
J:うん。ほんとにたくさんのコードでもないよ。読むのもそんなに大変じゃない。インターフェイスと実タイプのハッシュテーブルがあるだけだから。
C:でも、そのコードの流れ方が見慣れなくてね。
J:そうだね。流れ方、特に非結合(Decouple)のところが一番価値があるかな。あと、制御逆転の特徴はほかにも小さいものもあるけど、柔軟性をもたらす非結合で、シンプルなものでもこれは絶対あることかな。もうひとつ、混乱をもたらす原因に、IoCは得てして大きいんだ。いろいろなサービスを提供するから、すべてを理解するのに時間かかる。今僕がプロジェクトを始めるとしたら、Windsorを使うけど、それはもう使ったことがあるからなんだ。
マイクロカーネルって何さ?
C:で、自分でIoCコンテナを書いてみた後、マイクロカーネル…Windsorの小さいバージョンを使った方がいい?
J:うーん。Windsorとマイクロカーネルは、一緒に使うものなんだ。マイクロカーネルはコアになっている。エンジンで、大事な内臓部分だよ。Windsorはその設定部分を担ってるってそれだけで。
C:あ、そうか。じゃあ、小さなバージョンってわけじゃないんだね。むしろ、心臓部分。
J:そう。Windsorの小さなバージョンってわけじゃないんだ。Windsorを使ってみてから、次に行く感じ。マイクロカーネルはWindsorより多くのサービスを提供するし。Windsorはマイクロカーネル入口を提供してXMLの設定ファイルを読んだりしているんだよ。そのあたりでOrenとか実装したBinsorってのがあるし、Booってのを実装したBinsorってのもある。多種多様だよ。Donald BelchamはC#をつかってCindsorってのを作ってるし、Craig Neuwirtは読みやすい設定インターフェイスをつくって、それはもうWindsorの一部になっている。マイクロカーネルを使うなら、かなり低レベルまでつっこんだ制御逆転コンテナを扱うことになる。普通はそこまでやらなきゃいけないってことは、あまりないね。
R:そうか。
J:Windsorはもっと高レベルの抽象化を、利用者の効率を上げるために提供してくれてるんだ。だからここが入口となる。さっきの入力確認の例のときとかね。だから「ねえ、IValidation ルールを実装したすべてのコンポーネントちょうだい。」って言って、Windsorがその時にその情報を持っていない、といった場合、マイクロカーネルが適切なメソッドを呼び出して、Windsorに切り替えす。そっから、Windsorは、「ねえ、コンポーネントちょうだい」っていう代わりに「インターフェースを実装したコンポーネントちょうだい」っていえるようになる。だからマイクロカーネルを必要とする状況はかなり限られている。
R:例外処理だね。
J:新しいレベルの処理だよ。
R:うん。僕なら例外的なものとして扱うものだよ。
J:いままでは、Windsorはずいぶん大きなXMLファイルがあって、このインターフェイスにはこのタイプを生成しろ、このタイプはみな依存性があるタイプで、デフォルトの値はこれね、って。
R:Springっぽいね。
J:Springっぽいよ。似たような構造を持っている。WindsornoXML設定ファイルは、Springのよりちょっとめんどくさいかな。
R:ふうん。
J:でも、それでもXMLはどうしても、言葉多すぎになるよね。
R:でもそれって、もともとそういうものだろ?
J:そうだね。簡単にXMLの海で遭難してしまう。だからいままでずっとWindsorを使って設定してきてたんだ。でもいまはCraig Neuwirtの読みやすい(Fluent)インターフェイスの考え方が入ってきているから――それはJeremy MillerのStructureMapからとってきたものだけど、それを使うことが推奨されてる。つまり君のC#コードが「このインターフェイスには、これが実装しているコンポーネントで、これがデフォルトのプロパティだよ」ってもうそこにあるんだ。あと、もしGST計算したいとしたら、コンストラクタのプロパティが現行パーセントのdecimalを指定していたり、君がデータアクセスコンポーネントで、データベースの中の、そのテーブルの中のってのを問い合わせてくれたりってことをしてくれる。XMLのルートがあるところに、Fluentのインターフェイス有ってことさ。
やっぱりわかりにくい!見えたら(Visualize)この俺にも分かるかもしれん!
R:そういうの、可視化コンポーネントあるといいと思うけど。そしたらそういう関係が見やすくなる。
J:可視化コンポーネントはいらないと思う。Ruby on Railsのコミュニティでは、Convention over Configuration(設定より規約)だろ。Railsはとても規約に重点を置くから、何かすごい特別なことをやりたいわけでもなければ、他の人と同じことをすればいい。デフォルトを自分で設定しなくてもいいんだ。これってStructureMapとWindsorのFluentインターフェイスも同じことで、「すべてのコントローラを登録しちゃって」っていえばいいのとおなじだよ。ASP.Net MVCでやるなら、IControllerを実装するのと同じ。いほら、Controllerを逆転するときは、非結合を使って、アドミニストレータを持ってくるためにIAdministrationインターフェイスつかったり、ホームコントローラを使うのにIHomeを使うだろ。ProductコントローラにはIProductとか。こういうペアがあるのは、設定より規約って考え方からなんだ。何かとIFooでペア、みたいな。
C:うん。それはそもそもから、そうだね。
J:Windsorに、こういうそもそもの設定をしろって言ってて、タイプとか、マッピングとか。
C:そうだね。
横道:コンファレンスでハプニング
R:同意するよ。もちろん可視化できたらもっといい、とも思うけど。ただ、何かおかしくなったとき、すべてがそうやって抽象化されているから、比較的デバッグしにくいんじゃないのかな。
C:こう言うとAOPの考え方の話に戻るけど、AOPがいいのはテストしやすいってことだけでなく、デバッグしやすいってことも要件だと思うんだ。だって、仲介者(Interceptor)が、前条件と、後条件をもってくるって、新しいコンセプトだろ。これって、今までRemotingでやってたことじゃないかな?
J:デバッグについてだけど、おもしろい話があるんだ。StructureMapは環境テストって機能があって、Jeremyが名付けたんだけど、これは何ができるかっていうと、属性をメソッドに投げると、依存逆転コンテナが起動して、コマンドをテストメソッドで使うことができる。だからコンポーネントを作って呼ぶとき、データ接続がおかしいと気付いたりする。テストするときに、この顧客データを持ってこれるか、この名前と値のペアを持ってこれるか、そんな環境のテストだね。SMTPサーバーに入れるかとかもそうだね。で、JeremyはこのStructureMapの機能すごく誇りに思っている。だってこれでIoCがずいぶん簡単にできるようになったからね。「ねえIoC、起動して、スモークテストして、接続OKから確認して。」SMTPでもメッセージキューでも同じだよね。Jeremyがこれをかなり誇りにしてて、VancouverのDevTeachでプレゼンしたんだけど、Windsor作ったOrenが聴衆の中にいて、Jeremyが「ほら、これがWindsorにできなくて、StructureMapにできることだよ!」って言っちゃったから、Orenがラップトップ持ち出して、30分間で、コードを修正しまったんだ。「もうできたよ。今からコミットする」って僕に言ってきてさ。
C:すごいな、イカれてる。君らはまったく。
R:Oren Einiだしね。やつはイカレてる。
J:いいやつだよ。でもうん。彼は世界に明日がないみたいにコード書くよね。
R:あの集中力は普通じゃない。
J:うん。30分間でだよ。Jeremyの新しい機能を追加しちゃった。
C:「挑戦してくるな。殺してやる」
R:「お前をコードの山に埋めてやる」
C:「埋葬だ」
視覚より、規格。
J:その時って彼がUnityをビシュアライズの設定コンポーネント使えないかって聞いてた時だった。僕がWindsor使ってた限りでは、それは必要ないかなと思っていたんだけど。もし設定がおかしくなったら「IFooの実装が見つからないよ」っていうだけだし。で、利用者は「ああ、値を与えなかったみたいだね」ってすぐにわかるところだ。それに今までよくあった設定方法も使えるんだよ。ほぼ名前づけの規則に従うだけだ。
Orenがいってたんだけど、IoCとWindsorを自分が書いたコードに取り入れたことがあったそうだ。もちろん名前づけ規則に沿ってね。大体12人くらいの開発者と一緒に仕事してたらしいんだけど、そこを離れなくちゃいけなくて、この基盤部分がどうなるか、ちょっと気にはしてたらしい。1年後、そのプロジェクト・リードから電話がかかってきて、「この設定ファイルは何?名前付け規則に沿ってるみたいだけど」ってね。そのプロジェクトではそうする必要なかったんだ。新しいクラスやインターフェースを加えたけど、そんなに名前付け規則にそってなくて、(IoCとWindsorを取り入れてたので)それでも大丈夫だったんだ。
R:うまくいっているときはそうやって回るけど、何か変なことが起きた時にどうしてそうなったか分かりにくいんじゃないかな、と思うけど。
J:全くそうだよね。リチャード。たぶん皆、どうしてうまく回っているかを理解しないといけないんだと思うんだ。開発チームがそれだけ効率よく回っているのはどうしてかってね。
もちろん知識を教えあうことは重要だけど、それより設定より規約っていうのを遵守することの重要さだよね。正直言って、何かおかしなことが起こった時、コンテナはすぐに「このコンポ―ネントXを作ろうとしているんだけど」って
フラグを立ててくれる。そういったものは依存を入れ子式に持ったもので、それに対するログ取りのための実装もない状態で、
どこが悪いかわからない、って状況の時にビジュアライズのコンポ―ネントの必要性の話が出るね。
でも、そんなにコンポーネント同士の関係が複雑で、ビジュアライズのコンポーネントが必要となってくるなら、そのコンポーネント同士の関係を、もう一度見直す必要があるんじゃないかな。
なんだかんだで、物事単純にしておく方がいいんだ。結合をきつくしてまわないでね。じゃないと結合を避けるために構造自体を、切ったり割ったりするはめになるからね。
もう一つ、IoCでInterface とAbstract Classに依存するようになったら、コードから依存自体を取り除くのは大変なことじゃない。どんなコンポーネントともきつく結合しているわけではないので、リファクタして、テストを適用しても、実際の機能には抵触しないでいられる。
既存の、レガシ~♪ プロダクトで使えるの?
R:James、このIoCを現行のアプリケーションに導入するのは・・・簡単かな?
C:うわ聞いちゃった。
J:結構それは難しい。
C:それって基盤からってことでしょ。
R:一方で、これはそんなに難しいことではなさそう、とは思うけどもう一方では、いやいや、結合を説くのが難しいことって多々あるぞ!
C:リファクタ地獄になるんだよね。
J:そういうの頑張っちゃう前に、Micheal Featherの「Working Effectively with Legacy Code」(日本語訳:レガシーコード改善ガイド )を読むといいよ。
R:Micheal Feather?
J:Micheal Featherの「Working Effectively with Legacy Code」だよ。もしこのショウに招待できるならやったほうがいい。彼は素晴らしいやつだよ。いいアイデアでいっぱいだ。僕は実際会ったことないんだけど、彼の本はアーキテクチャや、どうやってアプリケーションをくみ上げるかってことについて再考するチャンスになる。
Michaelは、レガシーコードは、つまりテストがないコードだってことなんだ。
R:興味深いね。
J:そのコードがが20年前に書かれたか、一週間前に書かれたかは関係ない。テストがないコードには変更に際して柔軟性がない。テストサイクルやよくわからないから、自信持って変更できないというなら、それは結合ばかりのアプリケーションだということになる。そういうものにはとにかくテストをつけろ、ということ。Michaelの本はどうやってテスト不可能なコードベースにタスクを加えるか?ってことを例示してくれるよ。テストがあれば、依存性を切り分けていくことができる。
それができたら、制御逆転と依存性注入を使ってアプリケーションの構造を柔軟にする。数ステップかかるプロセスだね。この話をよく人に教えるんだけど、いろいろな理由で失敗することもあるんだ。
問題点を一つづつ挙げて、Michael の本の話もしたし、僕のおすすめのほかの本を参考に模した。2か月かけて、どうアプローチするか表にして、12人の開発者と一緒に150,000行のコードベースをどうにかしようとした。2か月後、結合をずいぶん減らせた。彼らのコードで一番難しかったのは、あちこちにSingletonがあって、あれはテストするのがすごく難しいんだ。Singletonは、たいてい他のSingletonとやり取りしているから、特に結合を強くなる場所なんだ。一つのSingletonをてすとしようとしると、全てのアプリケーションをテストするって大がかりなことになる。ともあれこのアプリケーションから結合を取り除くのに2か月かかった。今までのこのアプリケーションはひどく維持しにくいもので、それから比べるとずいぶんよくなったよ。
結局テストなんすね。
R:面白いのはすべてのコードがテストされるとなると、そのテストがどう制御されるかってことと、それだけ理屈に合ったテストかってことが常に問題になるよね。
テストがそろってしまえば、変更によってもたらされる、"結果としての変更"はどのくらいか、すぐに判るようになる。
J:そうだね。Richard。コードをリファクタするってことは、コードを改善するということだ。もちろん今ある機能はそのままで。これを効率k的にやるには、まずテストで固めてやる。単体テスト、Integrationテストなどだ。変更を加えるときには、「このSwitchブロックはみっともないね。これはコマンドパターンに変えられないかな?」とか「このコマンドパターンは役立たずなので、Switchブロックに変えたらシンプルでいいんじゃないかな」とか、そういうことを行きつ戻りつするうちに、どれだけコードが改善されるだろう?そんなときテストが、何も悪いことはしてないよ、とか、もしそれがいいテストなら、現実の運用の再現だし、そうなるとコードに変更してもいい。単体テストとインテグレーションテスト2分後、変更によって何か壊れたかわかるし。
いままで「今日一日、コード変え続けて、明日はテストしよう!」みたいなことやってきただろう。疲れちゃうじゃないか。すべてのテストをやった後に、また壊れるのは、全てのテストケースを終えた後に何かが壊れちゃうってのは、長いフィードバックのサイクルだよね。
本当に、IoCやんなきゃだめですか?
C:みんなIoCのコードが多すぎるって言ってる人たちが、「僕のアプリケーションは動いてる問題ないので、IoCなんてやんないよ。どうして頭っから逆さになって物事考えないといけないの?」っていうのにどうこたえる?
J:**じゃ、やらなきゃいい。**今のコードで動いてて、結合で問題がなくて、一発屋のアプリケーションでメンテナンスる必要がなくて、二度とコードに触ることもないのであればね。もしそうだとしても僕は今のやり方でやると思うけど。ただ、もし、コード同士が癒着して、変更が難しくて問題になっているのであれば、僕が言ったようなテクニックを使った方がいい。すぐに効能はないかもしれないけど、一定の速さで変更をすることができるようになる。いままで6か月でやってたことを、一日でとかね。
めんどくさい、Conflictとかある?
C:いままで、ほかのプロダクトと拮抗したことある?たとえば、CSLA.NETとか、ただのアプリケーションのフレームワークだけど、IoCの邪魔になったこととかある?
J:フレームワークにもよるね。IoCをあつかおうとしているなら、依存性を隠してしまう。もしフレームワーク自体が、アプリケーションのあちこちに手を伸ばしているものなら、拮抗するかもね。
C:ファクトリーとかね。
J:そうだね。制御をみつけるのを難しくするのは、ClassicのASP.Netで、あれは、ページの一部にリクエスト、リスポンス、入力確認と、全てが入り込んでいる。ASP.Netのパイプラインをすべて使わないと実行できない形だ。JP Boodhooが、Model Viewプレゼンターのパターンの話をしてたけど、あれはInversion of ControlがASP.Netで適用された例だね。
C:MVC フレームワークは、明らかにこちら側だよね。
J:うん。MicrosoftのMVCはテスト可能性を完全にうめ込まれたものだね。制御逆転がそのまま入っているってことだ。大きな変化が起きたのは、Scott Gathrieが10月のALT.Netのコンファレンスで話した時だ。「MVCに好きな制御逆転のコンテナをいれちゃって。僕たちはそんな話を待ってるよ!」
C:いいじゃん。
J:彼は、Spring.Netや、Widsorや、Unityでの例をプレゼンしてた。どんなコンテナでも使えるってね。ASP.NetのMVCのチームは、開発者が何を望んでいるかってのをいつも気にかけている。
C:ほらね。MVCフレームワークに入っていく理由を探しているなんて時間の無駄だよ。
J:うん、でもしMVCフレームワークに入っていくってんなら、制御逆転のことを見てみた方がいよ。だって…
C:この二つは常にいっしょだから。
J:この二つは、いいソフトウェア開発テクニックで、より良いソフトウェアを作るためのもので、常時いっしょにいるけど、非結合で、独立してて、関心も分離している。ソフトウェア・エンジニアリングのいいアイディアがつまっているんだよ。制御逆転もしかり。
エピローグ。
C:だんだん時間なくなってきているけど、ほかに何か言い残したことある?みんなに知っておいてほしいこととか。君が言った記事とか、ブログとかにはリンク貼っておくけど、Psake?これの話してくれる?
J:「サキ」って発音だよ。
C:Pは発音しないんだ。
J:これはMakeのツールでRuby On Rail用だよ。RakeはRubyを使ったMake、BakeはBooを使ったMake。これはBuildスクリプトを、XMLを使った.Netや、MSBuildをつかうのではなく、Powershellを使うんだ。それつかって、Psakeという小さなフレームワークを作るんだ。先週リリースされたんだけど、全てのビルドをやってくれるよ。
C:いいじゃん。
J:Powershellスクリプトを書いて、それをタスクに分けて、「これは、ビルドの代表で、こっちは導入のステップで、こっちはアーカイブのパッケージをzip化する」ってわける。それからちょうどMSBuildでやるみたいに、依存性を特定する。でもこれはPowershellでやるから、XMLの面倒な<カッコ>を扱う必要なくて簡潔なんだ。これがRakeやBakeより好きだなと思うのは、RakeとBakeは高レベル言語で、アダプタやブリッジを実装しないといけないんだ。
(Psakeでは)ビルドとして呼び出したいときに、ちょっとしたファンクションを書いて、ちょっとコマンド実行してMSBuildを呼び出してパラメータを投げる。.Netと同じでXMLを読解する.Netオブジェクトを作って、適切なコマンドを書いて、エラーを扱ったり、レスポンスをやり取りしたりする。Psakeはスクリプト言語のPowershellでかかれているから、こういったことはそのまま自然についてきているんだ。僕が数か月ぼんやり考えていたことなんだけど。「そだな、こういうの書いてみよう」と半日かけて書いてみた。Powershellはそのままでいろいろついてくるから、182行だったよ。コメント入れてもね。
R そんだけ?
J:そんだけだよ。
C:すげえ。
J:コメントなしだったら100行くらいじゃないかな。ビルドをPowershellで書くのは。Powershellいいよね。何かを作ろうとしたときにいろいろなことができるし、もしかしたら僕がやっているのはドメイン限定言語をビルドの周りに書いたのかもね。シンタックスをちょっときれいにしたりしたよ。他の人が見た時にお手本になるように。これ(Psake)もショウからリンクをつけてね。見てほしいから。もしかしたら誰かが今持っている問題を解決するかもしれない。
これがいいな、と思ったのは、別に今使っている.NetやMSBuildを捨てなくてもいい。もしPsakeを一緒に使いければ、「じゃ、.Netのビルドを走らせて、Solutionをビルドして。コンパイラはここ。zipはここね。これがテストする方法で、こっちがサーバーにデプロイする方法。」ってわければいいんだ。
Powershellのいいところは、Powershellプロバイダモデルがあるところだね。Exchangeが使うActiveDirectoryのプロバイダってのがあるし、Exhange Administaraionに使われるスクリプトってのもある。IIS7はPowershellスクリプトと、Powershellコマンドレットがついてきてるよね。MicrosoftはPowershellをずいぶん研究してるね。僕の予想するに、たぶんこれで、ビルドやテストだけでなく、デプロイや、レジストリ登録やIISの設定までまでできるようになると思うよ。
コマンドラインでね。
C:URLについてだけど、このshrinkster.com/zurって、Psakeの君のアナウンスメントがあるところだけど、このKovacsマシンっての、shrinkster.com/zv4って、これが、一番大きい、おっかねえモジュールマシンじゃないの? これって何?(訳者注: このページ今では死んでます)
J:うん。実はメインボードが死んじゃったんだ。マザーボードが何かの理由で動かなくなった
R:うわやだね。
C:やだやだ。
J:問題なのは、それがAMD939マシンで、知っているかどうかわかんないけd
R:持ってるよ
C:僕も持ってる。
J:AMDはAM2に完全に乗り換えたところで、939のマザーボードはもう手に入らないんだ。
R:だね。939はもう終わった。
C:知らなかった。
J:でも僕のプロセッサはAM2では動かないんだよ。RAMもAM2とは合わない。だから今あるコンポネントはすべて新しいものなんだよね。
C:そうなると終わりだよね
J:で、James Atwoodの組み方をScott Hanselmanのところで見て。
C:ああ。あれか。
J:最終兵器な、開発者向けの組み方を見てね、そのとおりにやって、いろいろ調べて。いろいろアップデートもかけて、今のシステムにしたんだ。結構いいよ。在庫部品なのにね。Windows Experienceレベル5.9だよ。
R:いいじゃん
J:最近では、教育ビデオやポッドキャストをやってて、これの使用感はとてもいいよ。音声の速度を上げる必要がある時はCamtasiaは4プロセッサを使ってて、しれちCamtasiaのビデオを同時に使ってもスムーズに使えるよ。
C:ナイスだね。
J:エンコーディングをリアルタイムの速度でもできる。
C:カッコいいな。James、情熱的な説明をありがとう、なによりもいい説明だった。いい先生だよね。簡潔に短くまとめてくれて、リスナーも大喜びだと思うよ。
R:DNR TVの方にも来てよ。
C:絶対そうしたよね。
J:その話もしようね。招待してくれてありがとう。ハッピーカナダの日だね。
C:大ジカに気をつけてね!
R:ナイスだね。
J:スウェーデンだったら酔っ払い大シカだね。聞いたことなかったらググってね!