Upgrade to Pro — share decks privately, control downloads, hide ads and more …

これだけは知っておきたいクラス設計の基礎知識

 これだけは知っておきたいクラス設計の基礎知識

JJUG CCC 2023 Spring 発表資料(ステップアップセッション)。
私がクラス設計をするときに重視している考え方とやり方を紹介。
主な内容
・クラス設計のスキル 3段階
・クラス設計の技能を習得するシナリオ
・7つの基礎知識
① 入出力と計算判断
② プログラムの中核と周辺
③ モジュラー性
④ データ抽象
⑤ カプセル化
⑥ 契約プログラミング
⑦ 不変(イミュータブル)

増田 亨

June 04, 2023
Tweet

More Decks by 増田 亨

Other Decks in Programming

Transcript

  1. クラス設計 技能習得のシナリオ 2023/6/4 6 情報 ⇒ 知識 ⇒ 技能 クラス設計の

    参考情報 クラス設計の 知識 クラス設計の 技能 外部 自分 今日の内容 書籍 ネットワーク 外部から得た情報を 自分の体験や知識と 関連づける 手を動かして習熟する 繰り返して体で覚える 理屈ではなく感覚
  2. 分けてつなぐための7つの基礎知識 ① 入出力と計算判断 ② プログラムの中核と周辺 ③ モジュラー性 ④ データ抽象 ⑤

    カプセル化 ⑥ 契約プログラミング ⑦ 不変(イミュータブル) 2023/6/4 10 この発表から入手した情報を まず自分の経験・知識と関連づける そのあと、手を動かして体で覚える
  3. ① 入出力と計算判断 (続き) • 計算判断クラスの例 • LocalDate • BigDecimal •

    String • ArrayList • 入出力クラスの例 • PrintStream (System.out、System.err) • java.io.*, java.nio.*, java.net.*, java.sql.*, … • @Controller, @Repository, @Entity, … 2023/6/4 13 計算判断のための専用クラス (入出力から隔離する) 入出力は特定のクラス/パッケージに 分離して閉じ込める
  4. ② プログラムの中核と周辺 2023/6/4 14 業務視点の クラス群 中核 通信アダプター HTTP @Controller

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

    計算判断クラス (業務ロジック) いろいろな 関心事 業務視点の 計算判断クラス (業務ロジック) 業務視点の 入出力クラス 記録/参照、通知/転送 業務視点の 計算判断クラス (業務ロジック) 通信 アダプター 永続化 アダプター 設計 設計 設計 業務視点の 入出力クラス 記録/参照、通知/転送 中核 中核 中核 中核 中核 周辺 周辺 周辺 ライブラリやフレームワークを アダプターの設計と実装に活用する
  6. ② プログラムの中核と周辺(続き) ➢書籍『ドメイン駆動設計』ドメインを隔離する • ソフトウェアの複雑さは対象となる業務活動に起因する • その複雑さをうまく扱う工夫の経験談 ➢書籍『リファクタリング』 • サンプルコードは(意図的に)業務視点のクラスになっている

    • 業務視点のクラスの不吉な臭いと改善方法の経験則 ➢ヘキサゴナル(Ports & Adapters)アーキテクチャ • 業務視点のクラスをフレームワーク・UI・データベースから独立させる 2023/6/4 16 業務視点でクラスを設計する 関連する情報
  7. ③ モジュラー性 ➢いろいろな部品 • パーツ 断片なども含む(部分) • コンポーネント 組み立て(一回の結合)を意図した部品 •

    モジュール 「組み換え」を意図した部品 ➢モジュラー性の特徴 • 用途がわかりやすい(単体で独立した機能) • モジュールとモジュールをつなぎやすい • モジュールの修正や組み換えが楽で安全 ➢モジュラー性を向上することがよいクラス設計の基本 2023/6/4 18
  8. ③ モジュラー性(続き) 2023/6/4 19 モジュラー性の着眼点 業務視点の 計算判断クラス (業務ロジック) 中核 ①

    入出力と計算判断 ② プログラムの中核と周辺 この二つの分離原則が重なる場所 ここのクラス設計をしっかりやると、 プログラム全体をわかりやすく分けて整理できる 業務視点の計算判断ロジックが断片化したり重複したりすると プログラムの見通しが悪くなり、変更がやっかいで危険になる ここのモジュラー性が、事業活動の変化への適応能力に直結する
  9. ④ データ抽象 ➢データの型を操作(メソッド)の集合で定義する 例 • 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 計算判断クラスを設計する基本知識 この考え方とやり方を体で覚える
  10. ④ データ抽象 (続き) ➢業務視点でデータ型を発見する(業務知識から設計する) • 金額 • 数量 • 比率

    • 日付、日数 • 時刻、時間 • 範囲 (金額範囲、数量範囲、日付範囲、時刻範囲、… ) • 区分 (分類区分、状態区分、適用区分、…) • 多値 (金額リスト、数量リスト、範囲セット、区分セット、… ) 2023/6/4 21 計算判断クラスを設計する基本知識
  11. ④ データ抽象 (続き) ➢単一値(金額、数量、日付、時刻など)のメソッド候補 • 同値の判定 isSame() • 比較 isGreaterThan()/isLessThan(),

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

    • 部分範囲 一つの範囲の一部を取り出す ➢区分のメソッド候補 • 区分への変換 from(), of(), parse(), … • 区分の判定 for() • 移動 next(), previous() 2023/6/4 23 計算判断クラスの設計パターン 自分の知識・経験と関連づける 手を動かして体で覚える
  13. ④ データ抽象 (続き) ➢多値(配列や順序)のメソッド候補 • 絞り込み filter() • 変換 map()

    多値から別の多値への写像 • 集約 reduce() ➢値(集合)のメソッド候補 • 和(足し算) • 差(引き算) • 共通部分 • 要素を含む 2023/6/4 24 計算判断クラスの設計パターン 自分の知識・経験と関連づける 手を動かして体で覚える
  14. ⑥ 契約プログラミング ➢基本アイデア • モジュールをつなぐ唯一の手段はメソッドの公開 • メソッドの仕様を明確にするとモジュラー性が改善する ➢メソッドの仕様を明確にする方法 • メソッドの利用者と提供者の約束事を明示する

    • 事前条件(利用者の義務) メソッドの引数の型と数 • 事後条件(提供者の義務) メソッドの返す型 • 不変条件( 同上 ) インスタンスの状態の整合性の保障 2023/6/4 27 モジュラー性を改善する考え方とやり方 メソッドを契約プログラミングの視点で設計する 既存のクラス(LocalDate, BigDecimal, Stringなど)のメソッドをこの視点から評価してみる
  15. ⑥ 契約プログラミング(続き) ➢金額#割る(数量) ⇒ 単価 • 端数の処理は型からは判断できない(単価型で有効桁数は定義可能) ➢金額#割る(整数) ⇒ 金額

    • ゼロ除算が起きる可能性がある • 負の金額になる可能性がある • 端数の処理は型からは判断できない ➢金額#割る(自然数) ⇒ 金額 • 端数の処理は型からは判断できない 2023/6/4 28 事前条件(引数の型)と事後条件(返す型)の例:金額の割算 引数の型(事前条件)と返す型(事後条件) で計算判断ロジックの仕様を表現する おまけ:金額#割る(金額) ⇒ 比率
  16. ⑦ 不変(イミュータブル) ➢実行中にモジュールの状態が変わると、使う側の負担が大きい • 挙動が不安定になる • 防御的なコードが不必要に増殖する ➢基本アイデア • 一度作ったインスタンスは状態を変えない

    • 状態の変更の代わりに同じ型の別のインスタンスを生成する 2023/6/4 29 モジュールのつなぎ方を安定させる 不変方式のクラスの使い勝手を評価する(String, BigDecimal, LocalDate) 可変方式のクラスの使い勝手を評価する(StringBuilder, ArrayList, HashSet)
  17. クラス設計 技能習得のシナリオ 2023/6/4 31 情報 ⇒ 知識 ⇒ 技能 クラス設計の

    参考情報 クラス設計の 知識 クラス設計の 技能 外部 自分 今日の内容 書籍 ネットワーク 外部から得た情報を 自分の体験や知識と 関連づける 手を動かして習熟する 繰り返して体で覚える 理屈ではなく感覚
  18. クラス設計 7つの基礎知識 ① 入出力と計算判断 ② プログラムの中核と周辺 ③ モジュラー性 ④ データ抽象

    ⑤ カプセル化 ⑥ 契約プログラミング ⑦ 不変(イミュータブル) 2023/6/4 32 この発表から入手した情報を まず自分の経験・知識と関連づける そのあと、手を動かして体で覚える Any questions?