97K Views
February 13, 25
スライド概要
Developers Summit 2025 登壇資料 (13-B-1)
著書『アーキテクトの教科書 価値を生むソフトウェアのアーキテクチャ構築』(翔泳社)
13-B-1 Architecture to Design より良い設計を目指して Feb. 13, 2025 Takeshi Yonekubo
About Me 米久保 剛 (よねくぼ たけし) 株式会社電通総研 ITアーキテクト 『アーキテクトの教科書』(翔泳社) X: @tyonekubo note: https://note.com/yonekubo 12:30〜 3F 休憩ラウンジ 翔泳社書籍販売コーナー にてサイン会実施!
Key Concept アーキテクチャを、 アプリケーションを、 良い設計にするために
Key Concept 重要なコンセプトと 思考をインストールしよう
Key Question 1. なぜ設計をするのか? 良い設計とは何か?
Key Question 2. 良い設計をするために 大事なことは何か?
Key Question 3. 設計はどのように 進めるとよいか?
Section 1. なぜ設計をするのか? 良い設計とは何か?
分割 ソフトウェア設計の基本は、分けること 一枚岩のプログラム 分割されたプログラム 振る舞い 振る舞い 提供する振る舞いは変わらないなら、なぜ分割するの?
分割理由① 認知容量の問題 大きすぎるものは 人間の脳にとって 認知負荷が高すぎる Divide and Concur 分割して統治せよ
分割理由② 能力の獲得 分割によって生まれる 構造と(要素同士の)相互作用が 振る舞い以上の力を与える
たとえば、 ✓わかりやすい ✓テストがしやすい ✓拡張しやすい 理解容易性 テスト容易性 拡張性
品質特性 ソフトウェア品質を測定可能な特徴として定義したもの 機能適合性:振る舞い要求(機能要求)に対する品質 その他特性:非機能要求に対する品質 機能適合性 性能効率性 互換性 使用性 信頼性 セキュリティ 保守性 移植性 JIS X 25010 (ISO/IEC 25010:2011) の8つの品質特性
品質特性によって示される、 非機能的な能力をソフトウェアに与えるために 必要な設計を行う
設計の抽象レベル ソフトウェアの設計では抽象度を意識する必要がある 抽象度 アーキテクチャ設計 抽象 方針 全体 モジュール設計 コンポーネント設計 クラス設計 具体 詳細 部分 出典:米久保 剛 『アーキテクトの教科書』翔泳社(2024) 図2.1.1をもとに作成
上位目的 ソフトウェアは、ビジネスを成功に導くために 上位目的を達成するものでなくてはならない 経営理念・ビジョン 経営戦略 IT戦略 ITシステム
良いアーキテクチャであるための 重要な条件: 合目的性
達成指標 要求される品質を満たすこと、 品質特性の達成度合いで評価される 機能適合性 性能効率性 互換性 使用性 信頼性 セキュリティ 保守性 移植性
品質特性の特定 ビジネスを理解し、システムにおいて 重要な品質特性、品質副特性を特定する ビジネスの理解 • 環境、法規制 • 製品戦略 • ビジネスや業務の特性 品質特性リスト(例) ✓ 性能効率性/時間効率性 ✓ 互換性/相互運用性 ✓ セキュリティ/機密性
アーキテクチャドライバ 品質特性に加えて、制約その他の アーキテクチャ選定に影響を与えるものを識別 制約(ビジネス/技術) 品質特性 アーキテクチャドライバ 影響を与える機能要求 その他の影響を及ぼすもの
アーキテクチャの設計 アーキテクチャドライバに基づいて、 最適なアーキテクチャを設計する 出典:米久保 剛 『アーキテクトの教科書』翔泳社(2024) 図3.1.1
合目的性は重要だが、 設計は人間による営みである以上、 人間の認知と行動に焦点を当てた観点も重要 良い design
“まず人間のニーズ、能力、行動を取り上げ、 それからそのニーズ、能力、行動に合わせて デザインする” 出典:D.A.ノーマン 『誰のためのデザイン?』新曜社(2015) 第1章 人間中心デザイン Human-Centered Design : HCD
ソフトウェアのユーザー ソフトウェア ソースコード UX DevX エンドユーザー 開発者 ソースコードのユーザーは開発者自身 開発者体験を高めるように design すべき
開発者体験 コードを書く時間 << コードを読む時間と言われる 安全に、素早くコードを変更できること たとえば… ✓変更すべきコードを容易に特定できる ✓コードが読んで理解しやすい ✓自動化されたテストによって守られている
認知負荷 脳内のワーキングメモリの容量は限られており、 認知負荷が大きいとオーバーフローを起こす →課題外在性負荷(偶有的複雑さ)を減らすこと 対象そのものが本質的に持つ 課題内在性負荷 複雑さによる認知負荷 対象とは直接関係しない、 課題外在性負荷 外的要因による認知負荷 学習のための認知活動で発生する 学習関連負荷 負荷
メンタルモデル “メンタルモデルは、その名からも分かるように人の頭の 中にあって、モノがどう動作するかについてのその人の理 解を表す概念モデルである。” 出典:D.A.ノーマン 『誰のためのデザイン?』新曜社(2015) 第1章 design によって表現される概念モデルと、 ユーザーが頭の中に構築するメンタルモデルが 合致することが大切
ドメインモデル システムが対象とする問題を、ソフトウェアという 解決空間で扱うための表象が、ドメインモデル 分析モデル (問題空間) ドメイン専門家 ドメインモデル (解決空間) 開発者
共通の語彙(ユビキタス言語) 共通の語彙を定義してドメイン専門家と対話し、 それを用いて解決空間を design する 分析モデル (問題空間) ドメイン専門家 ドメインモデル (解決空間) 開発者 開発者が良いメンタルモデルを構築 →開発者体験の向上
Section 1. まとめ 良い設計: ✓上位目的を正しく把握し、 それを達成できる(合目的性) ✓開発者の認知負荷を下げて、本 質的な問題に集中できる
Section 2. 良い設計をするために 大事なことは何か?
SOLID原則 DRY原則 KISS原則 Tell, Don’t Ask原則 ..and more 設計原則
設計原則 設計原則を学ぶことは大切だが注意も必要 SRP 単一責任の原則 OCP オープン・クローズド の原則 リスコフの置換原則 LSP ISP DIP インターフェース分離 の原則 依存関係逆転の原則 要素にはただ一つの明確な責任を持 たせる 拡張に対しては開いて、修正に対し ては閉じる 派生型はその基本型と置換可能であ ること 目的ごとの小さなインターフェース を用意する 方針から詳細に依存してはならない 出典:ロバート・C・マーチン『アジャイルソフトウェア開発の奥義』SBクリエイティブ(2004) をもとに作成
SOLID原則の注意点 SOLIDは寄せ集めであり、不揃いである SRP 単一責任の原則 OCP オープン・クローズド の原則 リスコフの置換原則 LSP モジュールやレイヤーの ISP インターフェース分離 関係性に関する原則 の原則 DIP 依存関係逆転の原則 要素にはただ一つの明確な責任を持 たせる オブジェクト指向の継承 拡張に対しては開いて、修正に対し 関係に特化した原則 ては閉じる 派生型はその基本型と置換可能であ ること 目的ごとの小さなインターフェース を用意する 方針から詳細に依存してはならない
SOLID原則の上位目的 変更に強い設計をするために用いる原則 この目的で、状況に応じて適切に原則を適用する SRP OCP LSP ISP DIP 変更容易性 拡張性 置換可能性 変更容易性 安定性 変更の影響範囲を局所化する 振る舞いを追加する際の変更量を極小化する 派生型の置き換えを安全に行う 変更の影響範囲を局所化する 不安定なモジュール(詳細)の変更の影響が 安定なモジュール(方針)に及ぶのを防ぐ
原理と原則 原理は、普遍的、根本的な理(ことわり) 原則は、原理によって導かれる、共通的な決まり
設計原理 「CLEAN」:5つのコード品質 Cohesive Loosely Coupled Encapsulated Assertive Nonredundant { 設計原理 } 凝集性 高凝集 ❷ 疎結合 疎結合 ❸ カプセル化 抽象化 ❹ 断定的 関心の分離 ❶ 非冗長 非冗長 ❺ 出典:David Scott Bernstein『レガシーコードからの脱却』オライリー(2019) をもとに作成
設計原理❶ 関心の分離 大きなもの、複雑なものをそのまま取り扱わない まずは関心事によって分離する 観点の例: ✓手続きとビジネスルール ✓種別、区分 ✓利用者 ✓抽象度
設計原理❷ 高凝集 分けたものそれぞれの凝集度を高くする 関連性の高いデータと操作が、 一箇所にぎゅっとまとまっていて、 余分なものがない状態 データ 操作 操作 データ 操作
設計原理❸ 疎結合 他の設計要素に対する依存度を弱くする ✓依存する要素数を減らす ✓呼び出す操作を粗粒度にする ✓インターフェースに依存する
設計原理❹ 抽象化(方針と詳細の分離) 設計要素のクライアント(別の設計要素)にとって 本質的で重要なものを抽出する(抽象化) 抽象化されたインターフェースが示す方針と、 実装の詳細とを分離し、 後者はクライアントから隠蔽する
設計原理❺ 非冗長 複数の箇所で繰り返して同じことを行う、 冗長性があれば取り除く “冗長性は必ずしも形状の繰り返しではない。冗長性とは 意図の繰り返しなのだ。” 出典:David Scott Bernstein『レガシーコードからの脱却』第9章
設計原理は互いに関連し合う { 設計原理 } 関心の分離 ❶ 高凝集 ❷ 疎結合 ❸ 抽象化 ❹ 非冗長 ❺ “「CLEAN」コードの品質はお互いに 助け合う。1つの品質を向上させれば、 ほかの品質も向上する。” 出典:David Scott Bernstein『レガシーコードからの脱却』第9章
改めて、SOLID原則 設計原理の観点でSOLIDを眺めると… SRP OCP LSP ISP DIP 単一責任の原則 オープン・クローズド の原則 リスコフの置換原則 インターフェース分離 の原則 依存関係逆転の原則 関心の分離、高凝集 抽象化(方針と詳細) N/A 関心の分離、疎結合 抽象化(方針と詳細)、疎結合
Section 2. まとめ 設計で大事なこと: ✓設計の原理を理解する ✓設計原則は上位目的と、背後に ある設計原理を押さえておくこ とで、より効果的に使える
Section 3. 設計はどのように 進めるとよいか?
全体から部分へ どのように分割していくかが、設計の鍵 全体 抽象度 アーキテクチャ設計 モジュール設計 コンポーネント設計 クラス設計 部分
システムアーキテクチャの設計 システム全体をどのように分割するか? ①まずは論理的なユニットとしてのサブシステム分割 ②デプロイ単位として物理的にサービス分割し配置決め 出典:米久保 剛 『アーキテクトの教科書』翔泳社(2024) 図3.3.5
ドメイン駆動で論理分割する ドメイン 収益をもたらす事業領域 例)レコード会社における「CD・レ コード事業」「音楽配信事業」「イ ベント事業」 サブドメイン ドメインを構成する専門知識の 領域 例)「企画」「制作」「販売」「著 作権管理」 境界づけられたコンテキスト 解決空間における境界分割 出典:ヴォーン・ヴァーノン『実践ドメイン駆動設計』翔泳社(2016) 図2-2
サブシステム分割のポイント 境界付けられたコンテキスト(サブシステム)は設計要素 設計原理に従い、関心の分離を行い 高凝集・疎結合を目指す イベントストーミングなどの手法を用いて ドメインに関する知識を引き出し、整理する
物理的なサービス分割(分散 or NOT) マイクロサービス vs モジュラーモノリス マイクロサービス化によって得たい能力が明確で、 分散化のデメリットと比較して勝つかどうか ✓処理特性、パフォーマンス ✓デプロイ頻度 ✓言語やミドルウェアの適合性
アプリケーションアーキテクチャの設計 分割したサービス(アプリケーション)毎に 基本構造と分割方針を定める レイヤード パイプライン 出典:米久保 剛 『アーキテクトの教科書』翔泳社(2024) 図3.4.2/図3.4.5
レイヤー設計:クリーン“な”アーキテクチャ クリーンアーキテクチャ、オニオン、ヘキサゴナル。 いずれもレイヤードアーキテクチャの亜種で本質は同じ Controller Controller DIPを適用 依存関係を 逆転 Service Service Repo 変形 Repo RepoImpl RepoImpl
モジュール設計:関心の分離、高凝集 モジュール = サブシステムを分割した設計要素 高凝集なモジュール設計のコツ ✓原則として一種類のアクターに対して、関連度の高い ユースケースのセットを提供する
モジュール設計:疎結合、抽象化 WebやDBなどの実装の詳細、他のモジュールとの 相互作用は、抽象化されたポートを介して アダプター層で行う (Ports and Adapters) モジュール間相互作用の手段 ✓ドメインイベント ✓オーケストレーション
コンポーネント設計とは モジュールレベルの振る舞い = ユースケース 下位レベルのコンポーネントの相互作用によって ユースケースの振る舞いを実現する
コンポーネント分割の例 入力ポート 処理フロー 出力ポート 中核ロジック 出典:Scott W. Ambler 『オブジェクト開発の真髄』日経BP(2005) 図10.9
ロバストネス分析(予備設計) ラフスケッチを描く or CRCカードを用いたワーク コントロール オブジェクト 境界 オブジェクト 実体 オブジェクト 出典:Doug Rosenberg, Kendall Scott 『ユースケース入門』ピアソン(2001) 図4-6
コンポーネントタイプ ユースケースの実現という演目における、 キャストの役割を意識する <<主演>> <<脚本>> <<脇役>> アプリケーション サービス リポジトリ 処理フロー 副次的な関心事 ドメイン オブジェクト ドメイン サービス 中核ロジック
クラス設計(詳細設計) コンポーネントに割り当てられた振る舞いをより小さく 分割し、プログラミング言語の最小単位へ落とし込む 注文 ❶ ドメイン観点の分割 ❷ 技術観点の分割
クラス設計 ❶ ドメイン観点の分割 ドメイン知識に基づいた分割 ✓値オブジェクトや区分型(Enum) ✓ID型、ファーストクラスコレクション 注文ID 注文 注文合計額 金額 * 商品ID 注文明細 明細金額 金額
クラス設計 ❷ 技術観点の分割 デザインパターン=解決空間の技術制約下で 問題解決をうまく行うための定石 ※言語のパラダイムや特性、表現力に依る 部品表 構成部品 * Visitor 例) Visitorパターン Concrete Visitor 複雑なオブジェクト構造 を走査するアルゴリズム を分離する
設計・実装の進め方 どの順序で設計・実装を進めるべきか? ❶ ボトムアップ ❷ アウトサイドイン ❸ インクリメンタル ユースケース モジュール コンポーネント クラス
設計・実装の進め方❶ ボトムアップ 依存ツリーの末端のクラスから実装を完成させて統合 →統合のリスク(歪な設計、考慮もれによる手戻り) Helper Domain Object Service Domain Object Helper Helper
設計・実装の進め方❷ アウトサイドイン モックオブジェクトを活用し、外側から実装を進める (実際には行き来) →習得が難しい (※詳しくは書籍『実践テスト駆動開発』参照) Helper Domain Object Service Domain Object Helper Helper
設計・実装の進め方❸ インクリメンタル ユースケースの一部分を 少しずつ、繰り返し統合する →おすすめ Helper Domain Object Service Domain Object Helper Helper
設計・実装の進め方❸ インクリメンタル ユースケースを実装していく順序: ✓ハッピーパス→代替パス→例外パス ✓代表種→派生(バリエーション)
設計・実装の進め方❸ インクリメンタル 実装を完成させる順序はボトムアップだが、 アウトサイドインの観点も大事 (2)クライアント 側の呼び出しを 記述 (1)インター フェースや公開 メソッドを定義 Helper Domain Object Service (3)実装・テスト を完成させる Domain Object Helper Helper
Section 3. まとめ 設計の進め方: ✓全体から部分へ、 アウトサイドイン ✓設計原理に従って適切に分割す る
まとめ
Key Takeaway 1. なぜ設計をするのか? 良い設計とは何か? 上位目的を達成すること 開発者が本質的な問題に集中 できること
Key Takeaway 2. 良い設計をするために 大事なことは何か? 重要な設計原理を理解するこ とで設計原則を状況に応じて うまく使う
Key Takeaway 3. 設計はどのように 進めるとよいか? 全体から部分へ どの抽象レベルでも設計原理 に従って考える
ご清聴ありがとうございました ENJOY DESIGNING!
参考文献リスト タイトル 著者・訳者 出版社(出版年) アーキテクトの教科書 価値を生むソフトウェアのアーキテクチャ 米久保 剛 著 翔泳社(2024) 増補・改訂版 誰のためのデザイン? 認知科学者のデザイン原論 D.A.ノーマン 著 岡本 明、安村 通晃、伊賀 聡一郎、野島 久雄 訳 新曜社(2015) アジャイルソフトウェア開発の奥義 第2版 ロバート・C・マーチン 著 瀬谷 啓介 訳 SBクリエイティブ (2004) レガシーコードからの脱却 ソフトウェアの寿命を延ばし価値を高める9つのプ ラクティス David Scott Bernstein 著 吉羽 龍太郎、永瀬 美穂、原田 騎郎、有野 雅士 訳 オライリー・ジャパン (2019) 実践ドメイン駆動設計 エリック・エヴァンスが確立した理論を実際の設計 ヴォーン・ヴァーノン 著 に応用する 翔泳社(2016) オブジェクト開発の真髄 UML2.0を使ったアジャイルモデル駆動開発の全て Scott W. Ambler 著 越智 典子 訳 日経BP社(2005) ユースケース入門 ユーザマニュアルからプログラムを作る ダグ・ローゼンバーグ、ケンドール・ス コット 著 長瀬 嘉秀、今野 睦 訳 ピアソン・エデュケーショ ン(2001 )