『整理して分解する』 〜 複雑なソースコードをコントロールする方法 〜
2023/11/10
2023/12/03
継続的なソフトウェア開発で複雑になってしまったソースコードに対処する方針について説明してみます。
手に負えない複雑さ
業務で扱っているソースコードをちょこっと修正したつもりなのに、他の場所でバグが発生する。機能追加するための調査に時間がかかる。そのような状態は、ソースコードが複雑になりすぎて手に負えない状況になっていると言えます。
主担当のプログラマーには修正できたとしても、サポートにはいったプログラマーにはとても手が出せない代物です。
最初から複雑であった訳ではない
複雑ではないソフトウェアというのは、例えばrailsのscaffoldで生成した後、多少の機能追加を行なったようなソフトウェアです。新規にソフトウェアを作ったときは、特に迷うことなくコードを追加することで目的の機能も実現できて、修正もできるし拡張も可能です。
しかし、継続的に機能追加をしながら運用を1年も行なうと、妙に更新頻度の多い神コントローラーや神モデルが出てきて、複雑さが目立ってきがちです。
複雑さを制御する
神コントローラーや神モデルに宿った複雑さを制御可能にするには、整理して分解するしか道はありません。
分解したから全体としてシンプルになるかというと、そうゆう訳にはいかないのですが、適切に分解すれば個々の要素はシンプルになりコントロール可能となり、個々の要素が協調して仕事をすることで、全体として見たら複雑な仕事をこなせるようになっている。という状態になります。
「整理して分解する」の目指すのはそのような状態です。まず最初に「整理して分解する」ことを強調しているのは、複雑さを制御する目的であれば、様々な便利な設計原則を適応するより前に、分解する場所を探すことが必要になるからです。
分解の方針
「整理して分解する」方針というのは、いくつか考えられます。
1. コードをブロックとして把握する
長いメソッドを処理の塊でプライベートメソッドに分けるというのも、方針の一つです。よくある例では、「入力チェックをした後、外部システムのAPIを呼び出し、テーブルの更新し、不要になったファイルを削除する」のような処理が、ずらずらと1つのメソッドで記載されていたら、それぞれをブロックとして見做すことができるので、プライベートメソッドに切り出すことができます。
2. 副次的な処理の塊をイベント処理と見做す
あるメソッドの処理が「ユーザーの入力した内容をデータベースに登録して、その後その結果を、管理者にメールで通知する」となっていた場合、メール通知は、副次的な処理として、イベントと見做してロジックを切り離すことができます。イベント処理はフレームワークが提供している仕組みを使うのが簡単です。
3. コードの一部に現れる概念に注目する
より効果的な「整理して分解する」方針は、注目した概念とそれ以外に分解することです。
概念とは、人間が認識している対象に名前を付けたものという、簡易的な定義とするとしたら、複雑なコードから意味のある塊(様々な箇所に散らばっているかもしれない)を見付けて、それに適切な名前を付けて概念として切り離します。
この方針は、一度で劇的に効果を発揮する訳ではないですが、適応を繰り返すことで効果が高くなります。
概念をクラスとして実装するということは、概念は機能を提供する側となり、それ以外が概念を利用する側となります。
このとき、機能を提供する側と機能を利用する側の関係(インターフェース)をどのようにするかによって、設計の善し悪しに影響します。
機能を提供する側のインターフェースをどのように定義するのが適切かという観点において、SOLID原則などの設計原則が参考になります。また、概念をどのようなオブジェクトとして振る舞わせるかを考えるにあたり、『オブジェクト設計スタイルガイド』が良いガイドになります。
まとめ
継続的なソフトウェア開発で複雑になってしまったソースコードに対処する方針について説明してみました。
「整理して分割する」ための方針をリストアップして説明してみたのですが、他の方針を知っている方がいたら教えてください。
複雑なソースコードに対処することは簡単なことではないので、地道に整理して分割していきましょう。