アクションフォームを使うべきか?使わないべきか?

そこでまた疑問なのですが・・・
SAStrutsのページでは、基本的にActionクラスにActionFormも同梱するのを推奨しているようですが、dewa様の図だと、DtoとしてActionFormを分離されていますよね。


これによるメリットはなんなのでしょうか?


メリットは以下の2点と考えています。

  • ソースコードの可読性(メンテナンス性)の向上
  • テストしやすくなる

逆に、デメリットとしては、若干生産性が落ちることだと考えています。


ちょっと長くなりますが、この結論に至ったプロセスについて説明します。


私も最初は、アクションだけで実装していたのですが、複雑なユースケースの場合にソースコードが肥大してきました。肥大化対策を起点として、紆余曲折を経て、以下のようにアクションとアクションフォームを分離した方が良いと考えるようになりました。


【その1】
アクションが持つプロパティを画面入出力項目とそれ以外に分離して、画面入出力項目をアクションフォームへ移すとソースコードの可読性(メンテナンス性)が良かった。(アクションフォームの責務は、対応するアクションと同じユースケースの画面入出力項目を扱うことと位置付けました。)


【その2】
画面入出力項目を扱うクラスに関連するデータ変換処理の責務を負わせる方が自然だと考えました。実際に、データ変換処理メソッドをアクションフォームに置くことで、アクションクラスの肥大化を抑えることができ、さらに、ソースコードがスッキリしました。


【その3】
特定のユースケースで使用する繰り返し項目用Dtoや検索条件Dtoなどをアクションフォームの内部クラスとして定義すると、責務面でも自然だし、ソースコードも複雑にならなかった。


【その4】
アクションに存在していたデータアクセス処理部分をテストしやすくするために、メソッド分割したが、入力データの流入経路がメソッド引数とプロパティの両方が指定できるために、入力用のテストデータをセットしにくかったので、データアクセス処理部分をサービスクラスへ移動しました。

すると、入力値はメソッド引数のみで定まるため、インターフェースがハッキリして、テストしやすくなりました。この際、アクションフォームの内部クラスとして定義した検索条件Dtoなどを積極的にサービスメソッドの引数に渡すようにします。(サービスは特定ユースケースのデータクラスに依存してしまうので、サービスの粒度もユースケースを想定しています。(※))


この実装方針は以下の問題点があることが分かっています。

  • 若干の生産性の低下
    • (内部クラスも含めて)作成するクラス数が増えてしまう
  • ユースケース単位のデータクラスをセッションの扱いにくい(次のいずれかの方法)
    • アクションフォーム自体をセッションスコープにする方法(個人的にはこの方式はイヤ)
    • セッションスコープのDtoを別で作成して、アクションにDIする方法(本来であればアクションフォームの責務なのに、別の箇所で処理しなければならないので、設計的に美しくない。)
  • 検証メソッドがアクションにしか置けない
    • 画面入出力項目に関する責務については、すべてアクションフォームで処理したいところ。しかし、フレームワークの制約で、検証メソッドはアクションフォームに配置できない。(現行では、検証メソッドはアクションに配置します)


追記:
1.0.3-rc1 より、アクションフォームでも検証メソッドを記述できるようになります。


とは言いつつも、少し誤解を招いてしまいましたが、私はあらゆる状況で「アクションとアクションフォームの分離」が最適と主張している訳ではありません。『大は小を兼ねる』的な発想で比較的無難な[方針2]を紹介させて頂いたという訳です。実際には、状況に応じて使い分けるのが良いと思っています。これについては、以前に書いた以下のエントリをご覧ください。


 「8割の簡単な処理」と「2割の複雑な処理」への対処方針
 http://d.hatena.ne.jp/dewa/20080531#1212211267


アクションとアクションフォームを分離している方針は、上記のエントリで説明している[方針2]に相当します。

 [方針2] 2割の複雑な処理にあわせる
   * 品質重視。ただし、簡単な処理の生産性は落ちる。

ちなみに、アクションフォームを作らずにアクションのみで勝負する場合は[方針1]です。そして、基本はアクションのみだけど、複雑なユースケースの場合にアクションとアクションフォームの両方を作る場合は[方針3]です。


[方針1]にしても[方針2]にしても、どこかで無理が出てきます。なので、簡単な箇所には簡単なアーキテクチャを適応して、複雑な箇所には複雑なアーキテクチャを適応する[方針3]が、本当は自分は一番理想だと考えています。(でも、こういう考え方って、なかなか受け入れて貰えないんだろうなぁ。)


SAStrutsはまだまだ新しいプロダクトなので、このあたりの定石は固まっていないので、他の人の意見も聞きたいところです。


※ ちなみに、SAStrutsのメイン開発者のid:higayasuo さんは、サービスの粒度はエンティティの方が良いと考えており、私と主張が異なっているので注意してください。アクションフォームも基本的には作成すべきではないと考えていらっしゃるようです。
アクションフォームの使用が推奨されるようになりました。