【ITニュース解説】Domain modeling, Units-of-Measure, and Property-based testing, oh my
2025年09月09日に「Dev.to」が公開したITニュース「Domain modeling, Units-of-Measure, and Property-based testing, oh my」について初心者にもわかりやすいように丁寧に解説しています。
ITニュース概要
プログラミング言語F#で遊園地のアトラクションをモデル化し、安全なプログラムを設計する手法を解説。身長の「cm」や時間の「s」といった単位を型として扱うことで計算ミスを防止し、不正な値の生成を制限するテクニックも紹介する。(118文字)
ITニュース解説
ソフトウェア開発において、システムが扱う対象、例えばテーマパークの「乗り物」や「来園者」といった現実世界の概念やルールを、プログラムのコード上で正確に表現する設計手法を「ドメインモデリング」と呼ぶ。この手法の目的は、ビジネス上のルールから逸脱した不正なデータがシステム内に存在しないようにし、プログラム全体の安全性と正確性を高めることにある。ここでは、関数型プログラミング言語であるF#を用いて、テーマパークのシステムを題材に、堅牢なドメインモデリングを実践する過程を解説する。
まず、システムの中心となる「乗り物(Ride)」というデータ構造の設計から始める。乗り物には名前、最低年齢、最低身長、待ち時間といった情報が含まれるが、これらの情報には守られるべきルールが存在する。例えば、名前が空欄であったり、最低年齢がマイナスの値であったりすることは現実にはあり得ない。このような不正なデータが作られるのを防ぐため、「プライベートコンストラクタ」というテクニックが用いられる。これは、オブジェクトを生成するための設計図(コンストラクタ)を外部から直接呼び出せないように非公開(private)にし、代わりに特定の信頼できる関数を通してのみオブジェクトを生成できるようにする仕組みである。この関数内で、渡された値が妥当であるか(名前が空でないか、年齢が正の数かなど)を厳密にチェックすることで、システム内には常に正しい状態のオブジェクトしか存在しないことを保証できる。
さらに安全性を高めるため、「制約付き型」という考え方も導入される。これは、例えば「空でない文字列」や「正の整数」といった、特定の条件を満たす値しか格納できない、独自の新しい型を定義するアプローチである。もし不正な値を使ってこの型のインスタンスを生成しようとした場合、プログラムを強制終了させる例外を発生させるのではなく、F#の「Option型」という仕組みを使って処理の失敗を表現する。Option型は、処理が成功して値が存在する状態(Some)と、失敗して値が存在しない状態(None)のいずれかを取り、これによりプログラムの実行を止めることなく、失敗したケースを安全に取り扱うことが可能になる。
F#には、ドメインモデリングをさらに強力に支援する「Units-of-Measure(単位)」という独自の機能がある。これは、数値データに対して「年(yr)」「センチメートル(cm)」「秒(s)」といった物理的な単位を型情報として付与できる機能である。この機能の最大の利点は、異なる単位を持つ値同士の計算や比較を、プログラムの実行前にコンパイラがエラーとして検出してくれる点にある。例えば、「最低年齢(単位:年)」と「待ち時間(単位:秒)」を誤って足し合わせようとするコードは、コンパイルの段階で型エラーとなり、単位の混同によって引き起こされる潜在的なバグを未然に防ぐことができる。
しかし、このように安全性を追求した設計は、時として新たな課題を生むことがある。今回の例では、乗り物の型を非公開(private)にした結果、その内部のデータに外部からアクセスできなくなった。これにより、プログラムが正しく動作しているかを確認するための「テスト」を書くことが困難になるという問題に直面した。この問題を解決するため、非公開の「Ride」型と全く同じデータ構造を持つ、公開された(public)「RideView」という閲覧用の型を別途用意するという手法が取られた。そして、非公開のRideオブジェクトを公開されたRideViewオブジェクトに変換するための専用の関数を設けた。この工夫により、テストコードからでも安全にオブジェクトの内部状態を確認できるようになり、システムの安全性とテストのしやすさという二つの要件を両立させることができた。
このように、ドメインモデリングでは、プライベートコンストラクタ、制約付き型、そして単位といった機能を組み合わせることで、プログラムの堅牢性と正確性を大幅に向上させることが可能である。設計の過程で発生するトレードオフや課題に対し、創造的な解決策を見つけ出していくことは、実践的なソフトウェア開発における重要なプロセスと言えるだろう。