プロジェクトをXcode 8/Swift 3に変換した時の自動変換結果から変更点をチェックする

Xcode 8.0が正式に出ました。あるアプリケーションのプロジェクトをコンバートした時に自動的に書き換えられた結果をもとにどのような変更があったのかを記録しておきます。なお、このプロジェクトは、Swift 2.3の時に、Swift 3でdeprecatedになるという警告の箇所は、警告が出ないように変更した結果です。それ以前のバージョンのSwiftで作られたソースでは、もっと様々な変更の必要があると思います。まず、ターゲットは、iOS 9.3のままの状態でコンパイルが通るようにしてみました。

クラスそのものが変更されたもの

以下のクラスについて、名前が変更されています。矢印の左側が、Xcode 7.x(iOS 9.3)の場合の記述で、矢印の右側の記述に自動的に変換されたことを示しています。NSの付いたクラス名が付いていないものに変わってきています。おなじみのNSURLやNSErrorが、配列や文字列ど同様NSのないクラス名に変更されています。クラスの機能については大きくは変わっていないようです。NSURLSession及びその名前で始まるNSURLSessionTaskも含めて、頭の「NS」はなくなっていますが、今日現在、ドキュメンテーション中に「NSURLSession」が残っていたりします。最後のURLSession.AuthChallengeDispositionは列挙型です。

  • NSUserDefaults→UserDefaults
  • NSError→Error
  • NSURL→URL
  • NSBundle→Bundle
  • NSURLSession→URLSession
  • NSURLCredential→URLCredential
  • NSURLAuthenticationChallenge→URLAuthenticationChallenge
  • NSURLSessionAuthChallengeDisposition→URLSession.AuthChallengeDisposition
  • AnyObject→Any

インスタンスを得るメソッドがシンプルなプロパティに

「UIApplication.sharedApplication()」などは頻繁に記述していたのですが、Applicationという単語の重なりがなんか重い感じがしていましたが、「UIApplication.shared」のように、長いスタティックメソッドが短いプロパティに変更されました。コードがかなりスッキリします。以下のリストの最後から2つ目にあるにあるDipatchQueueクラスは、iOS 10から搭載されたクラスで、dispatchで始まるGrand Central Dispatch関連のAPIをクラスにラップしたものです。このクラスのドキュメントはまだ完全に埋まっていませんが、クラスはiOS 10からなのにメソッドのsync(execute:)のようにiOS 4から関数としてサポートしているものもあり、要するにやっとクラスとして使えるようにAPIを整えたという状況のようです。最後のUIColorクラスは、いくつかの色のオブジェクトを得るスタティックメソッドが用意されていましたが、これもColorの重複があったものの、redやgreen、blackといったプロパティで得られるようになりました。

  • UIApplication.sharedApplication()→UIApplication.shared
  • NSBundle.mainBundle()→Bundle.main
  • standardUserDefaults()→standard
  • UIScreen.mainScreen()→UIScreen.main
  • dispatch_get_main_queue()→DipatchQueue.main
  • UIColor.redColor()→UIColor.red

アクセス修飾子

従来の3種類から、open、public、internal、fileprivate、privateの5段階に変更されました。openとfileprivateがSwift 3より導入されたものです。従来のprivateは、全部fileprivateに変更されてしまいます。省略時にinternalになるのは変更ありません。
Swift 2.xではprivateによるアクセス制限はクラス単位ではなくファイル単位でした。したがって、1ファイルに2つのクラスを定義した場合、privateなプロパティでも別のクラスからアクセスができました。Swift 3ではファイル単位でのfileprivateと、クラス単位のprivateに分離しました。従来のprivateが現在のfileprivateになったということで、こうした変換を行なったのでしょう。
一方、publicとopenについては、元のpublicは現在はopenに対応します。いずれも、モジュール外からアクセス可能にするための修飾子ですが、Swift 3ではpublicはサブクラス化やoverrideできないという制約が付きます。

オプショナルバインディングの書き方

Swift 2位の時に、letの後にカンマで区切って複数の代入文が書けるようになり、ifを多重にネストしなくてもよくなったのですが、Swift 3ではカンマで区切ったそれぞれの代入文にletが必要になりました。以下の、let b = yのletは今までは不要だったのですが、これが入るようになります。

var x: String?
var y: String?
if let a = x, let b = y {
   print(a,b)
}

UIKitのAPIの変更

メソッド名やプロパティ名などがあちらこちらで変わります。ただし、総じて読みやすくはなります。例えば、UIViewControllerのshowViewController(_:sender:)、dismissViewControllerAnimated(_:completion:)、presentViewController(_:animated:completion:)の各メソッドが、show(_:sender:)、dismiss(animated:completion:)present(_:animated:completion:)へと極めて短くなりました。また、最初の引数にはキーワードをつけないということで統一されていて、最初のキーワードは関数名に組み込まれていましたが、状況によっては引数のキーワードとして使うようになりました。なので、dismissのように通常のメソッドでも、最初の引数にキーワードが付くことがあります。一方、UINavigationControllerクラスではpopViewControllerAnimated()がpopViewController(animated:)にはなるなど変化はあるものの、大きな変化のないクラスもあります。

UIViewクラスのhidden、userInteractionEnabledプロパティはisHidden、isUserInteractionEnableとなりました。Boolean型のプロパティのインタフェースを「is+属性名」としたということで、この部分はJavaなどのルールに即したということでしょう。また、プロパティ名にあった「URL」はほぼ「url」で置き換えられており、URLで始まるプロパティもurlで始まるようになっています。定数についても、以前は.Badgeのように頭文字は大文字でしたが、.bridgeのようにドットの次は小文字になりました。たまたま、Objective-Cで作ったクラスを入れていたのですが、そのクラスの定数も同様に頭文字が小文字になったので、この処理はブリッジ部分での変更であることが確かです。結果的に、クラス以外の頭文字は小文字というルールが浸透した感じです。

さらに、メソッドだったものもプロパティとして扱えるものは、プロパティになりました。UIViewControllerクラスでは、supportedInterfaceOrientationsメソッドがあり、それをオーバーライドして返り値をプログラムで記述することで、自分で作っているビューコントローラでの挙動を変更できました。これが、supportedInterfaceOrientationsプロパティに変わります。ただし、その後は、{…} で値を返すように記述することで、プログラムがゲッターとして機能します。つまり、var プロパティ名 : クラス に続いて { get { } set { } } と記述するのがセッターやゲッターの基本ですが、ゲッターだけなら、{ …..; return xx; } のように引数指定なしのクロージャのように記述するだけで変わりません。従って、メソッドからプロパティに変わっても、{ } 内は同じです。

func supportedInterfaceOrientations()->UIInterfaceOrientationMask // Swift 2.x
var supportedInterfaceOrientations:UIInterfaceOrientationMask // Swift 3

関数を定義する時、最初の引数にキーワードがないとき、単に記述しないで済みましたが、Swift 3では _ の記述が必要になりました。

@IBAction func tapRegistering(sender: UIButton) { // Swift 2.x
@IBAction func tapRegistering(_ sender: UIButton) { // Swift 3

@escapingが追加されるクロージャーの引数定義

WKWebViewのデリゲートメソッドの部分では、引数のクロージャーを持つものがありますが、メソッド定義の記述に@escapingが加わりました。Swift 2.3(iOS 9)ではこの@escapingはない状態で定義されていました。このアノテーションを追加することで、引数に設定されたクロージャーがメソッド実行後に消えてなくなってしないように保持をします。このクロージャー自体をlazyで指定したプロパティで使う場合や、あるいは配列にlazyプロパティを指定してさらにmapメソッドを適用することで、mapメソッドのクロージャーの適用を配列の要素を取得する時点で行うことができるのですが、そのmapメソッドの引数にクロージャーを指定するような場合に、@escapingで保持を指定するということになっています。

func webView(_ webView: WKWebView,
 decidePolicyFor navigationResponse: WKNavigationResponse,
 decisionHandler: @escaping (WKNavigationResponsePolicy) -> Void) {

ちなみに、iOS 10/Xcode 8とはあまり関係ありませんが、配列に対するlazyプロパティについてはブログ等でほとんど見られないので、ちょっと試して見ました。サンプルプログラムを見てください。配列mに対して、mapメソッドを直接ではなく、lazy.map()で適用します。nはprintすると、「LazyMapRandomAccessCollection<Array<Int>, Int>(_base: [1, 2, 3], _transform: (Function))」と出てくるように、特殊なコレクションです。このnをsubscriptによりアクセスすると、そのアクセスした時にmapメソッドを実行して結果を返します。kの値は最初は100ですが、lazy.map()の後に、kの値を変えて配列の要素にアクセスすると、その時のkの値が適用されて、201 202という値が得られます。まさに、メソッドの適用をlazyにするという仕組みと言えるでしょう。

var m = [1,2,3]
var k = 100
let n = m.lazy.map({s in return k + s})
print(n[0]) // 101 と出力
k = 200
print(n[0], n[1]) // 201 202 と出力

このプロジェクトはすでにSwift 2.3の段階で警告も含めてクリアしているので、++演算やそれを使ったfotなどの警告となっていた記述は一切ない状態だったので、それほど時間がかからずに変更はできました。こうして違いが出たところは概ね自動的に変更してくれるので、それはそれでいいのですが、仔細に見ることで色々と新しい機能も理解できるようになります。

[開発プロセス#10] バインディングとイベント処理の記述

ここまでのところで、ロバストネス図を出発点として、Webアプリケーション向けに設計図を作成するための表記方法を検討してきた。バウンダリーを詳細化して、必要な要素に分解してダイアグラムに記述することや、処理をコントローラーという大きな単位でなく、処理ステップという小さな単位で術することで、具体的な設計情報をダイアグラムに入れることができることを示した。続いて、クライアントサイトでのバウンダリーとエンティティの関係をバインディングという視点で見た時にどのように記述するかを検討し、そこから、イベントのハンドリングを記載する方法を検討する。

Web、すなわちHTMLでのユーザーインタフェースコンポーネント、つまり、ユーザーからの応答を受け付けるコンポーネントは、さほど種類は多くはない。ここではまず、テキストフィールド(INPUTタグでtype属性がtext)と、ボタン(BUTTONタグ)の2種類のコンポーネントを考える。例えば、ボタンを押すと、何か文字列がテキストフィールドに入るといったごく単純なプログラムを作りたいとしたら、ロバストネス図的には次のようになるだろう。今回は処理のステップまでは考えないので、コントロールは丸い矢印線のアイコンで記述することにする。

step1

ここで、バインディングの実装が入るとどうなるかを検討する。バインディングを一般的に記述すると、変数とコンポーネントの値が連動することと言える。ここでのコンポーネントは、テキストフィールドやあるいはHTMLの場合はノード(タグ要素)そのものも示す。そして、コンポーネントの値を得るには変数を参照することで可能となり、コンポーネントの値を変更するには変数に代入するということで実現する。つまり、変数がコンポーネントに成り代って存在することであり、変数とコンポーネントの状態の管理は、全てが自動的に、つまりはフレームワーク側で行うことが期待されてる仕組みである。タグによって動作が違う点の吸収など、実装上は様々なことを検討する必要があるが、ここではバウンダリーの値と変数の値が連動する点に集中することにする。前のロバストネス図を、テキストフィールドに対する変数があるとすれば、変数に代入すれば、その値がテキストフィールドに反映するという流れを次のように記述できる。

step2

しかしこれでは一方向だけの処理である。現実には、変数とテキストフィールドの双方向のやりとりが発生していて連動しているのだが、ここで、ステレオタイプを利用した表記を導入する。点線矢印にbindingというステレオタイプを記述することにした。本来は鏃を両側に記述したいのであるが、クラス図の点線矢印は依存関係を示すものなので、双方向という記述はできなくなっている。もちろん、ここでの点線は依存ではないのだが、処理の流れに実線を利用しているので、ここでは依存の矢印で代用し、ステレオタイプをつけることにする。なお、bindingは双方向であることが前提なので、鏃が片方でも誤解をすることはあまりないと考える。

step3

テキストフィールドが2つあって、一方で値を変更すると、もう一方に自動的にその値が反映される状態を記述すると、一例はこのようになる。テキストフィールドごとに変数を確保したとしたら、テキストフィールド2向け変数が更新された時、Observer実装が機能して、あるコントロールの処理が機能し、その結果、別のテキストフィールドの変数に値が代入されるということを意味している。処理2への矢印にobservedというステレオタイプをつけたが、observerは処理2、observableなものはテキストフィールド2向け変数である。ただ、この記述は仮のものである。

step4

ここで、observer実装により変数の変更によって処理が実行される状態を次のように記述する。つまり、監視している処理2から、監視対象のテキストフィールド2向け変数に対して、点線矢印を引き、ステレオタイプとしてobservingと記述する。背後で様々なメカニズムを持つとしても、設計時に概念として知っておくべきことは、何が何を監視しているかということだ。処理2では、テキストフィールド2の変更がbinding-observingとたどることで、処理2が開始される。処理2はテキストフィールド2向けの変数の値を得て、テキストフィールド3向け変数にその値を代入し、テキストフィールド3の値が更新される。

step5

続いてイベント処理も同様に記述できることを示す。イベントは、HTMLのコンポーネントにおいては既定値で発生させることができるようになっている。フレームワークによってはモデルのコンポーネントで独自のイベントを発生するようものもあるが、ここではHTMLの標準の仕組みを考える。以下の図で、ボタン2に対して処理3から、やはり点線矢印が引かれており、event-clickというステレオタイプが記述されている。eventは固定のキーワードで、ダッシュの後に、イベント名(ここでは「click」)を記載し、つまりはボタン2でクリックイベントが発生すると、処理3が実施されることを明確に記述することができる。この図では、ボタン2のクリックにより、テキストフィールド3向け変数に値が代入されるので、テキストフィールド3の値が更新される。

step6

イベントやobserverの実装の記述を利用すれば、バインディングの処理そのものを記述することができる。システム設計上は、bindingというステレオタイプで線を引くだけでいいが、実装をするとなると、次の図のようになる。つまり、テキストフィールドからのいくつかのイベントを拾い、その結果を対応する変数に反映させる作業が必要になる。一方、変数の変更があれば、observingしているコントロールに処理が移り、変数の値をテキストフィールドに反映させる作業が必要になる。この図を見ると、明らかにループしそうだ。テキストフィールドの変更結果が変数を更新し、その結果observerによりテキストフィールドを更新する。ただ、HTMLの場合、そこでイベントは発生しないので、無限ループにはならないが、処理に無駄が出る。これを回避する方法としては、変数の更新処理において、obeserverを動作させるものとさせないものを用意して、適切なメソッド呼び出し(あるいは引数設定)をするといった方法がある。何れにしても、バインディングについては、通常は図の上の表現でも良いが、これまでに検討してきた結果をもとに、その部分を詳細に記述することも可能である。

step7

クライアントサイドでの設計で必ず考慮すべきイベントの表記も含めて、JavaScriptレベルの実装に近づけるより詳細なダイアグラムの記述ができるようになってきたと言えるだろう。

[開発プロセス#9] コントロールの処理の詳細化

前回までで、バウンダリーを詳細化するところまでを記述したが、またまた時間が空いてしまった。サーバーが起動しなかったり、開発の作業に集中したりなどしていた。

さて、続いて、コントロールの中を詳細化する。実際に詳細化できるのかを検討する前に、なぜ詳細化しなければならないのかを改めて検討しておく。多くのフレームワークは、コントローラーという1つのクラスを作ることからチュートリアルが始まる結果、1つのクラスで作るものだと思い込んでいたり、あるいはクラスを複数用意するとしても、連携する手法は特にフレームワークで用意されていないなど、「巨大な1つのコントローラー」を用意する素地が、意図しなかったとしてもフレームワークがお膳立てしているという状況であるとも言えるだろう。一方、最近、ある仕事で、ethnamというグリーが当初開発したethnaの後継というPHPのフレームワークを使う機会があった。このフレームワークは改めて、フレームワークの機能との対比を考えるときの題材の1つにする。このフレームワークの特徴は、コントローラーというクラスを作るのではなく、中心的なコントローラーに対応する決められた名前のメソッドがあるという点である。決められていることは、prepare、perform、preforwardという3つのメソッドが順番に呼び出されるということだ。prepareは結果次第でのちの作業をキャンセルできることから、バウンダリに近いところにあってデータの検証などを行う入力用ビューコントローラーと言える。一方、最後のpreforwardは、出力の直前に呼び出されることから、出力用のビューコントローラーと言える。中間のperfomは、まさに、コントローラーとしての役割を持ち、ここでモデルへ働きかけるなどのビジネスロジックとのやりとりを記述することになる。これらのメソッドが保持されるクラスは決められた場所に作成するようになっているため、コントローラーの粒度はクラスよりもメソッドの方が適切だと言えるフレームワークである。コントローラーというクラスを作る話と、コントローラー相当のメソッドがあるという話は、設計の上では極めて大きな違いがある。抽象的な記述から、フレームワークにあった実装を行うという方針でもいいのだが、この方針だと属人的な実装テクニックや、あるいは「言わずもがな」なルールを読み解かないといけない場面が多そうだ。結果的に、大きな単位で何をすべきかは考えるのがモデルの1つの目的ではあるもの、コードの段階ではもっとも粒度の低い1つのステートメントを記述しなければならない。ならば、コントロールの中の粒度をより細かくして一度考えてみる必要があると思われる。また、フレームワークの機能との対比をする上では、やはり一度は細かな処理に分ける必要があると考える。

まず、次の図は、クラス図を元に、一覧と検索を持つようなWebページのモデルを記述したものである。astah*でクラス図を用意して、バウンダリーは大まかながら、主要なコンポーネントを抜き出して1画面を枠で囲う形式で記述した。モデルは、この段階では概略として記述し、コントロールの中の処理の1ステップずつをクラスで記述した。

クラス図0

この図を描きながら考えたことは、まず、処理には順序があるということである。入力されるバウンダリーから、出力されるバウンダリーに向かっていけば判別つかなくもないが、図を明確にするには、処理の順序を矢印で示し、どちらが先なのかを記載する必要があるということだ。

続いて、どうしても「分岐」は必要になる。前の図は、クラス図で適当に書いたものである。この点から、前の図にはないが、繰り返しや並行処理的なものを記述が必要になることは十分に可能性があるがある。

ここまでに至るまでにすでにお気付きのように、コントロールの処理を詳細化したものは「フローチャート」なのである。もっとも、UMLでフローチャートに近いものといえば、アクティビティ図である。前述のモデルをastah*のアクティビティ図で記述してみた。ほとんど同様な図が描かれているが、バウンダリーやエンティティのアイコンに接続された矢印が今ひとつうまく処理できていない。astah*でこの状態にするには、オブジェクトのオブジェクト名を空、ベースクラスをバウンダリーで使ったクラス名を選択することででき、その後に右クリックして、標準アイコンを選択するもこのようになってしまった。フローチャート部分は作りやすいが、astah*での作業は明らかにクラス図の方がみやすい図を作れる。

アクティビティ図0

この先、図をどうやって作成するかは問題だが、とりあえず、クラス図に戻り、バウンダリーの詳細化を行った。画面要素のキーあるいはフィールドの記述をコンポジションでバウンダリーに追加したが、「JavaScriptアラート」のような手法の指定もあるかもしれない。特にこういう場合の記述はないと思われるので、点線矢印で適用先を記述した。

クラス図0_0

このモデルから実装の方針をもう少し進めよう。バウンダリーの集合が3つあるが中央にある「エラー表示」はシンプルにJavaScriptのアラートを使うとしたら、「エラー表示画面作成」は、単にJavaScriptでwindows.alert(“…”);を実行することである。また、検索ボタンを押した時には検索条件はクライアント側にあるのだから、赤線枠で囲った部分は「検索条件入力画面」のページの中にJavaScriptでの記述が行えることになる。また、そうなれば、エラー表示に伴う「OKボタン」のクリックによる「検索条件入力画面生成」の処理を行う必要はない。その画面を崩さずにアラート表示したのであれば、単にアラートの表示だけでもOKである。結果的に、「エラー表示」は「検索条件入力画面」の一部となった。あとは、検索条件の検証ルールが与えられれば、実装はできそうである。

クラス図0_0_0

残りのアクティビティを分類して見る。分類の基準は、順次実行するアクティビティであるという点になる。つまり、まとまって実行されるアクティビティのセットは少なくともある段階では同一のメソッドの連続したステートメントに記述されていることになるので、その点から分類をする。そうなると、「検索条件入力画面生成」が1つ、さらに「条件を与えて顧客情報検索」「検索結果表示画面生成」が別の分類となり、図中ではそれぞれ分類2と分類4で囲った。分類4の中にある2つのアクティビティは、データ検索とビューの生成といった違うことを行なっている。そうであるのなら、さらに分類すべきであるとも考え、図中の分類3で囲った部分が抽出される。結果的に全部バラバラということにもなるが、分類4のみ2つのアクティビティからなるとも言える。

ここで、まず、分類3の「条件を与えて顧客情報検索」であるが、データを扱っているので明らかにモデルに関わる機能である。そして、いくつかある「画面生成」は明らかにビューに関わる機能である。図の右側に対応するコントロールを記述したが、それぞれ対応するオブジェクトを記述できることから、この図はロバストネス図をさらに詳細したものであるという点は明白である。

実際に実装するとなると、分類3「条件を与えて顧客情報検索」はデータ処理が含まれており明らかにサーバーサイドの処理となる。2つの「画面生成」は、例えばPHPのフレームワークのCodeIgniterであれば、サーバーサイドで記述をする。これくらいの機能ものだと1つのコントローラークラスにまとめてしまってもさほどのコード量ではないと考えるかもしれない。

ここで重要な点がある。それは分類1はクライアント、分類2〜4はサーバーサイドでの実装を行う点が、ある状況では決定づけられてしまうということだ。一般にはサーバーサイドのフレームワークの場合「画面生成」という処理から先は自動的に行われる。画面生成に必要な状況をコントローラーで作り出すのが開発作業である。そこで注目したいのは、考慮すべきクライアントとサーバーの切れ目である。画面生成はどちらかといえば、フレームワークでほぼ自動化されいているので、考慮対象外である。一方、「入力内容検証」後にエラーなしとなった場合、「条件を与えて顧客情報検索」に移行する場面がある。ここは矢印が1つだが、実際には、サーバー側にはPOSTメソッドの受け入れから、該当する処理が記述されたメソッドを呼び出すまでの処理(例えば「ルーティング」など)が入ることになる。これらは自動的にできないメソッドも多い。

これらの検討結果を加えたモデルは次のとおりである。まず、検索条件の入力はフォーム(HTMLのformタグ)で記述することにして、フォーム自体をサブシステムとして記述する。入力結果を検証した結果、サーバーへPOSTするのは、ブラウザが本来持っている機能である。また、POSTを受け入れるのフレームワークあるいはCGIとして持っている仕組みを利用できるので、これらは実装対象ではない。ただし、正しく受け入れがなされて意図したメソッドが呼び出されるようにするための処置は必要であり、それはフレームワークごとに違っている。

クラス図0_0_0

このように小規模なWebアプリケーションでもクライアントとサーバーの分離やフレームワークのサポートの有無を考慮しながら、実装ポイントを探るということが必要になる。従来のオブジェクト指向を基調としたモデルでは粒度が粗く、実装の具体的な手法までをモデルまで記述することはしなかった。言い換えれば、実装した結果の要約を逆解析するようなものであったとも言える。現実の開発でここまであるいはさらに細かい詳細化がモデルの段階で必要かどうかという議論はあるだろうが、その点は別にしてもWeb開発の学習やフレームワークの理解にはこうした手法が有効であると考える。

[開発プロセス#8] 画面要素に関するモデル記述の試案

前回より少し間が空いてしまった。また、タグをきちんとつけていなかったのを直した。

ロバストネス図やコラボレーション図を作るとき、バウンダリー、コントロール、エンティティの3種類に分類することは、図の中の各要素の役割を考える上で必要かつ多すぎない点から、やりやすい方法ではある。しかしながら、1つの問題は、バウンダリーの表現力が低いことである。「一覧画面」や「何か操作をする」という大まかな1つのアイコンがあるのがよく見られる作図結果である。この記述をまずは詳細化できないかを考えてみる。ここでは、モデルとして、クエリー結果の一覧があり、その一覧の中に各行に対するボタンがあり、その一覧とは別にテキストフィールドやボタンなどのフォーム要素が並んでいるような状況を考える。フォーム要素は、一覧に対する検索条件を当たるものや、あるいは一覧にレコードを追加するものなのが考えられるが、動作は違うものの要素としての構成は同じようなものと見ることができる。

まず、これらのすべての要素を含むWebページが、コントロールから生成されたことを明確に示す必要がある。一方、ページ内部のコンポーネントのうち、単に表示するようなものについては、そこからコントロールを呼び出されることはないので、図の中で特別な記述は不要である。一方、ボタンなどのフォーム要素や、あるいはイベントを受け付ける要素については、それぞれが別々の動きをするので、その点が記述できなければならない。ICONIXの手法を解説したダグ・ローゼンバーグらの書籍『ユースケース入門 ユーザマニュアルからプログラムを作る』では、次の図のような記述を行なっている。つまり、バウンダリーの中で、特別な動作を行うような要素もやはりバウンダリーであるが、画面全体は画面の一部の集約(コンポジション)としている。図中の点線枠に入っている部分が、1つの画面を構成するバウンダリー群となる。なお、一覧表示の各行に「詳細表示」ボタンがあるとすれば、UML的記述をするには多重度の記述を行うことで、複数存在することが示すことができる。この点は書籍には明示されていない。

画面要素を分離

ここで、実際に開発をする場合に必要な情報が込められているかどうかを検討する。この図にない要素としては、ページが一覧と検索領域に分かれていることや、一覧にどんなフィールドが表示されるのかといったような内容である。これらを含めて記述するとしたら、次の図が得られる。画面の領域を、「一覧表示」と「検索条件入力領域」の2つのサブシステムで表現し、それらのサブシステムは「一覧表示画面」の集約であるとした。一覧表示は、通常は「ヘッダ」「内容」「フッタ」の3つの領域を持つのは、HTMLの定義からも明確である。一覧表示のサブシステムはこの3つの要素が常にあるものとして最初から配置されているとする。「内容」については、繰り返されるのであるが、UML上での一般的な表現はないので、repatingというステレオタイプを付与することにする。この場合は、一覧のないように「名前」と「住所」フィールドが配置され、それぞれの行には該当するレコードに対応する「詳細表示」ボタンが組み込まれることを意味する。

画面要素を分離_0

このようにUMLの記述を拡張することで、画面構成も含めたモデルの記述ができるようになる。しかしながら、画面を構成する要素については、その実物を想像しやすいようなアイコンにすべきと考える。

[開発プロセス#7] 開発対象システムのモデル記述

システム開発でモデルを作成することにより、これから作るシステムが要求に合致したものであるのかといった側面の検討だけではなく、効率の良い実装が可能であるのかといった側面や、予想される改変や拡張に対して実現可能性やその効率性、テストのしやすさなど、実装に直結すること以上に利用できる。しかしながら、その作成するモデルは、様々な手法がある。要求の記述という点ではユースケース図とユースケース記述が出発点にはなるが、データベース主体の開発だと、ここでER図の作成を主体にすることが多い。データベースの構造は対象ドメインの状況を記述できるようになっている必要があるのだが、その結果、全てがデータベースの設計結果であるスキーマに集約されているという見方をしてしまいがちである。ある作業を、スキーマで解決するか、あるいは実装するプログラムで解決するかはもちろん考えるのではあるが、では「ここの処理はプログラムで」というアイデアはER図やクラス図では不明確である。メモを残すなどの工夫が必要になる。

一方、Webシステムではワイアフレームといったざっくりとした画面のデザインをもとに、画面遷移を定義することで、システムの全体像を示そうとする。しかしながら、画面デザインが反映するのは、システムへの実装以前にドメインに対して実施される分析をもとにして作成されるビジネスモデルであり、実装に直結したER図等のモデルからのズレが生じする場合もある。しかしながら、HTMLでの動的なユーザーインタフェース作成機能は限られていたので、例えばチェックボックスであればどういう動作をすべきかということを逐一記述しなくても、半ば「常識的な判断」で進めることであまり大きなブレは発生しなかった。さらに、結果的にビジネスモデルとER図で記述されるスキーマとはあまり変わらないことお多いので、HTMLのモックアップが「設計」として扱うのは、デザイン主体の開発会社では頻繁に見られる方法である。

このように、ある程度のスキルや、ワークフローができてくると、途中を省略する傾向は強く、単一の会社でそれが回っている間は特に問題視はされないだろう。しかしながら、Webの世界は変化が激しい。特にここ5年くらいの時期はクライアントサイドの作り込みの度合いが高くなり、ユーザーインタフェースは複雑化している。その結果、Webのクライアントサイドは多階層的な機能分離を図る必要が出るなど、スマホのクライアントのネイティブアプリケーションに近い構造になっている。

こうした状況が変わってきた時、ワークフローを見直す必要があると考える。今までの知見や常識として暗黙知的に取り扱っていた知識だけでは、新しい問題に対する解法がない可能性が高く、最適な設計ができなかったり、チーム内での意識の疎通が悪くなる。そのために、本来的な詳細なモデルを記述するということが必要なのである。そこを出発点にして、省略やあるいは詳細化をするとしても、Webシステムのモデル記述の手法を一定のレベルで確立する必要があると考える。

UML自体の汎用性は高く、その点では有用性も高いのは事実である。しかしながら、UMLやその周辺手法を使ってWebシステムの記述をするにあたり、次の点に対して何らかの解決策が必要と考える。

  1. 詳細化するとき、明確なルールは特にない
  2. クラス図を主体にすると、オブジェクト指向が前提となる
  3. ボックスがクラスやオブジェクトで、呼び出しが矢印線的な切り分けによる分かりやすさはあるが、処理の記述では呼び出し線に名称を書くことになり、図を見やすく作ることが困難になりがちである

まず、1の詳細化についてである。作成したモデルと、使用するフレームワークの提供機能を比較検討して、実装箇所を特定するには、極端に言えば、プログラムの1行レベルまでを、モデル内の1つの要素として記述することも必要とされる。また、ロバストネス図やシーケンス図では「画面」を1つの要素として扱うが、実際に処理の流れを追う場合、ボタン1つ1つは原則として異なる動作をするので、ボタン1つ1つを要素として表したいということになる。このための指針が費用である。

2つ目のオブジェクト指向である点は、Javaのプログラムだけを作るような場合には確かに有効ではあるが、HTML、CSS、JavaScriptが絡む世界では必ずしもオブジェクト指向ではない。つまり、クラスやオブジェクトを1つの単位として考える場面は実装時にはあるかもしれないが、分析時にはどちらかと言えば、より細かい単位での要素を記述したい。最終的にはメソッドが集まってクラスになるとしても、対象としたのはメソッドであり、その中でどんな処理をしたいかということである。

3つ目は、コミュニケーション図でオブジェクトからオブジェクトに線を引き、線に添えてメッセージ呼び出しを記述する。この方法は実体あるいは実体化可能なものはボックスであり、メッセージは矢印線であるという明確な分類があるものの、簡単なモデルでも、オブジェクトとメッセージを見やすく配置するのはかなり大変である。ましてや、複雑なモデルだとなおさらである。ここではメッセージの記述が作図作業を煩雑にしている点は明白であり、それに代わる表記方法を検討すべきであると考える。

これらの懸案をまずは見える範囲での解決を行った上で、Webシステムのモデルを記述することにする。まず、1〜3に対する提案を次回より行う。

 

[開発プロセス#6] Webクライアントの機能モデルのパターン

前回はWebクライアントがMVVMパターンによる機能分類での説明が可能であることを考察しましたが、もう1つ忘れてはならないのが、PACすなわちPresentaion Abstraction Controlというアーキテクチャパターンだ。F.ブッシュマン他の『ソフトウェアアーキテクチャ ソフトウェア開発のためのパターン体系』(POSA本)では、1つのコンポーネントの内部構造として、可視化を行うPresentation、データモデルの維持管理を行うAbstraction、そして、PresentationやAbstractionとやりとりをしつつ、PACのコンポーネントの外部とのやりとりを行うControlの3つの要素を持つと定義されている。そして、その1つのコンポーネントをエージェントとして、システムとしてはエージェントの階層構造を持つとしている。以下の図は前回の記事で示したものと同じものである。

MVVM Client-Side

これを、PACでの分類で考えれば、[入力項目1、入力データ1]、[入力項目2、入力データ2]は、それぞれエージェントとであり、その中でのPresentationとAbstractionコンポーネントであると捉えることができる。ただし、Controlを明確に分類するのは難しいと考えるが、いずれのコンポーネントも、バインディングという仕組みをControlとして持つと考えられ、入力が発生したことを別のエージェントに伝達するという構造として捉えることができる。そして、それらの上位のエージェントとして、[エラー表示、NULL、入力値検証]といったPACエージェントがあり、さらに、その上位に[NULL, NULL, 送信]というPACエージェントあるいは単なるオブジェクトがあるという見方もできる。こうした見方をすれば、Webクライアントの動作はPACパターンでの識別による記述も可能であると考えられる。

今回は短いが、以上である。

[開発プロセス#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つの大きな目的です。すなわち、ドキュメントに記述されることを、ドキュメントに対する負荷を可能な限り最小化したプロセスとして再考するのが目的です。以下、まとめてみました。

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

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