2012年9月26日水曜日

model を物理レイヤーと論理レイヤーに分割する。

エンタープライズrailsという書籍に、モデルをphysical レイヤーと logical レイヤーに分けろ、というアドバイスがあった。この分け方が絶対かといわれるとよくわからないが、私も基本的にはこの考え方には賛成だ。

モデルのレイヤーを分けて考えるということはrailsのような密結合のフレームワークにおいて長期にわたってメンテナンスするコードを書くのであれば必須の事項になると思う。

どのようなレイヤーが必要になるかはアプリの複雑度によると思うが、最低限必須なレイヤーが上で書かれているphysical(DB層) とlogical(ビジネスロジック層) の二つのレイヤーだ。モデルのメソッドを physical と logical に分離し、controller から呼び出すのは基本的に logical 層のメソッドに限定する(厳密に守る必要はないと思うが)こととする。

例えばブログの記事を投稿する、というビジネスロジックがあったとする。内部的にはこれは Post というモデルのインスタンスを save するということになる。しかしこの save という単語はビジネスロジックの単語ではない。ビジネスロジックでは post だ。ビジネスロジック上の「投稿」という処理を表すのが post であり、そのDBレイヤーでの実現方法としてsaveがある。

def post
  save
end

大事なことは、全ての post は save であるかもしれないが、全ての save は post ではないということだ。つまりこれらは異なる概念であり、混同すべきではない。controller から save を直接呼ぶというのはこれを混同していることになる。

以前 before_save の弊害について書いたことがあるが、その問題の具体例がこれにあたる.。たとえば、記事の投稿をするときに記事データからタグを除去するなど正規化の処理をかけたいという要件があったとしよう。これを before_save で実現するというのは post と save を混同しているということに他ならない。全ての save が post 処理ではないのに、post 時のフックがすべての save 時に発動してしまう。このような予期しないフックが見えないところで動いていると予想しづらいバグを生む。バグが起きたのでフックをはずそうということになったはいいが、一度発動した状態で運用が続いていたものに対して、そのフックを本当に外しても大丈夫か、というのを考えるのは骨が折れる。

また別の面でも問題がある。一般的に、仕様変更はビジネスロジックの概念の単位で行われることが多い。「post時の処理にxxxを追加」という要求は出てきても、「save時の処理にxxxを追加」という要求はあまり出てこない。ビジネス上の要件はビジネス上の言葉で表現されるからだ。だからcontroller と model のインターフェース部分にビジネスロジックのレイヤーを設けることには変更に強くなるという点で非常に意味がある。




0 件のコメント:

コメントを投稿