【62】プリミティブ型よりドメイン固有の型を
1999 年 9 月 23 日、火星探査機「マーズ・クライメイト・オービター(MCO)」は火星を周回する軌道への突入に失敗し、燃え尽きました。3 億 2730 万ドルが失われた原因は、ソフトウェアのエラーでした。そのエラーは、具体的には「単位の混在」でした。同じ数値の単位を、地上のソフトウェアではポンドとしていたのに対し、宇宙船ではニュートンとしていたのです。その結果地上では、宇宙船のスラスタ推力を実際の約 4.45 分の 1 とみなしてしまうことになりました。
データの型付けがもっと強ければ、あるいはドメイン固有の型が使われていれば問題の発生を防げたという事例は数多くありますが、MCO の事故もその 1 つと言えるでしょう。プログラミング言語 Ada には、これを根拠とする機能が多数組み込まれています。Ada は、安全性が特に重要視される組み込みソフトウェアの実装を目的として設計された言語だからです。Ada は型付けが強く、プリミティブ型とユーザ定義型の両方について、以下のような静的チェックをするという特徴があります。
type Velocity_In_Knots is new Float range 0.0 .. 500.00;
type Distance_In_Nautical_Miles is new Float range 0.0 .. 3000.00;
Velocity: Velocity_In_Knots;
Distance: Distance_In_Nautical_Miles;
Some_Number: Float;
Some_Number:= Distance + Velocity; -- コンパイラが型エラーを検出
さほど要求の厳しくないドメインでも、文字列や浮動小数点数といった言語(あるいはそのライブラリ)の提供するプリミティブ型を使うより、ドメイン固有の型を使う方が好ましいという場合は珍しくありません。最近では Java、C++、Python など、抽象データ型をクラスとして表現する言語も増えています。たとえば、Velocity_In_Knots
(速度のデータを扱う型。単位は常に「ノット」)、Distance_In_Nautical_Miles
(距離のデータを扱う型。単位は常に「海里」)といった型を、クラスとして表現することができるのです。こうした型を定義すれば、コードの品質を大きく向上させることができるでしょう。それは具体的には次のような利点があるためです。
- コードが読みやすくなる。ドメインの重要な概念を表す言葉がそのまま型の名前になっているので、Float、String といった型名が使われるより、意味がわかりやすい。
- テストがしやすくなる。機能一つ一つがカプセル化され、他から独立するため、1 つ 1 つのテストがしやすくなる。
- コードの再利用が容易。同じコードを複数のアプリケーションやシステムに簡単に再利用できる。
この種のアプローチは、静的な型付けの言語でも、動的な型付けの言語でも同様に有効です。両者の違いは、静的な型付けの言語では、コンパイラが型のチェックをしてくれるのに対し、動的な型付けの言語では、ユニットテストで型のチェックをせざるを得ないということくらいでしょう。ただ、型チェックの手段は違っても、ドメイン固有の型を使う目的や、その使い方は基本的に同じです。
マーズ・クライメイト・オービターの事故を貴重な教訓とし、ドメイン固有の型を積極的に使ってソフトウェアの品質を高めるべきです。