Slide 1

Slide 1 text

これだけは知っておきたい クラス設計の基礎知識 有限会社システム 増田 亨 JJUG CCC 2023 Spring Step Up Session 2023年6月4日

Slide 2

Slide 2 text

アプリケーション開発者 業務系アプリケーション ドメイン駆動設計/リファクタリング Java/Spring/IntelliJ IDEA/JIG 著書『現場で役立つシステム設計の原則』 ~変更を楽で安全にするオブジェクト指向の実践技法 設計コミュニティ「現場から学ぶモデル駆動の設計」主催 自己紹介 2023/6/4 2

Slide 3

Slide 3 text

ソフトウェアの設計 2023/6/4 3 プログラム 永続化 通信 ⇒ クラス設計 ⇒ テーブル設計 ⇒ プロトコル設計

Slide 4

Slide 4 text

ステップアップする 2023/6/4 4

Slide 5

Slide 5 text

クラス設計のスキル 3段階 初級 クラス構文を使って読み書きができる 中級 既存のクラス設計を参考に なんとなく真似ができる 上級 なぜそういう設計をするのか なぜそういう設計を避けるか 複数の判断軸を持っている 2023/6/4 5

Slide 6

Slide 6 text

クラス設計 技能習得のシナリオ 2023/6/4 6 情報 ⇒ 知識 ⇒ 技能 クラス設計の 参考情報 クラス設計の 知識 クラス設計の 技能 外部 自分 今日の内容 書籍 ネットワーク 外部から得た情報を 自分の体験や知識と 関連づける 手を動かして習熟する 繰り返して体で覚える 理屈ではなく感覚

Slide 7

Slide 7 text

プログラムの設計 分けてつなぐ 2023/6/4 7

Slide 8

Slide 8 text

プログラムの設計 「分けて」整理する コードを整理する どうやって? クラス コード整理の基本単位 メソッド 文(ステートメント)を集めて整理する パッケージ クラスを集めて整理する 2023/6/4 8

Slide 9

Slide 9 text

プログラムの設計 「つないで」動かす プログラムを動かす どうやって? メソッドを定義して公開する つないで動かす唯一の仕組み オブジェクトを生成してメソッドを呼び出す • メソッドを呼び出す側 利用者 • メソッドを提供する側 提供者 2023/6/4 9

Slide 10

Slide 10 text

分けてつなぐための7つの基礎知識 ① 入出力と計算判断 ② プログラムの中核と周辺 ③ モジュラー性 ④ データ抽象 ⑤ カプセル化 ⑥ 契約プログラミング ⑦ 不変(イミュータブル) 2023/6/4 10 この発表から入手した情報を まず自分の経験・知識と関連づける そのあと、手を動かして体で覚える

Slide 11

Slide 11 text

分けて整理する 2023/6/4 11

Slide 12

Slide 12 text

① 入出力と計算判断 ➢入出力と計算判断を分ける。これがクラス設計の鉄則。 • 同じクラスに入出力と計算判断を混ぜない • 同じパッケージに入出力と計算判断をまぜない ➢入出力を特定範囲(クラス/パッケージ)に閉じ込める ➢入出力クラスは計算判断クラスを使ってよい ➢計算判断クラスは入出力クラスを使ってはいけない 2023/6/4 12

Slide 13

Slide 13 text

① 入出力と計算判断 (続き) • 計算判断クラスの例 • LocalDate • BigDecimal • String • ArrayList • 入出力クラスの例 • PrintStream (System.out、System.err) • java.io.*, java.nio.*, java.net.*, java.sql.*, … • @Controller, @Repository, @Entity, … 2023/6/4 13 計算判断のための専用クラス (入出力から隔離する) 入出力は特定のクラス/パッケージに 分離して閉じ込める

Slide 14

Slide 14 text

② プログラムの中核と周辺 2023/6/4 14 業務視点の クラス群 中核 通信アダプター HTTP @Controller @RestController RestTemplate 通信アダプター JMS @JmsListner JmsTemplate 永続化アダプター JDBC @Repository @Entity 周辺 周辺 スケジュール アダプター @Scheduled 周辺 周辺 関連する考え方:『ドメイン駆動設計』「ドメインを隔離する」; ヘキサゴナル(Ports & Adapters)アーキテクチャ アプリケーションの全体像

Slide 15

Slide 15 text

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

Slide 16

Slide 16 text

② プログラムの中核と周辺(続き) ➢書籍『ドメイン駆動設計』ドメインを隔離する • ソフトウェアの複雑さは対象となる業務活動に起因する • その複雑さをうまく扱う工夫の経験談 ➢書籍『リファクタリング』 • サンプルコードは(意図的に)業務視点のクラスになっている • 業務視点のクラスの不吉な臭いと改善方法の経験則 ➢ヘキサゴナル(Ports & Adapters)アーキテクチャ • 業務視点のクラスをフレームワーク・UI・データベースから独立させる 2023/6/4 16 業務視点でクラスを設計する 関連する情報

Slide 17

Slide 17 text

分けてつなぐ 2023/6/4 17

Slide 18

Slide 18 text

③ モジュラー性 ➢いろいろな部品 • パーツ 断片なども含む(部分) • コンポーネント 組み立て(一回の結合)を意図した部品 • モジュール 「組み換え」を意図した部品 ➢モジュラー性の特徴 • 用途がわかりやすい(単体で独立した機能) • モジュールとモジュールをつなぎやすい • モジュールの修正や組み換えが楽で安全 ➢モジュラー性を向上することがよいクラス設計の基本 2023/6/4 18

Slide 19

Slide 19 text

③ モジュラー性(続き) 2023/6/4 19 モジュラー性の着眼点 業務視点の 計算判断クラス (業務ロジック) 中核 ① 入出力と計算判断 ② プログラムの中核と周辺 この二つの分離原則が重なる場所 ここのクラス設計をしっかりやると、 プログラム全体をわかりやすく分けて整理できる 業務視点の計算判断ロジックが断片化したり重複したりすると プログラムの見通しが悪くなり、変更がやっかいで危険になる ここのモジュラー性が、事業活動の変化への適応能力に直結する

Slide 20

Slide 20 text

④ データ抽象 ➢データの型を操作(メソッド)の集合で定義する 例 • int型 ==, !=, <, >, +,- , *, /, % • BigDecimal型 add(), devide(), multiply(), subtract(), … • LocalDate型 isAfter(), isBefore(), plus(), minus(), with(), … • DayOfWeek型 from(), valueOf(), plus(), minus(), … • String型 isEmpty(), length(), substring(), replace(), … 2023/6/4 20 計算判断クラスを設計する基本知識 この考え方とやり方を体で覚える

Slide 21

Slide 21 text

④ データ抽象 (続き) ➢業務視点でデータ型を発見する(業務知識から設計する) • 金額 • 数量 • 比率 • 日付、日数 • 時刻、時間 • 範囲 (金額範囲、数量範囲、日付範囲、時刻範囲、… ) • 区分 (分類区分、状態区分、適用区分、…) • 多値 (金額リスト、数量リスト、範囲セット、区分セット、… ) 2023/6/4 21 計算判断クラスを設計する基本知識

Slide 22

Slide 22 text

④ データ抽象 (続き) ➢単一値(金額、数量、日付、時刻など)のメソッド候補 • 同値の判定 isSame() • 比較 isGreaterThan()/isLessThan(), isAfter(), isBefore() • 加算・減算 add(), plus(), subtract(), minus() • 掛算・乗算 multiply() (整数倍と単位付き数量倍の違い) • 割算・除算 devide() (整数除算と単位付き割算の違い) • 最大・最小 MAX, MIN (有効な範囲) • 基本型の変換 toString()/parse(), intValue()/of() 2023/6/4 22 計算判断クラスの設計パターン LocalDate, BigDecimalなど既存のクラスを参考にする 業務の関心事を特定し、それらしい名前をつける(日本語推奨) 手を動かして習熟する

Slide 23

Slide 23 text

④ データ抽象 (続き) ➢範囲のメソッド候補 • 範囲の判定 範囲の重なり・連続、前後、包含、… • 範囲の合成 二つの範囲を一つにまとめる • 部分範囲 一つの範囲の一部を取り出す ➢区分のメソッド候補 • 区分への変換 from(), of(), parse(), … • 区分の判定 for() • 移動 next(), previous() 2023/6/4 23 計算判断クラスの設計パターン 自分の知識・経験と関連づける 手を動かして体で覚える

Slide 24

Slide 24 text

④ データ抽象 (続き) ➢多値(配列や順序)のメソッド候補 • 絞り込み filter() • 変換 map() 多値から別の多値への写像 • 集約 reduce() ➢値(集合)のメソッド候補 • 和(足し算) • 差(引き算) • 共通部分 • 要素を含む 2023/6/4 24 計算判断クラスの設計パターン 自分の知識・経験と関連づける 手を動かして体で覚える

Slide 25

Slide 25 text

⑤ カプセル化 ➢データ抽象(データ型を操作の集合で定義)をクラスとして実装する ➢基本アイデア • 値を表現するデータ構造(フィールド一式)を公開メソッドで囲む • 実装(ソースコード)は公開する(隠蔽しない) • 実装に依存したプログラムを書けないメソッドだけを提供する ➢カプセル化の成功例 • Java 9 でStringクラスの実装は全面的に書き換えられた • Stringクラスを使うプログラムに影響はなかった 2023/6/4 25

Slide 26

Slide 26 text

つないで動かす 2023/6/4 26

Slide 27

Slide 27 text

⑥ 契約プログラミング ➢基本アイデア • モジュールをつなぐ唯一の手段はメソッドの公開 • メソッドの仕様を明確にするとモジュラー性が改善する ➢メソッドの仕様を明確にする方法 • メソッドの利用者と提供者の約束事を明示する • 事前条件(利用者の義務) メソッドの引数の型と数 • 事後条件(提供者の義務) メソッドの返す型 • 不変条件( 同上 ) インスタンスの状態の整合性の保障 2023/6/4 27 モジュラー性を改善する考え方とやり方 メソッドを契約プログラミングの視点で設計する 既存のクラス(LocalDate, BigDecimal, Stringなど)のメソッドをこの視点から評価してみる

Slide 28

Slide 28 text

⑥ 契約プログラミング(続き) ➢金額#割る(数量) ⇒ 単価 • 端数の処理は型からは判断できない(単価型で有効桁数は定義可能) ➢金額#割る(整数) ⇒ 金額 • ゼロ除算が起きる可能性がある • 負の金額になる可能性がある • 端数の処理は型からは判断できない ➢金額#割る(自然数) ⇒ 金額 • 端数の処理は型からは判断できない 2023/6/4 28 事前条件(引数の型)と事後条件(返す型)の例:金額の割算 引数の型(事前条件)と返す型(事後条件) で計算判断ロジックの仕様を表現する おまけ:金額#割る(金額) ⇒ 比率

Slide 29

Slide 29 text

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

Slide 30

Slide 30 text

本日のまとめ 2023/6/4 30

Slide 31

Slide 31 text

クラス設計 技能習得のシナリオ 2023/6/4 31 情報 ⇒ 知識 ⇒ 技能 クラス設計の 参考情報 クラス設計の 知識 クラス設計の 技能 外部 自分 今日の内容 書籍 ネットワーク 外部から得た情報を 自分の体験や知識と 関連づける 手を動かして習熟する 繰り返して体で覚える 理屈ではなく感覚

Slide 32

Slide 32 text

クラス設計 7つの基礎知識 ① 入出力と計算判断 ② プログラムの中核と周辺 ③ モジュラー性 ④ データ抽象 ⑤ カプセル化 ⑥ 契約プログラミング ⑦ 不変(イミュータブル) 2023/6/4 32 この発表から入手した情報を まず自分の経験・知識と関連づける そのあと、手を動かして体で覚える Any questions?