[続開発プロセス#11] MVCパターンベースのWebアプリケーション

これまでの流れで、要求から設計を進めてきました。先にデータベースのスキーマを考える点では、SQLデータベースを使う的なことが早めに決まっているような流れになっていますが、GUIのモックアップから必要な機能を出して設計としてまとめるということをやってきました。ただし、原則としては開発環境の制約に関係なく、要求を元にした必要かつ実現可能性があるような汎用的な設計までができました。ここから、実際に実装が可能な設計を検討します。まず、このような例の場合一番わかりやすい、MVCあるいはMVC2パターンを検討します。

MVCパターンでの制約は、まずは文字通り、モデルとビューを分離して、コントローラーでそれらを統合するという構成にするということがあります。これは制約というより、一種の設計方針として認識されてており、制約という何かできなくなるような「縛り」というよりも、設計を進めやすくする「方針」のような捉え方をされている方も多いと思います。

そして、多くの場合は、HTMLのテンプレートをベースに、クライアントに送り出すHTMLコードを生成します。HTMLがビューであるという見方と、ビューによって生成されたものという見方があり、フレームワークによってその辺りの位置付けは微妙に違っているかと思います。また、テンプレート処理を行うのがサーバー側かクライアント側なのかという点も制約は異なると思われます。ここでは、サーバーサイドで完結するタイプのフレームワークを使っているとしましょう。

主要な制約としてはこのくらいではないかと考えられます。それ以外は、通常は開発言語で記述をするので、自由度は高くなります。巨大なクラスを作っても、小さなクラスに分けても、動くと言えば動きます。

まずは、モデルの抽出です。本質的には、MemoList、PickingUpのクラスで必要な機能が抽出されているので、それを受け付けるという処理を考慮し、テーブルとして用意するmemoとcategoryにそれぞれモデルを割り当てるのが素直な方法と考えられます。CategoryModelの最後の2つのメソッドは、ポップアップメニューの選択肢を構築するためのデータ取得のメソッドになります。

続いてコントローラーとして、MemoListController、CategoryListControllerを導入します。ここで、レイヤー構造となるような大きな区分をパッケージで分類しておきました。UI側の要求をコントローラーで捌き、データベースとのやりとりをモデルによって処理しやすい形式に整えるといった典型的な設計になります。ですが、これは、単にクライアントからの処理が関係しそうな箇所を繋いだだけであって、意図が正しいかを検討しなければなりません。

WebのMVCフレームワークの1つの大きな制約は、クライアントサイドではHTML/JSの世界であり、それがサーバー側でPHPなりJavaなり、異なる世界が展開されていることです。その橋渡しは、テンプレート処理ですが、テンプレート処理はページ構築時に全てを構築することにフォーカスしがちです。

しかしながら、ページを提示後の様々な処理にどう対応するかを、ページのテンプレートの段階で検討しておき、対処をしなければなりません。その後に、HTMLの部分的な要素をテンプレート処理して得ることもあるかもしれませんが、一方、単にJSONで送って返ってくるようなWeb API的な動作が欲しい場合もあるでしょう。

そこで、ここでまず、次の図のようにHTMLのテンプレートを設計します。ページ内の要素に適当に名前をつけてテンプレートそのものをモデルとして記述してみます。事実上、1つのクラスは1つのタグ要素に対応するものに近いレベルで記述しましたが、動作上必要な要素だけが抽出されています。なお、クラス名はタグ名でもいいような気もしますが、ここではそれらしい名前を記述しました。ルートはPageTemplateあり、これがbodyタグと考えても良いでしょう。モックアップの左側にあるカテゴリのボタンが並ぶ部分はCategoryBox、右側でメモの一覧が見えている領域はMemoListとしました。Memoの1行ごとにMemoLineがあり、メモの文字列はMemoTextです。このモデリングは、比較的細かく考えた方が良いでしょう。とは言え、これを書くのは結構面倒なのは確かです。できるエンジニアはこれを頭の中でさっさとやってしまうわけですが、今は開発プロセスの検討をしているので、あえて書いてみました。メモの文字列を表示するinputタグはMemoTextクラスに相当しますが、入力された文字列はvalue属性で得られます。これはブラウザ側の標準機能であるので、ここではprivateの記号で記述しましたが、スコープの意味ではなく、ここでは既定義されているという意味合いでマイナス記号を使いました。

テンプレートの要素をよく見て、その要素が何らかの応答をしなければならない場合には、HTMLelementステレオタイプのクラスはメソッドを記述することにしました。前の図のように、MemoListは書き換えればデータベースへ反映しなければなりません。そういうことで、MemoLineの子要素は全て、update()メソッドを持つ必要があります。update()メソッドのスペックとしては、書き直したら、どこかのタイミングでサーバーに修正データを送り、データベースを更新する必要があるということです。一方、CategoryBox以下のボタンでは、ボタンをクリックすることで、メモ一覧を新たにする必要があり、その意味で、updateMemoList()メソッドの定義があります。さらにこれだけで十分ということではなく、カテゴリが階層化されていて、大分類を変更したら小分類の選択肢が変化するという仕組みが必要になります。つまり、大分類のポップアップメニューを選択すると、小分類のリストをどこかから取ってきて、選択肢を入れ替える必要があります。実装方法はいろいろありますが、この小分類の更新を行うためにMemo_MajourCategoryクラスに、updateMinorCategory()メソッドを定義します。こうして、ページの初期状態をテンプレートとして記述するのはもちろんですが、それがページとして展開された結果を想定して、表示後に必要とする機能をモデルに組み込むことを行います。なお、UI Componentステレオタイプのものは、ここでは詳細設計対象外とします。

テンプレートから元のクラスを検討しましょう。次の図は、テンプレート処理した結果をクライアント側に展開しました。ここで、Webアプリケーションとしての制約があります。クライアントとサーバーの間はHTTP通信によってのみコミュニケーションを取ることができるということは実は大きな制約です。MVC系フレームワークを使う場合、もちろん通信はURLによって柔軟に作り分けることができるのですが、機能を組み込むときに最初に考えることは、それぞれの通信処理でテンプレートを使うかどうかです。ページ全体を生成するときにはテンプレートを利用するのは当然ですが、一方、修正したデータをデータベースに反映する作業はテンプレートを使わなくても良いでしょう。以前だと、サーバーの通信後に常にページ更新をしていたので、それは常にテンプレートを使っていたということになりますが、AJAXを出すまでもなく、現在の仕組みでは単にWeb API的な通信の実装はそれほど難しいことではありません。

ここで、まず、ページを表示するときには、テンプレートをベースに、初期的なメモの表示ルールを適用して、ページ全体を表示します。そのためのメソッドを、MemoListControllerにgetMemoListPage()メソッドとして定義するとします。テンプレートを利用したHTML生成を行って返すことを示すためにTemplatingというステレオタイプをつけておきました。そして、このメモリストでは左側の小分類を押して表示するボタンや、全部のメモを表示するボタンは、同じようにgetMemoListPage()メソッドを使ってページを書き直すのが効率的な設計ではないかと考えられます。この「ページを全部書き直す」作業は、基本的にはHTML上のリンクであり、そのリンクがサーバー側のメソッドを呼び出すので、コントローラーに直接つないでしまっています。ページネーションはコンポーネントとして利用すことにしていましたが、このページネーションも、getMemoListPage()メソッドを使ってページ全体を書き換えるのが1つの方法です(できればリスト部分だけを更新したいですが)。ここの実装はこの設計では細かくは追いませんが、方針としてはMemoListControllerにつながることで進めることにします。

一方、メモの文字列や日付時刻、そして分類の選択肢は、変更をすると、その結果をデータベースに書き直したいわけです。ただし、その作業は、自動的には行えず、要素上で発生したイベントに応じてクライアント側のプログラムを呼び出し、そしてサーバーに要求を伝える必要があります。そのために、クライアントサイドにEditingSupportというクラスを用意しました。もちろん、inputタグ要素の種類に応じて適切なイベントによってこのクラスのメソッドが呼び出されるように、実現可能性を加味した設計にしなければなりません。そして、EditingSupportでは、サーバー側のMemoListControllerにあるupdateMemo()メソッドを適切なパラメータで呼び出すように作ります。こうして、要素の変更からそれがデータベースまで更新される流れがクラス図上で明確に現れてきました。大分類のポップアップメニューを選択した場合、小分類の選択肢を更新するという作業には、ここではPopupUpdateSupportクラスを用意しました。

大分類を示すMemo_MajourCategoryからコールされるのですが、一方でMemo_MinorCategoryのポップアップメニューの選択肢をコントロールできないといけません。select側あるいはoption側のどちらでもいいので適切な参照が必要になり、あらかじめ参照を配列等に記録するか、呼び出し時に更新する要素を指定するなどの方策が必要になります。詳細はここでは省きますが、いずれにしても、JavaScriptで実装すべき内容が、独立したクラスで明確になりました。クラス図なのでクラスで書きましたが、実装じは単に関数でも大きな違いはないと思われます。

ここまで設計を進めれば、MVCフレームワークだと概ねどのフレームワークでも、似たような作業で実装を進めることができるでしょう。フレームワーク特有の事情がある場合は、もちろん、それも考慮して設計を進めます。通常はオブジェクト指向プログラミング環境ですので、クラス図で作った設計との親和性が高いのは当然のことと思われます。

現実の設計では、ここでのコントローラのように、テンプレート処理をしたりしなかったり、あるいは更新処理を受付たり、部分的なHTMLを生成したりと、メソッドによって様々な動作を設計することになります。ここではコントローラーにまとめて書きましたが、むしろメソッドごとに1つのエンティティとして記述した方がわかりやすいかもしれません。フレームワークを利用する場合には、テンプレート処理でスマートにページ生成ができることが強調されますが、ページ表示後の動作についてはそれ以上にたくさんの解決すべき問題を生み出します。フレームワークを使うことで簡素化される面はいろいろあるかとは思いますが、テンプレート処理後の動作を詳細に検討するという作業を、試行錯誤でやっている人は多いのではないかと思います。このように、モデルベースで考えてみれば、どんな仕組みをクライアントとサーバーに持たせるかは全体を見ながら検討できるわけで、より良い側面は多々あります。特に、うまく設計できないで悩んでいるなら、まずはモデルとして設計することは強くお勧めできます。

次回は、同じ設計を別の環境に適用することを考えてみます。

[IM] INTER-MediatorでFileMakerを使うときの注意

FileMakerは、テーブル、TO、レイアウトといったオブジェクトを利用する。Web共有からテーブルを直接指定はできない。また、TOも指定できない。指定できるのはレイアウトのみである。レイアウトが事実上のテーブルに相当するエンティティとなる。したがって、定義ファイルのnameキー、viewキー、tableキーには、レイアウト名を指定する。たまたま、同じ名前のテーブルやTOがあっても、FileMakerのWebアクセス時に実際に利用するのはその名前のレイアウトである。

フィールドのタイプで、日時の記録用に「日付」「時刻」「タイムスタンプ」の3つがある。Web経由では、「月/日/年 時:分:秒」のフォーマットにしなければならない。また、日付フィールドに時刻を含む文字列を入力したり、時刻フィールドに日付を含む文字列を入力すると、エラーになり処理は何もなされない。その「日付等の書式エラー」の番号が500なので、余計なことを考えてしまいそうだが、この500はFileMakerが規定したエラー番号である。

[続開発プロセス#10] UIの大枠から機能を検討する

少し間が空きましたが、開発プロセスの中で、まずはUIのモックアップを中心に要求を固めて、そこから設計に入る場合に、まず、データベースのスキーマから入る方法があるというのを説明しました。レイヤー構造で構築する場合、データは低い位置にあるので先に決めるという点に意義はないとは思いますが、一方で、あらゆる状況を加味したデータベース設計ができるのかという問題もあります。ですが、ここでは先に決めるという流れでプロセスを追っています。

データベース設計ができれば、そこに対してどんな仕組みをかぶせることで動くアプリケーションができるのかということを考えます。UIの設計から、まずは目に見える機能を取り出し、それをどのように構成するのが良いのかを考えます。ここで、「機能の一覧」を書き出すことが1つの方針としてはあり得るのですが、その機能をある程度分類しないと、構成が定まりません。そこで、メモのページ全体をMemoPoageとして、それらが、メモ一覧を示すMemoListと、左側のカテゴリ一覧を示すPickingUpの2つのクラスのコンポジションであるという見方をします。まず、目に見える範囲を狭めて、開発単位となるブロックを見つけるということです。ここで、一覧だと、1行のコンポーネントが複数あるようなことを示さないといけないのかと言えば、これは経験則的には不要だと考えます。ここで「リスト」と言ってしまうことで自明だからです。言い換えれば、1行の要素が繰り返されるということ自体は、そのクラスが持っているという見方をして、過剰に細かくは書かない方が設計は素直で読みやすくなるということです。データベースのテーブルを記述する場合に、クラス図では1つのボックスしか書かないのと同じ理由です。しかしながら、何らかの定義はどこかにあるわけですので、その点も書きたい場合はメモを追加するか、あるいはクラス名の意味をどこかに記載すればいいでしょう。なお、このようなクラス図からオブジェクトを図を想像できるかどうかということは、ダイアグラムの理解には重要なポイントであることは間違いないのですが、設計上どうすればいいかを詳細に決めると多分面倒なだけになりますし、大雑把にするとチーム内でコミュニケーションが中途半端になる可能性があります。機会があればこれは検討したいテーマです。こうして作成したのが以下のクラス図です。

緑色の3つのボックスがUIのブロックを1つのクラスとして記述したものです。中身は、ボタンや編集など、ほぼ、ページ上でのイベントに対応するもの、そしてそのリスト自体を生成するためのものが記載されているだけなので、細かくは説明しません。それぞれ、どのテーブルを利用するかで2つのテーブルに線を引きました。また、MemoListは、ページネーションと日付時刻のピッカーを、別に用意されているUIのコンポーネントを使うことにします。ここでは、MemoList上にある要素とは別のもの(ここでのページネーション)や、要素の動作を補助する必要があるものを(ここでの日付時刻ピッカー)抽出します。ただ、このUI Componentsは、実装先によって実態は異なると思われます。ここではまだ実装を加味しないということで進めてきましたが、実際にはこのように実装先の状況が徐々に現れることになります。プロセス的にはまず設計をして、実装に関わることを検討しようということを書いていますが、線引きは明確にはできないと思います。ここで重要なことは要素として抽出しながらも、一定の範囲で実装を意識したという点をメモにするか、きちんと意識しておくことです。

ここまでの設計の図を見る限りは、明白にレイヤー構造です。このような簡単なアプリケーションなら、もう実装は簡単にできると言っても良いでしょう。手慣れた方ならここまで図にしなくても、頭の中で設計ができてしまっており、自身の知識を持ってすればすぐに実装の作業ができるはずです。こういう状態を「スキルがある」ということになるかと思います。そのような状態の効率良さは当然ながらあるわけで、その結果「設計は不要」という考えにもつながるでしょう。設計不要論については今回は扱わないつもりですが、設計の行為を体系的に記述するため、ここで終わらずにさらに設計の検討を進めるのが一連の記事の目的です。よって、まだ続きます。次は、実装環境の制約を加味した設計を作っていきます。

SELinuxを避けずにINTER-Mediatorの稼働ができた

CentOSはSELinuxが既定値で機能しており、ちょっとしたことでも阻止されます。例えば、Apacheのドキュメントルートを/var/www/htmlとは異なる場所に設定したい場合、Apacheの設定以外にSELinuxでの許可を得る必要があります。セキュリティは重要とわかっていても、「ちょっと試す程度だしいいか」ということで、SELinuxの機能をオフにしてのその場しのぎはきっと世界的に普通に行われていると思います。SELinuxでググって見れば、オフにする方法のサイトばっかり出てきます。

実は最近、ある場所で、LinuxをセットアップしてWebアプリを納品することがあったのでした。INTER-Mediatorではなく、スクラッチから作っているWebアプリですが、コマンド呼び出しなどを多用するもので、SELinuxでの運用をまずは目指したものの、ちょっと行き詰まったのでした。そこでどうするか? 恐る恐る、SELinuxはなしでいいかを聞いたら、あっさりOKだったのです。セットアップ時に忘れないように切らないとと思っていたら、最初からオフだったし、Firewallは完全オフだったりと、清々しいVMだったりして、もしかして、世間的にはそんな感じなのか?とも思いつつ、ちょっと安心したりしました。

しかしながら、『INTER-MediatorはSELinuxでは動かない』となってしまうのも良くないので、サンプルの多くが稼働できる状態まで可能なポリシーファイルを作成して、レポジトリに掲載するところまでができました。その記録を書きますが、私自身はSELinuxの全貌を理解しているわけではなく、むしろほんの一部しか理解していません。実際のアプリケーションを動かすためのプラクティス的な情報しかありませんが、SELinuxで悩んでいる人や、将来のINTER-Mediatorのメンテナンスのためにブログを書いておきます。ちなみに、以下の作業は「 sudo yum install policycoreutils-python」でパッケージを1つ追加しないとコマンドが使えません。

SELinuxは、非常に大量の設定があるというのはまずは知るべき事実でしょう。最初に書いたように、ドキュメントルールが/var/www/htmlであるという定義があり、別の場所をルートにしようとしたら、この制約をオフにするか、別の場所に許可を与えるなどの処置が必要になります。OSやサーバー等の至る所に設定がなされており、全体像を把握するのはまず無理と思われます。設定ポイントというか、1つ1つの制約機能には、階層的に名前がつけられていて、場合によってはそれを読み解く必要もあるかもしれませんが、その方法は別のブログ等に委ねます。まずは、大量の設定があって多くは「禁止」状態になっており、必要なものを「許可」するというファイアウォール的な作業が必要であるということを理解しておく必要があります。

そこで、SELinuxの世界では、Boolean値と呼ばれれる定義定数があり、個別の設定よりも、もう少し粒度が荒いレベルでの許可を、論理値なので簡単に設定できるようにすることを意図した仕組みがあります。PHPのクラス等でメールを送りたいのなら、「sudo setsebool -P httpd_can_sendmail 1」コマンドを入れます。httpd_can_sendmailというのが既定値の論理値変数で、この値が1なら「許可」となります。通常はこの値は0になっていてメール送信は禁止されていますが、このコマンドを入れればメールを送信できるようになるという具合です。なるほど、それじゃあ、変数を探せば…と最初に考えるわけですが、変数が多すぎて訳がわかりません。変数名から「Webサーバーの」などと言った情報はあるので、頑張って読めばいいかと思いましたが、あまりに多過ぎて諦めました。ググっても「この変数です」というのが全ての場合では分かるまでには至りません。この方法は、簡易的に対応可能な場合だけに限るようです。

次に目をつけたのは、SELinuxでのログ(/var/log/audit/audit.log)を元に、禁止していることを許可するような設定を自動的に取り出してくれるという方法です。方法はいろいろ取れると思いますが、アプリケーションをインストールして、いろいろな作業を行い、そこで禁止されたことを拾い出すという仕組みが用意されているのです。「sudo audit2allow -a」のようにすれば、ログから得られた禁止情報を元に、許可すべき項目などを画面で見えるのですが、「sudo audit2allow -a -M ファイル」とすれば、カレントディレクトリに「ファイル.te」と「ファイル.pp」の2つのファイルを作ります。これらのファイルには、禁止された項目を許可するための設定記述が入っています。そして、「sudo semodule -i ファイル.pp」により、収集した許可設定をシステムに与えることができます。.teファイルが人間が読めるもので、それをコンパイルしたものが.ppファイルです。ちなみに、.teはテキストの略ではなく「Types Enforcement」の略だそうです。.ppは「Policy Package」です。つまり、audit2allowにより、禁止されたポリシーを許可する設定を作るということになります。自分で.teを編集して.ppを生成することもできるのですが、ほぼ、操作をした結果で必要な許可のための記述は得られるようで、操作、audit2allow、semoduleをひたすら繰り返し、エラーが出ないような状態になるまで地道に繰り返しました。また、アプリケーションをいくつか変えるなどして、なるべく多くの機能をカバーできるようにしました。本当はこれもきちんとプランをした方が良いのでしょうけど、まずは完全なものではなく実用になるものと思って手作業を進めました。なお、audit2allowでファイルは更新されますが、元のログファイルが同じであれば、以前に生成された定義は常に入ることになるので、同じファイルに気にしないで何度も定義の生成をしても構いません。

audit2allowでは、論理値変数についての情報も得られるのですが、生成された.ppファイルをsemoduleコマンドで取り込むことで、論理値変数の設定は特にはしなくても良いようです。いくつかのサイトを見ながら作業を進めたのですが、「setenforce 0」でSELinuxをPermissiveモードにして、監査とログ投入は行うのだけども、エラーとしないで実施可能な状態にして、ログに溜め込み一気に.te/.ppファイルを作るという方法が紹介されていました。なるほど。ただ、今回は、どんな風に「動かない状態」が発生するかを確認することもあって、1つ1つやっていきました。

ただ、SELinuxの設定の中にはログを残さないというタイプのものもあるようで、実際、いろいろやっているとそういうのに引っかかったようです。そこで「sudo semodule -DB」と入力することで、全ての監査結果がログに残るようになります。このコマンドを入れないと、収集漏れが発生していたということです。INTER-Mediatorのレポジトリで、dist-docs/selinuxディレクトリに生成したファイルを入れてあります。

もちろん、単に許可するとだけだと、セキュリティ的に甘くなるのではないかということも十分に考えられます。ポートを開くと言っても、決められたポートだけにしたいというセキュリティ上の要求はあるでしょう。それをSELinuxで賄うことで、INTER-Mediatorで作るWebアプリ以外での制限はしやすくなるものの、自動生成したポリシー設定からさらに難易度は上がりそうです。SELinuxを無効化するよりも遥かにましだということで納得しようと思います。

参考にしたサイトは以下の通りです。ありがとうございます。こちらの方が、本稿よりも詳細な情報が得られます。

[続開発プロセス#9] データベースの設計から入る

前回までに、サンプルとして作るメモアプリケーションと、その要求項目をまとめました。本来は、そこから「要件定義」をするところかもしれませんが、要求+UIデザインがあれば、基本的には要件と呼ばれる項目もピックアップされていると考えて、今回はシンプルなアプリケーションでもあるので、割愛します。ここから分担して作業するような場合には確かに要件定義も必要かもしれませんが、ここで紹介しているアプリケーションだと表現の違い程度のものしかありませんので、文書化する手間を省きます。

実際に作成するものが決まって来れば、全体の機能からだんだんと詳細化する様な方法がまず1つあります。これに対して、まずはデータベースのスキーマを確定させ、ドメインをデータベースの中に実現することを優先する方法もあります。複雑なアプリケーションの場合は前者のように、機能を分析して、どういう構成をするのかということを先に考え、並行してデータベースの設計をするのが良いと思われます。一方、シンプルなものは、データベースをまずは設計して、UIとDBの間をどのように埋めるのかということを考える方が効率が良いと思われます。ということで、今回は、まずはER図レベルのものを作ることにします。要求項目等から、以下のようなER図あるいはクラス図を作成しました。

前者はER図、後者クラス図です。ここでは、どんなテーブルがあって、どんなフィールドがあって、関連付けをどう行うかということが記載されていればいいので、どちらの図でも大きな違いはないと思います。見ての通りAstah*を使っているので、どちらかと言えば、クラス図の方が自由度が高いこともあって、私は通常はクラス図で記述します。クラス図では付加的な情報はステレオタイプを活用することで、ちょっと見慣れるのに時間がかかるかもしれませんが、記述は可能なので、そうした仕組みを用意しています。

要するに、メモとカテゴリの2つのテーブルがあるということです。メモに日付時刻のdtフィールド、メモのmemoフィールドがあるのはいいとして、2レベルのカテゴリ設定のために、2つの外部キーフィールドtop_category_id、sub_category_idを用意して、カテゴリつまりcategoryテーブルのcategory_idフィールドに関連づけています。カテゴリは、目に見えるデータはcategory_nameだけですが、階層化の管理をここではテーブル内に持たせることにします。本来は、カテゴリとカテゴリ間の関連を別々のテーブルで表現するのが役割を分離した設計になるかもしれません。ですが、2レベルということで、主キーとなるcategory_idと、自分の上位のカテゴリを示すparent_category_idのフィールドを用いるだけで概ね問題ないと判断して、このようにしました。parent_category_idがNULLであれば大分類、category_idに存在する値があれば小分類とすることができ簡便です。もちろん、1つの小分類項目は、1つの大分類項目にだけ所属できるので、完全にツリー状の構造になるでしょう。前回のUIサンプルのカテゴリ一覧(ページ左側)にあるような大分類、小分類の構成にするには、例えばテーブルのデータは次のようになります。

category_idparent_category_idcategory_name
1仕事
2ホーム
3趣味
41毎日
51レポート
61進行中
71気付き
82レジャー
92学校行事

本来、こうした状態をキープするためには、カテゴリの修正ページはそこそこ複雑になります。もちろん、名前を書き直すのは容易ではありますが、大分類を消した時、小分類も一緒に消すのかどうか、あるいは残すのか。また、それぞれの分類を消した場合、その分離を設定しているメモの方はどのような扱いにするかなど、検討事項はいろいろありますが、今回の設計例ではこれも省略します。ちょっと省略しすぎかもしれませんが、お許しください。

メモを一覧表示する部分はあまり難しさはないと考えますが、結果的に残るのは、分類のリストからの検索と、新規入力時に大分類と小分類のポップアップメニューがあることです。後者は、大分類と選択すると、それに所属する小分類のポップアップメニューに更新しなければなりません。しかし、この段階では、まず、そうした具体的に実装されるべき機能を把握することに進みます。

Chart.jsのチャートのサイズ増加が止まらん!

Chart.js v2.5使ってます。久しぶりに開いたページの中にChart.jsによるレーダーチャートがあるのですが、描画後、チャートがビヨーン、ビヨーンとサイズがデカくなるのでした。以前はそんなことはなかったはず、なんでやねん! 変なプログラムを書いてしまったか?と思ったけど、そうではない。デバッガを見ていると、canvasのwidthとheight属性が、すごいスピードで+1ずつインクリメントしているのです。durationの値は0にしている。そこに100とか数字を入れても同じだったので、これの問題ではないということですね。かなりあれこれ探したら、なんと、公式ドキュメントに書いてあるじゃないですか。「canvasのコンテナはposition: relativeにしなさい」ということで、なんとか、ビヨーンはなくなりました。しかし、もう、画面に何も表示されないくらい、チャートがデカくなっていくのは悲しい画面でしかないですね。ということで、Chart.jsのcanvasは、divなどで囲ってください。

[続開発プロセス#8] 設計作業の実例(ドメイン分析とUI設計)

ここからは開発プロセスに従って、実際にどのように設計を進められるかを検証しながら、問題点やポイントを把握して行くことにします。サンプル開発のテーマですが、あまり難しすぎると把握が大変で、プロセスそのものとは関係ない情報を大量に捌くことになりかねないので、なるべくシンプルなものにしました。テーマは「1行メモ」です。もちろん、ものすごく簡単なので、すぐに作れるという方は多いとは思います。とはいえ、小さな開発でも突き詰めればきりがありません。要求をしっかり掘り下げるといくらでも細かな点は抽出できます。過剰に複雑にならないように、とは言え、ステークホルダーの要求に答えるというプロセスを考えるためには、一見するとすごく簡単なテーマがいいのではないかと思います。

以下、まずはINTER-Mediatorで構築することを中心に考えます。モックアップも、INTER-Mediatorを使って作りますが、データベース定義などしないで、モックは単に見栄えのチェックのためのものだけを作ります。

まずは、最初の要求が発生するとして、次のように要求が出てきたとします。

  • [R1] 1行メモを複数記録でき、一覧で見ることができる
  • [R2] メモ作成あるいは変更時の日時を記録することができる
  • [R3] 1つ1つのメモは、大分類と小分類を設定することができる
  • [R4] それぞれの分類は、予め定義されたものから選択するようにできる
  • [R5] 小分類の項目は1つの大分類項目に所属する形式にする(大分類と小分類は階層的な関係になっている)
  • [RX-1] 利用者、1人1人の1行メモを管理でき、他人のメモを見たり修正できたりはしない
  • [RX-2] 大分類、小分類の項目を編集する機能が必要

項目にコードを割り振っています。RはRequirementのつもりですが、RXの番号があるものは、要求としてはあるけども、設計作業を単純にするために、以後は無視するものとします。思いつく全ての要求を入れてしまうと、プロセスよりも状況の把握の方が膨大な情報量になるので、その点はご容赦ください。もちろん、無視した要求が重要なこともあるかと思いますが、ここでは、プロセスを通すことをまずは説明したいと思います。

上記のような要求がある場合、ざっくりとモックアップを作ってみるとこんな感じでしょうか? INTER-Mediatorを読み込んでいるので、テーマが適用されていますが、あとは単にinputやselectタグを適当に並べているだけで、特にデータベース処理などはしていません。要するに、tableタグにtrタグが3つ含まれていて、「複数のメモがある」感じを出しているだけです。

こういうのを作ると、もう、ここでいろんな要求が増えてきます。ちなみに、「メモ」あるいは「リマインダー」って、多くの人は「いいアプリがない」とお悩みなようで、どうやら、一人一人が要求するスペックが多岐に渡っていて、落とし所が見つかりにくいテーマなようです。ということで、以下、要求が出てくるとは言っても私の好みという色彩は強いので、メモアプリケーションとして評価はしないでください。あくまで、プロセスとしてこういう流れがありうるのかどうかということです。以下のような要求が追加されました。

  • [R6] 一覧に表示するメモは、分類に応じて絞り込みができるようにする。
  • [R7] 分類に関係なく全部のメモを表示したい。
  • [R8] メモがたくさん出てくる可能性がある。だとしたら、10ずつ表示するなど、ページネーションが必要になる。
  • [R9] 日付の入力はキータイプだけではなく、JavaScriptのコンポーネントを利用したい。

これらを含めたモックアップとして、次のように発展させたとします。絞り込みのため、左側に分類名のボタンを用意します。ページネーションは「とりあえず配置する」ということを示す赤い文字列を示すに留めています。一定以上の労力がかかる作り込みは、モックアップでは避けた方が良いでしょう。その代わり、例えば、このように赤字でコメントを書くということを行うことで、コミュニケーションを図ります。

この辺りまで進んでくると、おそらくディテールについて、いろいろな意見が飛び交うでしょう。まず、前の図だと、分類やメモそのものはテキストフィールドにありますが、最初に書き込んだ文言から変更しないことが多いのだから、テキストフィールドである必要はないと言えます。また、文字数が長くなると、欠ける可能性もあるので、メモの一覧には編集機能を付けないのがいいのではないかということになります。

であれば、入力や編集はどうするか? 1つの方法としては、以下の図にあるように、メモの一覧の下などに、メモの入力用エリアを設けて、ここで最初の入力ができるようにすることになるでしょう。他にも方法がありそうですが、ここでは別領域を設けることで合意したとします。

  • [R10] メモの一覧は、表示のみにする
  • [R11] 新しいメモを入力するためのUIを、一覧とは別に用意するタイプにする

左側の絞り込みを見てみると、小分類での絞り込みはできそうですが、指定した大分類だけの絞り込みもしたいのではないかということになりました。要求についてはR6が詳細化されたとみることができるでしょう。

  • [R6-m1] 一覧に表示するメモは、分類に応じて絞り込みができるようにする。この時、小分類だけでなく、大分類を指定しての絞り込みができるようにする

入力と表示を分けましたが、このままでは、メモの編集ができません。書き損じた場合はどうするのということもありますし、分類を変えたい場合も手段がありません。要するに、CRUDの考慮が必要になるということになりました。項目の削除は、一覧に「削除」ボタンを作る。そして、項目の内容を変更することは、どちらかと言えば主要な操作ではないので、リストをクリックするか、あるいはボタンを押すなどの方法で、別のページに遷移して修正ができるようにしようということになりました。ただし、この別ページ部分は今回の流れでは追わないことにしましょう。

  • [R12] 一覧にあるメモを「削除」ボタンで削除できるようにする
  • [RX-3] 既存のメモの内容を変更するための編集ページを用意し、遷移して修正できるようにする

他にはどうでしょうか? リストや分類項目の並べ方が確定していません。これについてもやはりいろいろな意見があるでしょうが、次のようにしましょう。

  • [R-13] メモの一覧では、作成修正日時の逆順で表示する。
  • [RX-4] 絞り込みの部分での項目の順序は、分類項目の編集時に指定できるようにする。

ちょっとしたアプリケーションのつもりでも、結構、項目は出てくるものです。ここまでのところでは、要求に関して、UI設計を進めることで、要求に不足する情報を補うことを意図した作業を進めてみました。メモについてはドメインと呼べるほどの知識はないのかもしれませんが、アプリケーションによってはそのドメイン部分の理解を何かの方法で進めながら、要求とUIの部分を進めました。次回は続いて、要件定義からモデル化を進める部分に進みましょう。

設計作業のサンプルで用いたファイルは、こちらで共有します。

今現在のINTER-Mediatorのポジション

INTER-Mediatorは「少ない作業でデータベース連動Webアプリケーションを開発できるフレームワーク」と説明してきました。しかし、この文章の中にある言葉の意味も、10年も経過するとかなり違ってきているということに気付き、現状をどう説明すれば良いかを考えてみました。

まず、システム開発をする時に、どんな手段あるいは手法を取るかということについて、いろいろな軸はありますが、コアとなる素材の選択は重要な作業です。スクラッチからの開発、あるいはサービスを使って事実上は開発しないという両極端の間にいくつか段階があると言えます。

軸に並べているのは、隣同士は近い関係にあり、中間的なものもありうるだろうということが考えられるからです。ただ、距離については正確ではないでしょう。この軸は、順序尺度と比例尺度の中間的なものを想定しています。それぞれのポイントは次のように定義してみました。

名称説明
スクラッチ開発多くの部分を独自にプログラムを記述するなどして開発される形態。今時は、純粋にスクラッチなものは少ないかもしれない。
フレームワークフレームワークを利用して、その上でシステムを拘置する形態。ネイティブ系であればOSに用意されたフレームワークを使うことが多いが、Webだと多数のフレームワークがあり、何を使うかを最初に検討することになる。
カスタマイズ基本的な機能が揃っている環境をベースに開発を行う。ページ要素などは用意されていて部品のように使ってページを作るなどの仕組みを持つもので、主として汎用的な用途の機能が提供されている。具体的にはFileMakerやKintoneなどがこれに相当する。
ソリューション(利用)一般的によく行われる業務のシステムが概ね構築されており、カスタマイズ等の手法で利用者の要求にマッチさせるようなシステム開発の形態。カスタマイズの仕組みは容易にできる点が特徴ものから、開発言語によるものまで様々ある。salesforce、ServcieNowなどがこれに相当する。
サービス利用すでにサービスが起動しており、開発作業なしに簡単な設定だけで業務が進められるようになる形態。業務が法令に則っているような場合などは、十分に実用的なサービス設計ができる。freeeなどがこれに相当する。

この軸上で、INTER-Mediatorは、フレームワークが中心になりますが、カスタマイズという側面と、スクラッチ開発の側面に広がるものと考えています。よく、INTER-MediatorとKintoneの違いはどこなんだと聞かれることがありますが、INTER-Mediatorは中心はフレームワークであるということであり、Kintoneはカスタマイズ開発向けであるということになります。

なお、これらの分類は新規開発という状況での検討事項ではありますが、図中に示したように、開発後にメンテナンス開発をかける時には、開発物そのものが仮にスクラッチであっても「カスタマイズ」で対応可能という状況や、フレームワーク的に使ってかなり作り替えるとか、ソリューションとしてプロダクトライン的に使うなどの側面でも評価できると思いますが、この記事ではメンテナナス開発については詳しくは取りあげません。最後に少し記述があります。

この軸に沿った分類をした時、現実にどの程度のソリューションが作られたかを想定してみました。もちろん、きちんととした統計を取ったわけではありません。想定していない分類の統計は取れないので、情報もないですが、ここではイメージで図を作成してみました。線の曲がり具合などは異論はあるかもしれませんが、言いたいことは、スクラッチ開発は相対的に減り、フレームワークを使ったような開発も減ってないとしても相対的には減り気味、一方でカスタマイズやソリューション、サービス利用は年々増えているという傾向があると考えられます。

サービス利用やソリューションの比率が上がるということは、一般的な業務や、法令で決められたような業務については、その領域での開発で済んでしまうということに他なりません。そうなると、INTER-Mediatorやその他のフレームワークは居場所がなくなるのでしょうか? これはそうではありません。むしろ、サービスやソリューションで解決できない領域の業務システムを中心に据えるべきでしょう。その会社、あるいはその部署で独自に行うような業務をシステム化して効率を高めることは、競争力の原動力になるのは古くから言われている話です。開発対象の特性を考えて、向き不向きを考える必要があり、軸の右の方は、そうした一般的でない業務や、あるいはサービスやソリューションそのものの開発素材という方向性を意識すべきです。

では、カスタマイズはどうなるかと言うと、これは相対的には広がっていると思われますが、ほとんどの製品がベンダーロックインがかかってしまう点があって、「減らない」だけなのではないかとも考えられます。しかしながら、ソリューションが進展すると、ベンダーロックインはもう関係ないことになりそうですし、より標準的に業務を進める方向へと流れるとしたら、カスタマイズから左に向かう流れはなかなか止められません。結果的にカスタマイズ各社も「すぐに使えるアプリケーションがあります」的なプロモーションを展開することになります。

INTER-Mediatorは、フレームワークを軸足にしたカスタマイズ性を持つ開発素材であると言うことになりますが、そこからは広がらないのでしょうか? そんなことはないと思います。例えば、クラウドで簡単に使えるサービスや、あるいは開発ツール的なものを組み合わせれば、カスタマイズ領域に展開できると考えられます。また、ソリューションを作ってしまって、それを素材としたビジネスも考えられます。そう言う意味では、すでに存在するINTER-Mediatorは、軸の左方向へは展開可能です。ただ、現状、数人のコミッターの状況ではそこまでできないので、コア機能の充実にフォーカスしているわけです。

いずれにしても、ソリューション、カスタマイズ、フレームワークの領域の製品は、いろいろなメリットがありますが、開発が楽になる的な表現がよくされますけど、本質は「改変が楽」と言う点にあります。つまり、メンテナンスしやすいと言う方向性を持ちます。その特性を行かせるのは、やはり「過去に作ったことがない」ようなシステムでしょう。作って検証し、そしてさらに開発を続けると言う枠組みにうまく入れる製品が望まれると言えます。もちろん、これは、既存ソリューションの改造でも同じことは言えます。そのような点でのコミュニケーションが重要であると言うことも、以上の考察から得られる結論です。

INTER-Mediatorは「少ない作業でデータベース連動Webアプリケーションを開発・改変できるフレームワーク」と説明するのは変わりないとして(最初からちょっと変わっていますが)、ここでの考察を組み込んだスローガンを考えないといけません。これは宿題ということで、お許しください。

[続開発プロセス#7] ここまでのビッグピクチャー

ここまでに説明したことを図解してみます。以下の通りです。要するに「通常の開発」とさほどの違いはありません。UI設計を独立させていることと、実装設計モデルという考え方が入っているだけです。

ちなみに、「こんなにたくさんのドキュメントを作れというのか?」という気になるかもしれませんが、メリハリは付けるべきであるし、開発のイテレーションでは更新しないというドキュメントも出てくるかもしれません。むしろ、どの成果物に力を入れるべきかを考えながら、さらにこれから深掘りしようと思います。

そういうわけで、皆さん、良いお年を!