エンティティの分析と設計

Created: 2025-09-08

ドメイン・モデル (Domain Model)の中心となるエンティティの分析モデルと設計モデルの違いについて考察します。

分析モデルから設計モデルの構築では非機能要求(特に品質属性 (Quality Attribute))への考慮が重要な拡張項目です。

しかし、構造モデル自身にも拡張すべき項目が存在します。

中でも代表的なのが、エンティティを操作 (Operation)するための用途別オブジェクトの導入です。

本記事では、プログラムにおけるエンティティ表現の設計方針とアーキテクチャ、およびその自動生成の可能性について深掘りします。

プログラムにおけるエンティティの表現

SimpleModelingリファレンス・プロファイル (SMRP, SimpleModeling Reference Profile)ではプログラミング言語としてScalaを採用しています。

したがってエンティティの設計はScalaプログラムとして具現化されます。

SMRPではエンティティを操作する方式として、ここではバリュー・オブジェクト (value object)を使用する方式を採用しています。 このためエンティティの設計はScalaで記述したバリュー・オブジェクトの設計が中心となります。

単純な対応の限界

以下の図は、エンティティを操作するバリュー・オブジェクトを1つだけ使用する場合の入出力アーキテクチャの例です。

単純なバリュー・オブジェクトを軸とした入出力アーキテクチャ
図 1. 単純なバリュー・オブジェクトを軸とした入出力アーキテクチャ

バリュー・オブジェクトを使った場合、データの更新時に「データ読み込み・上書き・書き戻し」の非効率な処理になってしまいます。

また、型安全性を犠牲にして汎用的なRecord型を使うと、プログラムの信頼性 (Reliability)が低下します。

異なる目的の処理に同一のバリュー・オブジェクトを使うと、使用方法との不整合が起きたり、余分な考慮が必要となったりします。

データ操作アーキテクチャ

図はSMRPで採用しているデータ操作アーキテクチャです。

エンティティ入出力のアーキテクチャ
図 2. エンティティ入出力のアーキテクチャ

エンティティの入出力を行う際、アプリケーションは以下の選択肢を取ることができます。

  • オペレーション用のエンティティ・バリューを使用

  • I/O用のエンティティ・バリューを使用

  • レコード機能を使用

  • プラットフォーム (Platform)の機能を直接使用

より上位の機能を使用するほど、型安全性によりプログラミングの容易さや信頼性が向上します。

Record

SMRPでは汎用のレコード・オブジェクトを用意しています。

細かな用途ごとに専用のScalaクラス (Class)を用意するのは煩雑であり、工数もかかります。 また、似て非なるクラスの数が増えすぎると、逆にバグ (bug)の発生を誘発してしまう可能性もあります。

こういった隙間の処理のための受け皿として使用するのがレコード・オブジェクトです。

SimpleModelingLibでは、以下のレコード・オブジェクトを用意しています。

  • org.simplemodeling.record.Record

エンティティの用途別クラス

分析モデルではエンティティを1種類のクラスとして定義しますが、設計モデルでは用途別に複数のクラスを定義し、それぞれ相互変換できる構成が望まれます。

シンプルなアプリケーションでは、エンティティとScalaクラスは一対一の関係で十分ですが、アプリケーションが本格的になると、用途ごとに複数のScalaクラスが必要になります。

エンティティの種類
図 3. エンティティの種類

分析モデルではエンティティを1種類のクラスとしてモデル化しますが、設計モデルでは用途別に複数のクラスを用意し、それぞれの相互変換を可能にしておく必要があります。

主な用途分類

  • ロジック処理用

  • ビュー (View)

  • エンティティ操作

    • 読み込み

    • 新規作成

    • 更新

    • 一括更新

  • 外部連携

モデル空間における配置

アプリケーションのオペレーションスペースには、ロジック処理用のバリュー・オブジェクトが配置されます(図中では Entity Value for Operation)。

ビュースペースには、外部表示用のバリュー・オブジェクト(Entity Value for View)が配置されます。

エンティティ操作用には、以下のバリュー・オブジェクトがそれぞれの目的に応じて設計されます。

  • 読み込み用:Entity Value for Read

  • 新規作成用:Entity Value for Create

  • 更新用:Entity Value for Update

  • 一括更新用:図では省略

外部連携用には、Entity Value for Exchange が用意されています。

分析モデルの例

SimpleModeling (シンプルモデリング)では、分析モデル・アップ・ダウン (Analysis Model Up/Down)のコンセプトに基づき、CML (Cozy Modeling Language)で記述した分析モデルから設計モデルを作成します。

以下のソースは、分析モデル Reservation をCMLで記述した例です。

Error[java.io.FileNotFoundException: Users/asami/src/dev2025/simplemodeling-org/src/main/doxsite/domain-modeling/project.d/analysis-design-entity/src/main/cozy/reservation.cml (No such file or directory)] === 分析モデルをScalaで実現

分析モデルを素直にScalaオブジェクトとして実装すると、以下のようになります。

Error[java.io.FileNotFoundException: Users/asami/src/dev2025/simplemodeling-org/src/main/doxsite/domain-modeling/project.d/analysis-design-entity/src/main/scala/com/example/sample/entity/Reservation.scala (No such file or directory)] == 設計モデル

分析モデルから派生させた設計モデルとして、以下の用途別Scalaオブジェクトを定義してみましょう。

  • ロジック処理用

  • ビュー

  • エンティティ操作

    • 読み込み

    • 新規作成

    • 更新

    • 一括更新

  • 外部連携

ロジック処理

CQRSのコマンド(Command)では、更新処理を中心として複雑なドメイン・ロジックが実行されます。

これらの処理では、メモリ上でエンティティの操作を行います。 そのため、メモリ上での複雑なドメイン・ロジック処理に必要な情報量を持ったクラスを定義する必要があります。

Error[java.io.FileNotFoundException: Users/asami/src/dev2025/simplemodeling-org/src/main/doxsite/domain-modeling/project.d/analysis-design-entity/src/main/scala/com/example/sample/entity/logic/Reservation.scala (No such file or directory)] ロジック処理に必要な情報は、参照先オブジェクトの内容を展開してバリューとして保持する必要があります。

ただし、参照先オブジェクトの全情報を展開する必要はありません。 外部に公開可能な情報のみを展開して保持します。 ビューほどは厳密でなくても構いません。

たとえば、属性 (Attribute) user はデータ型 (Data Type) UserId ではなく、展開されたバリュー User として保持されます。

ビュー用のクラスも、参照先のオブジェクト (Object)を展開して保持する構成になります。

ビュー

クラウド・ネイティブ・アプリケーションは必然的にCQRSのアーキテクチャになります。 CQRSのアーキテクチャでは、問い合わせに対するデータとしてビューを用意します。

このビュー向けのエンティティのバリュー・オブジェクトが必要となります。

Error[java.io.FileNotFoundException: Users/asami/src/dev2025/simplemodeling-org/src/main/doxsite/domain-modeling/project.d/analysis-design-entity/src/main/scala/com/example/sample/entity/view/Reservation.scala (No such file or directory)] 参照処理に必要な情報は、参照先オブジェクトの内容を展開してバリューとして保持する必要があります。 ただし、参照先オブジェクトの全情報を展開する必要はありません。 外部に公開可能な情報のみを展開して保持します。

たとえば、属性 resource はデータ型 ResourceId ではなく、バリュー Resource として保持されます。

同様に、属性 user は UserId ではなく、展開されたバリュー User を保持します。

エンティティ操作

データベース上で永続化 (Persistence)されるエンティティに対して操作を行うためのバリュー・オブジェクト群です。

読み込み

エンティティを単体で読み込む際に使用するScalaクラスです。

データベースとの親和性を高めるため、基本データ型 (Type)を中心に構成されます。

Error[java.io.FileNotFoundException: Users/asami/src/dev2025/simplemodeling-org/src/main/doxsite/domain-modeling/project.d/analysis-design-entity/src/main/scala/com/example/sample/entity/read/Reservation.scala (No such file or directory)] 属性にはScala/Javaの基本型やSQLで扱いやすいを用いています。

interval 属性は、アプリケーション内部では ZonedDateTimeのInterval ですが、データベースに格納するために String で保持されます(XMLやJSONにエンコード)。

読み込み用のクラスでは、分析モデルの定義に従って Option を適切に使用します。

新規作成

エンティティを新規作成する際に使用するScalaクラスです。

必須項目は必ず指定されるようにし、それ以外は Option で定義されます。

Error[java.io.FileNotFoundException: Users/asami/src/dev2025/simplemodeling-org/src/main/doxsite/domain-modeling/project.d/analysis-design-entity/src/main/scala/com/example/sample/entity/create/Reservation.scala (No such file or directory)] ==== 更新

エンティティを更新する際に使用するScalaクラスです。

IDは必須属性として含まれ、それ以外の更新対象属性は Option で定義されます。

Error[java.io.FileNotFoundException: Users/asami/src/dev2025/simplemodeling-org/src/main/doxsite/domain-modeling/project.d/analysis-design-entity/src/main/scala/com/example/sample/entity/update/Reservation.scala (No such file or directory)] 実際には、Option だけでは「今回の更新で無視する項目」なのか「NULL に設定して値を削除したい項目」なのかが曖昧になります。

一括更新

エンティティのIDを使わず、条件と更新値の組み合わせで一括更新したい場合に使用されるScalaクラスです。

Error[java.io.FileNotFoundException: Users/asami/src/dev2025/simplemodeling-org/src/main/doxsite/domain-modeling/project.d/analysis-design-entity/src/main/scala/com/example/sample/entity/updates/Reservation.scala (No such file or directory)] 基本的には Update クラスと同様の構造ですが、id 属性が含まれていません。

id 以外の条件に一致するエンティティを一括で更新する用途に用いられます。

外部連携

外部連携を行う場合には、Scalaクラスと各種データフォーマット(XML, JSON, YAMLなど)との相互変換が必要になります。

  • XML

  • JSON

  • YAML

  • HOCON

  • Properties

  • gRPC IDL

これらの変換処理を都度手書きするのは大変なため、可能な限り汎用のデータ変換ライブラリを利用します。

SimpleModelingのリファレンス・プロファイルでは、Catsファミリーの Circe を採用しています。

Error[java.io.FileNotFoundException: Users/asami/src/dev2025/simplemodeling-org/src/main/doxsite/domain-modeling/project.d/analysis-design-entity/src/main/scala/com/example/sample/entity/exchange/Reservation.scala (No such file or directory)] データベース連携と同様に、各フォーマットとの変換を容易にするために、属性はできるだけ基本型に抑えます。

Circe が直接サポートしていないフォーマットであっても、この形式のクラスであれば比較的容易に連携処理を実装できます。

文芸モデル駆動開発

ここまで、ドメイン・モデルにおける分析モデルと設計モデルの対応について、特にエンティティの永続化の観点から考察してきました。

型安全なエンティティ操作を実現するためには、一つのエンティティに対して用途に応じて複数のバリュー・オブジェクトを定義する必要があります。

これらのクラスを人手でコーディングするのは非常に手間がかかりますが、この問題はプログラムの自動生成によって解決できます。

SimpleModelingでは、モデル・コンパイラ「Cozy」を用いて、CMLで記述された分析モデルから、以下のような用途別の設計モデル(Scalaクラス)を自動生成します。

  • ビュー

  • ロジック処理

  • エンティティ操作

    • 読み込み

    • 新規作成

    • 更新

    • 一括更新

  • 外部連携

まとめ

本記事では、ドメイン・モデルにおけるエンティティの分析モデルと設計モデルの違いに注目し、それぞれの用途に応じたバリュー・オブジェクトの設計方針と、Scalaでの具体的な実装例を通じて、その構成と役割を明らかにしました。

また、各用途(ビュー、ロジック処理、操作、外部連携)ごとに最適化されたクラス群を用意することで、型安全性と開発効率の両立が可能になることを示しました。

さらに、モデル記述とコード生成を統合する文芸モデル駆動開発 (LMDD, Literate Model-Driven Development)(Literate Model-Driven Development)の枠組みの中で、Cozyによる自動生成の活用が、この設計方針を持続可能なものにする鍵であることも紹介しました。

今後は、他のドメインへの適用や生成対象の拡張、さらにUIモデルやAPI仕様との統合といった展開も期待されます。

参照

用語集

ドメイン・モデル (Domain Model)

Undefined

品質属性 (Quality Attribute)

Quality Attributeとは、ソフトウェアが機能を実行できることに加えて、どの程度の品質で要求を満たすかを表す特性です。Security、Performance、Availability、Reliability、Resilience、Observability、Maintainabilityなどが含まれます。

操作 (Operation)

UMLにおけるOperationは、関連するBehaviorを呼び出すための名前、型、Parameter、Constraintを定めるClassifierのBehavioral Featureです。Operationは呼び出し契約を定め、MethodなどのBehaviorがその実現を担います。

SimpleModelingリファレンス・プロファイル (SMRP, SimpleModeling Reference Profile)

SimpleModelingのリファレンス・プロファイルです。 SimpleModelingによる文芸モデル駆動開発の説明を具体的にするために、リファレンス・プロファイルを定義しています。

Scala

Undefined

バリュー・オブジェクト (value object)

バリュー・オブジェクトは、ドメイン・モデルにおいて属性や説明などの意味的まとまりを持った値の集合を表すオブジェクトです。 エンティティのような永続的識別子は持たず、不変であり、等価性は値によって判断されます。

信頼性 (Reliability)

Reliabilityとは、指定された条件と期間のもとで、システムが要求された機能を一貫して遂行する性質です。Availability、Fault Tolerance、Recoverabilityなどを含む観点から評価します。

型安全 (type safety)

型安全とは、プログラムにおける型の整合性をコンパイル時または実行時に保証する性質を指します。 型安全性が保たれているとき、ある型に対して定義されていない操作を実行しようとした際にエラーとして検出され、 意図しない動作やバグの発生を防ぐことができます。 Scalaは強い静的型付けと型推論を併用することで、高い型安全性を維持しつつ柔軟なプログラミングを可能にしています。

プラットフォーム (Platform)

Platformとは、ソフトウェアを構築、配置、実行、運用するために共通して利用する技術的な基盤とサービスの集合です。

クラス (Class)

Undefined

バグ (bug)

俗語的にソフトウェアの不具合を指す用語。厳密な技術的定義はなく、Defect や Fault、Failure を広く含む日常的な表現。

ビュー (View)

Viewとは、Modelを特定のPurposeとConcernに応じて選択し、理解、判断、検証、利用できる形で投影した表現です。ViewはModelの一部を見せるものであり、元のModelとは別に意味を所有しません。

Cozy Modeling Language (CML)

CML(Cozy Modeling Language)は、オブジェクト・モデルのうち、プログラム生成と実行へ接続する実行可能モデルを記述するSimpleModelingの形式モデリング言語です。

分析モデル・アップ・ダウン (Analysis Model Up/Down)

分析モデル・アップ・ダウンとは、分析モデルを中核に据え、そこから概念モデルや設計モデルを「上(アップ)」へ導出し、また具体的なコードやデータ定義などを「下(ダウン)」に展開する双方向的なモデリング手法です。

シンプルモデリング (SimpleModeling)

SimpleModelingは、KnowledgeからDomain Modelを構成し、CMLで形式化し、CozyとAIによって実行可能ソフトウェアへ実現し、Textus上で動作させる、モデリング中心のソフトウェア開発方法論と技術体系です。

モデル (Model)

Modelとは、対象を特定のPurposeとConcernに基づいて選択し、理解、判断、検証、構築に利用できる形で表した抽象です。対象そのものではなく、目的に必要な要素、関係、意味を保持する表現です。

データ型 (Data Type)

UMLにおけるData Typeは、InstanceがIdentityではなく値によって識別されるClassifierです。Data TypeのInstanceは、同じ値を持つ場合に区別されません。

属性 (Attribute)

Attributeとは、ClassifierのInstanceが保持し得る値または参照を表すStructural Featureです。Attributeは名前、Type、Multiplicity、既定値、Constraintなどによって特徴付けられます。

オブジェクト (Object)

Objectとは、Classまたは他のClassifierによって分類され、構造、State、Behaviorを持ち得るInstanceです。Objectは、同じClassifierの他のInstanceと区別して参照できる個体として扱われます。

永続化 (Persistence)

Undefined

型 (Type)

Undefined

Cozy

Cozyは、CMLと各種DSLで記述されたModelを解析し、プログラム、設定、文書などの実現成果物へ変換するSimpleModelingのツールチェーンです。

文芸モデル駆動開発 (LMDD, Literate Model-Driven Development)

文芸モデル駆動開発(Literate Model–Driven Development, LMDD) は、自然言語による語りと形式的なモデル構造を統一されたテキスト基盤上で統合するソフトウェア開発手法です。従来のモデル駆動開発(MDD)を拡張し、ドキュメントとモデルを単一の整合的ソースとして扱います。 LMDDでは、開発成果物の記述要素と構造要素をSmartDox言語を用いて同時に表現します。この統合的な表現から、ModelDoxが構造データを抽出し、CML(Cozy Modeling Language)がドメイン固有モデルを定義し、Cozyが実行可能なコード、ドキュメント、構成情報などの成果物を生成します。 人工知能(AI)は、語りの文脈を解析し、構造の整合性を検証し、モデルおよび生成成果物の改良を支援することでLMDDプロセスに関与します。すべての成果物はテキスト形式で表現されるため、トレーサビリティ、バージョン管理、標準的な開発環境との相互運用性が確保されます。 ドキュメント、設計、実装の間に形式的かつ機械可読な関係を定義することにより、LMDDは人間による記述と機械による推論が同一の表現層で機能する、AI支援型モデル駆動開発の基盤を提供します。