単一責務の原則

オブジェクト指向の原則 単一責務の原則 #04_3層構造の例

「3層構造」のお話をしていきたいと思います。プログラマーになりたてのころなど,先輩プログラマーなどに,よくこういう話を聞いたことがあるのではないかと思うのですが,「なんでもかんでも,画面のプログラムに,全部の機能入れては駄目だよ」と。「画面」と「ビジネスロジック」と「データアクセス」という,「3層に分けて書くのがいいのだよ」みたいなことを聞いたことがある人もいるかもしれません。

これもこの単一責務の原則に由来しているというか,この辺の原則に従うことで,導き出しているような作りになっています。

現状私が推奨しているパターンとしては,この3層構造というよりは,もう少し違ったかたちで,ドメイン駆動開発とかでは推奨していますけど(C#ドメイン駆動開発等を参照方)例えばこんな感じということですね。データアクセスとかビジネスロジックとか画面とかいうのは,大きく分けると,「最低限ここが分かれてくるよね」というようなことですね。

1.1    データアクセス

・永続性のあるシステムはあまり変化しない

・ビジネスルールとまったく関係ない次元で変化する(SQLServerのバグや仕様変更など)

例えばデータアクセスですね,SQLServerとかOracleとか,ファイルとかというところは,基本的にそんな大きな変更というのは頻繁に起こるわけじゃないわけなのですが,ビジネスルールとは全く関係ない次元で,変化するという性質がありますね。

例えばSQLServerのバージョン上がったよとか,バグが出たよとか,仕様変更したよとかというのがたまにありますね。SQLServerでも文字列を扱う時は,「実はここにこういう感じでアクセスしてくれないとちょっと文字化けします」とか,「日本語だったらいいのだけど中国語のOSでやったらここがこうなるのでここはこうしておいてください」みたいな不具合報告などが,たまに発見されたり,意図的な仕様変更がされたりといったことが,たまにあります。

そういう場合というのは,SQLServerにアクセスしているところを全部探して,修正していかないといけないのですが,こういうものが受注画面や発注画面,在庫画面などの画面ロジックに書き込まれていると,いたるところで画面からSQLServerに接続されるコード入ることになり,しらみつぶしに探して,ロジックを修正していかないといけないという事態になってしまいます。

そうならないように,データアクセスする箇所を独立させて,「データアクセスはここでやっているよね」みたいな感じで,受注テーブルはこことか,発注テーブルはこことかいう感じで,クラスを分割し,独立して作っておけば,このファイルとこのファイルとこのファイル,このクラスとこのクラスとこのクラスみたいな感じで限られたクラスの修正だけで済むようになります。そうなると,修正箇所も少なく,影響箇所も限定的になるため,テスト工数も最小限に抑えることが出来ます。

1.2    ビジネスロジック

ビジネスロジックは頻繁に変化する

・取得したデータの編集など,自分で仕様を調整する部分

ビジネスロジックというのは業務ロジックのことです。例えば何かビデオレンタルシステムとかだったら,お客さんのカードをピッと読み込んで,こんな感じで出てくるからとかという,システム独自の仕様です。こういった業務ロジックは,業務の都合等で,頻繁に変わることがあります。要はポイント5倍デー始めようかとなったら,追加仕様として改造が必要になるかもしれないし,今までの「この割引率はちょっと変えよう」とか,「このチェック処理をちょっとこう変えた方がいいよね」という,我々がというか,ユーザーがというか,そのシステムでやりたいことというのを,自分で考えてやるので,SQLServerの仕様とか,マイクロソフトとか全然関係ない次元で,自分たちで考える仕様の変更ということになります。

だから業務ロジックは,業務の都合でどんどん変わっていくので,そこはそこで独立しておかないといけないといけないわけです。だからこのビジネスロジックとデータアクセスというのが一体化しているということは・・・

マイクロソフトの仕様とか,Oracleの仕様とかと,我々が独自で勝手にやっている業務ロジックの仕様とを,混ぜちゃっていることになるので,非常にこの結び付きがひどくて,使いづらいものになっていく訳ですね。マイクロソフトとかOracleの仕様変更と,我々が勝手にやる仕様変更とどっちが起きても,ソースコードをいじらないといけなくなるので,「どういう変更に対してこれは変えるクラス」みたいな感じで,独立して作っていくということが重要になってきます。

1.1    画面

データを取得してリストに表示

→グラフに表示する場合

データを取得する部分は関係ない

画面にしても,画面とビジネスロジックで言うと,画面というのは,Windowsフォームだったり,WPFだったり,Web画面だったり色々ある訳なのですが,その画面のテクノロジーに起因しますね。例えば,画面だったら,マイクロソフト標準のテキストボックスを貼り付けるのか,グレープシティのInputManを貼り付けるのか,そういったサードパーティーのコントロール貼り付けたり,時代の流れに伴って変化していったりしますね。例えばユーザーコントロールに不具合があったり,バージョンが変わったり,「テキストボックスでこういう処理をしたいね」とかという,画面は画面の事情の変更が出ますね。それとビジネスロジックとは関係ないわけです。

例えば定期的に温度を計測し,ある特性があれば検知するロジックを作ったとしますね。それとテキストボックスのチェックとか,グラフの見せ方とか,そういったこととはまた別の話なわけですよね。だから,そこは画面の技術とビジネスロジックというものは,切り離しておかないと,グラフの見せ方変えたいだけなのに,画面ロジックに精密なロジックまで同じクラスに入っていたら,画面事情の修正でも,同じクラスをいじってしまうみたいな感じになるわけですね。だから「このクラスをいじるってことはこういう変化が起きた時」とか,「ここをいじるってことはここに影響してくるね」というのが,分かるように作っておかないと,全部が1個のクラスにあったら,どこかを修正したら,別の関係ない部分がおかしくなっているかもしれないですね。そういう事にならないように,精密なロジックなどは,それはそれで独立してポンっと置いておきたいわけです。そういうような感じで,「画面」「ビジネスロジック」「データアクセス」というのは,結構昔からこのように分けて実装されることが一般的です。

「アジャイルソフトウェア開発の奥義」では,「ビジネスルールと永続性のあるシステムを結合するのは,自らトラブルに飛び込むようなものだ」というふうに書かれています。

これは,今言ったように,関係ないロジックが,他のロジックの修正に引っ張られてしまうので,他の変更理由に引っ張られてしまうので,無駄にクラスをいじることになりますね。だからそっとしておけるクラスというのは,できるだけ多い方が良くて,「これが変わったらここだけ変える」みたいな感じで,作っておくというのが理想ということです。

オブジェクト指向の原則 単一責務の原則

C#を正しい3層構造で造れてますか?

非売品コースを受け取る

#00_はじめに
#01_単一責務の原則とは
#02_原則違反の例
#03_変更理由単位でクラスを分ける
#04_3層構造の例
#05_修正箇所を最小にできる
#06_修正する場所が明確になる
#07_共通化しましょうという話ではない
#08_少々悪いコードでも問題視しない理由
#09_探しやすいコード
#10_クラスは機能ごとに小さく作る
#11_小さなクラスがそれぞれに協調して目的を達成させる
#12_多数の部品群のなかから摘まんで作る
#13_クラスはどこまで小さくすればいいのか
#14_アンダーソン式単一責務の原則
#15_最小カプセルの検証_監視タイマークラス
#16_最小カプセルの検証_受注画面クラス
#17_最小カプセルの検証_ユーザークラス
#18_最小カプセルの検証_商品マスターデータアクセス
#19_登場人物に合わせたモデリングの四角と線
#20_四角と線を最小カプセル化する
#21_アンダーソン式手順
#22_パターンを見つけ出す
#23_プログラミングの自問
#24_さいごに

【参考図書】ピーコックアンダーソンが参考にした書籍一覧