MVVM+MVCパターンを大規模システムにスケールする

大規模プロジェクトで MVVM を導入するときの注意 | Moonmile Solutions Blog をもう少し突っ込ん考えてみます。大規模といっても、みずほみたいにできあがらなくて破綻したパターンもあれば、特許庁の場合のように設計時で破綻した場合もあれば、豊洲のように作ってからそもそも破綻しているのもあるわけで、常々プロジェクトの成功率は30%程度なので、大抵は破綻します。まあ、途中でプロジェクトとしてうまく失敗させる(一気に解散する)か、うまくプロジェクトを軟着陸できずにだらだとお金をつぎ込んで「失敗」させることがことができず終わる二百三高地になるやもしれません。

さて、それなりの資源(人と金)をつぎ込んでペイができるかどうかのバランスを保つ場合(公共事業の場合は、バランスを保たなくてもよい場合もあるので別)、「失敗が許されない」パターンがあります。しかし、失敗が許されないの対偶を人は「必ず成功する/させる」と受け取りますが、実は「全面的に失敗という状態にならければよい」わけで、部分的に成功であればつぎ込んだモノへの回収ができます。端的に言えば、工事進行基準になるのですが、実際ソフトウェアの開発工程に工事進行基準を持ち込んで、プロジェクトが半分で頓挫したときにそのプロジェクトには半分の価値があるのか?というと怪しいところがあります。と言いますか、大抵の場合、無いです。例えば、脱サラでよくやる飲食店のパターンは、初期投資でキッチンを購入したりするのですが、途中で潰れるとキッチンを下取りできるので、そこそこペイができます。が、ソフトウェア開発の場合、注力するもののほとんどが「人件費」なので、途中で頓挫したからといって、それを中古として出すことはできません。まあ、頓挫したサイトを売り買いするパターンもあるけど(会員データ込みとか?)大抵の場合は、工事進行基準とかEVのように価値が右上がりになるのではなく、プロジェクトの終了直前(完了直前)に一気に価値があがるのが普通です。ですが、長期のプロジェクトは人数が多い大規模なプロジェクトになると、最後の一気にあがる価値の時期に達しない場合は、まるごと価値がなくなるということなり、EV的(アーンドヴァリュー的)になだらかな価値が生み出されているという訳ではありません。

image

発注側としては、まるで既製品の車を買うように完成した品を即使いたいわけですから、納品直前に支払いをするほうが得なので、↑の図は望ましい形になります。支払を遅らせるという点で、資金活用もできますからね。ですが、請負側としては、支払いは納品により一括だし、途中の破綻のリスクを負わなければならず、たまったものではないので、プロジェクト工程を分けて分割支払いにします。

image

こんな風に段階的にリリースして、価値を発注側に提供して支払いを得ます。プロジェクト工程でいれば、要件定義とか設計工程とか製造工程とかいうやつですね。実際、それぞれの工程に確かな「価値」があるかどうかはわかりませんが、価値があるかのように振る舞うわけです。それぞれの工程が別の人物/会社にて行われているときには、いわゆる「作り逃げ」の手が使えるわけで、豊洲とか特許庁のあれはそのパターンです。その工程の本来の「価値」とは何かを忘れ去っています。

さて、段階的なリリースをプロジェクトの各工程にあてはめましたが、アジャイル開発のイテレーション開発の方法では、この段階的なリリースは「完成品」をしてひとつのプロジェクトとしています。スクラムで言えば、2週間ごとにリリースするとか、コアな部分だけ先に作って後から顧客の要望を取り入れる(あるいは削っていく)という方法がありますね。そのような、短期的なリリース(分割リリース)をもって、全体のプロジェクトを長期に引き延ばせば、マイグレーション開発というスタイルになるだろうし、そこは保守/運用を絡めて継続的に開発していくというスタイルを取ります。勿論、この継続したスタイルや段階リリースがすべてのプロジェクトに当てはまるわけではありません。近いところでは、Apple の Map の惨事は、ひょっとして「段階リリースの一部」といえば許せるかもしれませんが、製品とみたときはダメですよね。紙の書籍であっても、買ったときは表紙だけあって、あとから中身をちょっとずつ届けますと言われても、表紙が紙の状態では買いません(当たり前)。段階的なリリースあっても、顧客の視点からみて「何らかの形で価値が完成されて」いないと、価値とはみなされませんし、対価を支払う気にはなりません。そうそう、「月刊○○」のように毎月500円ずつ買わせるというパターンは、実は段階的な価値提供の成功例かもしれません。

発注視点で分割する

車のように完成したものしか価値がない場合と違って、実はソフトウェア開発において「分割リリース」は、発注側にとってもメリットがあるものです。必ず、そのプロジェクトが完成すると保障されているとしても(プロジェクトが失敗するリスクを0としたとしても)、発注側にとって5年後に5億円を支払って価値を得るよりも、1年目に1億円を支払って活用したしたときの価値を得たほうが投資率はいいですよね。また、4年後のオリンピックを目標にするならば、4年後に4億円を支払って価値を得るというスタイルよりも、1年目に2億円の支払いをして半分の価値を得たほうが、先行者利益を得られる可能性が高まります。

そんな訳で、長期かつ大規模なプロジェクトの場合、発注側の視点での「分割リリース」が意外と重要になってきます。大抵の場合は、ウォーターフォール開発やイテレーション開発の視点でプロジェクト工程として分けたり、アジャイル開発にして顧客の要望に沿わせたりするのですが、それとは違う視点での「分割」の仕方が必要なことがわかります(そういう視点で、アジャイル開発をしているならば別ですが)。

大規模プロジェクトを発注視点で分割する

5から10名程度がアジャイル開発の基本ならば、人海戦術的にウォーターフォールやPMBOKを活用するのが規模の大きい開発の基本とはなるのでしょうが、もう少し平易に、前段階の時点での分割を考えます。

先に話したように、顧客/発注側の都合を加味してプロジェクトを分割してみると、

  • 投資効果の大きい部分を先行リリースする。
  • 先行リリースされたものを使う場合は、完成品よりも人手がかかる。
  • 先行リリースされたものは不備/不足が多いため、人手で回避する。

ということになります。どこかの Xamarin.Forms のプロジェクトを想像させますが、まあ、あれと似たような感じです。OSS ならば、ひとまず公開してしまって(Xamarin.Forms はクローズドからスタートだけど)、それ自身に価値があるのかどうかを市場評価したうえで、継続的に開発をすすめるか/あるいは撤退するかの判断ができますよね。開発者は無限に時間を使えるわけではないのですから。

これは、多少ポンコツではあっても駅まで荷物を運べる車が便利とか、多少メンテナンス料金がかかったって時間が1/10で済むのであればロボットで自動化させたお菓子の生産ライン、みたいな感じですよね。人は、最初の材料を入れるところと梱包のところを任されていたり、ロボットが動かなくなったときのために張り付くわけです。

そうそう、iPhone のような完成したスタイルを求める場合は、分割リリースのほうが嫌われるわけで、そのあたりは Apple Map の叩かれ具合と Bing Map の叩かれ具合から察することができます。

分割リリースによる多少の不具合/不備を、発注側が受け入れるかわりに、先行投資としての価値を発注側が最終リリースのときよりも多く受け取れる、という価値を発注者側が熟知している、という前提が重要になります。

image

それらを前提にして、発注側視点で分割をしたとき、たとえば MVVM パターンの場合、大規模開発に参画している会社/チームは、View や ViewModel などに特化している訳ではなく、それぞれの業務知識の範囲≒ドメイン内で分割します。

請負視点を加味する

さて、発注視点であれば、投資効果の高い部分からの開発&リリースをすればよいということになります。ということは、設計段階において、いくつかの制限がでてきます。

  • とあるモジュール/ライブラリ/コンポーネントが、先行リリースで独立して動けること
  • とあるモジュール/ライブラリ/コンポーネントが、継続的に改修可能であること
  • とあるモジュール/ライブラリ/コンポーネントが、他システムと連携して動作可能であること

一見、当たり前のように見えますが、最終リリース型のウォーターフォール開発を行ったとき(最終リリース型のアジャイル開発でも同じ)、各コンポーネントは独立して動く必要なく他コンポーネントと密接な連携をしていても構いません。また、最終系までリリースが延期されるので、リリース後の改修を考慮に入れなくてもよいパターンが存在します。それにより、拡張性を無視することによる開発の効率化やコストカットが可能です。また、リリースまで動作が保証されないので、他システム/コンポーネントとの連携動作は最終リリース時まで保留になっていてもよいのです。たとえば、テスト環境できっちり動作することがプロジェクト運行時に保証されていれば、それが途中途中で他コンポーネントと連携させて無理に動作させる必要はありません。いわゆる、糊やにかわ的な部分を作る必要がなくなり、これもコストカットに貢献しています。

このため、多分にしてコスト高になりがちな分割リリースですが、そのコスト高をうわまる先行投資のペイを発注側が求めているならば(あるいは、発注側に認めさせることができれば)、このような分割リリースのための設計は意味があります。

ひとつの方法は「デザイン・ルール」のモジュール化により、各依存関係(設計時の変更工数も含め)を求めて、できるだけ関係の少ない状態にします。この本自体は、アイデアに過ぎず実体は伴わないのですが、私は「アイデア」として利用しています。

MVVM+MVC と TDD を活用する

肝としては、「設計段階で分割を考慮した設計をする」だけなのですが、そのあたりをアーキテクトと呼んだり呼ばなかったりしますが、まあ、少なくとも分割を考慮しない設計をした場合は、分割リリースはできません。継続リリースも困難ですよね。

image

一例を出すと、

  • ブラウザ
  • クライアントアプリ C#
  • サーバーシステム PHP

というシステムの分割の仕方があります。クライアントサイドでは MVVM パターンを使い、サーバーサイドでは MVC パターンを使う。Model はシリアライズ機能を用意しておき、ネットワーク系でデータのやり取りを行う。データベースは、サーバーサイドにあるパターンですね。クライアントは、Windowsデスクトップクライアントと、ブラウザでアクセスするクライアントを用意します。ブラウザからは、jQuery で Web API を調節呼び出してもよいし、別途 CakePHP 側にブラウザ用の View を作ることもできます。

当然のことながら、それぞれのコンポーネントは業務に直結しているわけではないので、各システム(在庫システムとか顧客管理システムとか)に応用が可能だし、実際応用ができます。コンポーネント自体は、独立で動作できるように TDD を用意しておきます。

難点としては、何かの機能を付け加えようとしたときに、クライアントサイドからサーバーサイドの一貫を見直さなければいけません。機能を追加したときに(特に削減したときに)、他のシステムに提供している機能が変化していないかを随時チェックする必要があります。それらを、手作業/人海戦術でやっていては、お金がいくらあっても足りません。何らかの形で自動化を行います。逆に言えば、自動化できないのであれば、そこの機能は常に切り捨てられるものであり、一品ものでしかないということです。

上記のシステム例で言えば、それぞれのコンポーネントのインターフェースが揃った状態で、ひとまず分割リリースの用意ができています。インターフェースしかないので、中身がからっぽだから何も動作はしないけど、でも、分割リリースができる程度の動作はするわけです。つまり、動くものの価値を発生さることが可能です。ほら、さきの EV 的な価値創出に近づいたでしょう。

image

そりゃ、要件定義も大切だけど(機能を絞るとか)設計がボロボロだったら、何もできあがりませんよね…ってな具合です。

横断型の TDD は、コンポーネントごとに TDD を作る方法とは違うので、これはまた別途書きます。あと、連携するコンポーネントが多くなると、先に書いた通り機能を追加する旅にあちこち手を入れる(MVC パターンだったら必ず3箇所に手を入れるとか)になるので、ここも別途手法を変えます。じゃないと手数ばかりかかって余計大変になるので失敗する率があがります。

カテゴリー: 設計 パーマリンク