🚢

開発プロジェクトをタイタニック号にしないために

2024/05/24に公開

家の使い勝手をよくするために片付けやDIYしていると、「これはリファクタリングだな」と思いませんか?最近、いろいろな物事をついついエンジニア視点で解釈してしまうクセが身についてしまいました。

今回の記事ではタイタニック号とレガシーコードには共通点があると思ったので、そこから開発プロジェクトを沈没させない方法をまとめたいと思います。

なぜ、タイタニック号は沈んだのか

まずはタイタニック号が沈んだ原因分析から始めましょうか。沈没までの経緯は次の通りです。

  1. 複数の船から連絡された氷山についての警告を無視
  2. 氷山にぶつかってしまった
  3. 船内にどんどん海水が浸入した
  4. 浸入した海水は、とうとう隔壁を乗り越えて隣の区画へ
  5. 複数の区画が浸水し、船体が折れた

タイタニック号の沈没について理解するには、区画、隔壁といった船の構造について知る必要があります。

21世紀現在、新たに建造されるすべての大型船では、船体内部は船底から上甲板へ達する水密隔壁により多数の水密区画に分割されていて、浸水時にも浸水範囲を限定することで浮力を大きく失わないようにしている。また、船底は「二重底」(Double Bottom)になっており、万が一、座礁などで浸水が始まっても沈没しないだけの必要な浮力を温存することや、たとえ多数の水密区画が浸水するような重大な事故においても出来るだけ長い避難時間を稼げるように考慮されている。(wikipedia『船体』より)

つまり船の中は複数の区画に分かれていて、区画を隔てる壁を防水隔壁と呼ぶそうです。

そしてタイニック号の場合、この防水隔壁の高さが不十分で、隔壁の上部から隣の区画に海水が流れ込む設計になっていました。

設計者の想定としては、隣の区画へ海水が流れ込むためには船体が傾くほどの損傷を受ける必要があり、4区画までは損傷を受けても海水が流れ込まない設計になっていました。しかしタイタニック号と氷山の衝突では6区画が損傷・浸水してしまったので、船体は大きく傾き、海水は防水隔壁を乗り越え、どんどん隣の区画へと海水が流れ込みました。

タイタニック号には他に二隻の姉妹号の製造が予定されていました。三隻目のブリタニック号はタイタニック号沈没の後に起工したためその設計は大きく見直されており、二重船底部位や防水隔壁の拡張など安全面の強化が図られました。

タイタニック号とレガシーコードの共通点

開発プロジェクトをタイタニック号の話に準え(なぞらえ)ます。まずタイタニック号は開発プロジェクトにおけるプロダクト、船の損傷はバグ、そして海水はデバックが必要な範囲です。

タイタニック号 開発プロジェクト
船の損傷 バグ
海水 デバックが必要な範囲

するとタイタニック号とレガシーコードは以下のように対比できます。

「タイタニック号は、損傷からすべての区画に海水が浸入する可能性がある設計であった。」
「レガシーコードは、バグが発見されるとすべてのコードのデバックが必要になる可能性がある。」

開発プロジェクトを沈没させない安全対策

タイタニック号の沈没から、ブリタニック号では二重船底部位や防水隔壁の拡張など、浸水範囲を限定するための設計が見直されました。

開発プロジェクトにおいて、デバックが必要な範囲を限定する方法を2つ紹介します。

  • 単体テストを書く
  • 高凝集で疎結合な設計にする

単体テストを書く

単体テストを書くことで、デバック範囲をコントロールできます。

もしバグに関係しているはずのコードに単体テストを書いていないコードがあれば、そこにバグがある可能性が高いのでそこからデバックします。

関心を分離する

「関心を分離する」というのは設計の大きな原則の一つです。

関心の分離が実践されていると、あるバグが発見されたときに、そのバグに関係のあるコード/ないコードという判断が簡単になり、関係のあるコードのみをデバックすることができます。

関心を分離する具体的な手法の1つとしてモジュールの設計について紹介します。関心によってモジュールを分割し、モジュールの凝集度が高くなるよう、モジュール同士は疎結合になるよう設計します。

モジュール、疎結合、凝集度というと難しく感じるかもしれませんが、次のように考えてもらうと分かりやすいと思います。

まず、モジュールとはコードを書いているファイルのことだと考えてください。

「凝集度を高めよう」については「ロジックを分類して、それらをどのファイルに書くべきかルールを決めましょう」ということです。チームでルールを共有しておくことでそれぞれのファイルには同じ関心に分類されるコードが集まります。有名なルールについては後述します。

「疎結合にしよう」については「あるコードが他のコードに依存している状態をできるだけ少なくしましょう」ということです。あるコードが他のコードに依存していることを結合と表現します。

これらが実践されているとデバック範囲が限定されるためデバックがスムーズに進められます。

関心を分ける具体的なルール

ロジックをどのように分けるのか、そしてどのような依存を許可するのか、というルールにはいくつか有名なものがあります。

  • レイヤードアーキテクチャ
  • ヘキサゴナルアーキテクチャ
  • クリーンアーキテクチャ

これらの各手法はドメイン駆動設計(Domain-Driven Design)の具体的な実装パターンとして紹介されるケースが多いですね。

私はドメイン駆動設計を全面的に採用したことはないのですが、ドメイン層をきっちり分けるという設計はいつも採用しています。ドメイン層が適切に分けれられていれば、他の部分については有名なアーキテクチャを採用しなくてもあまり大きな問題はないと考えています。例えばクリーンアーキテクチャを100%採用するためにはチームとして大きな学習コストを払う必要があるでしょう。そのためチームのレベル感とのバランスが重要だと思っています。

まとめ

船の設計パターンにおいては、ある設計が安全性に与える影響を評価しやすいと私は思います。隔壁の上部が空いているケースと空いていないケースで、どちらがより安全かというのはイメージしやすいですよね。

しかし、ソフトウェアの設計パターンは安全性に与える影響を評価することが難しいです。
それぞれの共通点を理解することで、ソフトウェアの設計パターンによる安全性の理解が深まると思い、記事にしました。それでは快適な開発ライフを。

Discussion