現場で役立つシステム設計の原則
種別:kindle
プロジェクト:仕事
開始1:2017/09/04
終了1:2017/09/22
開始2:2018/08/20
終了2:2018/08/20
目次
- 第1章 小さくまとめてわかりやすくする
- なぜソフトウェアの変更は大変なのか
- ソフトウェアの変更に立ち向かう
- 変更が大変なプログラムの特徴
- 変更するたびに変更が大変になる
- プログラムの変更が楽になる書き方
- わかりやすい名前を使う
- 長いメソッドは「段落」に分けて読みやすくする
- 目的ごとに変数を用意する
説明用の変数の導入
- メソッドとして独立させる
- 異なるクラスの重複したコードをなくす
- 送料のドメインクラス
- 狭い関心事に特化したクラスにする
- メソッドは短く,クラスは小さく
- 小さなクラスでわかりやすく安全に
- データとロジック
- 基本データ型の落とし穴
- 値の範囲を制限してプログラムをわかりやすく安全にする
- 「値」を扱うための専用のクラスを作る
- Stringで持つのではなく、
Telephoneクラス=Value Object
を使う - Factoryでインスタンス作ろうとしてだめなら例外というのがよいのかね。
- Stringで持つのではなく、
- 値オブジェクトは「不変」にする
- 完全コンストラクタ(値を変えるときは別インスタンスを返すhoge.minus(100)見たく
- 「型」を使ってコードをわかりやすく安全にする
- 引数にValueObjectを使うと安全になる
- 複雑さを閉じ込める
- 配列やコレクションはコードを複雑にする
- コレクション型を扱うコードの整理
- コレクション型を扱うロジックを専用クラスに閉じ込める
- 顧客の追加や削除、カウント、絞込抽出などをやるコレクション専用のクラスを創る
- ファーストクラスコレクションオブジェクト 使う側のプログラムの記述が簡単になるように、使われる側のクラスに便利なメソッドを用意するのがクラスベースオブジェクト指向設計のコツ
- コレクションオブジェクトを安定させる
- return new Customers(result.add(customer));
- Collections. unmodifiableList( customers);
- getList()がほしいときは使う側でなにをしたいかを考えてコレクションオブジェクトに持ってこれないか考える→顧客にaddしたいのか
- addするときも新しいオブジェクトを使って動作させる、あるいはunmodifiableListして返す
- 変更出来ない顧客のリストにして返すと副作用を防げる→これむずいな。前提として顧客クラスにロジックを集めておくことが必要
- コレクションオブジェクトは業務の関心事
- なぜソフトウェアの変更は大変なのか
-
第1章のまとめ
- 第2章 場合分けのロジックを整理する
- プログラムを複雑にする「場合分け」のコード
- 区分や種別がコードを複雑にする
- 判断や処理のロジックをメソッドに独立させる
if(isChild()){ childFee(); } childFeeはFeeクラスの中の値を変える (isメソッドはそこそこ使いこなせているかな)
- else句をなくすと条件分岐が単純になる
* 早期リターンとガード節
-
複文は単文に分ける
- if節の疎結合
- 区分ごとのロジックを別クラスに分ける
- childFeeクラス、adultFeeクラス
- 多態性
- 区分ごとのクラスを同じ「型」として扱う
- インタフェース使え、多態。コレクションで力を発揮する
-
- 区分ごとのクラスのインスタンスを生成する
- Javaの列挙型を使えばもっとかんたん
- 区分ごとの業務ロジックを区分オブジェクトで分析し整理する * 区分タイプ
- 状態の遷移ルールをわかりやすく記述する
allowed = (xxxx,EnumSet.of(aa,bbbb));boolean canTransit(from,to)
- 第2章のまとめ
- プログラムを複雑にする「場合分け」のコード
- 第3章 業務ロジックをわかりやすく整理する
- データとロジックを別のクラスに分けることがわかりにくさを生む
- 業務アプリケーションのコードの見通しが悪くなる原因
- データクラスを使うと同じロジックがあちこちに重複する
- データクラスを使うと業務ロジックの見通しが悪くなる * 画面の構造に引きづられる * データベースの都合に影響される
- 共通機能ライブラリが失敗する理由
- 業務ロジックをわかりやすく整理する基本のアプローチ
- 【COLUMN】 データクラスが広く使われているのはなぜか
- データとロジックを一体にして業務ロジックを整理する
- 業務ロジックを重複させないためにはどう設計すればよいか
- メソッドをロジックの置き場所にする
- 業務ロジックをデータを持つクラスに移動する データを持つクラスに業務ロジックを集めることがコードの重複や散在を防ぐ、オブジェクト指向の基本です
- 使う側のクラスに業務ロジックを書き始めたら設計を見直す * 動いたから良しとして放置するか、設計改善を続けるかそこが分水嶺
- メソッドを短く書くとロジックの移動がやりやすくなる
- メソッドは必ずインスタンス変数を使う
- 凝集度が高いクラスを作るようになる
- リファクタリングし続ける
- テストがあるのが前提だな
- 引数だけで動くメソッドはそこにある必要がない
- クラスが肥大化したら小さく分ける
- クラスが全てのインスタンス変数を使うようになる
- パッケージを使ってクラスを整理する * classなら修飾子つけずにパッケージスコープ、メソッドは継承考えてprotected、パッケージにpublicをひとつもって扉にするイメージで良いのかしら?
- 三層の関心事と業務ロジックの分離を徹底する
- 業務ロジックを小さなオブジェクトに分けて記述する
- 業務ロジックの全体を俯瞰して整理する
- どのパッケージに置くべきか、どのパッケージの内容を知っていてよいか、だめか、を整理、改善し続ける
- 三層+ドメインモデルで関心事をわかりやすく分離する
- 第3章のまとめ
- データとロジックを別のクラスに分けることがわかりにくさを生む
- 第4章 ドメインモデルの考え方で設計する
- ドメインモデルの考え方を理解する
- ドメインモデルで設計すると何がよいのか
- ドメインモデルの設計は難しいのか
- 利用者の関心事とプログラミング単位を一致させる
- 分析
- 設計
- 分析クラスと設計クラスを一致させる
- 業務に使っている用語をクラス名にする
- データモデルではなくオブジェクトモデル
- ドメインモデルとデータモデルは何が違うのか
- データとドメイン。データ中心主義からの離脱がドメイン駆動なのかな。。
- なぜドメインモデルだと複雑な業務ロジックを整理しやすいのか
- ドメインモデルをどうやって作っていくか
- 部分を作りながら全体を組み立てていく
- 全体と部分を行ったり来たりしながら作っていく * パッケージ図 * 業務フロー図 * Q.パッケージの切り方がよくわからない A.イテレーションしながら覚えていく =>言語化が重要そう
- 重要な部分から作っていく
- 独立した部品を組み合わせて機能を実現する
- ドメインオブジェクトを機能の一部として設計しない
- ドメインオブジェクトの見つけ方
- 重要な関心事や関係性に注目する
- 業務の関心事を分類してみる
ヒト ・・・ 個人、企業、担当者 モノ ・・・ 商品、サービス、店舗、場所、数量、金額、率、説明、日付、位置、期間、状態 コト ・・・ 予約、注文、支払い、出荷、キャンセル、(対象、種別、時点に注目する)
- コトに注目すると全体の関係を整理しやすい
- コトは業務ルールの宝庫
- 何でも約束してよいわけではない
受注時のルールすべてを扱う大きなクラスは、考えないようにします。 数量パッケージと同じように、与信パッケージや基本契約パッケージについても独立して設計します。 そうやって、ある程度の部品がそろってきたら、組み合わせ方を考えます。 組み合わせてみながら、個々の部品を調整したり、不足している部品を追加することで、受注ルールに網羅できるだけのドメインオブジェクトが整っていきます。
- 期待されるコト,期待されていないコト
- 業務ルールの記述 ~手続き型とオブジェクト指向の違い
- 業務の関心事の基本パターンを覚えておく
- ドメインモデルで開発してもトランザクションスクリプトになりがち 基本パターンを覚えて慣れろ、と。それ以上のことは言っていない。
- 業務ルールを記述するドメインオブジェクトの基本パターン
<ドメインオブジェクトの基本の設計パターン> ・値オブジェクト 日付等をラップする ・コレクションオブジェクト 配列やコレクションをラップする ・区分 区分の定義と区分ごとのロジックを整理 ・列挙型の集合操作 状態遷移ルールなどを列挙型の集合として整理する <業務の関心のパターン> ・口座 現在値を表現、妥当性を管理 ・期日 約束の期日と判断 ・方針 ルールが複合する、複雑な業務ロジック ・状態 状態と状態遷移を表現する
- ドメインオブジェクトの設計を段階的に改善する
- 組み合わせて確認しながら改良する
一度作ったら終わりではない
- ドメインモデルの開発とは、小さな独立性の高いドメインオブジェクトをそろえて行く活動
- 業務の言葉をコードと一致させると変更が楽になる
- 業務を学びながらドメインモデルを成長させていく
- 組み合わせて確認しながら改良する
一度作ったら終わりではない
- 業務の理解がドメインモデルを洗練させる
- 業務知識を取捨選択し,重要な関心事に注力して学ぶ
- 業務知識の暗黙知を引き出す
- 言葉をキャッチする
自分が理解できていないという前提ですすめる 自分の理解を文書等で表現し、確認を取る
- 重要な言葉を見極めながらそれをドメインモデルに反映していく
- 形式的な資料はかえって危険
理解したつもりになる議事録 重要度の考えが盛り込まれていないので何らかの補助資料をつくると良い
- 言葉のあいまいさを具体的にする工夫
- 基本語彙を増やす努力
- 繰り返しながらしだいに知識を広げていく
- 改善を続けながらドメインモデルを成長させる
- 第4章のまとめ
- ドメインモデルの考え方を理解する
- 第5章 アプリケーション機能を組み立てる
- ドメインオブジェクトを使って機能を実現する
- アプリケーション層のクラスの役割
- 三層+ドメインモデルの構造をわかりやすく実装する
- サービスクラスの設計はごちゃごちゃしやすい
- サービスクラスを作りながらドメインモデルを改善する
- 初期のドメインモデルは力不足
- ドメインモデルを育てる
- 画面の多様な要求を小さく分けて整理する
- プレゼンテーション層に影響される複雑さ
- 小さく分ける
- 小さく分けたサービスを組み立てる
- 利用する側と提供する側の合意を明確にする
契約による設計と防御的プログラミング とはいえ、契約による設計は人数増えると徹底できぬが。。どう答えるのか? ・nullを渡さない/nullを返さない ・状態に依存する場合、使う側が事前に確認する→これは厳しいぞ。 ・約束を守った上でさらに異常が起きた場合は例外
- シナリオクラスの効果
- データベースの都合から分離する
- データベースの入出力に引っ張られる問題
記録という業務の関心事とDBのINSERTを分けて考えろ→プログラマは考えがち。 記録の方法は色々あるから、とかも関係しそうね。柔軟な思考のためにも。
- データベース操作ではなく業務の関心事で考える
- 実際のデータベース操作とリポジトリを組み合わせる
- サービスクラスの記述をデータベース操作の詳細から解放する
- データベースの入出力に引っ張られる問題
- 第5章のまとめ
- ドメインオブジェクトを使って機能を実現する
- 第6章 データベースの設計とドメインオブジェクト
- テーブル設計が悪いとプログラムの変更が大変になる
- データの整理に失敗しているデータベース
- 用途がわかりにくいカラム
- いろいろな用途に使う巨大なテーブル
- テーブルの関係がわかりにくい
外部キー制約がない→これな!!! キーとなるカラムの名前に一貫性がない
- データベース設計をすっきりさせる
- 基本的な工夫を丁寧に実践する
- NOT NULL制約が導くテーブル設計
NULLの値が入るカラムは別テーブルにする
- 一意性制約でデータの重複を防ぐ
- 外部キー制約でテーブル間の関係を明確にする
- コトに注目するデータベース設計
- 業務アプリケーションの中核の関心事は「コト」の管理
- ヒトやモノとの関係を正確に記録するための3つの工夫
not nullを徹底するために「記録のタイミングが異なるデータはテーブルを分ける」 updateを使わない→まじか!。→ 記録の変更は元データ、取り消しデータ、新規データで カラム追加を行わない、テーブルを追加する。既存データに嘘データをはめることになるため
- 参照をわかりやすくする工夫
・基本はコトの記録のテーブル ・導出の性能のためにコトの記録のたびに状態を更新するテーブルを用意 ・状態を更新するテーブルはコトの記録からいつでも再構築可能な二次的データ →結構良い考えかも。コネクション枯渇とかで死んだらつらいな。トランザクションとればよいか。
- コトの記録に注力したテーブル設計の問題
- 状態の参照
- UPDATE文は使わない
- 残高更新は同時でなくてもよい
トランザクションで処理しなくても良いのか。前の疑問が解決だな。 1時間前の情報です、みたいな。 非同期で別プログラムでやるとか。
- 残高更新は1ヵ所でなくてもよい
非同期メッセージング ・コトの発生を顧客サーバーに通知すると顧客管理サーバーは顧客探知の残高を更新する、みたいな
- 派生的な情報を転記して作成する
コトの記録を基本にして、そこから派生する様々な情報を目的別に記録する方式をイベントソーシングという。 コトのサブセットを作る方式。
- コトの記録から状態を動的に導出する
- オブジェクトの設計とテーブルの設計
- オブジェクトとテーブルは似てくる
- 違うものとして明示的にマッピングする
ActiveRecordをdisっているのかな。
- オブジェクトはオブジェクトらしく,テーブルはテーブルらしく
MyBatis SQLつかえと書いてある DB構造をドメインんオブジェクトと分離して考えることができるらしい
- 業務ロジックはオブジェクトで,事実の記録はテーブルで
-
第6章のまとめ
特性 オブジェクト テーブル 目的 データとロジック、特にロジックの整理 データの整理 関心事 導出や加工のロジック、データを使った判断ロジック 導出や加工の元になるデータ アプローチ 部分から全体 全体から部分 設計変更のリズム 頻繁 ゆるやか
- テーブル設計が悪いとプログラムの変更が大変になる
- 第7章 画面とドメインオブジェクトの設計を連動させる
- 画面アプリケーションの開発の難しさ
- 画面にはさまざまな利用者の関心事が詰め込まれる
- 画面に引きずられた設計はソフトウェアの変更を大変にする
- 関心事を分けて整理する
- 画面の関心事を小さく分けて独立させる
- 複雑な画面は異なる関心事が混ざっている
- 小さな単位に分けて考える
- 画面も分けてしまう
- タスクベースのインターフェースが増えている2つの理由
- タスクベースに分ける設計が今後の主流
- 画面とドメインオブジェクトを連動させる
- 画面もドメインオブジェクトも利用者の関心事のかたまり
- ドメインオブジェクトと画面の食い違いは設計改善の手がかり
- ドメインオブジェクトに書くべきロジック
- HTMLのclass属性をドメインオブジェクトから出力する
- 画面(視覚表現)とソフトウェア(論理構造)を関係づける
- 項目の並び順とドメインオブジェクトのフィールドの並び順
- 画面項目のグルーピング
- 画面のデザインとソフトウェアの設計を連動させながら洗練させていく
- 画面以外の利用者向けの情報もソフトウェアと整合させる
- 第7章のまとめ
- 画面アプリケーションの開発の難しさ
- 第8章 アプリケーション間の連携
- アプリケーションとアプリケーションをつなぐ
- ほかのアプリケーションとの連携がアプリケーションの価値を高める
- アプリケーションを連携する4つのやり方
- Web APIのしくみを理解する
- HTTP通信を使ったアプリケーション間の連携の4つの約束事
- 要求の対象を指定する
- 要求の種類を指定する
- エラー時の約束事
- 良いWeb APIとは何か
- 使いにくいWeb API ~大は小を兼ねるのか?
- アプリケーションを組み立てるための部品を提供する
- 発展性に富んだAPI開発のやり方
- 単純なことをかんたんにできるAPIの提供から始める
- 動かしながら設計を発展させていく
- APIを利用する側とAPIを提供する側の共同作業の環境を整える
- 中核となるAPIのセットを設計する
- Web APIのバージョン管理
1.新しいAPIを追加しても互換性のため古いAPIも継続して提供 2.古いAPIは残すが「303 See Other」を返し、新しいAPIの情報を返す 3.古いAPIのレスポンスとして「404 Not Found」を返却する 4.古いAPIを削除する
- APIを複合したサービスの提供
- ドメインオブジェクトとWeb API
- データ形式とドメインオブジェクトを変換する際に起こる不一致
- 導出結果か生データか
- 複雑な連携に取り組む
- 共通部分と個別対応部分を明確にする
- APIを進化させる
- 小さなアプリケーションに分けて組み合わせる
- 複雑なデータの交換
- 非同期メッセージングを使ったアプリケーション間連携
- 第8章のまとめ
- アプリケーションとアプリケーションをつなぐ
- 第9章 オブジェクト指向の開発プロセス
- 開発の進め方はオブジェクト指向で変わったのか
- 開発の基本はV字モデル
要件定義と設計を同時にやる 同じ人間が担当する
- 短期間で開発し修正と拡張を繰り返すことが重要になった
- オブジェクト指向の開発はうまくいっているのか
SI系 要件定義・設計・実装・テストが時期的にも人間的にも不連続で利用者の関心とプログラムの設計が不連続 WEB系 設計せずに実装するので大規模でスパゲッティーになる どちらもダメ
- どちらのやり方でも変更がやっかいなソフトウェアが生まれやすい
- 開発の基本はV字モデル
- ドメインモデルを中心にしたソフトウェア開発の進め方
分析と設計を同じ開発者が担当することで大量のドキュメント作成が不要 -> 1-1の詳細設計は不要になる -> 既にそんなドキュメント作ってない -> 離れているのに作らないのは辛いだけだな -> くっつけて作らないか、離してつくるか。 毎日部分、部分で分析からシステム試験までを繰り返す。テストがコードになってるのは前提っぽい。
- 業務ロジックに焦点を当てて開発を進める
- ソースコードを第一級のドキュメントとして活用する
- 多くのドキュメントは不要になる
- 重要になる活動
- 更新すべきドキュメント
ひたすらチャットとかメールとかラフスケッチの写真とかだけど以下は更新する
- 利用者向けドキュメント・・・そのまま要件定義的に使える
- 画面や帳票
- DB設計(エンティティ定義書)
- 全体を俯瞰するドキュメントを作成して共有する
- システム企画書やプロジェクト計画書のシステム概要説明
- プレスリリース
- 利用者ガイドの導入部
- 営業ツールのキャッチフレーズ
- 技術方式のドキュメントもソースコードで表現する
- 非機能要件はテストコードで表現する
- 分析と設計が一体になった開発のやり方をマネジメントする
- 見積もりと契約 前半は準委任契約、後半は請負、本当は全て準委任契約が望ましい。 =>契約の種類調べないと
- 進捗の判断
- 品質保証
- 要員と体制
- 第9章のまとめ * オブジェクト指向の良さを生かすには分析と設計を一体にする * 分析と設計を分割しない、同じ人が担当する * 分析設計の成果はコードで表現(自己文書化) * ソースコードを中心に進捗と品質をマネージ * 業務に理解と整理に意欲がある技術者(プログラムできる人)を作る
- 開発の進め方はオブジェクト指向で変わったのか
- 第10章 オブジェクト指向設計の学び方と教え方
- オブジェクト指向を学ぶハードル
- オブジェクト指向の説明は意味が不明
- なぜオブジェクト指向で設計すると良いのかがわからない
- オブジェクト指向をどうやって学ぶか
- 実際にやってみるしかない!
- 極端な規約でやってみる!
- 既存のコードを改善しながらオブジェクト指向設計を学ぶ
- 実際のコードで設計の違いを知る
- 重複したコード
- 長いメソッド
- 巨大なクラス
- リファクタリングは部分的に少しずつ
- 組み立てやすい部品に改善する
- 設計は少しずつ改良を続ける
- オブジェクト指向らしい設計を体で覚える
- 古い習慣から抜け出すためのちょっと過激なコーディング規則9ルール(ThoughWorksアンソロジー)
- 一つのメソッドにつきインデントは1段階まで
- else禁止
- すべてのプリミティブ型と文字列型をラップ
- 一行につきドットは一つまで 説明用の変数を作っていく
- 名前を省略しない
- 全てのエンティティを小さくする
- 一つのクラスにつきインスタンス変数は2つまで
- ファーストクラスコレクションを使用する
- getter/setter/プロパティを使用しない
- 古い習慣から抜け出すためのちょっと過激なコーディング規則9ルール(ThoughWorksアンソロジー)
- オブジェクト指向の考え方を理解する
- 『実装パターン』
- 『オブジェクト指向入門』
- 『ドメイン駆動設計』
- 第10章のまとめ
- オブジェクト指向を学ぶハードル
- 参考文献一覧
- 索引
2017/09/07
今日段階での内容では、他でも言われていることをもう一度確認する、という感じですね。
2017/09/09
なかなか面白くなってきた
- 業務の関心事とクラスを1対1に対応させる
- 早期リターンとガード節
Yen fee() {
if(isChild()) return childFee();
if(isSenior()) return seniorFee();
return adultFee();
}
- FeeFactoryとMapと画面 画面の値で新しいFeeクラスをもらう
static Map<String,Fee> types;
static
{
types.put("adult",new AdultFee());
types.put("child",new AdultFee());
}
static Fee feeByName(String key){
return types.get(key);
}
2017/09/22
2周目は予めSpringのチュートリアルをやった上でやったほうが良いね。 今日は眠くてほとんど理解出来ていない。こんな日もあるさー データベースに入れるところはどこに書けばよいのだ?→読み直し必要
2018/08/20
3週目も良かった。後半を充填的に読めたののが良かった。
LOG
2017/10/26 4016