Rのつく財団入り口

ITエンジニア関連の様々な話題を書いているはずのブログです。

【感想】 現場で役立つシステム設計の原則

現場で役立つシステム設計と実装、リファクタリング開発プロセスOOPとDDDの本

 ドメイン駆動設計(DDD: Domain Driven Design)の実践者としても知られる増田 亨さんの2017年7月の本。ネットでもかなり話題になったので読んだ人も多いのではないでしょうか。

 タイトルは「~システム設計~」となっていますが実際は設計以外の話もあるので、もう現場で役立つシステム「開発」全般で役立つ原則本となっています。
技術評論社から各種出ている一般的な技術書サイズで422とボリュームはありますが、内容はかなり推敲されていて文章はとても読み易いです。
 サンプルコードはすべてJava。しかし本書で述べられているテクニックはかの『リファクタリング』や『Code Complete』などのように特定言語の細かな仕様に囚われないもっと普遍的なところに焦点を当てているので、オブジェクト指向言語なら他の言語を使っている方でも、適宜応用して適用できるかと思います。
C#はそのままいけますね。動的言語だとPHPはインターフェースの意味が薄れますが名前空間のフォルダ分けを使っていればいけますね。Pythonは確か1クラス=1スクリプトファイルの原則がないので、多少変わるかも。)
 以下、各章で読み学んだことの整理と感想などを。

Chapter1 小さくまとめてわかりやすくする

 ソフトウェアの変更は基本的に大変である。理由は設計に問題があるから。メソッドが大きい、クラスが大きい、引数が多い……など。複雑さにどう立ち向かえばよいか、明確な視点で基本的なソースコードの例を交えながら始まります。

  • 分かりやすい名前を使う。
  • 長いメソッドは空白を入れて切れ目を入れる。
  • 変数は使いまわさず目的ごとに宣言、使っていく。
  • 内部のロジックをリファクタでメソッドに抽出する。
  • 異なるクラスで同じロジックを重複させない。
  • クラスの関心事を狭く→アプリケーションの対象領域(ドメイン)に特化したドメインンオブジェクトにする。
  • クラスは小さく、メソッドは短くして安全に。
  • intStringなどの基本データ型はなるべく使わずに値を範囲できる専用のクラスにする。(値オブジェクト: Value Object)
  • 値オブジェクトはインスタンス生成時にセット、setterメソッド付けずに不変にする。
  • 値オブジェクトを全面に使ってコードを分かりやすく、安全にする。
  • 配列やコレクション(Listなど)は生で使わずに専用クラスに閉じ込め、メンバ変数に入れてアクセス用のメソッドを作る。

 例もシンプルで分かりやすいので、プログラミングを学習中の方にも理解しやすいのではないでしょうか。感想としては値オブジェクトは存在は知ってたけど実務ではあまり使わないなあと思いました。配列やコレクションをクラスに閉じ込めてpublcなメソッド限定でアクセスるするのは分かるのですが、getList();全面禁止は現実では厳しいなあと。
 中のリストに変更が加わった時、Collections.unmodifiableList() で不変の値にする手法は何を隠そう知らなかったので(おい)参考になりました。

Chapter2 場合分けのロジックを整理する

 続いて業務システムではよくバグの原因や拡張時の難しさの原因になる、場合分けロジックに焦点を当てて進みます。

  • 区分や種別はコードを複雑にするので、分岐ロジックを独立したメソッドに切り出す。
  • if文はelseをなくして短く、判定時に早期リターンですっきり。
  • 疎結合のif文はelseで繋げずに独立したif文にするとすっきりする。
  • 区分は同じインターフェースを継承したクラスに分け、それぞれにロジックを書いてif文/switch文をなくす。
  • 区分をMapに持ったり、Javaなら列挙型(enum)に持てる。
  • 状態を列挙型に持ち、状態遷移をMap<状態、状態のセット>で持って遷移可能なロジックを1クラスに閉じ込める。

 例に出てくる区分の図や状態遷移の図は、まさにJava系の業務システムの現場で出てきそうな例で実践的ですね。区分の分け方をMapに書いたり列挙型で持つテクニックは、オブジェクト指向寄りでなく手続き型寄りで実装されているシステムでもすぐ使える技かと思います。(ネットの感想を見るとデザインパターンのStateパターンの方が良いという意見も見かけますね。)

 本章の参考文献としてはかの有名なマーチン・ファウラー本『リファクタリング』が出てきます。

 原典の方は分厚くてまだ……という人にも、本書は分かりやすく噛み砕いて書いてあるので入り口の入門書としても読めます。

Chapter3 業務ロジックをわかりやすく整理する

 この章あたりから、普遍的な改善テクニックから、ドメイン駆動設計に踏み込んだ内容になっていきます。

  • データだけを持つクラスと機能クラスを別にすると、変更に弱くなる。
  • データクラスを共通で使うと同じロジックが重複しがち。
  • データクラスを使うと、画面に引きずられたりデータベースのテーブル設計に引きずられたりしてどこに業務ロジックがあるか分かりにくくなる。
  • 共通機能化しても、汎用的過ぎたり逆に用途ごとに細かくしすぎたりしてうまくいかないことが多い。

 とデータの入れ物クラスは禁止!という流れになるのですが、現場の実務でコードを書いている方、設計している方にはこのへんは考えが分かれるところかもしれません。
 僕も今まで仕事で携わってきたシステムでデータクラスを使った設計のものは沢山というかだいたいそうだったし、世の中で稼働中のシステムにも沢山あるでしょう。
それにデータクラスを使い回すとロジックが重複しがちだ……という意見は、プレゼンテーション層/アプリケーション層/データソース層とレイヤーごとに別のデータクラスを持つ方式もあります。(こうすると、レイヤー間で変換するときにバグが入る恐れがあるというのはあるんですが。)
 章の中のコラムで、Javaの古い歴史や今やもう旧世代のフレームワークになってしまったStrutsの歴史に触れ、手続き型の延長で来たのでデータクラスが使われてきた事情がある……という話はその通りなので納得です。

 そして本書では、データとロジックは一緒のクラスに! 三層それぞれで関心事とロジックは徹底的に分離せよ!をメインに、ドメイン駆動設計のアプローチでの設計技法を解説していきます。

  • メソッドはロジックの置き場所にする。getterメソッドは基本禁止。
  • 使う側のクラスには業務ロジックを書かない。書いていたら適宜見直して別クラスに移動。
  • メソッドは短くを基本に。
  • メソッドはメソッド引数でなく必ずインスタンス変数を使う。
  • クラスが肥大化してきたららインスタンス変数とメソッドが対応した小さなクラスに分けていき、凝縮度を高めていく。
  • 関連性の強いクラスはパッケージで整理していく。

 インスタンス変数のみ使うというルールは現実的には厳しいと思いますし、じゃあstaticなメソッドの集合のUtil系クラスとかどうなるんじゃいという気もするのですが、後述のドメインモデルの中のクラスでのルールなのでしょうか。
 そして話は、一般的なレイヤー三層の関心事と業務ロジックの分離を徹底することに続いていきます。

  • 現実世界の業務を業務データと業務ロジックを1つにまとめた「ドメインオブジェクト」に流し込み、そして小さく分けていく。
  • システムが大きかったら、ドメインオブジェクトをパッケージごとに分けて整理していく。
  • 業務アプリの対象領域(ドメイン)をドメインオブジェクトの集合として整理したら、そこはドメインモデルという世界にする
  • ドメインモデルは3層と別の場所にする。

 要はドメインモデルという完全独立した王国があって中の国民はドメインオブジェクトのクラスのみ。データの保存は抽象的で、保存先がRDBかNoSQLかファイルかWebAPIかは関係なくドメインモデルは気にしない。ドメインモデルを呼び出す側が画面かバッチか、画面がどんなテクノロジーフレームワークで作られているのかもドメインモデルは気にしない。そういう技術から切り離されたピュアなオブジェクト指向オンリーの世界である。
 またドメインオブジェクトは単位が細かいので、(本書で明言されてはいませんが)テスト駆動開発とも相性がよく、ドメインオブジェクトひとつひとつごとにユニットテストがしやすくなる……
 というような理解でよいかと思います。
 このドメインモデルについては、本書の感想記事のひとつ、Python学習サービスのPyQでお馴染みのビープラウド社の社長さんのブログの感想と図がとても分かりやすいです。

shacho.beproud.jp

 本章の参考文献としてはこちらもマーチンファウラー本のちょっと難しい『PoEAA』、そしてJavaでDDDを実践する際に本書が推奨しているSpring本が挙げられています。

iwasiman.hatenablog.com

Chapter4 ドメインモデルの考え方で設計する

 引き続き、DDDの考え方を全面的に適用した設計手法の話。

  • ドメインモデルで設計する利点:ロジックの重複なし、関心事とコードが直結、変更範囲が狭まる。
  • 利用者の関心事(やりたいこと)=プログラムの単位を一致させる。
  • 分析クラスと設計クラスを一致させる。
  • 業務に使っている用語をそのままクラス名にする。
  • データクラスと機能クラスに分ける「データモデル」を基本に置いた設計でなく、オブジェクトモデルに基本を置いた「ドメインモデル」の設計にする。

 データモデル焦点だとテーブルの関連を示したER図ベースのクラス構成、ロジックに焦点を合わせると業務の関心事に似たクラス構成になる……という例は分かりやすいですね。
 そしてこのドメインモデルをどう作っていくかの話に続きます。

  • 部分を作りながら全体を組み立てる、ボトムアップのイメージになる。(手続き型だとトップダウン
  • 部分と全体を行き来しながら作る。パッケージ図と業務フロー図で俯瞰する。
  • 必要性の高い重要な部分から先に作る。
  • ドメインモデル置き場に蓄えられた独立した部品を組み合わせて、機能を実現させていく。
  • ドメインオブジェクトは機能の一部にしない。特定機能の一部、処理の順番などに依存しない単体で動かせる独立性の高い部品にする。

 そしてドメインモデルを構成するドメインオブジェクトの見つけ方の話へ。

  • 業務の関心事をヒト/モノ/コトに分類して見つけ、整理していく。
  • 特にコトに注目するとよい。
  • 上から下に手続き型で判断して処理が並ぶのが手続き型、オブジェクト指向ではロジックごとにオブジェクトを生成してその中で判断する。

ここで手続き型の上から下にずらーっと続くようなコードを指して「トランザクションスクリプト」と称しているのは、『エンタープライズアプリケーションアーキテクチャ』での用語ですね。

 続いて、ドメインオブジェクトの基本パターンの説明。

  • 値オブジェクト、コレクションオブジェクト、区分オブジェクト、列挙型の集合層操作が基本。
  • 業務の関心事は口座(Account)、期日(DueDate)、方針(Policy)、状態(State)パターンが多い。

 そして設計の段階的な改善方法については以下。

  • 最初に決めたクラス名はそれで作業を続け、不適切になってきたら変更する。
  • 一旦使う側のクラスにコードを書いてもよいが、長くなったら部品側クラスに移動する。
  • 値オブジェクトが多くなったてきたら親クラスにの中に集めたりしていく。(住所の中に郵便番号など)
  • 業務の言葉=コードで一致すると変更が楽になる。
  • 業務を理解していく。

 最後に、業務を理解するのが大事だという話になります。

  • 業務の暗黙知を引き出す。
  • 聞きなれない言葉をキャッチして、重要なものをドメインモデルに反映する。
  • コンテキスト図、業務フロー図、パッケージ図、主要クラス図で整理する。
  • 業務用語のあいまいさを具体的にし、徐々に増やし、知識を広げてドメインも成長させていく。

 本章の参考文献はDDDの原典といえばこれ、エリック・エヴァンス本。

 この本の入門的な内容にもなっているので、原典は難しそうでまだチャレンジできないという方にもDDD入門としておすすめかと思います。何を隠そう、僕も電子書籍でセールの時に購入済みなのですがネットの感想を見るにかなり難解ということで挫折しそうでまだ読んでません……w

Chapter5 アプリケーション機能を組み立てる

 本書ではアーキテクチャのレイヤーをプレゼンテーション層/アプリケーション層/データソース層の三層+独立したドメインモデルに分けて解説していますが、一旦DDDから離れて基本三層、アプリケーション層の話になります。
 アプリケーション層のクラスをサービスクラスと呼び、Javaでの実装フレームワークとして本書はSpringを推奨。アノテーションで他のレイヤーのクラスを組み込める例を示しています。

  • プレゼンテーション層には極力処理を入れない。
  • サービスクラスに処理が入り込みやすいので、ドメインモデルに切り出していく。
  • サービスを使う側、提供する側で提供の約束ごとを決めて設計をシンプルに保つ。「契約による設計」を重視、逆の防御的プログラミングで引数チェックなどを膨大にすると複雑になりがち。
  • プレゼンテーション層の影響を受けやすいので、登録系/参照系でサービスクラスを分ける。
  • 複数のサービスクラスを配下で呼ぶ組み合わせ用サービスクラスを作り、シナリオクラスとする。

続いてアプリケーション層とDBを繋げる際の話に。

  • DB操作でなく業務の関心事で考える。
  • ドメインオブジェクトの保管と取り出しはDBに縛られない架空の収納場所として、リポジトリクラスとして宣言する。
  • リポジトリクラスのメソッドで業務の関心事を宣言し(残高照会など)、実際のDB処理はその裏に隠す。
  • サービスクラスの記述は、DB操作とは関係なくする。

Chapter6 データベースの設計とドメインオブジェクト

 そしてデータソース層、RDBでの設計手法とDDDの適用の話。

  • テーブルのカラムの用途は分かりやすくする。
  • 複数の用途に使ってしまう巨大なテーブルを作らない。
  • テーブル名、カラム名で名前を省略しない。
  • 適切なデータ型を使う。
  • NOT NULL制約、一意性制約、外部キー制約をきちんと使う。
  • 記録のタイミングが違ったら別テーブルに分ける。
  • 記録の変更は禁止する。(UPDATE禁止、取り消しデータと新データをINSERT)
  • カラムの追加は外部キー制約でつながった新テーブルにすると影響範囲が狭まる

  • テーブルは「コト:の記録を基本として、記録のたびに状態を更新する別テーブルを補助で持つ。

  • 残高テーブルはUPDATE禁止にしてDELETE/INSERTで実行。
  • 残高の記録と残高の更新は同時でなくてもよい。
  • 非同期メッセージングなどを活用すれば、残高更新は一か所でなくてもよい。
  • 派生的な情報を転記してイベントソーシングしていく。

 RDB設計の普遍的な話もありますが、中では記録の変更禁止でUPDATE文禁止はやりすぎでは?と感じました。履歴テーブルに持つことが多いのではないでしょうか。
 続いてオブジェクト指向のオブジェクトとテーブル設計の関連について述べています。

  • オブジェクトとテーブルは互いに似てくるか、どちらかに合わせると失敗する。あくまで違うものとして扱う。
  • 互いをマッピングする仕組みはフレームワークによくあるが、ドメインオブジェクトには持ち込まない。
  • ドメインオブジェクトの設計にDBの知識や都合を持ち込まない。

 本書ではJavaEE6や7で導入されたDBアクセス機能のJPA(Java Persistence API)はテーブルを意識したアノテーションだから非推奨、オブジェクト設計とテーブル設計が別だという発想を元にしているMyBatisを推奨しています。このへん興味深いです。

Java Persistence API - Wikipedia MyBatis – MyBatis 3 | イントロダクション

 本章の参考文献に挙げられているのは『理論から学ぶデータベース実践入門』、『SQLアンチパターン』、『データベース・リファクタリング』。最後の1冊は2018年現在だとあまり見ない本ですね。

iwasiman.hatenablog.com

SQLアンチパターン

SQLアンチパターン

  • 作者:Bill Karwin
  • 発売日: 2013/01/26
  • メディア: 大型本

Chapter7 画面とドメインオブジェクトの設計を連動させる

 続いて今度はシステム入り口のプレゼンテーション層とDDDの適用の話。
 画面に引きずられて他のレイヤーも設計するとソフトウェアの変更が大変になる。業務ロジックの混在、複数画面に同じコードなど……。
 そこでここでも「関心事」を分けて整理、独立させていくのが大事だと論じています。

  • 複雑な画面は異なる関心事が混ざっている。(注文者と注文した商品、配送先...)
  • 巨大なクラス、メソッドで処理していたら、小さな単位で分けていく。
  • 画面も分けていく。(タスクベースのユーザインタフェーススマホ対応)
  • 画面とドメインオブジェクトが対応したら、そのまま使うか、表示用ロジックを持つビュー用オブジェクトを用意する2つの方法がある。本書ではそのまま使うのを推奨。
  • 画面とドメインオブジェクトが一致していなかったら、画面の関心事をそのまま表現すればドメインオブジェクトになるはず。
  • 項目のグルーピングは画面デザインの4原則:近接/整列/対比/反復 を使う。
  • 画面デザイン側/ドメインオブジェクト設計側で一緒になって検討していく。

 本書ではドメインオブジェクトをそのまま画面側に使う例で、画面に出すメッセージのロジックやHTMLのclass属性をドメインオブジェクトのクラスに書く例が載っていましたが、ここは疑問に感じました。
 あれほどドメインモデルは三層とは完全に切り離された領域だとこれまでの章で説明してきたのだから、いったん画面用のクラスに変換して使うのが普通なのでは……? 画面とドメインモデルにあまり差がない場合を想定しているのでしょうか。

 参考文献としては以下が載っています。

ノンデザイナーズ・デザインブック [第4版]

ノンデザイナーズ・デザインブック [第4版]

  • 作者:Robin Williams
  • 発売日: 2016/06/30
  • メディア: 単行本(ソフトカバー)

Chapter8 アプリケーション間の連携

 そして三層+ドメインモデルの話が終わった後は、アプリケーション(システム)同士で連携する時の設計手法まで述べているというおトクな内容になっています。
 本書では連携方式を4パターン:

  • ファイル転送/データベース共有/WebAPI/非同期メッセ―ジング

としてそれぞれの長所短所に触れたうえで、最近よく使われ、アプリケーションの変更容易性に影響するWebAPIにターゲットを絞って解説しています。

  • 要求の対象(リソース)をURIで定義
  • 要求の種類をHTTPメソッドで指定
  • エラー時はHTTPステータスコード、レスポンス内容で区別

 このへんは基本の話。そしてWebAPI設計手法の話になります。

  • APの粒度が大きすぎると、組み立て方は単純だが機能は限定的。粒度が小さいと、組み立てが複雑になるが幅広い機能に対応できる。バランスが大事。
  • まずは単純な用途のAPIを作り、動かしながら設計を発展させていく。
  • WebAPI用のフレームワーク/ライブラリを活用したり、APIドキュメント自動生成のツールを利用し、APIの提供側と使う側で協力して成長させていく。
  • 小さなWebAPIの設計原則:参照と登録を別APIにする(GETとPOST)、リソースの単位ごとにURIを分けて別APIにする。
  • URIにバージョン番号を入れる手法もある。
  • 提供する側は基本API提供のレイヤー、複合サービス提供のレイヤの2階層に分ける。提供する側は小さい単位の部品をメインにし、複合サービスは極力使う側で開発していく。

 そしてDDDのドメインオブジェクトをWebAPIにどう適用するかについては、の話。

  • データだけが関心事なので、ドメインオブジェクトの階層構造をWebAPIで返すのは意味がない。
  • ドメインオブジェクトにあってもWebAPIを使う側では不要のデータもあるので、DO→レスポンスオブジェクト→通信を返す、通信を受ける→リクエストオブジェクト→DOと途中に変換オブジェクトを持つと良い。
  • コード:対応する名前の導出結果については、コードを返し、コードから名称を得られる別APIを用意するのは密結合になるので△。
  • 導出するための計算ロジックは、どちらのアプリが管理すべきかで判断。日付は日付と時刻は別に扱う。現地時間か標準時間かはAPIの仕様で決め、タイムゾーンは入れず人間に理解できる表現にした方が良い。

 やはり何でもかんでもドメインオブジェクトをそのまま使うのではなく、ドメインモデルの外側では必要に応じていったん変換してから使う方式で良いんですね。
 日付の話は、タイムゾーンまで必要になるAPIもあるだろうし、状況によるのかなあと思いました。
 そして大規模システムになるとよく出てきて費用がかさんだり開発の難易度が上がったりする、連携先が複数になったり複雑な連携をする場合。こうしたケースWebAPIをどうすべきかの話が最後に載っています。

  • 基本API/拡張API/個別対応APIの3グループに明確に分け、それぞれを別に拡張していく。
  • 定期的に見直し、所属グループが違うと思ったら移動する。
  • より小さなアプリケーションに分ける、マイクロサービスの考え方が最近は出てきている。
  • 交換対象のデータが複雑で属性情報が多い場合は、JSONよりXMLを使うとよい。
  • 連携が複雑なときは、WebAPIより非同期メッセージングを使うとよい。独立性が保て、中間のメッセージング基盤のところでデータの中間加工が可能で、人間の仕事のやり方に似たやりとりができる。

 参考文献では『Web API: The Good Parts』『マイクロサービスアーキテクチャ』が挙げられています。後者は僕も仕事で大まかに読んだのですが、確かにシステム間連携が重要になってくると単に連携用のWebAPIの口を作るだけでなく、アプリケーションの単位を小さくして……という話になってもきますね。

Web API: The Good Parts

Web API: The Good Parts

マイクロサービスアーキテクチャ

マイクロサービスアーキテクチャ

  • 作者:Sam Newman
  • 発売日: 2016/02/26
  • メディア: 単行本(ソフトカバー)

Chapter9 オブジェクト指向開発プロセス

 続いては開発そのものだけでなく、開発マネジメントの視点からの章もあって本当にお得な本です。

  • 従来のVモデルはフェーズ区切りだったが、オブジェクト指向では「作業の単位」であり、何回も同じチームで繰り返す。
  • 短期間の開発と修正、拡張を繰り返すスタイルが増えた。オブジェクト指向が向いている。
  • フェーズごとに担当者を完全に分けて大きいソフトを作る(大手SI企業のウォーターフォール的手法)のも、逆に分析や設計を軽視していきなりプログラミング重視で進める(小規模のベンチャーやWeb系企業でありそうな手法)のも、両方まずい。

 そしてドメインモデルを中心に据えた開発では以下のようになると論じています。

  • 分析と設計を同じチームで一貫、業務ロジックに焦点を当てる。
  • 大量ドキュメントを作らず、同一チームでスピードを上げて作業。
  • ソースコード自体をドキュメントにする。
  • 対面での質疑応答やホワイトボードのラフスケッチ、記録を活用する。
  • ドキュメントは利用者向けのもの、画面や帳票の情報、DB仕様の3種類をメインに。
  • 全体俯瞰のドキュメントを作って活用する。
  • ビルドや環境構築のスクリプトも丁寧に文書化し、別途ドキュメントを作らなくて済むようにする。
  • 非機能要件は監視ツールや性能テストなどなど、ビルドスクリプトやテストコードも文書とする。
  • フェーズ別方式だと分析/基本設計は期間内の作業に対価を払いう準委任契約。そして詳細設計/実装は完成物に対価を払う請負契約が多い。オブジェクト指向では変化に対応しやすくするため、後半も準委任にすべき。
  • 分析や設計の進捗判断は、コードで行う。
  • 品質保証は、テストは業務視点寄りで行う。同じ人が分析設計実装をしていれば品質は上がり、その人が業務を理解していれば品質は大丈夫とみてよい
  • 分析、設計、実装を全てやるメンバで体制を組む。プログラムが一定できる人を条件、さらに業務要件の理解や整理にやる気のある人を選ぶ。
    (逆に分析設計はできるが実装はできない人はメンバーに選ぶなと読めます。)

 本章だけは参考文献も特になし。オブジェクト指向だと必ずこの開発プロセスになるよ、という話ではなく、エクストリーム・プログラミング/アジャイル/スクラム寄りの開発プロセス論にDDDを取り入れた場合はこうすると上手くいく、こうするべきだ……という、ちょっと理想論寄りの話だと受け取りました。
 というのは例えば進捗をコードで管理といったって実装はもう全然分からないマネージャーの人なんて現実には一杯いるし、品質保証もテスト結果を集計したり色々やることはあると思います。全フェーズですべて同一チームメンバですべて同じ場所で作業するのも現実には難しいし、突き詰めるとSI系開発では実践は無理で自社でサービス継続開発してる会社でないと実現できないのでは?という話になってきそうですがそれはさておき。
 本章はお手本として参考にしたり、詳しくは開発プロセスを論じた各方面の本に進んだりしていけばよいと思います。

Chapter10 オブジェクト指向設計の学び方と教え方

 一番最後は、本書を読んだ個人だけではなく、チームで共通理解するための学習方法も載っています。こういうアプローチがあるのは良いですね。

  • 昔からオブジェクト指向の説明は分かりにくい
  • 長所を説明されても、開発を途中で抜けたり保守で小さいレベルの修正しかしていない人だと、何がよいのか実感できない

 『オブジェクト指向でなぜ作るのか』本でも解説しているOO特有の分かりにくさですね。

iwasiman.hatenablog.com

オブジェクト指向でなぜつくるのか 第2版

オブジェクト指向でなぜつくるのか 第2版

  • 作者:平澤 章
  • 発売日: 2011/04/07
  • メディア: 単行本

これを解決する方法を本書では2つ述べています。

①既存コードを改善しながらオブジェクト指向を学ぶ

 かの有名な『リファクタリング』を参考に、ソフトウェアの変更を実地で学ぶ方法。
 重複したコードの抽出、長いメソッドの分割、巨大なクラスの分割、、リファクタは部分的にやっていく、小さな部品の組み合わせにする、よりよい名前に改善、新しいロジックは別クラスに抽出、クラスを束ねるクラスを作る……と、同書のサマリ的に各種手法を示唆しています。
 プログラミングの学習自体もそうですが、設計の改善、コードの改善も実際にやるのが一番ですね。改善対象のアプリケーションが存在しないとできないというのがありますが、やはりこちらかと思います。

②Object OrientedなOOらしい設計を覚えるために、過激なコーディング規則を適用する

 2008年発行の『ThoughtWorksアンソロジー』を参考にした9か条の規則。

www.thoughtworks.com

 このThoughtWorks社はかのマーチン・ファウラー氏などアジャイル関係のその筋の凄い人たちがいるアメリカの会社ですが、この本自体は日本ではあまり有名でない気がします。

この過激なコーディング規則をざっとまとめますと……

  1. 1つのメソッドにインデントは1段階まで(メソッド抽出を徹底)
  2. else句禁止(ガード節と早期リターンを活用し判断を簡潔に)
  3. プリミティブ型と文字列型はすべてラップ(値オブジェクトを使う)
  4. 1行にドットは1つまで(2ドット以上は説明用の変数にいったん格納)
  5. 名前を省略禁止(QtyでなくQuantityなど)
  6. エンティティを小さくする(メソッドは3行以内、クラスは50行以内、パッケージ内のクラスは10個以内)
  7. 1クラスのインスタンス変数は2つまで(クラスの意図を明確に、巨大な神クラスを作らない)
  8. ファーストクラスコレクションを使う(対象の配列やListを1つだけ持つ独立クラス)
  9. getter/setterメソッド、プロパティを使用しない(データクラス撲滅、コンストラクタで入れたら後は不変)

 うーん凄まじいですね。要は本書でも解説してきた各種テクニックを徹底できるルールなんですが、なんという苦行。これを前触れなくプログラミング中の現場で途中からいきなり適用されたら発狂する人が出るんじゃないしょうか。(笑)
 まあOOの達人になって極めるとこれぐらいになるということで、まずは参考に留めるのが現実的でしょうか。
 取り上げた以外の参考文献は、2007-2008年ごろのちょい古めの本が挙げられています。

実装パターン

実装パターン

気になったところ

★非常によい内容でサンプルコードも簡単めで分かりやすいのですが、それだけにif() {のスペースが抜けてる、1行のif文の前後の {} が省略した記法になってる、enumが小文字、staticなコードの書き方……など、Javaの一般的なお作法にちょい従ってないところが気になりました。……と思ったら、同様の感想がネットに幾つも出てました(笑) やっぱりみんな同じことを思うんですね。僕はif文の中は1行でも必ず {} で括る派です。

★本ですから主張が入るのは当然ですが、DDD的なアプローチでクラスのsetter/getter禁止やインスタンス変数オンリーとかテーブルのUPDATE禁止やNULL禁止、最後の過激なThoughtWorks流コーディング規則など、現実的に考えるとやりすぎじゃないかなあというところもちらほら。
 本書はブログ界隈やQiitaやはてブなどでも反響が大きかったのですが、ぐぐると関連する検索キーワードで「批判」が出てきたり、反対する意見も見かけます。概観すると実地の現場の開発が分かっている人ほど、「現実はそんなにうまくいかんぜよ」と懐疑的な感想を漏らしているように思います。
「設計にベストプクティスはない」と言われるように、特にオブジェクト指向周りのあれこれは唯一の正解がなく厄介な側面があります。本書は読む人の立場や状況にとって100%正しい教科書になることもあるし、正しさ70~80%の参考書になることもあるでしょう。「ここは書いてある通りだ」「ここはオレの意見だと違う!」などと考えるきっかけになる意味でも、本書には価値があるのではないでしょうか。

★あとネットの感想でよく見るのが、ドメイン駆動開発のコードのもっと本格的なサンプルが欲しいという話。
 確かに僕も感じました。本書のサンプルコードは簡潔な例なので、あ~確かにこのOO的、DDD的アプローチだと数量や金額の計算が簡単になるな~とスッキリ分かるのですが、もっとロジックが複雑だとどうなるんだろう、通貨にドルがあって国際化の時はどうすんだとかRDBの話で行くと性能は大丈夫なんだろうかとか、突き詰めるとキリがないんですね。
 僕もドメイン駆動開発に従ってシステムを丸ごと作った経験がないので実情が分からないのですが、DDDアプローチでの設計はどうも理想像っぽい側面があり、そんなに上手くいくのかな?とちょっと懐疑的にも思っています。
 自社Webサービスのコードとかお客さんに納入したシステムのコードとか丸ごとGitHubに載せたりしたら大問題ですが、DDD的に作った小規模アプリケーション一式のコードなんがあると分かりやすいですね。

 このドメイン駆動開発については日本でも調べたり探求している方もいるので、見ていくとよいかと思います。このブログで読者登録している所ですと例えばlittle hands' labさんのところなど。

little-hands.hatenablog.com

まとめ:オブジェクト指向ドメイン駆動設計、リファクタリング、画面/DB/WebAPI設計に開発プロセスまで1冊でお得に学べる良書

 というように、僕も主に非アジャイルSIer寄りの立場で開発経験がいろいろある分懐疑的な感想も持ちましたが、本自体は非常によくできています。字がけっこう大きい割に多岐にわたる内容がコンパクトに詰まっており、相当内容を練ったのだろうなあと推察します。
 参考書籍としてたびたび登場する『エリック・エヴァンスのドメイン駆動設計』は実際には1、3、4、5、7、8、10章とほぼ全体で参考に挙げられており、本自体がDDDアプローチを基本にしているのが分かります。一般的なオブジェクト指向に基づいた事項とドメイン駆動設計に基づいた事項は、ある程度切り離して読んだ方がよいでしょう。
 汎用的なオブジェクト指向の入門、そこから派生してドメイン駆動設計の入り口、コードのリファクタリングにも各レイヤーとDBとWebAPIの設計も、さらにプロセスからマネジメントからオブジェクト指向の学び方まで一冊に詰まってこのお値段。凝縮度の高いクラスのようにおトクな一冊です。

 Java言語を勉強中の方には1章から、2~3章あたりからはもう実際に開発している人向けでしょう。ある程度の規模の開発の現場に配属されたフレッシュなメンバーにも、数年目の中堅の人にも、リーダークラスの人、DBの人、上のアーキテクトクラスの人やマネジメントの人にも、それぞれの立場でそれぞれ得るもの、考えるものがある本だと思います。

 よく勉強会や読書会に使われているのも見かけるので、そういった催しでお題にするのも面白そうです。

おまけ リンク集

 ググると出てきますが、著者の増田亨さんがご本人のブログで感想エントリをまとめられています。

masuda220.jugem.jp