Slide 1

Slide 1 text

これだけは知っておきたい クラス設計の基礎知識 有限会社システム 増田 亨 Original Version : JJUG CCC 2023 Spring Step Up Session 2023年6月4日 Revised : HireRoo Re:TechTalk #02 2025年4月9日

Slide 2

Slide 2 text

アプリケーション開発者 業務系アプリケーション ドメイン駆動設計/リファクタリング/データモデリング Java/Spring/IntelliJ IDEA/JIG 著書『現場で役立つシステム設計の原則』 ~変更を楽で安全にするオブジェクト指向の実践技法 訳書『ドメイン駆動設計をはじめよう』 ソフトウェアの実装と事業戦略を結びつける実践技法 自己紹介 2025/4/9 2 (2017年) (2024年)

Slide 3

Slide 3 text

ソフトウェアの設計 2025/4/9 3 プログラム 永続化 通信 ⇒ クラス設計 ⇒ 変更容易性 ⇒ テーブル設計 ⇒ データ完全性 ⇒ プロトコル設計 ⇒ 相互運用性

Slide 4

Slide 4 text

設計スキルを習得する 2025/4/9 4

Slide 5

Slide 5 text

クラス設計のスキル 3段階 初級 クラスを使ったコードを読み書きができる 中級 既存のクラスを参考に なんとなくクラス設計ができる 上級 なぜそういう設計をするのか なぜそういう設計を避けるのか 複数の判断軸を組み合わせて判断ができる 2025/4/9 5

Slide 6

Slide 6 text

クラス設計のスキル 習得シナリオ 2025/4/9 6 外部の参考情報 ⇒ 自分の知識体系に取り入れる ⇒ 習熟する クラス設計の 参考情報 クラス設計の 知識を構築 クラス設計に 習熟する 外部 自分 今日の内容 書籍 ドキュメント サンプルコード 外部から得た情報を 自分の体験と関連づけて 自分なりの知識を構築する 手を動かして 体で覚える 直観的に使える 活きた知識に変換

Slide 7

Slide 7 text

クラス設計の課題と解決の視点 2025/4/9 7

Slide 8

Slide 8 text

クラス設計の課題 •ソフトウェアの複雑さを扱いやすくする •ソフトウェアの変更を楽で安全にする 2025/4/9 8

Slide 9

Slide 9 text

クラス設計を考える3つの視点 関心の分離 依存関係 モジュール性 2025/4/9 9

Slide 10

Slide 10 text

関心の分離の失敗パターンと改善方法 10 混在 断片化 分離 集約 重複 一元化 いろいろ 同時に考える 異なる関心事は 別々に考える あちこちを 同時に考える 関連が強い関心事は 一箇所に集めて考える あちこちで 同じことを考える 一つの関心事は ただ一箇所で考える 2025/4/9

Slide 11

Slide 11 text

依存関係 依存関係が複雑でわかりにくい ⇒ 変更がやっかいで危険 関心の分離に失敗(関心事が混在、断片化、重複)すると、 依存関係が暗黙化する • どこが、どこと、どう関係しているか見つけにくい • コードを変更すると、想定外の個所に影響がでる ⇒ 暗黙の依存関係をクラスとメソッド呼び出しに変換して明示する • 依存関係を明示できれば、依存関係を改善できる(好循環が生まれる) 2025/4/9 11

Slide 12

Slide 12 text

モジュール性 モジュール性が高いクラス設計 • 関心が分離できている • 依存関係を明示できている ⇒ 複雑さが扱いやすい ⇒ 変更が楽で安全 クラスの初期設計とリファクタリング活動は モジュール性を向上するためのコスト • 費用対効果の高い個所を特定して、そこにコストをかける • 費用対効果の低い個所を特定して、そこにコストはかけない 2025/4/9 12

Slide 13

Slide 13 text

クラス設計の技法 2025/4/9 13

Slide 14

Slide 14 text

分けてつなぐ 2025/4/9 14

Slide 15

Slide 15 text

分ける どうやって? クラス コードを分割して整理する基本単位 メソッド 文(ステートメント)を集めて整理する パッケージ クラスを集めて整理する 2025/4/9 15

Slide 16

Slide 16 text

つなぐ どうやって? メソッドを定義して公開する クラスをつないで動かす唯一の仕組み • メソッド名 • メソッドの返す型 • メソッドに渡す引数の型 2025/4/9 16

Slide 17

Slide 17 text

クラスとメソッドを設計する5つの技法 ① 入出力と計算判断の分離 ② プログラムの中核と周辺の分離 ③ 業務特化のデータ型 ④ 契約プログラミング ⑤ 不変(イミュータブル) 2025/4/9 17

Slide 18

Slide 18 text

①入出力と計算判断を分離する クラス設計の鉄則 • 一つのクラスに計算判断と入出力を混ぜない • 一つのメソッドに計算判断ロジックと入出力操作を混ぜない • 一つのパッケージに計算判断クラスと入出力クラスを混ぜない 計算判断に特化したクラス • 入出力クラスを使ってはいけない 入出力に特化したクラス • 計算判断クラスを使ってよい 2025/4/9 18

Slide 19

Slide 19 text

計算判断クラスと入出力クラス 計算判断クラスの例 • LocalDate • BigDecimal • String • ArrayList 入出力クラスの例 • PrintStream (System.out、System.err) • java.io.*, java.nio.*, java.net.*, java.sql.*, … • @Controller, @Repository, @Entity, … 2025/4/9 19 計算判断のための専用クラス (入出力に依存しない) 入出力は専用のクラス/パッケージに 分離して閉じ込める

Slide 20

Slide 20 text

②ソフトウェアの中核と周辺を分離する 2025/4/9 20 業務視点の クラス群 中核 通信アダプター HTTP @Controller @RestController RestTemplate 通信アダプター JMS @JmsListner JmsTemplate 永続化アダプター JDBC @Repository @Entity 周辺 周辺 スケジュール アダプター @Scheduled 周辺 周辺

Slide 21

Slide 21 text

中核と周辺を分離するシナリオ 2025/4/9 21 いろいろな 関心事 いろいろな 関心事 業務視点の 計算判断クラス (業務ロジック) いろいろな 関心事 業務視点の 計算判断クラス (業務ロジック) 業務視点の 入出力クラス 記録/参照、通知/転送 業務視点の 計算判断クラス (業務ロジック) 通信 アダプター 永続化 アダプター 設計 設計 設計 業務視点の 入出力クラス 記録/参照、通知/転送 中核 中核 中核 中核 中核 周辺 周辺 周辺 ライブラリやフレームワークを アダプターの設計と実装に活用する

Slide 22

Slide 22 text

中核と周辺を分離するための参考情報 書籍『ドメイン駆動設計をはじめよう』 • 事業活動の理解をソフトウェア設計に活かす • 中核の業務領域とその他の業務領域を分類して、中核の業務領域に集中する 書籍『リファクタリング』、書籍『Tidy First?』 • サンプルコードは、意図的に、業務視点のクラスになっている • 業務視点のクラスの不吉な臭い(改善の着眼点)と改善方法 ポートとアダプタ(ヘキサゴナル)アーキテクチャ • 業務視点のクラスをフレームワーク・UI・データベースから切り離す方法 2025/4/9 22

Slide 23

Slide 23 text

③ 業務特化のデータ型 計算判断専用のクラス • 計算判断の関心事と入出力の関心事を分離する 計算判断に使うデータと計算判断ロジックを一箇所にまとめる • 計算判断ロジック記述の断片化を防ぐ • 計算判断ロジック記述の重複を防ぐ 業務視点の関心事を表現する • 業務に特化したデータ型(intやStringは汎用のデータ型) • 業務ルールに基づく複雑な業務ロジックを表現する基本語彙 2025/4/9 23

Slide 24

Slide 24 text

業務特化のデータ型を発見する 数量 金額、人数、個数、日数、… 比率 税率、割引率、割増率、配分率、… 時間 日付、時刻 範囲 金額範囲、数量範囲、日付範囲、時刻範囲、… 区分 分類区分、状態区分、適用区分、… 多値 金額リスト、数量リスト、範囲セット、区分セット、… 2025/4/9 24

Slide 25

Slide 25 text

データ型(汎用でも業務特化でも同じ) • プログラム(業務)で扱う値の種類の分類 • 値に対する有効な操作の集合で定義 • 有効な値の集合(値の範囲)で定義 2025/4/9 25

Slide 26

Slide 26 text

汎用データ型の有効な操作 • int型 ==, !=, <, >, +,- , *, /, % • BigDecimal型 add(), devide(), multiply(), … • LocalDate型 isAfter(), isBefore(), plus(), with(), … • DayOfWeek型 from(), valueOf(), plus(), minus(), … • String型 isEmpty(), length(), substring(), … 2025/4/9 26 基礎知識として参考にする

Slide 27

Slide 27 text

業務特化のデータ型と有効な操作の候補 単一値(金額、数量、日付、時刻など) • 同値の判定 isSame() • 比較 isGreaterThan()/isLessThan(), isAfter(), isBefore() • 加算・減算 add(), plus(), subtract(), minus() • 掛算・乗算 multiply() (整数倍と単位付き数量倍の違い) • 割算・除算 devide() (整数除算と単位付き割算の違い) • 最大・最小 MAX, MIN (有効な範囲) • 基本型と変換 toString()/parse(), intValue()/of() 2025/4/9 27 アプリケーションに必要十分な操作セットを見つける

Slide 28

Slide 28 text

業務特化のデータ型と有効な操作の候補 範囲型(金額範囲、数量範囲、日付範囲など) • 範囲の判定 範囲の重なり、前後、包含、… • 範囲の合成 二つの範囲を一つにまとめる • 部分範囲 一つの範囲から部分範囲を取り出す 区分型(顧客区分、商品区分、支払い区分など) • 区分に変換 from(), of(), parse(), … • 区分の判定 for() • 移動 next(), previous() 2025/4/9 28 こういうクラス設計の考え方を 自分の体験と関連づけて知識を構築し 手を動かして体で覚える

Slide 29

Slide 29 text

業務特化のデータ型と有効な操作の候補 多値を扱うデータ型:業務視点のデータ配列 • 絞り込み filter() 部分配列 • 変換 map() あるデータ型の配列を別のデータ型の配列へ変換 • 集約 reduce() 多値を単一値に集約(集計、最大、…) 多値を扱うデータ型:業務視点のデータ集合 • 集合どうしの和(足し算) • 集合どうしの差(引き算) • 共通集合 • 要素を含むか検査 2025/4/9 29 こういうクラス設計の考え方を 自分の体験と関連づけて知識を構築し 手を動かして体で覚える

Slide 30

Slide 30 text

④ 契約プログラミング 基本アイデア • クラスをつなぐ唯一の手段はメソッドの公開 • メソッドの仕様を明確にするとモジュール性が改善する • 関係がわかりやすくなり、連係動作が安定する メソッドの仕様を明確に定義する メソッドを提供するクラスとメソッドを利用するクラスの責任を明示する • 事後条件(提供クラスの義務) メソッドの返す型 • 事前条件(利用クラスの義務) メソッドの引数の型と数 • 不変条件(提供クラスの義務) インスタンスの状態の整合性の保障 2025/4/9 30

Slide 31

Slide 31 text

引数の型と返す値の型が変われば契約が変わる divideBy(整数型) ⇒ 金額型 ゼロ除算が起きる可能性がある 負数で割り算する可能性がある divideBy(自然数型) ⇒ 金額型 ゼロ除算や負数除算はできない 巨大な除数での割り算の可能性がある 端数に関する契約は不明 divideBy(数量型) ⇒ 単価型 数量型で除数の有効範囲を定義 単価型で小数点以下の有効桁数を定義 2025/4/9 31 例:金額型の割算(divideByメソッド)の契約 業務視点での契約プログラミング

Slide 32

Slide 32 text

⑤ 不変(イミュータブル) 実行中にクラスの状態が変わると、使う側の負担が大きい • 挙動が不安定になる • 防御的なコードが不必要に増殖する 基本アイデア • 一度作ったインスタンスは状態を変えない • 状態の変更の代わりに同じ型の別のインスタンスを生成する 2025/4/9 32 クラスのつなぎ方と連係動作を安定させる 不変方式のクラスの使い勝手を評価する(String, BigDecimal, LocalDate) 可変方式のクラスの使い勝手を評価する(StringBuilder, ArrayList, HashSet)

Slide 33

Slide 33 text

まとめ 2025/4/9 33

Slide 34

Slide 34 text

クラス設計のスキル 習得シナリオ 2025/4/9 34 外部の参考情報 ⇒ 自分の知識体系に取り入れる ⇒ 習熟する クラス設計の 参考情報 クラス設計の 知識を構築 クラス設計に 習熟する 外部 自分 今日の内容 書籍 ドキュメント サンプルコード 外部から得た情報を 自分の体験と関連づけて 自分なりの知識を構築する 手を動かして 体で覚える 直観的に使える 活きた知識に変換

Slide 35

Slide 35 text

クラス設計を考える3つの視点 関心の分離 依存関係 モジュール性 2025/4/9 35

Slide 36

Slide 36 text

クラスとメソッドを設計する5つの技法 ① 入出力と計算判断の分離 ② プログラムの中核と周辺の分離 ③ 業務特化のデータ型 ④ 契約プログラミング ⑤ 不変(イミュータブル) 2025/4/9 36

Slide 37

Slide 37 text

参考図書(外部情報) 2025/4/9 37 4月19日発売 第2特集 クラス設計の鉄則 自分の体験と関連づけて知識を構築する 手を動かして体で覚える