副作用のある処理を分離する設計とは?単体テスト自動化と静的解析を劇的に楽にする設計思想を徹底解説
単体テストの自動化や静的解析を導入しようとしたとき、思った以上にテストが書けず、解析ツールから大量の警告が出て困った経験はありませんか。
その原因を深掘りしていくと、ほぼ必ずと言っていいほど出会うのが「副作用のある処理が分離されていない設計」です。
私自身、SEとして業務システムやWebアプリケーションの開発に長年携わってきましたが、単体テストが進まない現場の多くは、この設計が原因でした。
この記事では、単体テスト自動化と静的解析の観点から副作用のある処理を分離する設計について、用語を丁寧に解説しつつ、実体験を交えて詳しく説明します。
副作用とは何か?まずは言葉の意味を正しく理解する
「副作用」という言葉を聞くと、薬の副作用を思い浮かべる方も多いかもしれません。プログラミングにおける副作用も、実はとても似た意味を持っています。
プログラミングにおける副作用とは、関数やメソッドが、戻り値以外の形で外部に影響を与えることを指します。
代表的な副作用の例
- データベースへの読み書き
- ファイルへの書き込み・読み込み
- 画面表示やログ出力
- 外部APIへの通信
- グローバル変数やクラス変数の変更
これらは業務システムでは必須の処理ですが、単体テストや静的解析においては非常に厄介な存在になります。
なぜ副作用があると単体テストが書きにくくなるのか
単体テストの基本は、「同じ入力に対して、常に同じ結果が返るか」を検証することです。
しかし副作用が混ざった処理では、テストの前提条件を整えるだけで一苦労になります。
筆者の失敗体験:DB更新と計算処理が混在したメソッド
私が新人SEだった頃、次のようなメソッドを書いていました。
- 注文金額を計算する
- 計算結果をDBに保存する
- ログを出力する
当時は「一つの処理だから一つのメソッドでいい」と考えていましたが、単体テストを書こうとした瞬間に問題が噴出しました。
テストのたびにDBを用意し、ログ出力の有無を気にし、失敗するとDBの中身が壊れる。
結果として「このメソッドはテストしづらいから後回し」という扱いになり、テストが存在しない危険なコードになってしまいました。
副作用のある処理を分離する設計とは何か
副作用のある処理を分離する設計とは、「純粋な計算・判断ロジック」と「外部に影響を与える処理」を明確に分ける設計のことです。
分離の基本的な考え方
- 計算・判定ロジック:副作用を持たない
- 入出力・保存処理:副作用を持つ
この考え方は、関数型プログラミングだけの話ではなく、オブジェクト指向や業務システム開発でも非常に有効です。
副作用を分離すると単体テストがどう変わるのか
副作用を分離した設計では、単体テストが驚くほど書きやすくなります。
テストしやすくなる理由
- DBやファイルを用意しなくてよい
- テストの実行速度が速い
- 失敗しても環境が汚れない
私が先ほどの注文金額計算処理を、計算ロジックとDB保存処理に分離したところ、計算部分のテストは数分で書けるようになりました。
それまで「テストが面倒」と感じていた気持ちが、「テストを書くと安心できる」に変わったのを今でも覚えています。
静的解析との相性が抜群に良くなる理由
静的解析ツールは、コードの構造や依存関係を解析して問題点を指摘します。
副作用が分離されていないコードは、以下のような警告が頻発しがちです。
- 循環参照
- 責務が多すぎるクラス
- テスト困難なメソッド
副作用を分離すると、クラスやメソッドの責務が明確になり、静的解析の警告数が目に見えて減ります。
実際、私の担当プロジェクトでは、設計を見直しただけで警告が半分以下になりました。
副作用分離を知っておくことで得られる具体的なメリット
① 単体テスト自動化が現実的になる
テストのための準備が減り、CI環境でも高速にテストが回せるようになります。
② バグの原因調査が圧倒的に楽になる
「計算が間違っているのか」「保存処理が悪いのか」を切り分けやすくなります。
③ 設計レビューで評価されやすくなる
責務が明確なコードは、レビューアーからの評価も高く、修正指摘が減ります。
応用編:さらに便利になる設計テクニック
依存性の注入(DI)を組み合わせる
副作用のある処理をインターフェース越しに注入すると、テスト時にモックへ差し替えられます。
「判断」と「実行」を分ける
「何をするか決める処理」と「実際にやる処理」を分けるだけでも、副作用の影響を大きく減らせます。
これは私が設計レビューで必ずチェックするポイントで、新人SEにも最初に伝える考え方です。
まとめ:副作用の分離はテストと品質の土台になる
副作用のある処理を分離する設計は、単体テスト自動化や静的解析のためだけのテクニックではありません。
コードの可読性、保守性、品質すべてを底上げする設計の基本です。
私自身、この考え方を身につけてから、テストが「面倒な作業」ではなく「安心を得るための作業」に変わりました。
ぜひ、今書いているコードの中で、副作用が混ざっていないかを一度見直してみてください。
その小さな一歩が、テストしやすく壊れにくいシステムへの大きな第一歩になります。

コメント