cfneo(仮称)のレイヤ

ColdFusionのフレームワーク的な何か、は今の時点でプロトタイプを作ってテストして補正して、という感じなのですが、そこで作ったレイヤと、先日のテストの整理についてをメモ。

ColdFusionのフレームワーク的な何かの現時点での概要

目的

ブラウザを通じてテストをする他ないColdFusionというものに対して、テストを有効かつ効率的に行えるような設計ガイドラインを作る。

詳細

ColdFusionは、今のところUnitTestを積極的に活用することを考慮されたものではなく、「作り捨て」が理想的なメソドロジーになり得るものではあるが、ColdFusionのアプリケーションが拡張・変更を受けた場合、そうそう「作り捨て」が許されるものではない点を課題として、拡張・変更を許容できるよう事前のアプリケーションの機能設計のガイドラインと、テストを行う対象について考察をより研鑽する。

これが大前提ですね。(その結果、テストへの思考につながった訳です。


で、ColdFusionのフレームワーク的な何か、に仮に「cfneo(仮称)」というコードネームを与えました。(現在の書きなぐりの実装で何もかも乗り切ろうというアプローチではなくそろそろ次のステップに移ろう、というような意味合いでこういう名前にしました)

そのcfneo(仮称)のレイヤなのですが、ざっと以下のように考えております。

cfneo(仮称)のレイヤ

  1. Screen(.cfm)
  2. Event Handler(.cfm)
  3. Validator(.cfc)
  4. Facade(.cfc)
  5. Flow(.cfc)
  6. Process(.cfc)
  7. Dao(.cfc)
  8. ApplicationCommon(Application.cfc)

Javaではお馴染みの7層モデルになりました。
ざっとそれぞれの役割をメモしておきます。

Screen

UIのうち画面用となるCFMファイル群です。この画面に許すのは、基本的にApplicationScope内のデータ、ApplicationCommon経由でのSessionScope内のデータ、画面に表示するストレージされたデータを得る為のDaoくらいかと考えています。
ColdFusionのおいしさの1つでもある「コードにクエリを埋め込める」というのは、テストを複雑にしてデバッグを困難にしかねない為、このファイル内でのクエリの実装はNGにして、代わりに画面表示に必要なロジックはOK、とした方が、Screenの役割をより明確にできそうですね。

ただし、このScreenのレイヤの実装は、FuseboxのようなURLと表示内容を切り出すようにしても良いとも思っています。

画面と1:1。

Event Handler

画面からGET/POSTでリクエストされる際のいわゆる「遷移先」です。
条件によって遷移先が変わる、といった事がなければColdFusionでは特に明示的にする必要がないレイヤなのですが、入力値検査などをJavaScriptだけで実装する訳にもいかないので、あえて明示的にレイヤを起こしました。

ColdFusionの場合、画面遷移はcflocationまたはcfinclude(と、アンカータグ)で行うのが一般的なのですが、これだとURL崩れを起こしやすい為、cfneo(仮称)ではcflocationに一本化する事を是としたいな、と。
その際、画面間でやり取りされるデータですが、Formという構造体オブジェクトに格納されている内容を、ApplicationCommon経由でSessionScopeにセットする等とするのが適当ではないかと考えています。

画面上のGET/POSTイベントに対して1つ。

Validator

入力値やステータスの審査の為のロジックを置く為のレイヤ。
データベースなどを参照しないで良い検査のみ、ここで実装します。エラーがあった場合などは、EventHandlerに例外を投げるなどして制御を戻し、エラーの内容の表示の為のあれこれはEventHandlerでApplicationCommon経由にSessionScopeへセットScreenレイヤに、といった流れにするのが妥当かと思います。
でも、なんとなく、レイヤとしてあえて設けなくても良いかも、とも思ってます。

Facade

EventHandlerから実行され、それをFlowに委譲する為だけのレイヤです。
集束単位はサブシステムごとか、業務ごとでしょうか。

このレイヤは、基本的にFlowのコール部分をcftransactionで囲む、くらいの役割しか持ちません。これはFlowレイヤ以降をテストする際、Commitされてしまわないようにテスト・ドライバで明示的にRollbackするなどしたいのですが、実際に稼動させる際にテスト用の設定の為に既存のコードを改修しなくても良いように、という事ですね。
JavaAOPを使ったりしている部分をColdFusionでカバーする為のレイヤです。キモイ><)

Flow

一般的にServiceと呼ばれるレイヤだと思うのですが、ここでも業務ロジックはなるべく実装したくないのでFlowと名付けました。

ここに置かれたコンポーネントでは、Processで個別に実装された業務ロジックを順序だてて呼び出していき、Processから返されたデータをもとに適切な結果を返すまで、というコール文の集合のような実装がなされるべきかな、と思います。

ただし、ColdFusionなので設計で何かしらの制約を加える事が難しく、ここですべての業務ロジックを実装してしまう、ということも全然可能です。

Process

業務ロジックを個別に実装するレイヤです。

基本的には、Flow上にあるすべてのIF条件がこのProcessに関数として定義されていくようなのが理想かな、と考えています。そうする事で、Flowの条件網羅を行う為に膨大なデータを用意しなくても、このProcess単体のテストで十分なデータを使うことで条件評価が正しく行われるかどうかの確認が容易になる、と考えたからです。
また、Daoへのアクセスもこのレイヤのお仕事です。

前述のように、Flowにすべての業務ロジックを実装するのであれば、このレイヤには共通ユーティリティ的なものしか残らない筈です。

Dao

データベースへのアクセスを行わせるお馴染みのレイヤです。
ColdFusionなので、cfqueryタグの実装のすべてがここに集約されます。

画面表示の為にScreenから、またはトランザクション実行の為にProcessから、このDaoは実行されますが、それ以外の箇所から使用しないよう機能を実装する際に気を付けておきたい処です。

ApplicationCommon

全レイヤに対して君臨するレイヤ。

Application.cfcというColdFusion独自のフレームワーク的なコンポーネントがあるのですが、その中核となる実装やコンポーネント呼び出しの為の簡易DI機能などをこのレイヤに集約させて、各レイヤがあまり密に結合しないようにする為に、こういったレイヤを設けました。


以上、JavaでWebアプリケーション開発をしている人にとっては、もはや常識とも言えるような構成だと思うのですが、ColdFusionのようなLLではまだまだ事前にこういった事を準備しておかないとな、と。


以上、メモながら。