Category Archives: アーキテクチャ

[開発プロセス#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ページにはサブミットボタンがないのは気持ち悪いと考える人が多いようです。現状で、送信ボタンのないユーザーインタフェースで受け入れられるようにするには、テキストフィールドの隣などに、「未送信」「送信済み」などとフィードバックの情報を表示するなどの工夫が必要です。

[開発プロセス#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などのアーキテクチャパターンで設計しても、実装できないかもしれないし、実装するために変形が必要な場合もあるのかもしれない。過去の様々な設計手法では、汎用化がされる一方で、使用するフレームワークの制約やあるいは特有のコールドポイントの扱いなどが考慮されたものは見たことはない。しかしながら、フレームワークによる制約は可能な限り早期に検討する必要がある事柄ではないだろうか。あるいは、フレームワーク制約を組み込む段階がいつなのかを明確にすべきではないだろうか。
  • サーバーとクライアントの分類はどうすべきだろうか? 最初はそれらは関係なく、要件満たすような必要な処理に分割し、あるところで「線を引く」という作業になるのだろうか? そうすれば、サーバーとクライアントの両方を巻き込むシステムの設計はスムーズにできそうだ。

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

(続く)