疎結合なコードを書くための考え方
Keywords
- 疎結合
- 保守
Contents
- 1. 疎結合とは
- 2. 疎結合なコードを書くためには
- 2-1. より抽象的なデータを使う
- 2-2. コンテキストをリセットして考える習慣をつける。
- 3. その他
疎結合とは
複数のクラス、メソッド、もしくはコンポーネント等がお互いに関連していない状態のことを指しています。 疎結合なコードはコードの修正の影響を受けづらく、また、再利用性が向上します。
例えば、下記のものは、結合度が高い例です。
axios.get('https://123.10.222.12/index').then(res=>{
});
このコードはIPアドレスを指定しており、サーバの情報を知りすぎています。もしこのIPアドレスがWebサーバの場合、サーバ構成を変更した場合このコード を修正する必要性が生じるかもしれません。
ただ、IPアドレスではなく、ドメインを指定すれば、サーバ構成の変更(Webサーバの台数を増やしロードバランサーを間に挟むようにする)の影響を受けません。
axios.get('https://www.example.com/index').then(res=>{
});
次のコードは、S3にファイルをアップロードする処理ですが、引数にユーザIDを指定しています。このS3へのアップロード処理という汎用的な処理に対して、ユーザIDというかなりビジネスに偏ったデータが渡されており、ユーザIDとは関係のないファイルをアップロードしたい場合は、このコードは使えません。
また、戻り値には、http://image.example.com
という詳細な文字列が使われており、ローカル環境やQA環境といった他の環境を使う場合にも、この本番環境のドメインが使用されてしまいます。
public static function upload(int $use_id, string $directory, string $filename, $file)
{
$content = file_get_contents($file->getRealPath());
$extension = strtolower(pathinfo($file->getClientOriginalName())['extension']);
$path = $_SERVER["ENV"] . "/". $user_id . "/" . $directory . "/" . $filename . '.' . $extension;
Storage::disk('s3')->put($path, $content, 'public');
return "http://image.example.com/" . $path;
}
疎結合なコードを書くためには
より抽象的なデータを使う
123.10.222.12というIPアドレスはとても具体的な値でしたが、www.example.comというドメインはより抽象度が高く、サーバー構成の変更の影響を受けません。
また、$user_idについても、この変数は使わず、ディレクトリの配列を使い下記のようなインターフェースにすれば、良いと思います。
public static function upload(array $directory_list, string $filename, $file) {
…
}
コンテキストをリセットして考える習慣をつける。
疎結合なコードを書くことを阻害する要因は、1つだけのコンテキストを考慮してコーディングをしているということもあります。
s3へのファイルアップロード処理の例で言えば、ユーザに関連する画像ファイル(プロフィール画像など)をアップロードする機能の開発時に、このようなコードを書いたのだと思いますが。そのユーザに関連する画像ファイル(プロフィール画像など)をアップロードする機能というコンテキストをなくし、ユーザとは関係のないファイルをアップロードすることも考慮すれば、このようなコードを書くことはなかったでしょう。
その他の例として、select文でidを指定して検索を起こった際に、取得できたレコード件数が0の場合に、404を返却する処理をDBアクセス層(DAOやRepository)で記述しているコードを見たりしますが、このコードはWebアプリケーションといったコンテキストの場合は問題ないですが、バッチ処理といったコンテキストで考えた場合は、扱いづらいコードとなります。バッチ処理では、HTTPは関係ないので、HTTPの知識である404を付加されても困ってしまいます。コントローラ層に書くべきでしょう。
その他
ヘルパーやFacadeを実装する場合には、上記の議論は別になりますが、その際もあるコンテキストでは便利だけど他のコンテキストでは使いづらい、ということを認識した上でコーディングすることが重要です。