ドメインロジックのモデリングと実装

ドメインロジック(ビジネスロジック)をどうやってモデリングして、どうやって実装するかの実践例を公開しました。

RDRA 2.0 ハンドブックの図書館システムの実装例 (github)

ビジネスロジックのもとになる業務モデルやビジネスルールのモデリングは、 モデルベースの要件定義手法 RDRA2.0 を使っています。

利用方法

アプリケーションの内容

RDRA 2.0 ハンドブックのサンプル「図書館システム」の以下の業務を実装しています。

business-usecase

http://localhost:8080でトップ画面を表示できます。

設計ドキュメント

JIGを使ってソースコードから設計ドキュメントを自動生成します。ドキュメントはbuild/jig に出力されます。
JIGドキュメントの生成には、 Graphviz のインストールが必要です。

実装の範囲

ビジネスルールを中心に実装しています。

RDRA 2.0で可視化した以下のビジネスルールと関連するユースケース・画面・テーブルを実装しています。

  • 貸出制限ルール
  • 予約の状態遷移

貸出業務と貸出制限ルール

composit-usecase-loan

restriction

予約の状態遷移

reservatoin-state

以下の業務は未実装です。

  • 蔵書管理(書籍の注文と蔵書として登録する)
  • 会員管理(会員の登録)

要件定義・仕様化・実装の継ぎ目をなくす開発手法

この図書館サンプルは、以下の考え方とやり方で実装しています。

三層構造+ビジネスロジック

layers ビジネスロジックを独立させるドメイン駆動設計のアプローチを採用しています。

ドメインオブジェクトを中心にしたアプリケーション構造

mapping RDRAの要件定義モデルと実装を、以下のように対応させています。

Spring MVCとMyBatisを使い、ドメインオブジェクトを中心に周辺の外部形式との双方向のマッピングを実現するアプリケーション構造を採用しています。

ドメインオブジェクトのモデル(ビジネスロジックの表現)

model

ソースコードから、JIGで自動生成したドメインモデルのパッケージ構成図です。
このモデルを中心に図書館アプリケーションを組み立てています。

CCSR: Continuous Concurrent Stepwise Refinment

開発手法として、要件定義・仕様化・実装の継ぎ目をなくすCCSR手法を採用しています。

この図書館サンプル実装は、CCSR手法の実践例として開発しています。

ccsr

参考記事: 要件定義・仕様化・実装の継ぎ目をなくすCCSR開発手法

RDRAアドイン

RDRA手法のモデリングツールとして、Enterprise ArchitectのRDRAアドインを使っています。

JIG (設計可視化ツール)

Javaで記述した内容を、俯瞰したり、一覧するためのツールです。

プログラミング言語で仕様を記述するCCSR手法を実践するために必須のツールです。

RDRA - CCSR - JIG 関係図

RDRA-CCSR-JIG

RDRAのモデル要素(左)、三層+ビジネスロジックの構造(中央)、JIGの出力ドキュメント(右)の対応関係です。

ビジネスルール駆動

図の青背景でしめした、RDRAで可視化したビジネスルールをドメインモデルとして実装することが、このアプリケーションの中核です。

RDRA 2.0で可視化された内容と、実装された内容の対応は、以下のJIGドキュメントで確認できます。

  • ユースケース複合図
  • パッケージ関係図(depth4, depth5)
  • 区分図と区分使用図
  • メソッド呼び出し関係図

参考情報

要件定義・仕様化・実装の継ぎ目をなくすCCSR開発手法

ソフトウェア開発の問題点

従来のウォータフォール型で、フェーズ分けと分業を重視し、手続き的なモジュール構造でソフトウェアを開発するやり方には、次の問題があります。

  • 開発、特に大量のドキュメントの作成に膨大な時間と費用がかかる(工程が多く、必要な人員も多い)
  • フェーズ分けと分業のため、関係者の間の認識合わせが難しい(伝言ゲーム)
  • ちょっとした変更でも、調査・修正・確認に膨大な時間がかかる(変更がやっかいで危険)

一方、アジャイルと呼ばれる開発のやり方でも、以下の問題が起きます。

  • 規模が大きくなると、どこになにが書いてあるか理解ができなくなる
  • 増築・改築の繰り返しが、全体の構造や品質を劣化させる
  • 全体を俯瞰したり構造を確認するための情報がなく、変更の影響がわかりにくい
  • ちょっとした変更でも、調査・修正・確認に膨大な時間がかかる(変更がやっかいで危険)

どちらのやり方でも 変更がやっかいで危険 になることが大きな問題です。

CCSR手法

CCSR手法は、ソフトウェアの変更が楽で安全になること、ソフトウェアの発展性を最も重要な品質特性である、という考えに基づく開発手法です。

CCSR:Continuous Concurrent Stepwise Refinement (継続的・並行的・段階的な発展)

ウォータフォールでもアジャイルでも実現できなかった、ソフトウェアの変更を楽で安全にするための開発手法です。

コンセプト

  • 要件定義・仕様化・実装の継ぎ目をなくす
  • ビジネスロジックに焦点を合わせる
  • 型によるモジュール構造で組み立てる

特徴

  • 要件定義手法として、要件の関係性可視化・関係者の合意形成を重視したRDRA手法を使う
  • ソフトウェアの仕様の記述に、プログラミング言語(Java)を使い、ツール(JIG)により可視化する
  • アーキテクチャとして三層+ドメインロジックを採用
  • 実装技術としてSpring MVC, MyBatis, Thymeleafを使用

f:id:masuda220:20200527095141j:plain
CCSR手法

従来の開発手法との大きな違いは以下の点です。

  • ソフトウェア仕様の記述に自然言語ではなくプログラミング言語を使う
  • 要件定義・仕様記述・実装を双方向でフィードバックしながら全体を発展させていく

仕様の記述にプログラミング言語を使う

CCSR手法の一番の特徴は、ソフトウェア仕様の記述にプログラミング言語を使うことです。

仕様記述にプログラミング言語を使うと、仕様と実装の継ぎ目をなくす効果は絶大です。

一方、要件定義と仕様記述の継ぎ目をなくすためにプログラミング言語を使うというアプローチはとまどいがあるかもしれません。

CCSRを実現する技法とツール

CCSRで採用したプログラミング言語による仕様記述が実践的で効果的な理由は次の通りです。

  1. 要件定義にRDRAを使うことで、整合性が担保され論理的な要件定義モデルが手に入る(仕様記述のインプットの質が高い)
  2. アプリケーション固有の型をどんどん定義(データの抽象化)して、仕様記述の語彙を増やす
  3. RDRAの要件モデルに直接的に対応する設計・実装パターンを用意する
  4. Javaで記述したソフトウェア仕様を図形表現で可視化したり一覧表にして確認できるツール(JIG)を活用する
  5. 要件定義・仕様の記述・実装の一連の活動を、ビジネスルールに焦点をあわせ、ビジネスロジックを軸にアプリケーションを組み立てていく

CCSRの実践例

RDRA 2.0 ハンドブック(Kindle Unlimited会員は 無償) で使われている「図書館システム」を、CCSR手法で仕様化・実装した具体例を、githubリポジトリに公開しています。

図書館システムの実装例

ビジネスロジック中心のアーキテクチャ

CCSRは、ビジネスロジックを中心にアプリケーションを組み立てる開発手法です。

ビジネスロジックの置き場所を独立させ、入出力の関心事から分離します。

f:id:masuda220:20200527101518j:plain
三層+ビジネスロック

ビジネスロジックドメインオブジェクトで表現し、それを中心にアプリケーションを組み立てます。

f:id:masuda220:20200527101614j:plain
ドメインオブジェクトを中心にアプリケーションを組み立てる

ドメインオブジェクトと外部形式のマッピングの実装例も、githubに公開しています。

オブジェクトと画面・テーブル・JSONとのマッピング

CCSR手法の改良と普及

CCSR手法は、さまざまアプリケーション開発で実際に使われ、改良を続けています。

また、ソフトウェア開発組織や技術者個人を対象に、ワークショップや学習の場を提供しています。

CCSR手法に興味があったり、体験してみたい方は、twitter( @masuda220 ) などで、お気軽にご連絡ください。

また、CCSR手法を使って実際に開発している現場に参加したい、とか、CCSRの手法やツールの改善活動に参加したいという方も大歓迎です。ぜひ、ご連絡ください。

参考資料

CCSR開発手法は、記事内に記述したgithubリポジトリ以外に、以下の情報も参考になります。

発展性を重視するソフトウェア開発の考え方

書籍:現場で役立つシステム設計の原則 ~変更を楽で安全にするオブジェクト指向の実践技法

ブログ:ソフトウェアのもっとも重要な品質は発展性 (2020/4/5)

スライド:ドメイン駆動設計 15年の取り組みでわかったこと (2020/3/30)

要件定義手法 RDRA

RDRA モデルベース要件定義手法

YouTube:RDRA2.0のサンプルをJIGで実装してみたよ (2020/4/30)

JIG(設計可視化ツール)

JIGの公開リポジトリ

ソフトウェアのもっとも重要な品質は発展性

 ソフトウェアでもっとも重視すべき品質は「発展性」なんだと思う。 機能要求や非機能要求は、時間とともに変化する。その要求の変化に対応してソフトウェアを発展させていける能力、つまり発展性こそがソフトウェアの価値を大きく左右する。
 発展性に問題があり変化ができないソフトウェアと、発展性に優れ変化と成長を続けやすいソフトウェアの価値の差ということだ。

発展性の価値

 顧客のニーズは変化する。また、市場の競合関係も変化する。そういう事業環境の変化にあわせて、ソフトウェアにも変化を続ける能力が求められている。
 また、顧客のニーズや市場環境の変化がゆるやかだとしても、事業活動をすれば組織は経験を通じて学び成長していく。開発チームに限っても、ソフトウェア開発運用の経験を積むことで、開発の考え方とやり方にさまざまな学びと成長がある。そうやって学んだ知識を適切にかつ迅速にソフトウェアに反映できるほど、事業により多くの価値を提供できるはずだ。

保守性

 従来のソフトウェア品質モデルだと、発展性に似た視点として保守性がある。
 しかし、保守性は発展性とは発想が正反対になる。保守性は文字通り守るための能力である。なにか正しい状態が事前に定義されていて、正しくないことを検出したら、定義済の正しい状態に戻す活動が保守性の基本の発想だと思う。  それに対し発展性は、次の展開を切り開くための能力だ。現在の状態を前提に、よりよい状態を模索しそこに向かって変化していこう、というのが発展性の基本の発想となる。

変更容易性

 保守性も発展性も「変更容易性」として同一視することも可能かもしれない。しかし、保守しようとするのか、発展しようとするのかの方向性の違いは決定的だと思う。保守性を確保するための工夫と、発展性を向上していくための工夫はおのずと異なるものとなる。

発展性を生み出すための工夫

 ソフトウェアの発展性を向上させるために、いろいろやってみた。次の三つの取り組みに手ごたえを感じている。

  • 要件定義・仕様化・実装の継ぎ目をなくす
  • ビジネスルールに焦点をあわせる
  • 型によるモジュール構造を基本にする

要件定義・仕様化・実装の継ぎ目をなくす

 代表的な二つの開発のやり方、ウォータフォールとアジャイルについてソフトウェアの発展性の観点から考えてみる。

ウォータフォール

 いわゆるウォータフォール的な開発手法は、要件定義・ソフトウェアの詳細仕様の記述・実装のためのプログラミングの三つの活動を分断する。
 要件定義・仕様化・実装の三つの活動を分断し、異なる技術者がそれぞれの活動を担当し、活動間の意図の伝達のために、大量のドキュメントを作成する方法を採用する。

要求と実装の乖離(かいり)

 このアプローチで発展性を向上するのは難しい。要求の発生から実装のあいだの工程が多い。時間もかかるし、なによりも、要求と実装との間に距離がありすぎて、要求の変化に対して伝言ゲームを繰り返した結果、要求とはかけ離れた実装になる。コミュニケーションの方向も一方通行で、実装の段階で発覚するさまざまな疑問・仕様の抜け漏れや矛盾についての適切な補足や修正が起きにくい。

手続き的なモジュール構造

 そもそもソフトウェアの変更が構造的に難しい場合が多い。ウォータフォール的な開発では、画面や機能単位に分割した手続き的なモジュール構造を採用する。手続き的なモジュール構造では、ビジネスルールに基づく計算ロジックや判断ロジックを、画面や機能の視点で分割したモジュール群に記述する。その結果、本来はひとつであるべきビジネスロジックが、モジュールのあちこちに断片化しかつ重複する。こういう断片化と重複は、ずさんの設計の結果ではなく、手続き的なモジュール構造を選択した場合の必然的な帰結になる。もちろん、設計が劣悪であれば、結果はさらに悲惨にものになる。
 多くのレガシーなシステムが現在直面している変更がやっかいで危険という問題は、ウォータフォール方式のソフトウェア開発で採用されてきた手続き的なモジュール構造が直接的な原因となっている。

変化の兆候

 ウォータフォール的な開発をリードしてきたSI'erや大手企業の情報システム部門も、いままでのやり方ではうまくいかない。なにか、新たな開発のやり方に取り組んでいかなければいけない、という危機感は少しずつ広がってきているようだ。そういうところからの相談が増えてきた。顧客の要求に対して、いままでのような重厚長大で、時間とコストをかけるやり方では対応ができないことが明らかになってきた。

アジャイル

 一方、いわゆるアジャイルな開発は、活動を分離せず、伝言ゲームのためのドキュメントの大量作成はやらない。ウォータフォールとは正反対のアプローチを模索してきた。しかし、そういうやり方で開発されたソフトウェアも、時間とともにレガシー化が進み、発展性がどんどん劣化してく問題が起きることが明確になってきた。

要件定義や分析設計スキルの軽視と劣化

 アジャイルが提唱され始めたころは、要件定義や分析設計について一定の知識と経験をもった技術者が取り組んでいたと思われる。しかし、アジャイルが広まるにつれ、要件定義や分析設計についてきちんと教育や訓練を受けない技術者が急速に拡大した。また、それほどの分析設計のスキルがなくても、小規模なアプリケーションであれば、それなりに動くソフトウェアを作れるようなフレームワークやその利用のtipsが簡単に手に入るようになったことも、この方向を加速させた。

問題の顕在化

 しかし、アプリケーションがある程度の規模になり、複雑なビジネスルールを扱うことが要求されるようになると、要件定義や分析設計のスキル不足の問題が顕在化するようになった。
 アジャイルというソフトウェア開発のやり方であっても、しっかりとした要件定義やソフトウェア仕様化の知識と経験が重要であることに、多くのアジャイル系の開発者も気づき始めている。

要件定義・仕様化・実装の継ぎ目をなくす工夫

 ウォータフォール的な開発のやり方でも、アジャイル的な開発のやり方でも、発展性を重視するのであれば要件定義・仕様化・実装の継ぎ目をなくすことに取り組むことで大きな可能性が生まれる。

ウォータフォールからの移行

 ウォータフォール的な開発のやり方に習熟した組織であれば、要件定義やソフトウェア仕様化についてのさまざまなノウハウの蓄積がある。問題は分業と一方通行の伝言ゲームである。分業ではなくひとつの技術者チームが要件定義・仕様化・実装を担当するようにすれば、伝言ゲームのためのドキュメントづくりは不要になる。
 要件定義から実装・運用までひとつのチームが継ぎ目なく担当することで、ドキュメントづくりは必要最小限になり、ソフトウェアの生産性は劇的に改善する。しかし、継ぎ目をなくすだけでは残念ながら発展性の向上はそれほど期待できない。手続き的なモジュール構造からの脱却が大きな挑戦テーマになる。(発展性を向上させるモジュール構造への移行については後述する)

アジャイルからの移行

一方、アジャイルな開発スタイルでは、そもそも継ぎ目はない活動を目指してきた。しかし、それは要件定義や仕様化の活動自体が軽視され、経験や知識が足りないという現象を生み出した。アジャイルな方法でソフトウェアの発展性向上にと取り組むためには、まず、要件定義やソフトウェアの仕様化の基本的なスキルをきちんと学び習得することが効果的だろう。アジャイル的な開発だけをしてきた技術者には要件定義や分析設計のスキルが大きな伸びしろになるはずだ。

モジュール構造の移行

 アジャイル的な開発であっても、多くの場合、モジュール構造は手続き的なアプローチのことが多い。アジャイルに取り組んでいるある程度の年齢の技術者は手続き的なモジュール構造で技術を覚えてきた人が多いのが実態だろう。また、Webアプリケーション用のフレームワークでは、手続き的なモジュール構造をフレームワークとして組み込んでしまっているものが多い。ソフトウェアの発展性を生み出すためには、手続き的なモジュール構造から抜け出すことがアジャイル系でも重要な挑戦テーマになる。

継ぎ目をなくす手法とツール

要件定義・仕様化・実装の継ぎ目をなくす手法とツールについては、現在、以下の取り組みをしている

仕様の記述言語と可視化

仕様の記述にプログラミング言語を使うことで、要件定義・仕様化・実装の継ぎ目をなくせる手ごたえを感じている。この仕様の記述にプログラミング言語を使うという取り組みの具体的な内容は、このブログで紹介していきたいと思う。
 プログラミング言語で書いたソースコードだけではわかりにく、全体の構造、クラス定義の一覧、メソッドの呼び出し関係などはJigというオープンソースのツールを使って関連図や一覧表を自動生成している。
 エクセルなどを使って自然言語で記述する詳細仕様よりも、プログラミング言語での記述のほうが、整合性や一貫性が明らかに向上する。また、アプリケーションの関心事に対応する独自の型を積極的に定義することで、ソフトウェアの意図が明確になることがわかった。独自の型をモジュール構造の基本にする点については、後述する。

関係性に注目するRDRAのよさ

 要件定義に使っているRDRA2.0は、要件のさまざまな視点間の関係性に注目して、要件定義の整合性を向上を図る手法である。その結果、要件定義とプログラミングの論理構造との対応がつけやすくなり、要件定義・仕様化・実装の継ぎ目をなくし、ソフトウェアの発展性の向上につながっている。

ソフトウェア開発の複雑さに立ち向かう

 ソフトウェア開発の複雑さを生み出す理由はさまざまあるが、本質的にはアプリケーションの対象とするビジネスの複雑さがその主たる原因だと考えている。したがって、ソフトウェア開発の複雑さに立ち向かうアプローチとしては、ビジネス活動の複雑さ、より具体的には、ビジネス活動を刺激し制約する決め事である「ビジネスルール」の複雑さをあつかうスキルを磨くことが、ソフトウェアの発展性を向上させるための重点課題になる。

ビジネスルールが複雑さの根源

 ソフトウェアの複雑さの根源はビジネスルールにある、というのはエヴァンスのドメイン駆動設計の基本的な考え方である。また、RDRA2.0で取り入れられたビジネスルールの分析とモデル化にも共通する考え方である。

ビジネスルールに焦点を合わせる効果

 ドメイン駆動設計に10年以上取り組み、また、RDRA2.0を使った要件定義に取り組んでみた結果、ビジネスルールに焦点を合わせて要件定義・仕様化・実装を継ぎ目なく行うことが、ソフトウェアの発展性を向上させること、またソフトウェア開発の生産性の向上に大きな改善を生み出すきとにたしかな手ごたえを感じている。

分析設計の知見の言語化への取り組み

 要件定義・仕様化・実装の継ぎ目をなくし、一貫してビジネスルールに焦点を合わせる取り組みの中から、ビジネスルールの分析パターンと実装パターンについて、いろいろな気づきが生まれつつある。ビジネスルールに焦点を合わせた分析設計の実践から生まれつつある暗黙的な設計の知見について、このブログで言語化に取り組んでみようと思う。言語化に取り組むことで自分自身の学びと成長につながることを何度も経験してきている。

モジュール構造の転換の重要性

 画面や機能の単位でモジュール構造に分解する手続き的なアプローチでは、入出力の手順の記述の中に、さまざまなビジネスルールに基づく計算や判断を記述することになる。このアプローチの問題点は、ひとつのビジネスルールのソフトウェア表現が、断片化し重複しやすいことだ。またビジネスルールがif文などに暗黙的に埋め込まれがちだ。

型によるモジュール化

 ソフトウェアの発展性を向上させるには、モジュール構造の考え方を抜本的に変えることが必要である。具体的には、型(値の種類)ごとのモジュール構造を、基本とすることである。  この考え方は、前述の「ソフトウェアの複雑さはビジネスルールの複雑さに起因する」という考え方と密接に関係する。

ビジネスルールを型を使って表現する

 ビジネスルールとは事実を表現する値(データ)に基づき、計算や判断によって、なんらかの結果(導出した事実)を生み出す決め事だといえる。このビジネスルールに関わる計算・判断のロジックを一元的に記述し、一貫性を持たせるための工夫が「型によるモジュール構造」である。

型はビジネスルールを明示する

 より具体的にはビジネスに登場する様々な値の種類(金額、日付、期間、区分、カテゴリ、..)を、分類・整理し、それぞれの値の種類を独自の型として定義し実装する、というアプローチである。
 独自の型を定義することで、その型の名前がビジネスルールを表現する豊かな語彙(ごい)になる。独自の型を積極的に使うことで、ソースコードがビジネスルールを具体的に語り出すようになる。どこに何が書いてあるかが明快になることはソフトウェアの発展性を生み出す力になる。

オブジェクト指向プログラミング

 値とそれを使った計算や判断ロジックを一つにまとめて独自の型として定義するのは、まさにオブジェクト指向プログラミングの根本にある発想である。さまざまなビジネスルールで扱う値を分類・整理して、その結果を独自の型として定義しプログラミンしていく技法についてもいろいろなパターンが明らかになってきた。ビジネスルールの表現にオブジェクト指向プログラミングを活用するやり方についても、このブログで紹介していきたいと思う。

 継続的・並行的・段階的な発展(CCSR)

 この記事で書いたソフトウェアの発展性を重視した開発のやり方に、CCSRという名前をつけた。

  • Continuous 継続的
  • Concurrent 並行的
  • Stepwise 段階的
  • Refinement 発展

の略語(頭字後)である。

CCSRへの取り組み

 ソフトウェアの発展性は、事前の設計や要件として作りこむ性質ではない。顧客ニーズの変化、ビジネスニーズの変化、事業組織や開発チームの学びと成長に合わせて、継続的に、さまざまな活動を並行的に、そして一歩ずつ段階的にソフトウェアを発展させていく取り組みが生み出す能力である。CCSRという体系化は、まだ仮説と検証の初期の段階である。しかし、個々の要素は、私自身のさまざまなソフトウェア開発経験の中で会得してきた工夫であり技法である。そしてCCSRとしての体系化に取り組み始めたこの半年で、初期の検証結果として、十分な手ごたえを感じている。

ともに取り組む

 CCSR手法のついて、より多くの人に知ってもらい、可能であればそれぞれの現場で挑戦・評価してもらい、お互いの知見を共有できることを願って、ブログとして言語化に取り組んでみた。イベントなどの登壇の機会があれば、そちらもでCCSRの言語化と紹介を積極的にやっていこうと思う。

興味のある方は、ぜひ、いっしょにCCSR手法を取り入れたソフトウェア開発に取り組んでいきましょう。

モダンなSIer開発手法 勉強会

昨日、株式会社ディマージシェアさん主催の モダンなSIer開発手法 勉強会 - connpassでお話した内容です。

発表に使った資料

要約

  • 発展性に焦点をあわせる(プロジェクト型からプロダクト型へ転換する)
  • オブジェクト指向ソフトウェア構築の考え方(型によるモジュール化)を基本にする
  • ドメイン駆動設計の考え方(ドメインロジックに焦点を合わせ、コアドメインに集中する)を取り入れる
  • 要件定義・仕様・実装を並行して行う
  • 仕様の記述にプログラミン言語(Java)を使う
  • ソースコードから仕様を可視化する
  • 段階的に継続的に品質を向上させる

補足

ソフトウェア開発の複雑さを多面的に捉える

ソフトウェアシステムアーキテクチャ構築の原理(第2版)の枠組みで考えてみる。

7つの視点

  • 合目的性
    • コンテキスト
    • 機能
    • 情報
  • 構造性
    • 開発
  • 実行性
    • 並行性(実行モデル)
    • 実行環境
    • 運用

合目的性を、RDRA2.0で要件定義をする
構造性を、型によるモジュール化で実践する現場で役立つシステム設計の原則

  

仕様をJavaで記述し、設計を可視化する

Jig : 設計可視化ツール
Jig チュートリアル

オブジェクト指向プログラミングを学ぶための推薦図書

オブジェクト指向プログラミングを学ぶ

オブジェクト指向プログラミングという言葉は、広い意味で使われている。 オブジェクト指向プログラミングをキーワードにすべての情報をかき集めて理解するというアプローチは現実には無理。 目に付いた重要そうなところを見繕って集めてみても、たぶん混乱するだけ。

この記事では、オブジェクト指向プログラミングのいろいろなアプローチの中で、

  • クラスを使って独自の「型」を定義するプログラミングスタイル
  • 関連するデータとロジックをまとめて、小さな入れ物に格納する「カプセル化」を重視するプログラミングスタイル

を学ぶための参考図書を紹介したい。

型とカプセル化に重点を置く設計スタイルがわかってくると、それとは異なるスタイル、異なる力点を置くアプローチとの違いが具体的にわかるようになってくる。*1 *2

まずは、オブジェクト指向プログラミングの中で、型・クラス・カプセル化に力点を置く設計スタイルを身につけることを現場で役立つ実践的な学び方として推奨したい。

型とカプセル化を重視したスタイルを学ぶための三冊

以下の三冊は、必携書。すべてを読み切り理解することはできないかもしれないが、手元において少しずつ身に着けていきたい古典的名著。

読み方のヒント

どの本も全部を順番に読んでいくというより、ざっと全体を眺めたら、とりえあず、要点をみつくろって読むのが良い。基本は拾い読み。 あとは、何かの機会に、少しずつ、拾い読みの範囲を広げたり、拾い読みしたところを、なんども読み直してみる。

リファクタリング」の読み方

「第3章 コードの不吉な臭い」に列挙されている臭いの最初の6つ(「変更の分散」まで)を、重点的に読む。そして、その中に登場する、リファクタリングパターンだけは、一通り読むようにする。同じパターンが何度もでてくるので、何が、リファクタリングの基礎的な技法かが理解できる。

それだけでも、だいぶ、クラスの使い方とかカプセル化の感じがつかめるようになってくる。

ドメイン駆動設計」の読み方

読みにくい本です。まず、その前提で拾い読みする。

すぐに理解できるかどうかは別として、この本の根底にある考え方や、何に重点を置いているかに触れるための、最初の必読個所は、以下。

  • まえがき
  • 第9章 暗黙的な概念を明示的にする
  • 第15章 蒸留
  • 結論

ドメイン駆動設計という設計スタイルが、何を重視しているかに触れるには、この4か所を、ぜひ読んでほしい。すべてが理解できなくても、エヴァンスのこだわりポイント、設計スタイルがよくでている個所。

エヴァンスの考え方の特徴は「ある重要な部分に集中する」ことを重視している点。全体を同じ設計スタイルで均一に仕上げる、という発想とは正反対。アプリケーションソフトウエアの全体に影響を及ぼすのは、ドメインロジックであり、ドメインロジックの中でも中核の関心事と周辺的な関心事がある。中核のドメインロジックの設計と実装に焦点を合わせることで、ソフトウェア全体の構造と秩序が保たれ、さらなる発展が可能になる、という考え方。

この設計スタイルを支える技法の説明としては、次の2つの章が基本。

  • 第5章 ソフトウェアで表現されたモデル
  • 第10章 しなやかな設計

ただし、この2つの章は、必読ではない。オブジェクト指向プログラミングの基本的な技法の話なので、型とかカプセル化が理解できていれば、改めて、この2つの章を読み直す必要はない。 この2つの章が「わけがわからん」と思ったら、値オブジェクトを具体例で解説した情報や、リファクタリング本にあたったほうが良い。

なお、エヴァンスの書き方は、章のはじめでわけのわからない(?)たとえ話から始まることが多い。なんのたとえ話か最初はわからず混乱してしまうのが、多くの人が陥るワナ。私もそうだった。最初は、たとえ話は読み飛ばすくらいでよいと思う。後ろの内容が理解できて、はじめて意味がわかる例え話が多い。

もう一つ注意点。 クラス図やデータベースが登場する個所を、データモデリングの話として読んでしまうことも、わりと多くの人が陥るワナ。データモデリングや手続き的なアプリケーションプログラミングができる人ほど、このワナに陥りやすい。そう読もうと思えば、そう読むこともできる。まあ、そういう視点から読むと、エヴァンスの書いていることは稚拙というか的外れというか、なんじゃこりゃ、という評価になるんだと思うけど。

「型」や「カプセル化」の話なんだ、ということをいつも意識して読んだほうがエヴァンスの伝えたいことをすなおに読み取ることができる。 たとえば、最初はメソッド定義のないクラス図の個所は読み飛ばすべきだし、データベースと関連づけて説明されている個所も読み飛ばしたほうが良い。 関心の焦点はあくまでもドメインロジックをどうやって独自の型で定義するか、そして、独自の型の定義にどんな意図と効果があるか、ということを読み取ることに焦点を合わせたい。

オブジェクト指向入門」の読み方

分厚いし内容も難解なので、読破しようなどとは考えないほうが良い。 しかし、オブジェクト指向プログラミングの考え方を学ぶには、この本には有用な情報が詰まっている。 契約による設計とか、コマンドとクエリの分離など、良く知られた設計原則は、この本で提唱されている内容。

著者のバートランドメイヤーさんは、ご本人がおっしゃっているように「分類マニア」。とにかく、品質の分類、判断基準の分類、継承の分類、... など、分類好き。テーマごとに細かく分類し、それをひとつずつ解説するものだから、この厚さになってしまう。 だから、基本的には、「ああ、また分類病がはじまったな」くらいの感覚で、最初はちょっと距離を置いて、全体をぼんやり追いながら、全体としてどんなことが書いてあるかを掴むことから始めるとよいと思う。

この本を隅から隅まで精読する必要はないと思うけど、

  • ソフトウェア構築の基本はモジュール性
  • オブジェクト指向は型によるモジュール化を選ぶ
  • 型をカプセル化するクラスが唯一のモジュール単位であるべき

というメイヤーの考えを知って損はない。 同意するかどうかは別として。

拾い読みするとしたら、重点ポイントは、以下。

  • 第3章 モジュール性
  • 第5章 オブジェクト技術への道
  • 第11章 契約による設計:信頼性の高いソフトウェアを構築する
  • 第17章 型付け
  • 第22章 クラスの見つけ方
  • 第23章 クラス設計の原則
  • 第27章 オブジェクト指向分析
  • 第28章 オブジェクト指向構築過程
  • 第29章 オブジェクト指向という手法を教える

拾い読むといってもちょっと多いかな。まずは、何が書いてあるかを知るには、ざっとこのくらいは目を通しておきたい。 「継承」について書いてある章は意識的に割愛してあります。メイヤーさんは、熱烈な実装継承押しなんですが、私は、逆に実装継承は、やらない派なので。 リスコフは、実装継承はカプセル化の原則をやぶるため好ましくないであろう、と予測していた。そして、その後の開発現場での実践でその予測が正しいことは、すでに実証された。つまり、実装継承はやめたほうがよいよ、という立場です。

もっと読みやすい本が欲しいよね

ということで、書いたのが、拙著。

現場で役立つシステム設計の原則 ~変更を楽で安全にするオブジェクト指向の実践技法

特に、以下の4つの章で、型とカプセル化の考え方をできるだけわかりやすくコードの具体例で説明してみた。

  • 1章 小さくまとめてわかりやすくする
  • 2章 場合わけのロジックを整理する
  • 3章 業務ロジックをわかりやすく整理する
  • 10章 オブジェクト指向の学び方と教え方

この本は、「Java言語入門」的な本と、難解な「ドメイン駆動設計」との間を埋める本が求められているのでは、という企画から生まれた本。 最初に話をもらった時、私自身、そういう間を埋める本があったらいいな、と思っていたので二つ返事で引き受けた。 出版できるまでは、いろいろあったんだけど、なんとか世に送り出すことができた。 おかげさまで、出版から2年たった今でも地味に売れ続けているので、それなりの評価はしてもらえていそう。 「若手にススメた」みたいな話を時々目にするので、本の企画意図通りの読まれ方がされているのかな、とうれしく思っている。

この本を書く時、「継承」「カプセル化」「ポリモーフィズム」「型」とか、いう言葉はださずに、コードの書き方の工夫に振り切って、なぜそうすることのメリットがあるかをできるだけ、わかりやすく書こうと思った。

わかりやすさという点では、それなりの結果がだせたのではと自負している。 まあ、そういうわかりやすさが気に入らない人もいるんだなあ、ということもわかった(笑)。役に立つことが書いてあるけど、書き方が悪い、というコメントを見たとき、役に立つことは伝わったんだよね?、伝わったのに書き方が悪いってどういうこと?という感じで、とても不思議だった。

あと、現実的ではないとか、実際には導入できない、というコメントもいくつか見かけたけど、「自分が実際にやって、それなりの結果を出してきた内容だけ」を書いたので、うーん、実際にやっているんですけど、という感じなんだよね。逆に言うと、例えば国際化対応とか、テスト駆動開発とか、私自身が実際にやっていないことは、何も書いてないんですよね。

まあ、わかりやすいので、読む人の持っている設計スタイルとの干渉が強くて、そういう反応もあるんだろうな、と思っている。何が書いてあるかは、それなりに伝わっているんだろうなあと。

今、読み直してみると、もうちょっと「型」と「カプセル化」という用語の説明をどこかでしたほうが良かったかなと思う。 あと「ポリモーフィズム」も、多重定義・総称性・部分型の三種類あることの説明と、それぞれのポリモーフィズムについてちゃんと説明してもよかったかもしれいない。

この本は、ドメイン駆動設計への入門書的な意味あいは確かにある。ドメインモデルを中心に設計することの意味とその効果について、そうとう意識して書いた。

ドメイン駆動設計と並んで、私が意識していたのは、バートランド・メイヤーのオブジェクト指向入門。 メイヤーさんは、オブジェクト指向はプログラミング技法にとどまらず、ソフトウェア全体の構造と秩序、ソフトウェアの開発プロセス、設計の学び方や設計の知見の共有と流通まで、ソフトウエア開発のさまざまな側面が大きく変わる革命なのだ、ということを力説している。 私自身、型とカプセル化を重視する設計スタイルを現場でいろいろ実践する中で、ソフトウェア開発のさまざまな側面に影響がでることを日々実感している。9章 オブジェクト指向開発プロセス、10章 オブジェクト指向の学び方と教え方の2つの章は、そういう現場で得た知見を元に、開発のやり方が変化しつつあること、型とカプセル化を重視する設計スタイルのわかりやすい教え方について、言葉にしてみた。

まとめ

後半は、自著の説明になっちゃったけど、独自の型を定義し、ドメインロジックをカプセル化する設計スタイルを学ぶ入門書としては、お役にたてるのではと思っています。

私の本の内容がものたりなかったら、ぜひ、前半でとりあげた三冊を手元に置いて、最初は拾い読みでよいので、読んでみてください。 型とカプセル化にこだわるオブジェクト指向プログラミングがわかってくると、世の中のさまざまなオブジェクト指向に関する情報の関係性(と無関係性?)が、いろいろ見えてくると思います。

*1:アプローチの違いは、こちらにわかりやすい説明と、参考情報へのリンクがあります→オブジェクト指向とは何ですか

*2:こちらも大きな流れとして参考になります→新人プログラマに知っておいてもらいたい人類がオブジェクト指向を手に入れるまでの軌跡

ドメイン駆動設計を理解する3つのキーワード

ドメイン駆動設計との出会い

10年前に、エヴァンスのドメイン駆動設計を初めて読んだ時は、書いてある内容がほとんど理解できなかった。 あまり、面白いとも思わなかった。

当時は、現場でバグだらけのコードと格闘していた。障害が報告されるたびに、リファクタリング本を参考に、該当個所の長いメソッドや大きなクラスを片端からリファクタリング。その結果、コードがわかりやすくなり、やっかいなバグが単純な修正で解消できてしまうことの効果に驚き、設計の重要性を再認識していた。

それ以前は、UNIXC言語OraclePL/SQLという、オブジェクト指向ではない世界で技術を身に着けてきた。 どちらかというとオブジェクト指向には、ネガティブな印象を持っていた。現場では役に立たんだろうと。

バグとの格闘の中で、リファクタリング(設計改善)の威力を肌で感じ、その考え方とやり方がオブジェクト指向に由来するということを知るにつけ、オブジェクト指向も食わず嫌いではなくもう少し学んでみようと思った。

ワーフスブラックの「オブジェクトデザイン」とバートランドメイヤーの「オブジェクト指向入門」を買い込んで読み始めてみた。 両方とも面白いと思うところもあったが、何を書いてあるのか、よくわからないところも多かった。

実践的なオブジェクト指向との出会い

大きな転換点は、ケントベックの「実装パターン」を読んでからだった。

オブジェクト指向とは何か、という説明ではなく、「変更の影響の局所化」「コードの重複の除去」「ロジックとデータの一体化」「宣言型の表現」などの設計原則を、なぜそうするのか、具体的にどうやるのかが、わかりやすいサンプルコードで説明されていた。

特に「実装パターン」の中の「Value Object」は、大きな転機になった。 この転機については、こちらの記事でも書いた。 masuda220.jugem.jp

「実装パターン」を何度も読み直し、いろいろ実践した後で、改めて「ドメイン駆動設計」、「リファクタリング」、「オブジェクト指向入門」、「オブジェクトデザイン」を読み直してみたら、それぞれの本の内容がだいぶわかるようになってきた。 特に「ドメイン駆動設計」の現場でのエヴァンスの設計に奮闘するさまざまなエピソードが、生きた事例として理解できるようになってきた。

その後、Value Object 以外にも、「ドメインを隔離する」「アグリゲート」「リポジトリー」「境界づけられたコンテキストとモデルの整合性パターン」などに関心を広げ、現場での設計に取り入れるようになった。

その結果、コードが整理され、エヴァンス本が目指す「進化と成長を続けるソフトウェア」というものがどういうものか、ある程度、理解できるようになった。ドメイン駆動設計は、ソフトウェアの変更を楽で安全する技法として実践的で効果的だという手ごたえを感じるようになった。

もやもや感

そういう手ごたえもあって、現場で実践するだけではなく、ドメイン駆動設計について、ブログを書いたり、イベントで登壇したり、他の現場に出かけて意見交換や助言をしたり、本を書いたり、いろいろアウトプットをしてきた。

アウトプットしながら、新たな気づきがあり、また次の実践とアウトプットということを繰り返してきた。

しかし、どうもすっきりしないもやもや感も抱えていた。 簡単に言えば、表面的形式的には実践できているかもしれないが、本質をとらえ切れていない、あるいは、本質を言語化できていない、という違和感。

現場でのソフトウェア開発の中で、エヴァンス本にでてくるブレークスルー的な手ごたえをいくども経験できたが、偶然感がつよく、もっと意図的にそこに近づく道があるのでは、という漠然とした予感めいたものもあった。

三つのキーワード

去年の夏に、あるイベントのワークショップ用に資料を作っている時に、その違和感を解消する手がかりをつかんだ。 ドメイン駆動設計と他の設計方法を比較して説明するスライドを作っていた時だった。

その資料と作った時点では、まだうまく言語化できていなかったが、それから数カ月、自分なりに手がかりを、なんとか言語化しようと試みてきた。 イベントやワークショップで、実際にいろいろなキーワード(の候補)を使って説明し、その反応を受けとめる中で、三つのキーワードが中核の概念として明らかになってきた。

それが次の三つのキーワード

  • ビジネスルール
  • 計算モデル
  • 型指向のプログラミング
ビジネスルール

エヴァンス本に繰り返しでてくる「ドメインロジック」「ドメインの知識」「ドメインの理解」などの言葉は、具体性に欠ける。 対象が広くぼんやりとしている。

ドメインロジック」をビジネスアプリケーションの分野に限定すれば、ビジネスロジックとなる。 そして、ビジネスロジックはビジネスルールとほぼ同じ意味になる。

ビジネスルールとビジネスロジックを区別するとすれば、ビジネスルールは、プログラムで表現するかしないかとは無関係な、実際のビジネスの活動の中の取り決めや約束事。ビジネスロジックは、ビジネスルールのある部分をプログラムで表現したもの。

いずれにしても「ドメインロジックに焦点を合わせる」は「ビジネスルールに焦点を合わせる」と捉えることができる。 実際のところ、エヴァンス本にも「ルール」という言葉は300回近く登場する。「ポリシー」や「制約」という言葉も含めれば、ドメイン駆動設計の重要な関心事の一つが「ビジネスルール」にあることはまちがいない。

ドメインロジック」を「ビジネスルール」と置き換えてみると、エヴァンスの意図するところが、より具体的に理解できるようになる。

ドメインの知識とは「ビジネスルールの知識」であり、ドメインエキスパートとは「ビジネスルールについての知識と経験が豊かな人」であり、「ドメイン層」はビジネスルールを記述する場所、というわけだ。

ドメイン駆動設計の考え方を理解し実践するカギは、「ドメインロジック」を「ビジネスルール」という、より具体的な対象としてとらえることだ。

計算モデル

ドメインモデル」も、あいまいでわかりにくい言葉だ。

エヴァンス自身が書いているように、ドメイン駆動設計でいうところの「ドメインモデル」はオブジェクト指向のコミュニティで生まれた設計の考え方の一部である。 オブジェクト指向も、いろいろな解釈がある。私は、データモデルへの対比という意味も含めて、オブジェクト指向のモデルとは「計算モデル」だと思っている。

実際に、エヴァンス本に登場するドメインモデルの例は、次のような計算モデルである。

  • 投資シンジゲートの配分比率計算(シェアパイ)
  • コンテナへの荷物の格納ルール
  • 輸送経路を自社に有利にするための経路選択のバイアスポリシー
  • プリント基板の配置ルールを基にした部品配置と配線の妥当性の判定

ドメインモデル」は、なんらかのルールに基づいた「計算と判定のモデル」ととらえると、だいぶすっきりする。

アプリケーション全体としては、データを永続化したり参照したりする仕組みが必要になる。しかし、「ドメインモデル」だけに注目すれば、データの記録と参照からは隔離した、純粋な「計算モデル」という理解がしっくりくる。

「計算モデル」を実行するには、計算の準備としてデータの参照が必要だし、計算結果を記録することも必要だろう。しかし「計算モデル」を、データの参照と記録から意図的に分離することで、「計算モデル」はプログラミングの対象として、よりわかりやすく、扱いやすくなる。

エヴァンス本では、リポジトリや集約の説明のところで、データの永続化の問題が登場するために、この「ドメインモデル=計算モデル」という図式が、ぼやけてしまっている。しかし、全体を読めば、ドメインモデルは「計算と判定のモデル」であり、「データの記録と参照」からは隔離されたものとして扱われていることがわかる。

リポジトリは計算モデルを入出力の関心事から分離する仕組みであり、集約(アグリゲート)はデータの集約ではなく、「計算の集約」を表現する手段だということだ。集約が維持するのは、データベース上のデータの整合性ではなく、計算の整合性であり一貫性ということだ。

型指向のプログラミング

計算モデルをプログラミング言語で表現する場合、例えばFORTRANのような手続き型の言語でももちろんできるが、エヴァンス本が採用している実装技法は、オブジェクト指向である。 エヴァンス本人が、あるイベントで述べているように、本を書いた当時は "I loved Object Oriented." 、 現在は "I still like it" と続けている。温度感は変わっているが、オブジェクト指向が基本であることは変わっていない。

問題は「オブジェクト指向」といってもいろいろなとらえ方があること。 ここらへんの詳しい話は、以下の説明が必読。

jp.quora.com

簡単に言えば「メッセージパッシング」で代表されるオブジェクト指向と、「型」で代表されるオブジェクト指向があり、両者は本質的に異なるアプローチであるということ。 エヴァンス本を読むと、若干の混乱があるが、基本的には「型」を基本とするオブジェクト指向と理解してまちがいないだろう。

ビジネスルールを「計算モデル」ととらえ、計算モデルをコードで表現するには、「型」に基づくオブジェクト指向プログラミングが役に立つ。

「型」とは、計算の対象となる「値の種類」であり、有効な値の範囲と、その値を使った計算を定義したもの。 計算モデルの表現技法として、「型」中心のプログラミングがぴったりというわけだ。

ビジネスアプリケーションであれば、金額、数量、日付、日数、期間などの値の種類を、それぞれ独自の型として定義し、型ごとに、有効な値の範囲と、必要な計算を定義する。

BigDecimal型やLocalDate型は、有効は値の範囲がとてつもなく広く、可能な計算も多岐にわたる。ビジネスの計算モデルを記述するには、焦点がぼやけてしまう。また、ちょっとした記述のミスでバグが混入する可能性が大きくなる。

その問題領域の計算モデルにあわせて、厳密に値の範囲を制限し、必要最小限の計算だけを定義した独自の型を用意することで、プログラムがみちがえるようにわかりやすく安全になる。

エヴァンス本の、配分比率の計算、コンテナの格納条件の判定、経路選定のバイアス計算などは、型指向でプログラミングする具体例になっている。暗黙の概念を明示したり、制約を表現したり、設計の意図を明確にし、変更を楽に安全にする技法として、クラスを使って型を定義するプログラミングスタイルを採用しているわけだ。

実際、価格計算とか日付計算がともなうビジネスルールでは、型指向のプログラミングで記述することで、ロジックを一か所にまとめてわかりやすく整理できる。

値を「型」として扱う設計パターンの代表であるValue Object パターンは、ビジネスルールの計算モデルを実装するための、基本であり最強の道具といってよいだろう。

実験は続く

「ビジネスルール」「計算モデル」「型指向のプログラミング」

この三つのキーワードでドメイン駆動設計を解釈し、実践してみる実験は、まだはじめたばかり。

自分としては、そうとう手ごたえを感じているけど、実際のコードでもっともっと実験し小さな失敗を繰り返しながら、知見を増やし、こうやってブログで書いたりイベントで登壇したり、いろいろな現場で設計に関心とエネルギーを持つ技術者たちと意見交換をすることで、さらに多くの学びができそうな予感にわくわくしている。

参考情報

ビジネスルール・計算モデル・型指向のプログラミングで作ってみたサンプルアプリケーション github.com

このサンプルアプリケーションを解説したときに使った資料

www.slideshare.net

型指向のプログラミングの設計ガイド: 設計ガイドライン · masuda220/business-logic-patterns Wiki · GitHub

参考書籍: gihyo.jp

アウトプットから始まる学び

ドメイン駆動設計やオブジェクト指向設計について、あれこれ考えていることを、自分なりに言語化して、少しずつアウトプットしてみようと思う。

アウトプットの機会を作ると、いろいろなインプットと試行錯誤が始まって、自分の学びが加速するはず。

創造的な学び方のコツ:ラーニングパターン #7 アウトプットから始まる学び