[開発プロセス#5] Webクライアントのパターン

前回はWebアプリケーションのモデリングを、ロバストネス図で行うことによって、MVCを基調とした考え方と大きな違いはないという点を考えました。もっとも、「感覚的にそうである」と言ってしまえばすぐに結論に至りますし、厳密な意味で同等あるいは同様であるということを証明するまでも至っていません。言えたことは、ロバストネス図で記述する内容が、Webアプリケーションの動作や構造を明らかにする上で検討することと、概ね共通しているという点くらいかと思います。

その議論の続きで、Webクライアント側のシステム設計を進めるにはどうすればいいかを考えます。Webクライアント、つまりJavaScriptとHTML、そしてCSSで表現可能な世界では、今でも簡易的あるいは補助的なプログラム作成が可能な程度で、本体はサーバーであるような印象を持つ人も少なくはないと思います。古い時代、確かに大掛かりなプログラムを動かす環境としては、ブラウザーは貧弱でした。しかしながら、10年ほど前、2007〜2008年くらいの時期にブラウザーのメーカーがJavaScriptの動作環境を飛躍的に効率化した頃から、世界は大きく変わり始め、jQueryによってDOMベースのプログラミングが一気に普及しました。DOMのAPIは昔からありますが、APIを使ってまとまったプログラムを書くのは比較的に難し買ったのですが、jQueryは簡素化された書き方で、クライアントサイドのプログラミングの機会を広げました。さらに、2009年にはAnglarJSの前身である<anglar/>がリリースされ、その後にBackbone.js、KnockoutJS、Ember.jsなどと本格的なフレームワークがリリースされました。当初は、サーバーサイドのMCVとクライアントサイトのMVCという考え方もあったのですが、サーバーとクライアントの本質的な違いに気づくのに時間がかかりませんでした。

ネットワークサービスではデータの共有が1つの重要な機能です。そうした仕組みはサーバー上でRDBあるいはNoSQL等を使って実現することになり、永続的に利用出来る仕組みは必ずサーバー側に構築されることになります。したがって、データベースを効果的に使うための「モデル」というレイヤーのプログラム群を構築したり、データ処理に直結するビジネスロジックは、サーバーサイドで実行されるのが素直な役割分担でしょう。一方、ユーザーインタフェースは結果的にクライアントのブラウザー側で実現されていることです。UXの向上を掲げるプロジェクトが一般的になり、Webのユーザーインタフェースでも、高いレベルの要求が発生しました。つまり、高いデザイン性とスムーズな応答が求められるようになり、ボタンを押せばサーバーを呼び出すというやり方を越えるべく、AJAXによりブラウザー画面の更新以外にも通信を行い、サーバーのやりとりの結果で画面の一部を更新するといった処理が必要になりました。つまり、クライアント側では高度なユーザーインタフェースをサポートするのが主要な目的であることがはっきりしてきたのです。

もちろん、MVCでも高度なユーザーインタフェースの管理は可能です。しかしながら、具体的にどうすれば高度なユーザーインタフェースを構築できるかを考えてみましょう。ユーザーインタフェースで入力した結果をJavaScriptのプログラムで処理をしたいとまずは考えます。加えて、ユーザーインタフェース要素で発生したイベントの処理を効率良く処理したいというニーズもあります。こうした主要なニーズ分解して考えれば、そのニーズに合致するアーキテクチャパターンはM-V-VMであると言えるでしょう。MVVMは.NET Frameworkの中にあるWindows Presentation Framework向けのアーキテクチャとして、MicrosoftのJohn Gossmanによって提唱されたものですが、Flashの対抗として出されたブラウザー拡張機能のSilverlight上でのアプリケーション開発が中心的な話題になっていたと思われます。

MVVMでは、Model、View、ViewModelをコンポーネントして、アーキテクチャが定義されています。しかしながら、この3つのコンポーネントよりも重要なのが、それらのコンポーネント間のつながりです。まず、ビューとビューモデルの間は、バインディングによって結合されていることが挙げられます。バインディグとは、例えばテキストフィールドがページ上に表示されているとして、そのテキストフィールドの中の文字列(つまり、コンポーネントの値)が、何らかのエンティティ(例えば変数や配列の要素、オブジェクトのプロパティなど)と論理的に結合されていて、大局的にはコンポーネントとの値とエンティティの値は、一方が変わると自動的他方にも伝達されて、常に同じ値になるということです。言い換えれば、ビュー階層にあるコンポーネントの変化は、自動的にビューモデルは知ることができるという意味にもなります。一方、モデルは、MVCのモデルと同様な意味を持つとされますが、サーバーサイドではシステム全体のエンティティに関連するものの、クライアントサイドでは、現在のビューにおいて扱うべきモデルに一般には限定されると考えられます。そのモデルはデータベースと関係させるかどうかについては様々な議論があり、今後検討します。まず、MVVMモデルにおけるモデルは、オブザーバーパターンを利用して、モデル内での変化がビューモデルに伝達されるという仕組みを持ちます。この「ビュー階層の要素のバインディング」と「オブザーバーで監視されたモデル」というのがクライアントサイドに要求される、基本的なアーキテクチャと言えます。これらの処理の実現は、JavaScriptでスクラッチから行うのはかなり重いものです。そのため、様々なフレームワークがありますが、JavaScriptのフレームワークは最近出てきたフレームワークも含めて、MVVMパターンを基調としていると考えるのが妥当だと考えます。

MVVM

現実にはフレームワークを使うことになるのですが、フレームワークを特定しないで、クライアントサイドの動作をロバストネス図の表記を使ってコミュニケーション図で記述してみました。例えば、入力項目がいくつかあり、それらのデータが揃うとサーバーにそのデータを送信するという状況を考えます。このような動作のUX的な良し悪しがありますが、ここではバインディグとオブザーバーによって、モデルビューに相当するコントロールオブジェクトにうまく処理が渡ることは確かなようで、それがダイアグラムで表現できていると言えるでしょう。

MVVM Client-Side

ここで議論があるのは、最後の「送信」でしょう。言い換えれば、サーバー側はモデルなのか、モデルビューの通信先なのかという点があります。ビューモデルが、モデルとビューの仲介であるという定義に従えば、サーバーに送るのはモデルの役割になります。しかしながら、それはモデルなのでしょうか?サーバーサイドにあるデータベースを、クライアントサイドで抽象化してみているのが、クライアントサイドのモデルという考え方もできるので、だとしたら、「送信」はモデルの1つに定義するのが的確かもしれません。

ここでアーキテクチャパターンが必ずしもすべてを表現できるものではないという考え方に立つこともできるでしょう。MVVMはクライアントの処理すべてを記述できるでしょうか? 例えば、ページを表示後、ある特定のclass属性を持つ要素の設定をプログラムで変更するような仕組みはBootstrapなどフレームワークの動作としては代表的です。その仕組みは明らかにモデルではないとしたら、モデルビューではないとしたら、どうなるでしょうか? この点を考えても、アーキテクチャーのベースはMVVMであることにより、高度なユーザーインタフェース構築の援助にはなるものの、全ての要素を、ビューとモデルとビューモデルに割り当てるのは無理がありそうです。

しかしながら、ロバストネス図を利用すれば、バウンダリやエンティティでないものは、なんでもコントロールオブジェクトとして定義しておくことができるので、コントロールの一部はビューモデルであるとしても、ビューモデル以外の仕組みも記述できます。MVVMを基調としつつも、ダイアグラムの自由度を利用することで、多彩な処理のモデル化が可能であると言えます。

ちなみに、MVVMの仕組みがあれば、「送信」ボタンは不要になりそうです。しかしながら、その種の「従来と違う」ユーザーインタフェースは不人気です。ボタンが不要でも、ボタンをつけることを要求されることになるでしょう。OS Xでは当初より「確定」ボタンがないにもかかわらず、Webページにはサブミットボタンがないのは気持ち悪いと考える人が多いようです。現状で、送信ボタンのないユーザーインタフェースで受け入れられるようにするには、テキストフィールドの隣などに、「未送信」「送信済み」などとフィードバックの情報を表示するなどの工夫が必要です。

[開発プロセス#4] 開発するシステムのモデリング

Webシステムに関する開発プロセスの続きです。

システムを設計する上では様々なモデリング手法が使われます。要求から要件を導く上で、ユースケース図を作ることや、ドメインモデルのクラス図あるいはデータベース構造を記述するER図などが使われます。開発プロセスにおいてそれらの関連性を検討に入れて、各段階で何を目的にどんな図を記述すれば良いかということが規定されていることで、作業がスムーズに行われることを目指します。例えば、ICONIXでは、ユースケース図を記述した上で、ユースケースで抽出された場面で何が行われるかをロバストネス分析を行い、より詳細化しつつユースケース上の漏れを発見するという手順を行います。ここで議論するプロセスでも、同様な流れで、ユースケースの検討の後に、ロバストネス図を記述することで、詳細設計に入ることを意図します。

なお、ユースケース図は非常にシンプルな図であり、UMLの中では唯一、エンジニアではない方々にも読み解いてもらえる可能性のある図であります。その意味では、要求を要件としてまとめてシステム境界を検討したり、利用者から見た動作が必要十分に揃っているかを検討するには役立ちます。しかしながら、ユースケース記述、つまり、1つ1つのユースケースについての処理手順をこの段階できちんと書くよりも、コミュニケーション図への記述に移った方が、効率的と考えます。ユースケース記述に記載するような内容は、事実上、コミュニケーションズにも登場します。一方で済むのなら、同じ事実を異なるドキュメントに記述することでのドキュメントのメンテナンスタスクが重くなる点を考えても、一方だけにすべきです。もちろん、エンジニアでない顧客とのやりとりには、ユースケース記述も有効かもしれませんが、それでも「動いていないシステム」について可否の判断は通常は誰もできないと思われます。ユースケースで大枠を固めた上で、個別の処理はロバストネス図で詰めるのが作業効率が高いと言えます。

ロバストネス図はUMLで定義されたダイアグラムではありません。1992年に出版されたIvar Jacobsonらの “Object-Oriented Software Engineering, A Use Case Driven Approach” において分析モデルとして記述方法が提示されています。ICONIXの手法を解説したダグ・ローゼンバーグらの書籍『ユースケース入門 ユーザマニュアルからプログラムを作る』では、「ロバストネス分析」としてその意味や分析時に検討すべきことなどがまとめらています。それぞれ、英語、日本語訳といろいろな用語がありますが、この一連の記事では、オブジェクトを「バウンダリ」「コントロール」「エンティティ」の3つにまずは分解することをスタートポイントとします。

基本概念

『ユースケース入門』での解説では、バウンダリはユーザーなどユースケース上のアクタとの相互作用を行うオブジェクトで、画面、ダイアログ、メニューなどがそれに当たるとされています。エンティティは、ドメインモデルに基づくデータのデータを保持するオブジェクトや、あるいはテーブルなどのデータベースエンティティとのやりとりを行うものです。コントロールにはアプリケーションのロジックが実装されるものとされています。

この3つのオブジェクトの通信に関して、次の表のような取り決めがされています。なお、アクタはバウンダリへの通信は行いますが、逆にアクタへの通信という概念は考慮されていません。画面に表示することまでしかシステムとしてはできないという意味で解釈できると思います。それ以外は、要するに、コントロールはバウンダリやエンティティと通信できるけど、エンティティやバウンダリは、コントロールとの通信しかできないというルールです。バウンダリ-コントロール-エンティティという流れを定義することが、ユースケース上の表現を名詞-動詞-名詞のスタイルに揃える結果につながると書籍では説明されています。

From\To バウンダリ コントロール エンティティ
アクタ × ×
バウンダリ × ×
コントロール
エンティティ × ×

こうした記述がMVCパターンと同じような意図があるのではないかということは、まず感覚的にわかります[Mukhtar2004]。また、Model=エンティティ、View=バウンダリ、Controller=コントロールという対比をすれば、MVCとロバストネス図は、「同じような分類」を記述ルールに導入していると言えます。

ここでまず、MVCつまりMode-View-Controllerパターンを改めて紹介します。もともとは、Smalltalkでの対話型アプリケーション開発の問題点を克服可能なパターン[Krasner1988]として考案されたものです。F.ブッシュマン他の『ソフトウェアアーキテクチャ ソフトウェア開発のためのパターン体系』(いわゆる「POSA本」)でも、当初の定義に基づいて解説されています。図に示した通り、オブザーバーを介したやりとりが本来の定義です。コントローラはモデルを変更すると、その変更をオブザーバーによってビューに伝えられ、ビューがモデルにデータを取得するというものです。この点では、現在のWeb開発で使われているMVCと分類されるフレームワークと、対象としている動作そのものが違っていると言えるでしょう。しかしながら、本来の定義はさておいて、「モデルとビューとコントローラーに分離する」というアイデアが一人歩きした結果、現在のサーバーサイドでのWebアプリケーションフレームの基本的な形態としてMVCが存在するようになりました。

一方、Web系フレームワークでのMVCの発端は、Java2 EEの初期に提示されたMVC2と呼ばれるパターンがありますが、これはもともとJavaServer Pagesの仕様書にあった「JavaServer Pages Access Model 2」という記述から命名されています[Wikipedia – JSP Model 2 architecture]。そこでは、ユーザのリクエストを受け取るJavaServlet、データを管理するJavaBeans、表示するページを生成するJavaPagesといった図があり、それぞれ、Controller、Model、Viewであると言えなくもないことから、いつしかMVC2という用語で呼ばれるようになったものですが、Wikipediaの記述によると、誤解が重なった結果の用語がMVC2であると示されています。

一方、D.Alurらの著書『J2EEパターン』では、MVCパターンとしてのカタログ掲載はありません。現在のMVCと言われているものに近いものは、Application Controllerというパターンであり、そのView Handler戦略というパターンの1つの展開方法であると言えます。図は書籍に示された通りに清書したものですが、コントローラがデータを取得し、それをビューに渡して画面生成するという一般的なWebアプリケーションの動作そのものです。

MVC Definitions

以上のように、すでにカタログ化されているMVCパターン自体が多岐に渡っており、共通する点は、「データを扱うモデルと、画面周りのビューは分離して、別のオブジェクトに統括させる」というくらいであると言ってもいいのかもしれません。その意味では、これはロバストネス図の考え方そのものと言ってもいいでしょう。MVCパターンで構築するとよく言われますが、現在のWebアプリケーションでは、「MVCを基調とした考え方で設計されたフレームワーク」を使っている点で、すでにMとVとCに分離するという世界に取り囲まれることになります。設計時に、MVCをどの程度の意識すべきかは多様な意見があると思いますが、ロバストネス図上での荒い分類の上で作って、それを実装時に適切なクラス設計に落とし込むという考え方で進めれば、まずは必要な機能の洗い出しとその相互作用を書き込むということに集約できます。それが、MVCを基調としたフレームワーク上で実現できれば、その世界でのMVCパターンを一定水準以上満たした設計であると言えるでしょう。

実際にロバストネス図を記述してみます。なお、astah*で作成するときには、クラス図で記述すると、以下の図のようになります。この場合はクラス間の関連性しか記述はできません。以下の図が、astah*で作成できるロバストネス図に近い図と言えるでしょう。

MVC Server-Side (class)

一方、コミュニケーション図で記述すると、以下の図のように、オブジェクト間のメッセージのやり取りも記述できます。一連の記事で検討している開発プロセスでは、前記のクラス図ではなく、以下のコミュケーション図を主体にします。ICONIXのプロセスでは、クラス図によるロバストネス図の次は、シーケンス図を記述して、やりとりを記述します。しかしながら、シーケンス図はちょっとした図を記述するのにも、比較的労力がかかってしまいます。正確に記述でき、ほぼ、実装に直結した記述ができるのは良い点ですが、ここでも「他の図では自明なもの」をシーケンス図で記述することはしなくても良いと考えます。つまり、ロバストネス図にメッセージのやりとりを記載する、つまりコミュニケーション図として記述をすることで、一定の範囲の処理はシーケンス図に書くのと大きな情報量の違いはないと思われます。言い換えれば、1つのスレッドで順々に処理が進むものなら、シーケンス図でなくても十分に表現が可能と言えることです。ただし、クライアントとサーバーの間のやりとりや、並行プロセスの同期等が絡むような処理があるような場合には、他の図ではなく、シーケンス図上できちんと設計を進める方が良いでしょう。

MVC Server-Side (com)

前の図は、Webページでよくある動作パターンを、コミュニケーション図上のロバストネス図として記述したものです。検索条件入力画面が出ているとして、そこで条件を入れると、検索条件に合ったレコードが一覧されるというものです。もちろん、今時は懐かしい感じのUXではありますが、分かりやすい例として示しました。本来、アイコンは「オブジェクト」であり、矢印は「メソッド呼び出し」などの実装に直結するものになるまで分析しないと設計にはならないかもしれませんが、まずはそういう実装に関することを緩く考えれば、このような図でも間違いではないと思われます。

しかしながら、それでは「検索処理」というクラスを用意するのでしょうか?「顧客データ」というモデルクラスを用意するのでしょうか? もちろん、それでも可能ですが、一連のロバストネス分析でのアイコンすなわちオブジェクトと呼ばれているのは仮想的なオブジェクト、あるいはオブジェクトの断片と考えるべきであり、メッセージ送信はメソッドの候補的な考えの方が良いでしょう。想定するのは、例えば、システムにこうした機能が20個あれば、20個のコミュニケーション図が作成されるかもしれません。そこでの処理の流れや、エンティティの使われ方を俯瞰した上で、コントールやエンティティの実現するというように考えて、ロバストネス分析時点では、実装にあまり左右されない、あるいは引っ張られない抽象的な記述からスタートして詳細化することで、必要な機能のモデルへの注入がスムーズに行われることになります。

しかしながら、最後には実装しなければなりません。全体を俯瞰すると言っても、フレームワークの機能が全部やってくれる処理もあるでしょうし、設定を渡す必要がある箇所、あるいは全部自分で実装しないといけない箇所があります。しかしながら、「必要とされる機能」をいったんモデル上に記述した上で、フレームワークとの接点を考え、その上で実装を行うという方針で進めることで、スムーズな開発や、あるいは設計変更時の対処等も含めて、モデルの役割と実装への貢献がより高くなるのではないかと考えられます。

ユースケースをまずは記述し、そこからコミュニケーション図をベースにしたロバストネス分析を行って、システムが行うべき処理の詳細化を行います。そこまで分析を進めた上で、データベースのスキーマをエンティティを中心に検討し、その結果をもとにモデルクラスの設計へと移ります。一方、バウンダリやコントロールの機能をどのようにクラスとして最終的に表現するかとなると、ここは飛躍が大きすぎます。そのためには、バウンダリとコントロールだけでなくより詳細な書き込みを行いたくなります。また、詳細化するとなると、モデル上に表現したいのはオブジェクトよりも粒度の小さな「何らかの処理」の単位になってきてます。ただし、Web開発は様々なプラクティスが確立された、ある意味でパターン化された開発タスクの世界でもあります。何でも表現できるという点で抽象度の高いモデルの役割がありますが、ドメインに特化することで抽象度は下がってもそのドメインで有益なモデルの改良版は同様に役に立ようにできるでしょう。このモデルの表現をどのように拡張するのかの検討を引き続く記事で検討します。

クライアントサイドのパターンとの検討を次回に記述します。

[開発プロセス#3]プロセスから何を実現したいのか?

一連の記事は「開発プロセス」というカテゴリを設定することにします。

1つ前の記事は、現在の開発ではアジャイルが前提である、あるいは勝手にアジャイルになるということも多々あるということで、アジャイルのプロセスに少し踏み込み、そこでドキュメントは不要なのではなく、いかに負荷をかけずにドキュメントを作るかという視点が必要であるということを説明しました。

実際にシステムを作る場合、当然ながら最初は100点を目指して作りますが、それを実現するためのいろいろな品質基準があります。例えば、ISO/IEC 25010:2011を基にしたJIS 25010:2013などがあります。製品品質モデルの上位カテゴリを見ると、機能適合性、性能効率性、互換性、使用性、信頼性、セキュリティ、保守性、移植性という項目が並んでおり、これらを一定以上のレベルで実現することで、品質を確保することにつながります。つまり、品質を高めるために具体的に何を行うのかを検討する材料はすでに工業規格となっています。

最近ではWebアプリケーションやスマホで稼働するアプリケーションを作る機会は多くなっています。開発時には、機能適合性、性能効率性、使用性という点について、すべての開発に関わる人が多少なりとも意識しやすところです。これらに関わる内容は、開発を進める上で、常に話題としてチームの中に流れ、また、チェックもされるということになります。信頼性は最も重視されることであるのですが、対策を具体的に行い結果をきちんと出すのはなかなか難しい領域でもあります。一般論で進めた結果、完成したシステムが不安定だったということは多くの開発関係者は体験しているでしょう。セキュリティや保守性は、どちらかといえば、当たり前的な意識がまずあって、場合によっては「常識」ということで、議論されない可能性もあります。極端な例ですが、システム請負会社はセキュリティ対策は仕様に入れなくてもやっていて当たり前という判決も出ています。当たり前なので議論の俎上に上がらないというのは、実は誰も気づかず、あるいは気づいても実装はしていないということにつながります。セキュリティへの注目が集まる一方で、臭いものには蓋をする的な意識が共有化されていないでしょうか? また、保守については、初期開発ではそこまで頭が回らないという切羽詰まった状況も日常化していないでしょうか。

機能や仕様を考える上で意識に上りやすい「機能適合性、性能効率性、使用性」、重要性は意識しているが実現が難しい「信頼性」、いくぶん消極的な方向に行きがちな「セキュリティや保守性」という傾向があるように感じます。「互換性、移植性」については要件や利用状況に絡むことであり、他の項目と傾向が違うように感じます。信頼性については、様々な手法やプラクティスがあることもあって、マネジメント上で注力すれば、それなりにやり方はある方法です。こうした分類から、セキュリティと保守性にテコ入れが必要なのではないかと考えます。

現在、多くの開発は保守開発である事は、多くの人が指摘するところです。IT関連費用のうち、運用コストが45%、新規開発24%、保守開発31%となったという調査もあります。開発関係者と話をしていても、実際、データベーステーブルがないところから開発ができるような機会はあまりなく、誰かが昔作ったシステムの改修といった仕事が増えていることが話題になります。また、従来からの開発手法では、新規開発と保守開発は明確に「契約」段階での分離があったかもしれませんが、アジャイル開発や、あるいは顧客のニーズが変化するような場合は、現実には初期開発の途中からでも保守開発の側面が強くなります。

事実上保守開発を普段から定常的にやっているのだとすれば、機能実装をスムーズにする仕様書という考え方に加えて、保守開発、つまり改変する箇所が明確になるような仕様書である必要があると考えます。そのためには、抽象度の低い具体的な機能のモデル内での明確化と、フレームワークやライブラリを利用する前提の上での境界線の明確化であると考えます。抽象度の高い記述方法で、自由に実装をしてしまうと、別の人がモデルを見たときに大まかなコンセプトは伝わりますが実装の上で考えたことはコードと突き合わせて解析しなければなりません。また、フレームワークの機能をどこまで利用しているのかが明確でないと、フレームワークの仕組みを保守するのか、独自に作ったプログラムを保守するのかも、やはりプログラムを読み解かないとわからないことになります。この点を踏まえて、どのようなドキュメントを作るのかを考えます。

なお、前述のJIS 20010では、保守性の項目に対する細目として、モジュール性、再利用性、解析性、修正性、試験性が挙げられています。「モジュール性と再利用性」は、適切な設計かどうかという点に大きく依存しますし、「試験性」も試験が可能なように作ってあるかどうかという点に依存します。一方、「解析性、修正性」について、開発プロセス上でより重視できるような仕組みを組み込むというのが大きな目的です。

保守開発の最も大きな問題点は、目の前で動いているコードしかないという状況で、改良にかからないといけない点です。また、巨大な既存システムの全貌はわかりません。全貌がわからないと保守できないというのは却下されべき言い訳としか理解されません。わからないけど改良しないといけません。その場合でも、改修対象の機能に絞って初期開発と同様のモデリングをすべきです。ただし、変更結果の波及範囲は検証すべきでしょうし、不明な箇所の扱いにも配慮は必要です。ここで、ドキュメントを書いている時間がないとか、費用がないといったことが言われて、それでもなんとかしたいという要望があることも事実です。時間や費用がなくても、最低限のドキュメントを揃えることが、まずは改修箇所の把握には必要です。その場合は、ボトムアップに解析をして、関連するデータベース内部のスキーマからER図を作ったり、特定の処理に限定してクラス図を作るなどすることで、効率化は図れます。一連の説明では、困難な場合でドキュメントは作るという前提で話を進めます。

次回から具体的に何を作ればいいかということを説明します。

[開発プロセス#2]何のための何を目指したプロセスか?

開発プロセスにおけるアーキテクチャ設計として先日記事を公開しましたが、継続して記事を続けるにあたって、ヘッダに [開発プロセス#N] (Nはシリアル番号)を入れることにします。前回は大まかな話でしたが、今回は検討する開発プロセスの目的を定めます。今回は、当たり前の話ばかりだと思います。

開発において、いきなりプログラミングすることはまずないと思いますが、何らかの検討を経て実装に入ります。実装なくしては当然ながら完成しないので、実装、すなわちプログラミングは開発の中心と思われているかもしれません。しかしながら、実際に開発経験があると理解できることは、事前に検討して問題解決していることと、実装しながら問題解決に当たるのとでは、前者の方がはるかに効率的であり、出来上がったコードの質が高くなるということです。「仕様書をちゃんと書けよ」ということになる一方、仕様に関する成果物に労力をかけないまま実装に入ることもあります。これらの上流工程にどの程度時間をかけて、どの程度の成果物を得ればいいのかということの議論は昔から今に至るまで、そしてきっと未来永劫続くことと思います。ウォーターフォール形式など、開発プロセスが決まれば、1つのプロセスの終了と、検討結果に関する成果物とが対応することになり、いわば自動的に仕様書を書くことが前提になります。一方、仕様書を記載したり、あるいは変更結果を反映させる作業は決して小さな負荷ではありません。アジャイル開発のように、完全な仕様書を書くよりも動くコードを書くことを優先させる手法も出てきている一方、このことを都合よく解釈して「アジャイルはドキュメントは書かなくてもいい」と決めつける人たちがいることも事実です(アジャイル勘違い集#3)。しかしながら、こうした決めつけが出てくる背景には、設計の成果物の労力に見合う結果が得られるのかという懸念があるのではないでしょうか。

実装に入るまでのプロセスを重要視し、仕様書を作るという立場は崩しません。しかしながら、アジャイルソフトウェア宣言には「包括的なドキュメントよりも動くソフトウェアを、」とあります。包括的な、すなわち完全なドキュメントでないけども、設計する上で考えたアイデアや制約などがドキュメントとして参照できる必要があります。ではコードをしっかり書けばいいという考え方もあります。Googleへの注目が増大される時代に、「Googleでは仕様書ではなくコードを見る」のだというイメージが定着し、ここでも勝手な解釈になるのでしょうけど「仕様書はなくてもすごいシステムは作れる」と思ったと考えられます。また、コードは常に最新であるという主張は間違いはありません。しかしながら、コードはコードであり仕様ではありません。コメント欄に記述できる内容も限られていますし、コード上で明示的ではないあるいはその真髄に迫るには時間をかけて解析しないといけないような様々なノウハウが実装には注ぎ込まれているはずです。コードで仕様に関するコミュニケーションがとれるとしたら、その内容に精通したプログラマ同士だけでしょう。オープンソース開発では、コミッターの時間的制約などでそうした状況になりがちであり、単体テスト等のテストを自動化することと組み合わせれば、十分にワークする方法であることは多数のオープンソースプロジェクトから言えるのではないでしょうか。しかしながら、コードを読み解くということは、時間をかけて解析したプログラマ以外に可能かというと、ほぼ無理でしょう。顧客や発注側はそこまではしない、あるいはできないでしょう。「しない」理由は、それをやるくらいなら自分で開発できるから発注しないからです。プロジェクト管理者、あるいはユーザーテストの管理者、導入教育担当、こうした開発に関わる様々な人が、プログラマ並みにコードを読むことができるかといえば、能力的なことだけでなくビジネスに直面するコストの問題でできないと言えます。

受託開発では顧客の要望がコロコロ変わるようなことは普通にあり、これは「消極的なアジャイル」とも見ることができます。追加の開発に対しても費用が出ないことあるのに、ドキュメントの更新に追加の費用を請求する雰囲気は現場にはありません。こうして「使えないドキュメント」が山積みされることになるのですが、その使えないドキュメントでも、過去のある時点をキャプチャした情報として活用せざるを得ない場合もあるわけです。

こうした現在の開発プロセスにおいて、成果物として何が求められるのかを再考するのが、一連の[開発プロセス]記事の1つの大きな目的です。すなわち、ドキュメントに記述されることを、ドキュメントに対する負荷を可能な限り最小化したプロセスとして再考するのが目的です。以下、まとめてみました。

  • 仕様書は作成する必要がある。特に強くコミットしているプログラマ以外のコミュニケーションにはなくてはならない。
  • 仕様書が膨大になると、更新が滞り、最新の結果が反映されなくなる。仕様の変更に対してドキュメントの更新は必要だが、その負荷を最小化したい。

この次は、開発されるシステムがどうなることを意図しているのかということを記載します。こちらの方が先に記載すべきかもしれませんが、目的の話題が何度か続くとういうところです。

開発プロセスにおけるアーキテクチャ設計

INTER-Mediatorに適した開発プロセスを考えていましたが、うまくまとまりません。なんでかなと考えたのですが、INTER-Mediatorを使うという前提なしで考えるべきであり、それを元にINTER-Mediatorへの適用をする必要があると考えます。つまり、一般的な意味でのWebアプリケーションだとかスマホアプリといったものを開発するときに、どんなアーキテクチャが前提となり、設計上何を考えれば要求・要件から実装に近づけるのかという一般論をまずはまとめるべきなのでしょう。最近、たまたま、いろんな仕事の中でアーキテクチャ関連の話題の基本を再勉強する機会があり、その中で一般論になんとなく近づいている感があるので、いっそのこと、考えながらブログでまとめていくという過程で進めようかと考えた次第です。

システム開発では、要求や要件を出発点として、仕様を策定して実装に持ち込みます。外部仕様、内部仕様という区分けがある場合もあります。また、データベースを使う場合は原則としてレイヤー構造になり、データベースが底辺を担うことからドメイン分析した結果をスキーマとして記述して、実装段階では確定したデータベース定義にすることになります。こうした、設計の定石とも言えることはたくさんあり、特定の開発チームや流派、カルチャーに応じてその表現は違うものではありますが、システムを意図した通りに稼働させるという意味では目指す方向は同じであり、場面によって言い方が違うだけの場合もよくあるわけです。一方、様々なノウハウがあるものの、ある要件を満たすようにシステムを作る場合の実装に向けた機能分解は、単一の答えが存在する問題ではありません。同程度に正しい解答はいくつも作れるでしょう。結果的に、「状況に合わせて最適化する」というなんとでも取れるようなアドバイスしか出てこないことにもなりかねません。しかしながら、機能をどのように分解して、それぞれの個別の動作をどのように実装するのかということが、開発の上では非常に重要な決定であることは言うまでもないことです。ベテランや才能のある人は、そういうことをスラスラとできるのかもしれませんが、初心者あるいはある領域の経験が浅いと悩むものです。手っ取り早く知りたいという要求は年々高まり、「ベストプラクティス」や「ティップス」といった情報が重宝されるようにもなります。

こうした設計を完成させるに至る知見は、例えばオブジェクト指向分析や、コンポーネント分析、パターンなど、様々な手法があります。それらをうまく束ねた統一的な開発手法も多数存在します。私が考えていることは、そうした開発手法の1つを作り上げることであり、その結果をもとにして、INTER-Mediatorでの開発手法を確立するということです。車輪の再発明っぽく見えるかもしれませんが、問題点を検討すると、やはり時代に応じた道具に対応した手法はその都度更新されていくものではないかとも考えられます。

現在の様々な開発手法が発展したのは、オブジェクト指向プログラミングが当たり前の時代になり、コンピューターの性能が高まり、そしてインターネットで世界中が繋がって、Webという基盤ができた頃の時代です。一方、現在はスマホ登場やフロントエンドの発展が著しく、サーバー単体での開発手法以上のものが求められています。従来はWeb開発とネイティブ開発、つまりOSのAPIを直接利用する開発は、大きく違っていたのに対して、現在は言語やフレームワークは違っても同じような実装をしているという感覚があります。この領域で業務をしている人は薄々気づいていることではないでしょうか。これは、何か共通のアーキテクチャを持ち込むべきではないかと考えました。まずは、そのための問題意識として持ったことを箇条書きにします。

  • Webシステムはサーバー中心なのは仕方ないとしても、クライアント側のアーキテクチャをどう表現するのが適切だろうか?
  • スマホアプリはサーバー接続する場合が多く、「サーバー側」「スマホ側」という2つのアプリケーションの連動を行っている。最近のWebも「スマホ側」が「JavaScript処理」に置き換わるだけの違いとも言える。つまり、今時のシステムは、サーバーサイド、クライアントサイドを統合的に議論できるアーキテクチャを基盤として持つ必要があるのではないか。
  • コンピューターが速くなり、メモリーも豊富になると、RDBである必要性は薄くなる一方、やはり安定した保存はRDBが理解しやすいとも言える。RDB前提のシステム設計はある意味安定するのだが、逆に必然としてRDBが出てくる理由付けはないのだろうか?
  • サーバーサイドのアーキテクチャはともかくMVCである。いろんなMVCが存在する一方、正しいとか正しくないとか、本物だとかそうじゃないという議論があるものの、MVCは大雑把な機能分類として考えれば、役立つ場面は多いのではないだろうか。
  • クライアントのアーキテクチャはMVCなのだろうか? 違うのだろうか? クライアントサイドの主要な機能はUIの運用とその高度化であるとしたら、MVVMがいろいろな意味で包括性の高いアーキテクチャではないだろうか? ただし、バインディングとオブザーバーを基調としているだけに、それらを実装していないフレームワークはMVVMとして俯瞰できるかどうかが難しい点であると言える。
  • MVCとMVVMを出発点に考えるとしたら、それらの中での機能分割の指標としては、ロバストネス分析をベースに検討できるのではないか、ロバストネス図の要素はビュー、コントロール、エンティティであり、ほぼMVCのコンポーネントに対応するものの1対1ではない。しかしながら、要件をロバストネス分析して、MVCやMVVMを基本としたアーキテクチャとして表現することは、オブジェクトし志向分析の結果を見ても可能であると考えられる。
  • MVCなどのアーキテクチャパターンで設計しても、実装できないかもしれないし、実装するために変形が必要な場合もあるのかもしれない。過去の様々な設計手法では、汎用化がされる一方で、使用するフレームワークの制約やあるいは特有のコールドポイントの扱いなどが考慮されたものは見たことはない。しかしながら、フレームワークによる制約は可能な限り早期に検討する必要がある事柄ではないだろうか。あるいは、フレームワーク制約を組み込む段階がいつなのかを明確にすべきではないだろうか。
  • サーバーとクライアントの分類はどうすべきだろうか? 最初はそれらは関係なく、要件満たすような必要な処理に分割し、あるところで「線を引く」という作業になるのだろうか? そうすれば、サーバーとクライアントの両方を巻き込むシステムの設計はスムーズにできそうだ。

とりあえず、思いつくまま挙げましたので、ポエムに近づきつつあります。これらの考えを少しずつほぐして、手法として使えるまでにすることが目標です。

(続く)