Help us understand the problem. What is going on with this article?

IntelliJ IDEA, PlantUML, Spock を使って DDD, UDD(仮) を試みている話

More than 1 year has passed since last update.

10月頃から、一部有志を集めて学習会を開いていて、その第一弾に選んだ題材が DDD (Domain-driven design) だった。

まだ道半ばであるが、ここいらで一度まとめておきたい。

tl;dr

  • Kotlin, IntelliJ, PlantUML, Spock の使い方の解説はない
  • DDD の解説はない
    • 正しい DDD とは、とかも無いです
  • UDD は、ubiquitous language driven design
    • 造語です
  • DDD を目指しドメイン設計を実施してみて、何が変わったのか
    • 実施前
      • 業務ドメインが分からなすぎた
        • でも、取り敢えず設計・作成するだけならこれでも行けた
      • でも、やっぱり業務知らないと、将来的に辛い
      • お客さんとのメンタルモデルの差を埋める何かが欲しい
    • 実施後
      • 複雑に絡んでいると思った業務が、やってみると意外とそうでもない (と思えるようになった)
      • ユーザとの共通言語可への道は見えた気がする
      • ドメイン層以外の実装が進むと、破綻しそうで不安
      • UML でのモデリングは、ドメインオブジェクトが熟れてくると不要になった
        • それだけ、コードによる表現力が高まったという証拠でもある
      • UDD と組み合わせると良さそうな兆し

悩み所

これまで、全く知識のない業界のシステム開発案件に開発者・設計者として何度か関わってきました。

初めは業務的な言葉・概念・知識がチンプンカンプンで苦労してた。
それでも、何度かお付き合いをしていく中で、徐々に業務情報も頭に入ってきて、最近ではようやく『あ、これはあれについて話しているんだな』と思えるようになってきました。

今これまでの過程を振り返り、自分の業務への無理解・無関心 が要因となって嵌った落とし穴がいくつかあったなぁと反省している事があります。

業務への無関心

『〇〇を追加して欲しいんだけど』
『えー… それは中々難しいですね…』

というどこにでもありふれる会話。
普段なら速やかに作業見積に進むところですけど、最近この過程で良くあるのが、 ( ああ、だからお客さんあの時あんなこと言ったんだ ) って、過去の点と点が繋がるような腹落ちの体験です ( アハ体験 である )

業務よりも技術・契約

『〇〇だし、データは同期などせずクライアントマシン毎に持てれば良いです。』
みたいなお話をお客さんがされていて。

こちらとしては、設計・技術・契約に関係することなので 『データはクライアントマシンが独立して持てば良い』 のところは聞き漏らさない様に注意してメモします。
でも、その前の 『〇〇だし』 の部分が、相手の業務上における何かしらの条件で、且つこちらがよく分かっていないものだったりすると、お客さんは『今はいいや』と気を使ってくれて結論だけ強調してくれ、こちらもあえて突っ込んでは聞かない
最悪なケースでは、お客さんの内輪話だったと判断しこちらの議事録に痕跡すら残らない (反省)。

この数ヶ月後、追加要望を頂いた時に、実はその業務上の条件が設計をも左右する大変重要な概念だったと分かり… ( 良くないアハ体験 )

何でこうなったのか

多分、設計できる最低限の業務情報さえ分かれば十分だ、とお互いに気を使いあっているから。

お客さんは、それが 設計を左右するような重要な業務情報だと思わない ため、わざわざ伝えようとはしない。

技術者は、それがそもそも何なのかを知らない。

活かしきれないドキュメントと議事録

とは言え、別に業務分析やってなかったわけではなく、むしろ資料 ( もちろんExcel !!! ) は大量にまとめていて

お客さんも極力分かりやすいようにドキュメント作ってくれるし、
技術側も要件を技術的に分析したドキュメント作ります。
お客さんと一緒に要件分析眺めながら確認したりも。

でも、なんというか、言語が違う んです。
お互いが、違うメンタルモデルで話している感じがする。

共通メンタルモデル

もっと、お客さんと技術者が一緒に作る共通のメンタルモデル作れないのかなぁ と思っていた所で、『そういえば DDD ってそういう事なのかな』と思って、やってみようと思いついた。

DDD (Domain-driven design)

DDD とは、ドメインに焦点を置いたソフトウェア設計手法。
詳細の説明はしません。

※ 12/7 追記
いい解説記事があったので、貼っておく。

こういうのを事前に見たかった…

※ 追記終わり

何を期待するのか

DDD で検索すると、レイヤードアーキテクチャや Value Object, Entity 等についての技術的な話題が多いのかなぁと思う。
(これを 戦術的設計 と呼ぶらしい)

我々が期待したのは、 その前段階の 顧客とユビキタス言語で話しながら、継続的に業務をモデリングし改善していく という部分である。
(これを 戦略的設計 と呼ぶらしい)

この戦略的設計を駆使することで、お客さんと技術者が一緒に作る共通のメンタルモデル ができるんじゃないかとの望みを託し、DDD 精通者も居ない中、手探りで初めた。

↓ 以下の記事が、モデリング ~ ユビキタス言語について手短かにまとめられていて参考になりました
猫でもわかりたいDDD(Domain Driven Design) 0から開発したことないあなたに その1
猫でもわかりたいDDD(Domain Driven Design) 0から開発したことないあなたに その2

参考資料

● Eric Evans (2003) Domain-driven design
翻訳本 : https://www.amazon.co.jp/dp/4798121967/

● Vaughn Vernon (2015) Implementing Domain-Driven Design
翻訳本 : https://www.amazon.co.jp/dp/479813161X/

DDD の参考本というと、大方この2冊が上げられると思う。
Evans 本は若い時に一度呼んだが、途中で挫折している。

● 増田 亨 (2017) 現場で役立つシステム設計の原則 ~変更を楽で安全にするオブジェクト指向の実践技法
https://www.amazon.co.jp/dp/477419087X/

上記書籍は、DDD を背景としたオブジェクト指向本である。
『DDD 試して見ようかな』と思えるキッカケったとなった本。

実施計画

6人参加で毎週2回、1~2時間かけて進めていった。

知識としては、私だけが先の参考資料をふわっと頭に入れ、あとは流れで進める。

練習のために、どんな業務システムについて分析しようか悩んだ末、ちょうど良い複雑さ であった『旅費精算』業務を対象とすることとした。

旅費精算

弊社では、出張後にかかった費用を精算するための書類作成を毎度行っている。
これが大変複雑で、毎回時間もかかるし、稀に間違いも発生していた。

参加者全員が技術者でありドメインの専門家となってしまうのは良くなかったかもしれないが、結果として、当事者意識が途切れず良かったと思う。

環境

言語 Kotlin 言語仕様としてコンパクト。覚えやすい。
開発環境 IntelliJ IDEA 開発環境としては、IntelliJ IDEA を選択。Kotlin だからと言う面もあったが、オブジェクト指向の利点を最大限活かすことを考え、しっかりした IDE を選んだ。
テストフレームワーク Spock ドメインオブジェクトの出来を確かめるための試験を担当。
VCS Github 書かれたコードは全て共有したかった。
モデリング ホワイトボード 基本的には、モデルはホワイトボードで皆で会話しながら進めていった。
PlantUML しかし、やはりグラフィカルなモデル関係をバージョン管理したいので、その為に PlantUML を使った。

どう進んでいったのか

ホワイトボードでのモデリング

基本的には、顧客として 発した言葉を、片っ端からホワイトボードに書いていく。
それをまとめたり、線を引いたりしてモデリングを進めていく。

毎回終わりに写真を撮り、メンバーで共有する。

第一回のモデリング結果


※ 一部加工

相当ぐちゃぐちゃだなぁ、という共通認識を共有したあたりで諦めた。

この後、範囲が広すぎる 事と、同じ用語でも違う意味合いがある ( i.e 出発時間 は、日当における意味と交通手段における意味が違う ) 事が判明し、次回からはいくつかに分割して順次詳細にモデリングしていくこととした。

これは、結果としては コンテキスト分け に繋がっている。

第二回以降のモデリング

これは、日当コンテキストについてのモデリング。
繋がりだけでなく、どんな情報を持って、どんな処理をするのかまで踏み込んで考えている。
この辺りになると、技術側の言葉が話されることが多くなったが、意識して業務情報に集中した。

ちなみに、最終的に日当コンテキストのモデルの数は、ここに並べたモデルの3倍程度にまで増えた。

PlantUML によるクラス図でのモデリング

ホワイトボードだけでも良いが、変更履歴をもう少しきちんとVCSで管理したいのと、ホワイトボードの清書もしたいという思いから、 PlantUML のクラス図を利用して図式化していた。


※ 日当コンテキストの一部モデル

環境

IntelliJ IDEAに プラグイン をインストールし利用する。

雑感

良かった点としては、それぞれのメンバーが好きに書けるため、みんなで一緒に進めるホワイトボードとは違い個人での検討には向いていたこと。

ただ、コードの方の表現力が上がってくると、わざわざ UML を見なくても良いんじゃない?という気がしてきて、終いには更新されなくなってしまった。

ソースコードと同期できるような機能があれば、もっと良かったのかもしれない。

Kotlin + IntelliJ IDEA

ということで、コンテキスト分けが終わり、グラフィカルなモデリングもある程度まとまってきたら、すぐにコードで書くようにした。

モデルの増加

グラフィカルなモデリングからコードにするこの段階で、一気にモデル数が増えた

業務情報に集中していたときよりも、それを技術で表現しようとしたときのほうがドメインモデルが洗練された。

しかしこれは、事前のモデリングが不要だったという話ではなく、相補的なものであろうし、もし先にコーディングから入ってしまうとそちらに引っ張られすぎると思うので、結果としてはこれで良かったのではと思う。

演算子による表現は分かりやすい

Kotlin は、中置演算子を簡単に Override できたのは良かったと思う。

// こういう書き方もよく見るけど、
fun calcFee() : Fee {
    return BasicFee(employee).multiply(distance.getRate()).multiply(time.getRate())
}

// こっちのほうが、一目で分かる
fun calcFee() : Fee {
    return BasicFee(employee) * distance.getRate() * time.getRate()
}

この BasicFeeは、従業員クラスを受け取りベースとなる金額 Fee クラスを返すが、その後の距離によるレートと時間によるレートとの掛け算で採取的な金額が導出される、と直感的に分かる。

open class Fee(val amount: BigDecimal){
    constructor(amount: Double) : this(BigDecimal.valueOf(amount)) {
    }

    // これだけで、* 演算子が定義できる
    public operator fun times(rate: Rate): Fee {
        return Fee(amount.times(rate.rate))
    }
}

Spock による UDD(仮)

※ 元々は BDD と書いていましたが、やってる内に 『BDD じゃないなぁ』と思うようになり、紛らわしいので UDD に変えました。

当初の目的としては、ドメインオブジェクトがコードとして正常に動くことを担保する為に Spock を導入していた。

けど、次第にユビキタス言語を上手くドメインオブジェクトが表現しきれているのかを確認するためにも使えるんじゃないかと思い立ち、途中からは積極的にお客さんの話したセンテンスを describe に書いて、その中にテストコードを書いていった。

ということで、ubiquitous language driven designUDD としました。

spock.jpg
※ 実際には、XXXX円には金額が入る

テスト手法

確認のしかたはシンプルで、ドメインオブジェクトが、ユーザの思考フロー・メンタルモデルをモデリング出来ているか目視で 確認する。判断はその人

まだまだ雑です。

ドメイン層以外の実装

現在は、ドメインオブジェクトの設計が大方終わりが見えてきた所であるが、これ以上はやはりメンバー全員が DDD の知識をきちんと持たないと難しいのかなぁと思っている。

これからどうするかは検討中。

学んだこと

業務ドメインへの理解が格段に進んだ

複雑に絡んでいると思った業務が、ドメインオブジェクトを設計することでとても理解が進んだ。
プログラマにとって、何かの構造を知るために『コードを書く』というのが、結構効率的なのかもしれない。

ユーザとの共通言語可への道は見えた気がする

UDD のコードは、本当に良くできていればお客さんとも共有できる可能性があるのでは、と感じた。

今後、実装を付け足していったらどうなるか不安

一番の不安は、これから実装を付け足していけば行くほどきれいなドメインオブジェクトは崩れていくんじゃないか、ということ。
色々と調べていると、『ドメイン層がインフラ層に影響を受けるのかどうか』について様々な議論がある事は知っている。

理想としては、ドメイン層だけのプロジェクトを作り、実装 (Infra, Application) は別プロジェクトに分けてドメイン層プロジェクトをインポートとかできないかなぁと検討している。

( 明らかに道半ばであるにも関わらず、こんな記事を書いてしまって大丈夫であろうか )

英語の壁

『わぁ、コードを眺めるだけで業務の流れが分かる。凄く良くモデリングされてる。』とはならないのは、クラス名も何もかも英語である という事が大きいと感じる。

日本語でプログラミングしようという試みもあるらしいが、どうなんでしょう。
ドメインオブジェクト的にはアリな気もするけど。

業務に応用できるのか

このままのやり方が通用するかと言われれば、難しいでしょう。
お客さんと相当な時間をかけてドメインオブジェクトを作り上げなければ行けないし。

個人的にあまりオブジェクト指向得意ではないと思っていたが、DDD をやってみて初めて『OOP 便利かも』と思うようにはなった。

まとめ

今回は、真っ最中の活動をまとめた為、ここに記したのはあくまで現時点での暫定的意見でしかない。

これからは、『ドメインオブジェクトの凄さは分かったけど、このまま洗練されたモデルを崩さずに実装はできるんかい』に立ち向かっていかなければならない。

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away