レガシーコードからの脱却 - ソフトウェアの寿命を延ばし価値を高める9つのプラクティス
という書籍の第9章がソースコードの品質を扱っていました。こういう概念的なものは自分で書き起こしておくと定着度が上がると思うので備忘録としてまとめます。
コード品質を構成する要素
-
[疎結合(Loosely coupled)](疎結合(Loosely coupled))
#凝集性(Cohesive)
まず、高品質のソースコード = 凝集性の高いソースコードです。
凝集性の高いソースコードはクラスやメソッドが1つのものだけを扱います。(単一責任の原則やUNIXの設計思想「1つのことを上手くやる」とも共通していると言えるでしょう。)
なぜ凝集性が高い方が高品質かというと、プログラムを変更する際にどのクラスを変更すればよいか判断しやすい・1つのクラスの変更が他のクラスに悪い影響を与えにくいからです。
クラス内に定義されているメソッドに共通性がほとんどない(例:ユーザにメールを送るメソッドとユーザ登録用メソッドが同一クラスに定義されている)場合や1つのメソッドで様々な処理を行っている場合(例:バリデーションとSQL発行)に凝集性が低下する傾向があります。
また、凝集度の程度は以下のように分類されます。(上に行くほど良い)
-
機能的凝集: 単一のタスクを定義する(例:2つの自然数の和を計算する)
-
逐次的凝集: ある部分の出力が別の部分になるような関数を集めたモジュール(例:全体でファイルを読み込み、処理をするモジュール)
-
通信的凝集: 同じデータを扱う関数をまとめたモジュール(例:ユーザ情報を扱う関数を集めたモジュール)
-
手続き的凝集: ある処理を行うときに実行される関数を集めたモジュール(例:入力値のバリデーションとデータ書きこみ)
-
時間的凝集: プログラムを動かしたときにモジュール内の関数が連続して動く(例: エラーログを書き込む関数とエラーを管理者に通知する関数を集めたモジュール)
-
論理的凝集: 論理的に同じような関数を集めたモジュール(例: 何かしらのデータ書き込みをする関数群)
-
偶発的凝集: 適当な関数が集まったモジュール
#疎結合(Loosely coupled)
疎結合とは個々のモジュールやコンポーネント同士が直接的に依存していない状態を指します。
別のモジュールを呼び出す際に直接呼び出すのではなく、つなぎ目となるコードを経由して呼び出すことで疎結合な状態が実現されると言われます。(個人的には別のコードを関節的に呼び出すことで疎結合になる理由がいまいち理解できません...)
凝集性と同じようにモジュールの結合度にも程度があります。(上に行くほど良い)
-
データ結合: 引数で単純なパラメータを渡す
-
スタンプ結合: 引数でオブジェクトを渡す
-
制御結合: 関数の処理を外部のデータによって制御している状態
-
外部結合: 1つのグローバル変数を参照している
-
共通結合: 複数のグローバル変数を参照している
-
内部結合: 他のオブジェクトの内部を参照している
業務では制御結合と外部結合の状態にあるコードをよく目にします。
制御結合を解消するためには詳細な処理を別モジュールや別関数に隔離して、呼び出し元では引数にかかわらず同じ処理をするようにしておくと良いようです。(その別モジュールが制御結合状態になるのでは...?という疑問もありますが...)
余談
こういう特定の技術や言語に依存しない知識は汎用性が高いと思うのでドンドン習得したいです。