関心の分離とプラグマティズム

大規模開発におけるソフトウェア・アーキテクチャ策定時のジレンマに関する私見

問題提起

まずは、JavaWorldに掲載されているAdam Bien氏の記事紹介から:
Lean service architectures with Java EE 6 | JavaWorld
こちらはEJB3.1の仕様とSOAにおけるビジネスコンポーネントアーキテクチャに関して非常に分かりやすく説明してくれている素晴らしい記事です。記事の中ではサービス指向の構成要素のうち主要なものとして以下の3つが提示されます。

  • Facade
  • Service
    • 業務ロジックの実際の実装
  • Domain structure
    • オブジェクトというより構造
    • 永続化を実装
    • カプセル化せずに状態をサービスに提供

アーキテクチャ策定時における重要な原則として、「関心の分離("separation of concerns")」ないし「分割統治("divide and conquer")」が挙げられると思います*1。これらはどちらも責務に応じた明確なレイヤリングと構成要素配置を提言しているものであり*2、これによって製造時には「どこに何を実装したら良いのか」、保守時には「どこに何が実装してあるのか」が分かりやすいアーキテクチャにすることができます。しかし、この分かりやすさは時としてデメリットを生み出すこともあります。この点に関して、前述の記事の一節を引用します。

Most service components are not complicated and consist mainly of basic data operations. In these cases the facade would just delegate to a service, which in turn delegates to the javax.persistence.EntityManager or a generic CrudService to perform its persistence tasks. Otherwise you will end up getting two dumb delegates: the facade would only delegate to the service, and the service to the CrudService (aka DAO). Delegates without additional responsibilities are just dead code. They only increase the code complexity and make maintenance more tedious. You could fight this bloat by making the service layer optional. The facade would manage the persistence and delegate the calls to the EntityManager. This approach violates the separation-of-concerns principle, but it's a very pragmatic one. It is still possible to factor reusable logic from the facade into the services with minimal effort.

ほとんどのサービスコンポーネントは複雑なものではなく、おもに基本的なデータ操作から成り立っています。このような場合には、ファサードは単にサービスに処理を委譲するだけで、そのサービスもEntityManagerや汎用的なCrudServiceに永続化タスクの実行を委譲することになるかもしれません。そうでなければ、間の抜けた委譲が2つあるという結果になるでしょう。つまり、ファサードはサービスに委譲し、サービスは専用のCrudService(つまりDAO)に委譲するといった具合に。自分の責務を行わずに委譲するだけというのは、単なる死にコードです。これではコードは一層複雑になり、メンテナンスも退屈なものになります。このような無駄な肥大に対しては、サービスレイヤを作っても作らなくても良い、とすることで対応することができるかもしれません。ファサードが永続化を管理し、EntityManagerの呼び出しを委譲しても良いとするのです。このようなアプローチは関心の分離原則には違反しますが、実に実践的なものです。この場合でも、ほとんど手間をかけずにファサードから再利用可能なロジックをサービスに移すことができます。
http://www.javaworld.com/javaworld/jw-04-2009/jw-04-lean-soa-with-javaee6.html?page=6

ここで説明されている「実践("pragmatism")の観点からの原則違反」が今回のテーマとなります。

考察

記事の中では「サービスレイヤを作るか作らないか選べるようにする」ことが提案されていましたが、この「選択肢として提示する」ということは、裏を返せば「どちらを選択するかの判断を誰かに委ねる」ことにつながります。問題なのはこの時の判断で、これは判断する人の技量に左右されるものであってはならず、しかもなぜそうなっているのか、という点に関する完全なトレーサビリティが要求されることになります。個別の局面における判断と決定のプロセスは品質とスケジュールに対する「ゆらぎ」となります。このゆらぎがプラスに働くかマイナスに働くかは実際に製造に携わるメンバーの技量に依存することになる訳ですが、多くの場合には、優秀なエンジニアが200点、300点を取れる可能性よりも、エントリクラスのエンジニアでも合格点が取れることを保証する方向に倒しているような気がします。今回の例に即して言うならば、関心の分離原則を重視するなら、委譲するだけのクラスの存在を甘んじて受け入れるということですね。


現実のプロジェクトをまわす上でのやむを得ない判断とは言え、こういった傾向が良いことであるとは思えません。「開発者を業務ロジックの構築に専念させる」と言えば聞こえはいいですが、このような考え方はプログラミングという作業から「考える」ことを撤廃する戦略であり、要するにプログラミングをつまらなくしてしまうものです。「じゃあどうすれば良いのか?」という問いについて明確な答えを持っている訳ではないのですが、常に頭の片隅にある問題ではあるのです。

*1:記事の中でも見出しとして言及されています

*2:「チームの分割」という要素もあると思いますが、今回は掘り下げません