設計こちらの本を読んででのレポートです。...と言われると、うまく言語化説明できない。そんな私にたくさんヒントを与えてくれた本でした。消化しきれていないところもあるのですが、腹落ちさせるためにもブログに落としてみます。思ったら、そうでもない?この本のすごいところこういうコードは修正が大変ですよね。風にリファクタリングしましょう!...と、身近なイケていないコードのリファクタリングの話を読んでいたはずが、いつの間にかドメイン駆動な設計の話に移っていきます。わからんかったけどとりあえず見た。」という事柄が、随分噛み砕かれ、理解しやすく書かれています。エリック・エヴァンスに勝てなかった方には大変オススメ。方にもおすすめの一冊です。(第1章より)ソフトウェアの変更は大変。どこに何が書いてあるかを理解するまでに、調査に時間がかかるちょっとの修正なのに、変更すべき箇所があちこちに散らべっている慎重に修正したのに、思わぬ副作用に苦しむこういった変更が大変なプログラムは以下のような特徴がある。メソッドが長いクラスが大きい引数が多いならばリファクタリングしましょう。わかりやすい名前を使う目的ごとに変数を用意するメソッドを独立させる異なるクラスの重複したコードをなくす狭い関心事に特化したクラスにするここまではおそらく、ほぼ万人に受け入れられる、「当たり前のこと」ではないでしょうか。うんうんそうだよね、と読める内容。ところがここからじわりじわりと、人によっては「お!?」と思うような内容が書かれています。Object)を用意する。基本データ型を使わない。数量を扱うために、Quantityクラスを作り、1以上100以下の様に制約も記述する。マイナスや非常に大きな値もの取りうるintをそのまま使わない電話番号を扱うのに、フォーマットのルールまで定めたTelephonNumberクラスを作る。Stringをそのまま使わない値オブジェクトを作ることで、業務の用語がプログラム中に現れるため、変更の際の調査が用意になる。値オブジェクトはImmutableに。いう意見が出てきそうなところです。実際、私が今まで仕事で見てきたプログラムでは、ここまで徹底して値オブジェクトが作られているものは見たことがありませんでした。コレクションオブジェクトを用意する。配列やコレクションを表に出さない。ループなど、コレクションを扱うコードは複雑になりがち。プログラムのあちこちに散らばり始めると読みにくくなる専用のクラスに閉じ込める。Listを直接表に出さないで、Customersというクラスを作り、そのインスタンス変数としてListを持つImmutableにするため、インスタンス変数をそのままGetterで返さない。確かに、Javaでは8以降Lambda式が導入され、コレクションに対する処理の記述力が高まりましたが、だからこそ(?)複雑なStreamによる、一見するとよくわからない処理がかえって増えたようにも感じていました。この方法にすることで、強制的に各処理に名前をつけざるを得なくなるため、可読性は高まりそうです。「一個のインスタンスだと思って蓋を開けたら実はリストだった。」ということもありそうに感じました。(第3章より)この章の主張はデータとロジックを別のクラスに分けることがわかりにくさを生むデータと機能が分離していると...同じ業務ロジックがあちこちに重複して書かれるどこに業務ロジックが書いてあるか見通しが悪くなるという内容。データとロジックはセットで。いう縛りを作ることで、自然にロジックが書かれる場所が定まり、どこに何が書いてあるのかわからなくなる事自体を防ぐ、という話です。Javaにおいて、データだけ持つデータクラス(=DTO、Entityクラス、JavaBeans、...)はよく見る手法...なのですが、Javaはオブジェクト指向であり、データクラスはふさわしくないデータクラスが広まったのは、Javaが業務サービスに導入された当時、COBOLやCなど手続き型言語の設計方法や開発方法が踏襲されたためJ2EEやStrutsはこの流れで生み出されてしまったと、なかなか衝撃的なことが。「Logicクラスって何??」と感じた原因がわかったように思えます。メソッドをロジックの置き場にする(=ロジックのないメソッド禁止)getterのように単に値を返すメソッドはダメ。メソッドはもっと役に立つもので無くてはならないもしgetterを見つけたら、getterを呼び出している側に注目。getした値を使って何かの「判断/加工/計算」をしているはず。その「何か」ごとデータを持つクラスに移動してみるこのようなリファクタリングを繰り返していくことで、徐々にロジックが「データを持つクラス」に集約され、ロジックが重複して実装されることがなくなる、としています。本書の特徴として、はじめから上に挙げたような、完璧なオブジェクト指向で実装されることを要求していません。実装当初はデータクラスや、ただのgetterを作るのは問題ない(そちらのほうが書きやすい場合がある)。動くようになったあとで、このようなリファクタリングを繰り返していくことで、ソフトウェアの変更容易性を善くすることができると主張されています。TDDと根底の考え方は一緒ですね。リファクタリングする。「『メソッドの振る舞いを記述したユニットテスト』は、テストそのものがリファクタリングの邪魔になるのでは?」と、感じました。大きなメリットユニットテストが書かれている時点でメソッドは小さく、テストしやすいもののはず。いうことに気づきました。メソッドは必ずインスタンス変数を使うインスタンス変数を使っていないメソッドはそのクラスのメソッドとして不適切。ロジックの置き場を再検討するべき。これは先程の、「データとメソッドは同じクラスに置く」と逆のことをいっています。このようなメソッドです。ROUND_HALF_UP);}このメソッドは引数から全ての値を得ており、インスタンス変数を全く使っていないため、このクラスに存在している明確な理由がないのだそうです。このような考え方はしたことがなかったので、衝撃的でした。APIの作り方(第8章より)ここまでは一貫して、ロジックはデータの近くに置くはじめから完璧なプログラムは書けない。徐々にリファクタリングして良い設計にしていくということが主張されてきました。データを使ったロジックはデータを提供する側のAPIに置くAPIを利用する側には極力ロジックを書かないしかし、どうやらそう単純ではないようです。いう問題について、どちらに置くにしてもロジックを持つ側の負担が増えるロジックをどちらのアプリケーションが管理すべきかで判断すると書かれており、「データを持っている方に置くべき!」という論調ではありません。それぞれのサービスを担当する人が違うことによって、一つのアプリケーション内で閉じた話とは、格段に難しさが増しているようです。基本データ(ここでは生年月日)の形式や内容の変更が利用する側のコードに大きく影響する逆に、導出結果を渡すAPIでは、基本データの形式や内容に変更があっても利用する側への影響は少ないとあります。基本データを変更することになるのは普通、提供側の都合(あるいは他の利用者の都合)だと思うので、ロジックを提供側に閉じ込めておいたほうが修正が早く、またテストもしやすくなると、個人的には思います。本書で一貫して述べられてきた、データとロジックを一緒にすることでロジックの分散を防ぐ、という内容に沿わせることを考えると、やはり、データを持っている側のサービスにロジックを書くほうが全体として適切な構成になるのではないでしょうか。(逆にこれで統一しないのであれば、提供する側は徹底してデータしか提供せずロジックは持たない、というルールにするべきだと思います。著者の増田さんご本人からコメントいただきました!ありがとうございます。APIのところは、私も、まだ悩みながらやっています。APIの利用者が特定できる少数の場合と、不特定の多数を想定する場合では、違う設計になりそうですね。2017年11月5日ご本人がまとめられている書評一覧を発見したのでメモ。他の方の意見が参考になります。#gunmawebGunma.webさんの勉強会に参加してきました。テーマはDDDでした...2017-11-12雑記:MVC「コントローラ」ってコントローラか。読者になる検索リンクはてなブログブログをはじめる週刊はてなブログはてなブログPro最新記事awkで特定の列を除外して出力するWindows10にOracleをインストールしようとしたらありがちな罠にハマった古いプログラムからも学ぶことがある...と思う。#rtechconf月別アーカイブ参加グループプログラミングインターネットテクノロジーはてなブログをはじめよう!taichiwさんは、はてなブログを使っています。ブログを報告するスターをつけました引用をストックしましたストック一覧を見る閉じる引用するにはまずログインしてくださいログイン閉じる引用をストックできませんでした。再度お試しください閉じる限定公開記事のため引用できません。