TeedaとDBFluteを使用時の設計指針

TeedaDBFluteを組み合わせて使用する際、ConditionBeanクラスは何処で組み立てを行うべきか?

ConditionBeanの組み立て処理は、SQL文を組み立てる処理に相当します。責務からすると、この処理はドメイン層のオブジェクトに内包する形で行われるべき、という考え方がでてきました。よって、Pageクラス内でConditionBeanの組み立てを行うのは、避けたほうが良いという意見がでました。

では、どこで処理するのが適切なのだろうか?

4つの選択肢から考えてみました。

選択肢1.Pageクラス
やはり、ConditionBeanの組み立ては、Pageクラスで行うべき。
理由は、Pageクラスに業務ロジックを置いても良いと考えるから。
Teedaでは、PageクラスがPOJOであるためテストしやすいので、業務ロジックを置いても良しとする。)
さらに、業務ロジックは画面に引きづられることが多く、実際には重複の機会が少ない。
多くの照会系の処理は画面ごとにDaoメソッドができる、それならば、
画面と業務ロジックが近いところにあった方がテストしやすいのではないか。
重複は発生した段階で共通クラスに切り出す。
実際には、DaoやBehaviorを呼ぶので、低いレイヤの処理の重複は自然に防ぐことができる。
  
【問題点】

  • Pageクラスの責務が重くなるため、Pageクラスのコードの可読性が下がる。
  • 本来であれば、Behaviorなどに収めるべき責務がPageクラスに存在すると、テストはやり難くなる。(PageクラスでもPOJOなのでテストできるが、Behaviorに収まっていたほうがテストしやすい。)テストできるできないではなく、テストしやすいかが重要。

選択肢2.Behaviorクラス
ConditionBeanの組み立てはSQL文を組み立てるロジックに相当するので、
プレゼンテーション層であるPageクラスに存在するのは相応しくない。
ConditionBeanの組み立て処理は、Behaviorクラス内で行うべき。
その方がテストがしやすい。

【問題点】

  • わざわざ専用の検索条件用のDtoクラスを作成する手間がかかってしまう。追記:さらに、PageからDtoへプロパティ値を詰め替える処理が発生しまう。
  • 複数のEntityを扱って1つのロジックを処理する局面において、特定のBehaviorが他のBehaviorを呼び出す構造になるので避けるべき。
  • 画面の複雑度に応じて、戻り値を格納するDtoを作成しなければならなくなってしまう。

選択肢3.Service
1Page=1Serviceの粒度でサービスを設計しておく。この場合、ServiceのメソッドにPageクラスのthisポインタを使って渡すことにより、パラメータ用のDtoを作成する必要がなくなる。(PageクラスをパラメータDto代わりに使用することができる。)
さらに、複数のEntityを扱う、業務ロジックを処理できる。複雑な画面であったとしても、戻り値を格納するDtoを用意する必要がない。サブアプリケーション単位で重複している処理は、サブアプリケーション単位の親Serviceクラスへ移動する。アプリケーション単位で重複している処理は、アプリケーション単位の親Serviceクラスへ移動する。DRY原則対策のリファクタリングが容易。

【問題点】

  • レイヤ数が増えてしまう。
  • Serviceのインターフェースを定義するのが面倒。
  • PageとServiceが相互依存になってしまう。(1対1で対応しているケースは良しと考える場合も。)

選択肢4.状況に応じて使い分ける(ハイブリッド)
基本は、Pageクラスにベタ書きして、複雑になったらServiceにConditionBeanの組み立て処理を移す。
状況に応じて最適化されるため、生産性が一番高い。フレームワーク開発者の設計思想(Super Agile)に近い。
局所的に見れは、ソースコードはきれいになる。逆に、他の選択肢は、簡単な処理をするだけでも、Serviceなどのようにインターフェース付きの冗長なソースコードを書かなければいけないのは、開発のリズム感がなくなってしまう。

【問題点】

  • ソースコードの実装にバラつきが出てしまう。場合によってはメンテナンス性が悪くなってしまう。
  • PageからServiceなどへ処理を移す方針が決めにくく、属人性がでてしまう。


自分なりの回答を考えたものは、次のエントリーで。。