第4回では、前回解説した上位のDAGをさらに下位に分解していく「プロセスの詳細化」と、「データモデルの設計」について解説する。

 まずプロセスの詳細化について述べよう。上位のDAGから、下位のDAGへ、適切な粒度で切り分けて行く作業である。具体的には第3回で切り分けたジョブフローを、再利用性などを加味しながら、フロー部品や演算子に分解していく。

 本来、非同期処理の設計手法は、過去の蓄積を見ればもっと普及・発展していてもよさそうなものだが、筆者が見た範囲では、参考になるのは1970年代の構造化手法くらいである。日本のバッチ処理の歴史は日本固有のものであり、下地があるわけだが、残念ながらこの部分はロストテクノロジーになっている気配がある。

 プロセスの詳細化は、基本的にはDAGを下位のDAGにドリルダウンするときの粒度感をどう考えるかということに尽きる。オブジェクト指向では、オブジェクトに対する責務の割り当てになるし、構造化手法ではモジュール分割ということになるだろう。一般的なシステムのモジュール分割では話が広すぎるので、ここではあくまで基幹バッチの非同期処理というドメインに絞って、特にそのDAGの段階的な詳細化という局面に焦点を当てて、その方法論を論じる。

 プロセスの詳細化では、大きく三つのポイントがある。「業務上の意味がある単位で分解する」「入力-変換-出力(STS)分割を援用する」「粒度を見極める」である。以下、順に解説していく。

三つのポイントでプロセスを詳細化

 一つ目のポイントは、業務上の意味がある単位で分解することである。

 DAGの各頂点は、下位のDAGへと再帰的にドリルダウンされていく。最上位のDAGは、最終的には最下層の頂点(演算子)に分解される。こうした切り分けは、業務的に意味のある単位で行うことが望ましい。業務的な意味付けが分かれるポイントを見逃してはならない。

 業務ベースの詳細化では、業務知識が絶対的に必要になる。業務知識を有するユーザーとのディスカッションやチーム内での議論も前提になる。この場合、よく言われるのが、「名前付け」の重要性である。処理への命名が適切である必要がある。名前付けやそのレビューの過程で違和感が生じたり、具体的な構成に落ちなかったりする場合は粒度感が適切でないことが多い。筆者らもこの辺りは試行錯誤の感が否めないが、構造化手法やオブジェクト指向のGRASP(General Responsibility Assignment Software Pattern)原則を利用しているのが現状である。

前処理、本処理、後処理に分ける

 二つ目のポイントが、入力-変換-出力(STS)分割を援用することである。

 STS分割は構造化手法では一般によく使われる手法であり、Source-Transform-Sinkの一連の固まりをベースにモジュールを分割する。

 基幹バッチ処理で最もよく利用されるパターンは、「前処理+本処理+後処理」である。COBOLでバッチ処理を記述した経験がある方なら、「COBOLの記述法そのもの」に見えるかもしれない。

 前処理では、たいていは本処理に入るためにデータの整形や若干のデータの付加が行われる。後工程の本処理を実行するために、データを変形・チェック・生成する処理であることが多く、場合によっては簡単なクレンジングも行う。

 それに続く本処理は、処理ロジックそのものにウェイトを置いた形の処理が望ましい。単純な処理の逐次実行にできれば見通しがよくなる。

 理想を言えば、本処理は完全に関数的なロジックであることが望ましい。つまり、それぞれの処理は入力に対して出力を行い、出力結果はグローバルな状態や前後の入力などに依存しないことが重要である。関数型の処理というと語弊があるが、副作用のあるような処理は前処理と後処理に置き、可能な限り純粋なロジックだけを本処理を実装する。これはテストの容易性の向上にもつながる。そうすればバグの混入が低減し、再利用性を高めることが可能になる。

 例えば、Excelでのワークシートに組み込まれたセルの関数を思い浮かべてほしい。セルの関数自体はセルの値には依存せず、関数の変更はワークシートやセル自体に影響しない。これは、分散並列性を高めるということにも留意されたい。

 そして、この分割は多層的に行われる。前処理、本処理、後処理がそれぞれ前処理、本処理、後処理に分かれ、さらに再帰的に分割することができる。図1は本処理をさらに二つに分割した例である。

図1●処理を階層的に分割していく
[画像のクリックで拡大表示]