パッケージ設計論 パッケージ設計の原則 再利用・リリース等価の原則(REP) 全再利用の原則(CRP) 閉鎖性共通の原則(CCP) 非循環依存関係の原則(ADP) 安定依存の原則(SDP) 安定度・抽象度等価の原則(SAP)
Factoryパターン
Application Designษڧձ#6 20-21ষWed Jul 24Kazuki Chigita
View Slide
• パッケージ設計の原則• 再利⽤・リリース等価の原則(REP)• 全再利⽤の原則(CRP)• 閉鎖性共通の原則(CCP)• ⾮循環依存関係の原則(ADP)• 安定依存の原則(SDP)• 安定度・抽象度等価の原則(SAP)• Factoryパターン今日話すこと
• パッケージを考慮した設計が何故求められるのか?• ソフトウェアアプリケーションの規模が⼤きく・複雑になるとそれを上⼿に体系化する必要がある.• これはクラスよりも⼤きな枠組みであり,これを「パッケージ」と呼ぶ• KotlinのPakageやいわゆるmodule等を考えるといい.• SOLID原則のように体系だった理論がある.• ここではそれを学ぼうね.導入
• パッケージ内部の凝集度に関する原則• 再利⽤・リリース等価の原則(REP)• 全再利⽤の原則(CRP)• 閉鎖性共通の原則(CCP)• パッケージ同⼠の結合度や安定性に関する原則• ⾮循環依存関係の原則(ADP)• 安定依存の原則(SDP)• 安定度・抽象度等価の原則(SAP)6原則
• パッケージ内部の凝集度に関する原則• 再利⽤・リリース等価の原則(REP)• 全再利⽤の原則(CRP)• 閉鎖性共通の原則(CCP)• パッケージ同⼠の結合度や安定性に関する原則• ⾮循環依存関係の原則(ADP)• 安定依存の原則(SDP)• 安定度・抽象度等価の原則(SAP)6原則様々な指標があるが一言で表すとするなら,モジュールがどの程度たった一つの機能に特化しているのかを考える尺度(メトリクス)
• 再利⽤・リリース等価の原則(REP : Reuse-Release Equivalency Principle)• REPは再利⽤の単位(つまりパッケージ)がリリースの単位よりも⼩さくなることはない .• つまり再利⽤されるもの(パッケージ)はリリース・トラッキングされなければならない.• 砕いた説明をするとパッケージを更新するときはリリースされる必要がある.• あるリリースでのパッケージ(クラス群)を再利⽤するか / しないかを決められるようにするべきということを⾔いたい.• Javaの例を上げると各リリースでjarファイルが吐き出され,特定のクラスを使うのではなくそのjarを使うべき.再利用・リリース等価の原則
• 全再利⽤の原則(CRP : Common Reuse Principle)• パッケージに含まれるクラスは,すべて⼀緒に再利⽤される.• つまり,パッケージに含まれるいずれかのクラスを再利⽤するということは,その他のクラスもすべて再利⽤することを意味する.• もっと砕いて⾔うならば,⼀緒に使われる傾向のあるクラスは同じパッケージに属する.• これはつまり,同⼀パッケージにあるものはクラス間に強い依存関係があるとも⾔える.<=> クラス間に依存関係がないものは同⼀パッケージにするべきではない.全再利用の原則
• 閉鎖性共通の原則(CCP : Common Closure Principle)• パッケージに含まれるクラスはみな同じ種類の変更に対して閉じているべき.• つまり,パッケージに影響する変更はパッケージ内のすべてのクラスに影響を及ぼすが,他のパッケージには影響しない.• 単⼀責任の原則(SPR)のパッケージ版といえる.• クラスの変更理由を複数持ってはいけないのと同様に,パッケージもまた変更の理由は唯⼀つであるべきであると主張している.閉鎖性共通の原則
• 凝集度は今の3つの原則を以て議論される.凝集度に関する原則の再考REP再利用のためのグループ化CRP CCP保守性のためのグループ化不要なリリース作業を減らすための分割
• 凝集度は今の3つの原則を以て議論される.凝集度に関する原則の再考REP再利用のためのグループ化CRP CCP保守性のためのグループ化不要なリリース作業を減らすための分割互いに反する理念に基づいている部分もあるので総合的にみて凝集度を評価するべき
• 問題提起• パッケージの依存関係をグラフとみなしたときに循環してはならない.• ⼀⼈で作っていたらこの現象は起きにくいが複数⼈でやってると起きることがある(それは時にビルドが通らないといった問題を引き起こす)• この問題を解決するために「ウィークリービルド」と「⾮循環依存関係の原則(ADP)」がある.• ウィークリービルド• 週のうち4⽇間は開発者お互いの開発のパッケージの依存等を気にせず開発を進め,最期の⼀⽇ですべての変更を統合しシステムをビルドするやり⽅.• 規模が⼤きくなるについれて統合のコストがでかくなる(それはそう)非循環依存関係の原則
• ⾮循環依存関係の原則(ADP : Acyclic Dependencies Principle)• 開発環境をリリース可能なパッケージに分割する.(つまりパッケージは仕事の単位となる)• あるパッケージに対して開発者を割り当て,リリース可能な状態になったらリリースする.• パッケージを追加するときは各パッケージをグラフのノードと⾒たときにDAGになるように追加する.• 閉路を作ってしまうとそれ全体が結果的に依存し⼀つの巨⼤なパッケージと化してしまうので避けるべき.• システム全体をリリースするときは末端のノードからボトムアップにリリースする.非循環依存関係の原則
• 循環を⽣じないようにパッケージを処理する例• 現在のパッケージ構成が以下のようになっている.非循環依存関係の原則p321 図20-1より
• 循環を⽣じないようにパッケージを処理する例• 現在のパッケージ構成が以下のようになっている.• ここでMyDialogsがMyApplication内のクラスを利⽤するケースを考える.非循環依存関係の原則p321 図20-1より
• 循環を⽣じないようにパッケージを処理する例• 何も考えずこれをやってしまうと,以下の図のようになる.非循環依存関係の原則p322 図20-2より
• 循環を⽣じないようにパッケージを処理する例• 何も考えずこれをやってしまうと,以下の図のようになる.• MyApplication – MyTasks – MyDailogsが閉路を⽣んでおり,これらが強く依存してしまう.• DAGに変換する必要がある.非循環依存関係の原則p322 図20-2より
• 循環を⽣じないようにパッケージを処理する例• DAGを殺すアイデアとしては以下の⼿順である.1. ⽮印の⽅向を逆転させる.2. 新しいパッケージを⽣む.1. ⽮印の⽅向を逆転させる• MyDialogsが利⽤するインタフェースを抽象クラスとしてMyDialogsに持たせ,MyApplicationsがそれを実装するようにする(依存関係逆転の原則 : DIP)非循環依存関係の原則p323 図20-3よりBeforeAfter
• 循環を⽣じないようにパッケージを処理する例2. 新しいパッケージを⽣む• MyDialogsとMyApplicationsが両⽅とも依存するようなパッケージを追加する.• 以上の⼿順を以てDAGをなくした.DAGはこの⼿順で必ずなくすことができる.非循環依存関係の原則p324 図20-4より
• 安定依存の原則(SDP : Stable Depndencies Principle)• 安定する⽅向に依存せよ.• 特定の種類の変更に敏感なパッケージ(A)を考えたときにこのパッケージが変更が難しいパッケージ(B)に依存されると途端に(A)の変更が難しくなってしまう.→このような問題を解決する.• 安定性とは?• 直感的には以下.• 多くのパッケージによって参照されているパッケージは変更が難しい→安定している(外部要因によって変更がされにくい)• 他のパッケージから参照されていないパッケージは変更が容易→不安定(外部要因によっての変更が簡単)安定依存の原則
• 定量的に⽰す.• " (内側に向かう結合度) : このパッケージの外にあり,このパッケージの中にあるクラスに依存するクラスの数• # (外側に向かう結合度) : このパッケージの中にあり,このパッケージの外にあるクラスに依存するクラスの数• (不安定度) : = &'&()&'• が0のときは安定度が最⼤であり.⾃⾝は他に依存しない.• が1のときは最も不安定であり,責任がない.• この定量評価を⽤いて原則を⾔い直すと,「パッケージAの不安定度はそれが依存するパッケージBの不安定度より⼤きくあるべき」と⾔っている.• もしも逆転している場合はDIPによって解決.安定依存の原則
• 安定度・抽象度等価の原則(SAP : Stable Abstractions Principle)• 安定度の⾼いパッケージはその拡張性を失わないために抽象的でなければならない.• 逆に,不安定なパッケージは具体的でなければならない.不安定であれば具体的なコードを簡単に変更することができるから.• 抽象度を定義する.• . : パッケージ内のクラスの数• / : パッケージ内の抽象クラスの数• 抽象度 ∶ = 3(34安定度・抽象度等価の原則
• 不安定度と抽象度でグラフを作ることを考える.• 苦痛ゾーン : 抽象度が低く安定(具体実装に強く依存される)領域• 無益ゾーン : 抽象度が⾼く不安定(依存するパッケージがない抽象クラスに意味はない)安定度・抽象度等価の原則p333 図20-13より
• 不安定度と抽象度でグラフを作ることを考える.• 苦痛ゾーン : 抽象度が低く安定(具体実装に強く依存される)領域• 無益ゾーン : 抽象度が⾼く不安定(依存するパッケージがない抽象クラスに意味はない)安定度・抽象度等価の原則p333 図20-13よりこの付近に散らばるべきっぽい
• 主系列からの距離を[0,1]に正規化し,標準偏差を⽰す.• 著者いわく ≥ 1は例外的なのか,問題があるのかの⼆択なのでここを治していくとよい.• それが安定度・抽象度等価(SAP)に従うということ.安定度・抽象度等価の原則p335 図20-14より距離 = 9):;<=
• 抽象インターフェースだけを利⽤して具体的なクラスのインスタンスを⽣成することを可能にする.• 開発途上の具体的なクラスがまだ⾮常に不安定なときに⼤きな助けとなる.• これを使うことで,具体的なクラスの作成に依存することなく,factoryだけへの依存が可能になる.• メリット : Factoryを⼊れ替えるだけ(中の実装を変えるだけ)で,アプリケーションで利⽤するオブジェクトを変えることができる(実装交換可能性)Factoryパターン
• ⾮factoryパターンをfactoryにする• こうすると,SomeAppがSquareやCircleを直接知ることがなくなる(具体的な依存をしない)Factoryパターン
• ロバート・C・マーチン他.アジャイルソフトウェア開発の奥義第2版オブジェクト指向開発の神髄と匠の技.SBクリエイティブ,2008参考文献