ネクストデザイン | |
DDBuilderは、ネクストデザインが開発した無料・無保証のツールです。
DDBuilderは、ドメイン駆動設計されたドメインモデル (Java実装モデル) から Java Web アプリケーションを自動生成します。 開発者は、Web アプリケーションを操作して、ドメインモデルを素早く検証できるようになります。 ドメイン駆動設計では、反復型開発が基本です。 開発者はドメインモデルを繰り返し洗練 (ブラッシュアップ) しながらシステムを完成に近づけていきます。 イテレーションを軽快に回せることは、ドメイン駆動設計による開発の重要な要素です。
[反復型開発の流れ]
ドメイン駆動設計では、ドメインモデル、実装、ユビキタス言語の3つを整合させながら反復することが重要です。
※反復型開発という名前は、イテレーティブ開発やインクリメンタル開発、アジャイル開発などと似ていますが、本記事では、特に区別しません。
[イテレーションの内容]
繰り返しの単位をイテレーションと呼びます。各イテレーションの中では、分析から設計、実装、検証まで行います。
各イテレーションでは、開発者はドメインモデルをリファクタリング (洗練) します。 次にドメインモデルの実装を変更し、変更後の振る舞いを確かめます。 確かめる方法は、JUnitテストからドメインモデルを動かすなど、色々と考えられます。 一つは、ドメインモデルをドメイン層に配置した Webアプリケーションの形で動かしてみることです。 Webアプリケーションを実行し、ブラウザからアプリケーション画面を操作し、結果を確認します。そうすれば、分かりやすく検証できます。机上では不十分です。 本稼働時と同じ実装フレームワークを使って確認することがベストですが、工数的に困難な場合もあります。 ドメインモデルを検証するために、本稼働時と同じ実装フレームワークである必要はありません。 本ツールが生成する Webアプリケーションは、Wicket + Java EE サーバを使用しますが、 そこで検証されたドメインモデルを、例えば Spring Boot + Thymeleaf 等に組み込むことは困難ではないでしょう。
イテレーションを軽量化して、ドメインモデリングに集中することが大事です。 以下に、ドメインモデルから検証用アプリケーション (Java Web アプリケーション) を自動生成する例を紹介します。
[関連] ドメインモデルの役割と例
[留意] ※DDBuilder は JPA Hibernate を使用が前提です。 そのため、エンティティクラスに @Entity や @ManyToOne などの Hibernate アノテーションを記述する必要があります。 ドメインモデルをリファクタリングするとアノテーションの変更が必要な場合もあります。 DDBuilder を使うことで、ドメインモデルの検証アプリを素早く作成できますが、アノテーションの変更も負担になりますし、不整合も起きやすい作業です。
簡単な「在庫管理業務」を例に説明します。
このドメインのドメインモデルには、4つのクラスが存在し、それぞれのクラス名、クラス図、Java実装コードは以下の通りです。
(クラス名)
倉庫クラス : Warehouse
在庫クラス : Stock
製品クラス : Product
在庫サービスクラス : StockService
(クラス図)
(Java 実装例)
package mycom.domain;
import java.util.List;
import javax.persistence.Entity;
import javax.persistence.OneToMany;
import mycom.domain.ddb.DdBaseEntity;
/**
* 製品
*/
@Entity
public class Product extends DdBaseEntity {
/** 製品名 */
private String name;
/** 在庫リスト */
@OneToMany(mappedBy="product")
private List<Stock> stockList;
/** コンストラクタ */
public Product() {
super();
this.name = "";
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public List<Stock> getStockList() {
return stockList;
}
public void setStockList(List<Stock> stockList) {
this.stockList = stockList;
}
@Override
public String getDDBEntityTitle() {
return "タイトル: " + this.getName();
}
}
なお、このドメインモデルは、自動生成機能を説明することが目的のため、ドメインモデルらしい振る舞い等は含んでいません。つまり、ドメイン駆動設計としては推奨されない、ドメインモデル貧血の状態であることに注意してください。
EclipseにインポートしたWebアプリケーションを起動します。以下は、そのWebアプリケーションに、Chromeブラウザからアクセスした時の画面です。
[ホーム画面]
http://localhost:8080/myapp/ にアクセスします。(myapp は DDBuilderの操作画面で指定したアプリケーションの名前です)
ホーム画面として、3つのボタンを持つ画面が表示されます。
例えば、ドメインクラス一覧ボタンをクリックすると、次のようなドメインクラス一覧画面が表示されます。
ここで、製品 Product 等のリンクをクリックすると、当該クラスのインスタンスの追加、更新、削除ができる画面が表示されます。
所謂、マスターメンテナンス画面のような操作ができます。
なお、Eclipseへのインポートや起動方法の詳細は「開発の流れ」を参照してください。
[目次に戻る]DDBuilderは、ドメインモデルのJava実装コードを読み込み、Webアプリケーションを生成します。 ユーザが実装したドメインモデルは、Webアプリケーションのドメイン層にに置かれます。 DDBuilderは、ドメインモデルからビュー層や永続化層を生成します。
生成結果は、1つのフォルダに出力され、そのフォルダは、そのままEclipse にインポートできます。 つまり、出力フォルダは「Eclipse 動的 Web プロジェクト」の構成になっています。 下図は、出力フォルダの内容です。
.settings, .classpath, .project は Eclipse の設定ファイルです。src フォルダ配下に、domain, persistence, service, viewパッケージフォルダがあります。lib フォルダの配下には、必要な OSS のライブラリが含まれています。
下図は、DDBuilderが自動生成する Java Web アプリケーションの構成図です。DDD本 (p.70) のレイヤ化アーキテクチャに準じています。
次のオープンソースソフトウェアを使用しています。
・ビュー層:Apache Wicket
・永続化層 (インフラストラクチャ層):Java EE JPA / Hibernate
レイヤ名について
DDD本では、ユーザインタフェース層 (プレゼンテーション層)、アプリケーション層、ドメイン層 (モデル層)、インフラストラクチャ層と命名されています。
[目次に戻る]開発者が実装するドメインクラス (エンティティ) と、DDBuilderが自動生成するクラスについて説明します。例として、開発者が Product.javaというドメインクラス (下図の黄色の網掛けのクラス) を作成します。次に、DDBuilderで自動生成を実行すると、下図ようなクラス (Javaファイル) とHTMLファイルが自動生成されます。下図は、すべてではなく、主なファイルです。 view, service, domain, persistenceはパッケージ名です。それぞれ、ビュー層、サービス層、ドメイン層、永続化層に相当します。開発者が Product.javaを実装すれば、ビュー層、永続化層のクラスは自動的に生成されます。自動生成されたものは、そのまま Java Webアプリケーションとして動作します。Productの登録、更新、削除、一覧がWeb画面で操作できます。
ビュー層の1つの画面は、同名のHTMLファイルとJavaクラスで構成されます。
例: ProductPage.htmlとProductPage.java。
これは、ビュー層で使用している Apache Wicket フレームワークの仕様です。Wicketは、JSP/Struts系のアーキテクチャではなく、Jave EE JSF 系のアーキテクチャです。HTMLファイルは独立しており、通常のHTMLと同様に編集できます。つまり、JavaやJSPなどの知識が不要なので、デザイン専門の方でも編集できます。Wicketでは、画面は、完全に Java オブジェクト指向プログラミングで実装できます。例えば、Productを使用するサービスが必要になった場合は、上図のSomeService.javaのように追加できます。もちろん、サービス名は適切な名前を付けます。数は制約されません。自動生成された画面だけでは不足する場合は、画面を追加できます。(上図では、CustomePage) 自動生成を再度実行しても、SomeServiceやCustomePageは上書きされません。詳しくは、「DDBuilderを使った開発の流れ」を参照ください。
[目次に戻る]このセクションでは、DDBuilderがサポートする関連の種類と、インスタンス属性型を示します。
この例では、JPAアノテーションを使って、エンティティ間の関連を定義しています。ただし、必ずしもJPAアノテーションを使って定義する必要はありません。というのは、実際のドメインモデリングでは、決定的に関連を決めることが大変難しい場合もあるからです。もちろん、関連を確実に定義できるところは、この例のように実装して、あいまいさが残る部分は、JPQLやネイティブSQLを使って、関連を実装することも検討すべきです。
UMLクラス図
サンプル コードには次の5つのクラスが含まれています。
(1) 著者 @Entity
public class Author extends DdBaseEntity
(2) 書籍 @Entity
public class Book extends DdBaseEntity
(3) 版 @Entity
public class Edition extends DdBaseEntity
(4) ISBN @Entity
public class Isbn extends DdBaseEntity
(5) 書店 @Entity
public class Store extends DdBaseEntity
関連タイプと属性型の Java サンプルコード
/*
* DDBuilderで使える関連タイプと属性型に関する例です。ドメイン駆動設計的な観点の例ではありません。
*/
package jp.co.nextdesign.domain;
import java.util.ArrayList;
import java.util.List;
import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.OneToMany;
import javax.persistence.Transient;
import jp.co.nextdesign.domain.ddb.DdBaseEntity;
/**
* 著者
*/
@Entity
public class Author extends DdBaseEntity {
private static final long serialVersionUID = 1L;
/** 名前 */
private String name;
/** 書籍リスト owning/parent */
@OneToMany(mappedBy="author", cascade=CascadeType.ALL, orphanRemoval=true)
private List<Book> bookList;
/** 書籍リスト owning/parent */
@OneToMany(mappedBy="author2", cascade=CascadeType.ALL, orphanRemoval=true)
private List<Book> bookList2;
/** コンストラクタ */
public Author(){
super();
this.name = "---";
this.bookList = new ArrayList<Book>();
this.bookList2 = new ArrayList<Book>();
}
//OneToManyで双方向関連を維持するためのコードを含むgetBookList(),
//setBookList(List<Book> bookList)の例
@Transient
private ArrayList<Book> latestBookList = new ArrayList<Book>();
public List<Book> getBookList() {
return this.bookList;
}
public void setBookList(List<Book> bookList) {
for(Book newBook : bookList){
if (!latestBookList.contains(newBook)){
newBook.setAuthor(this);
}
}
for(Book oldBook : latestBookList){
if (!bookList.contains(oldBook)){
oldBook.setAuthor(null);
}
}
this.bookList = bookList;
latestBookList = new ArrayList<Book>(this.bookList);
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public List<Book> getBookList2() {
return bookList2;
}
public void setBookList2(List<Book> bookList2) {
this.bookList2 = bookList2;
}
@Override
public String getDDBEntityTitle(){
return this.name;
}
/** debug */
public String getDebugInfo(){
String info = "<" + this.getClass().getSimpleName() + ">";
info += "\nname=" + this.getName();
info += "\n</" + this.getClass().getSimpleName() + ">";
return info;
}
}
[すべてのクラスを表示]
【注意】
この例は、DDBuilderがサポートする属性型と関連の型を示すためのものです。そのため、ドメイン駆動設計のドメインモデルとしての重要な責務 (メソッド) は省略しています。
【注意】
このサンプルモデルはシンプルですが、現実には、集約 (AGGREGATES) についても注意深くモデリングする必要があります。JPAのアノテーションを使って、すべての関連を実現しようとしないことです。JPQLやネイティブSQLを使って、関連を実装することも検討すべきです。
※引用:ここから (DDD本 p.123)
関係を最小限に抑えるように設計することにより、 関連を辿る処理は単純化され、 関係性の爆発的増加もある程度は制限される。 しかし、ほとんどのビジネスドメインは非常に強く相互に結びついているので、 結局はオブジェクトの参照を通じて、長くて深い経路を辿ることになる。 ある意味で、こうしたもつれはこの世界の現実を反映している。 現実には、はっきりした境界が引いてもらえることはめったにないのだ。 これはソフトウェアの設計における問題である。
※引用:ここまで (DDD本 p.123)
自動生成されたWebアプリケーションに自作のページを追加できます。
DDBuilderは、自作ページを上書きしません。
ページを自作する場合には、自動生成されたコードが参考になるはずです。
より複雑なページの例も本サイト内で公開しています。
・ページサンプル : Wicket DataTable ソート列 アクション列 テーブル
・ページサンプル : 改ページ付き・ソート列付き・1件複数行対応 テーブル
[目次に戻る]開発チームは、DDBuilderにロックインされる (しばられる) ことはありません。いつでもDDBuilderを切り離す (使用をやめる) ことができます。切り離した後は、WicketとHibernateを使ったシンプルな Java Webアプリケーションとして開発や保守を継続できます。あるいは、ドメインモデル層とサービス層を他のアプリケーションフレームワークに移植することもあるでしょう。
[目次に戻る]Java は、強い静的型付けのオブジェクト指向言語です。
DDBuilder では、ドメインモデルの実装言語は Java です。
自動生成されるアプリケーションも Java Webアプリケーションです。
Java は静的型付け言語なので、Eclipseなどのリファクタリング機能を使って安全に変更できます。
このことは、ドメインモデルを繰り返しリファクタリングしていくうえで、強力な利点です。
また、ドメインモデルを他の言語や他のフレームワークへ移植する場合にも、元の言語が Java であれば、より安全に移植できるでしょう。
[目次に戻る]自動生成されるアプリケーションのビュー層には、Wicketを使用します。Wicketは、ビュー層を担う Java Web アプリケーションフレームワークです。Struts系と違い、 オブジェクト指向プログラミングモデルを前提としたフレームワークです。HTMLとの独立性が高く、基本的にすべてをJavaコードで実装します。開発者が Wicketを意識するのは、自作ページを追加するときです。
[目次に戻る]自動生成されるアプリケーションの永続化層には、Hibernateを使用します。Hibernateは、JavaEE JPA実装の1つです。自動生成されるアプリケーションでは、特に指定がなければ、データベースとして、Java標準のJavaDBを使用します。なお、Hibernateは、PostgreSQL, MySQL, Oracle, SQLServer, DB2などの代表的なDBMSをサポートしています。なので、DDBuilderが自動生成したWebアプリケーションでも、設定ファイルを変更するだけでDBMSを変更できます。ドメインモデル層のクラスを実装するときには、JPA / Hibernate の知識が必要になります。主に、関連を定義するためのアノテーションの書き方などの知識が必要になります。
JPAのような洗練された ORM が無い時代は、ORM 部分を設計・実装することは非常に工数がかかる部分でした。また、バグの温床でもありました。ドメインモデリングに集中する為にも、JPA は必須と思います。
[目次に戻る]自動生成されたアプリケーションでは、Java EE JPA の永続化コンテキスト (EntityManager) を使用してトランザクション管理を行います。JPA の仕様としては、永続化コンテキストには、次の2種類があります。
[永続化コンテキストの種類]
(1) コンテナ管理
永続化コンテキストのライフサイクル (生成、破棄) は、EJBコンテナによって管理されます。
(2) アプリケーション管理
永続化コンテキストのライフサイクルは、アプリケーションによって管理されます。EJBコンテナは必要ありません。
DDBuilderが生成するアプリケーションでは、(2)のアプリケーション管理を使用しますので、特別なコンテナを必要としません。永続化コンテキストのライフサイクルは、自動生成されたコードによって行われますので、DDBuilder利用者は、特に意識する必要はありません。
トランザクションを管理するためには、トランザクションマネージャを使用します。トランザクションマネージャには、次の2種類があります。
[トランザクションマネージャの種類]
(1) JTAトランザクション
EJBコンテナが必要です。トランザクション管理は、EJBコンテナによって自動的に行われます。
(2) リソースローカルトランザクション
EJBコンテナは必要ありません。
DDBuilderが生成するアプリケーションでは、(2)のリソースローカルトランザクションを使用しますので、特別なコンテナを必要としません。トランザクション管理は、自動生成されたコードによって行われますので、DDBuilder利用者は、特に意識する必要はありません。
永続化コンテキストのライフサイクル、トランザクション管理の流れを下図に示します。
ユーザガイド [PDF] [2.5MB]
[OSSへの謝辞]
DDBuilderは次のソフトウェアを利用しています。
・Apache Wicket 7.4.0
・hibernate-entitymanager4.3.6.Final
・Derby10.10.2.0
・log4j2.5
・Eclipse jdt3.9.1
[動作確認済みの環境]
・Java 8
・Windows7 pro 32bit/64bit, Windows10 pro 64bit
・Eclipse IDE for Java EE Developers 4.4, 4.3
・Apache Tomcat 7.0, 8.0, 8.5, 9.0
[インストール不要]
インストール/アンインストールは不要です。ダウンロードしたzipファイルを適当な場所に解凍してください。不要になった場合は、 それらをエクスプローラなどで削除してください。
※ ダウンロードしたファイルを解凍すると、次の説明ファイルが含まれています。
「はじめにお読みください(使い方).txt」
「DDBuilder_Guide_Ver2.pdf」
[サポート]
使いはじめ等で、ご不明な点がありましたら「お問合せ」からご連絡ください。 (無料) ネクストデザインの都合で返信が遅くなる場合がありますが、ご了承ください。また、有料でのサポートも別途用意しております。詳しくはお問合せください。
[オープンソースで公開中]
GiHubでオープンソースとして公開しています。 [Apache License Version 2.0]
- DDBuilder (ツール本体)
https://github.com/nextdesign-co-jp/DDBuilder.git
- DDBuildertemplate (テンプレート)
https://github.com/nextdesign-co-jp/DDBuilderTemplate.git
[目次に戻る]DDBuilderは、ドメイン駆動設計の入門、学習にも役立ちます。 学習のためにドメインモデルを作成しても、ドメインモデルを動かすまでに時間がかかってしまい、ドメインモデリングに集中できなくなることがあります。 しかし、DDBuilderを活用すれば、すばやく動かしてみることができます。 実際にドメインモデルを実装して、具体的に動かしてみれば、ドメインモデルの役割や位置づけが理解しやすくなります。 机上だけで、ドメイン駆動設計を理解することは、簡単ではありません。 ドメインがアプリケーションの本質であるという考え方や、ドメインモデルを中心にした開発方法、イテレーティブな開発についても理解しやすくなるでしょう。