ソフトウェアアーキテクチャ研修

yamamoto kiyohiro

2021/11/26

研修の前に…
質問１
これまでソフトウェアアーキテクチャについて勉強したことがある研修の前に…
質問２
これらの単語を聞いたこと・見たことがある
・MVC
・３層（レイヤード）アーキテクチャ
・ヘキサゴナルアーキテクチャ
・オニオンアーキテクチャ
・クリーンアーキテクチャ
・ドメイン駆動設計(DDD)

研修の内容今日の研修では、これらについて…
・MVC
・３層（レイヤード）アーキテクチャ
・ヘキサゴナルアーキテクチャ
・オニオンアーキテクチャ
・クリーンアーキテクチャ
・ドメイン駆動設計(DDD)

研修の内容今日の研修では、これらについて…

話しません
・MVC
・３層（レイヤード）アーキテクチャ（少し触れる程度）
・ヘキサゴナルアーキテクチャ
・オニオンアーキテクチャ
・クリーンアーキテクチャ
・ドメイン駆動設計(DDD)

研修の内容設計パターンではなく「原則」について網羅的に触れます研修の目的・ソフトウェア設計の目的を知る
・優れた設計を行うための知識を身につける→ キーワードの認識、知識の関連付けの土台作り

・（おまけ）パターン紹介

今日の内容・ ソフトウェアアーキテクチャとは・目的
・２つの価値について・ソフトウェア設計における原則
・プログラミングパラダイム
・モジュールの原則
・コンポーネントの原則
・おまけ：パターン紹介
・クリーンアーキテクチャ

ソフトウェアアーキテクチャとは

ソフトウェアアーキテクチャとは��
https://ja.wikipedia.org/wiki/ソフトウェアアーキテクチャ

ソフトウェアアーキテクチャとは��
https://ja.wikipedia.org/wiki/ソフトウェアアーキテクチャ

ソフトウェアアーキテクチャの目的
ソフトウェアアーキテクチャの目的は、求められるシステムを構築・保守するために必要な人材を最小限に抑えることである― Robert C. martin

https://itkonekt.com/2019/12/19/robert-c-martin-uncle-bob-2/

ソフトウェアの２つの価値
ソフトウェアは「ソフト」な「ウェア（プロダクト）」である↓
振る舞いを簡単に変更出来なければならない

例：完璧に動作するが変更できない < 動作しないが変更が簡単

振る舞い(機能)アーキテクチャソフトウェアの２つの価値アーキテクチャ振る舞い(機能)

アイゼンハワーのマトリクス
https://note.com/parikan/n/n1f6658c53760

ソフトウェアの２つの価値アーキテクチャ振る舞い(機能)

アイゼンハワーのマトリクス
https://note.com/parikan/n/n1f6658c53760

ソフトウェアの２つの価値アーキテクチャ振る舞い(機能)

アイゼンハワーのマトリクス
https://note.com/parikan/n/n1f6658c53760

ソフトウェアの２つの価値
ソフトウェア開発者のジレンマ
ビジネスマネージャーがアーキテクチャの重要性を評価出来ない↓
そのためにソフトウェアエンジニアが雇われている
説明し、時には正面から戦う責任がある

ソフトウェア設計における原則

必要なこと良い設計を考えるにはどうすれば良いか？
↓
まず歴史を知る事が大切

先人がどういう課題を発見し、解決してきたのかを知る

ソフトウェア設計における原則
プログラミングパラダイム

プログラミングパラダイム

https://ja.wikipedia.org/wiki/プログラミングパラダイム

プログラミングパラダイム
中でも特に重要な３つのパラダイム

・構造化プログラミング・オブジェクト指向プログラミング
・関数型プログラミング

それぞれ特徴を見てみる

構造化プログラミング
パラダイムの要約「構造化プログラミングは直接的な制御の移行に規律を課すものである」

制限のないジャンプ（goto文）をif/then/else や do/while/until などに置き換えた
これにより分割統治が可能となりテストもしやすくなった構造化プログラミング：補足

http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.132.875

構造化プログラミング：補足
1968年 ダイクストラによる論文 : Go To Statement Considered Harmful「Goto 文は有害と考えられる」内容
人間は静的なプログラムを把握するのには向いているが動的なプロセスを把握するのには向いていない↓
構造化プログラミングに繋がったプログラムは証明可能な単位に分割統治できるようにオブジェクト指向プログラミング
パラダイムの要約「オブジェクト指向プログラミングは間接的な制御の移行に規律を課すものである」

ポリモーフィズムを使用することでシステムにあるすべてのソースコードの依存関係を絶対的に制御する能力
これにより「プラグインアーキテクチャ」を利用できる

関数型プログラミング
パラダイムの要約「関数型プログラミングは代入に規律を課すものである」

競合状態、デッドロック状態、並行更新の問題の原因が全て可変変数にある→ 不変なコンポーネントと可変なコンポーネントに分離する考えを得る

プログラミングパラダイムまとめ
パラダイムはプログラマから「何をすべきでないか」を伝えている
構造化プログラミング： goto 文を奪った
オブジェクト指向プログラミング： 関数ポインタを奪った
関数型プログラミング： 代入を奪った
そして、これらのパラダイムは 1958~1968 の 10 年間に発見された
それから何十年も重要なパラダイムは追加されていない
ツールもハードウェアも変わったが、ソフトウェアの本質は変わらない
これら本質を理解することが、良い設計の理解に繋がる

ソフトウェア設計における原則
モジュールの場合

モジュール設計に関する原則
パラダイムを見てきたが、では具体的にどのような設計が良いのか？
→ 良いモジュールに関する「原則」が様々に提唱されてきた

DRY : 重複を避けろ（Don't Repeat Yourself）
YAGNI : 必要になるまで実装するな（You Aren't Gonna Need It）
KISS : 不必要な複雑性を避けろ（Keep It Simple Stupid）
SOLID : オブジェクト指向において特に重要な５つの原則

SRP : 単一責任の原則
Single Responsibility Principle
オブジェクトはたったひとつのアクターに対して責務を負うべきである→ 立場の違うAとBが同じモジュールを使うとBへの変更でAも影響受ける

OCP : オープン・クローズドの原則
Open Closed Principle
ソフトウェアの構成要素は拡張に対しては開いていて修正に対して閉じていなければならない→ ソフトウェアの振る舞いは既存の成果物を変更せず拡張できるようにすべきLSP:リスコフの置換原則
Liskov Substitution Principle
S が T の派生型であればT 型のオブジェクトが使われている箇所は全てS 型のオブジェクトで置換可能である

LSPはアーキテクチャのレベルにも適用できるし、適用すべき

ISP : インターフェイス分離の原則
Interface Segregation Principle
インターフェイスを分離し、最小限の依存ですむようにせよアーキテクチャレベルにも適用できるシステムS → フレームワークF → データベースDのような依存の場合
Dの変更（障害）はSの変更（障害）となる

DIP : 依存関係逆転の原則
Dependency Inversion Principle
変化しやすい具象要素には依存したくない（String など変化しにくいものは OK）
そのようなものはインタフェースなどの抽象宣言にしたい

ただし誰が具象クラスを生成するかという問題がある
大抵のOO言語では Abstract Factory パターンを使う

ソフトウェア設計における原則
コンポーネントの場合

コンポーネント設計に関する原則
モジュールに関する原則を見てきたが、ではコンポーネントでは？
→ 良いコンポーネントに関する「原則」が様々に提唱されてきた凝集性に関する原則
・REP: 再利用・リリース等価の原則
・CCP: 閉鎖性共通の原則
・CRP: 全再利用の原則
結合性に関する原則
・ADP: 非循環依存関係の原則
・SDP: 安定依存の原則
・SAP: 安定度・抽象度等価の原則

ソフトウェア設計における原則
コンポーネントの場合
凝集性

REP: 再利用・リリース等価の原則
Reuse-release equivalence principle
再利用の単位とリリースの単位は等価となる（リリース番号がついていなければ互換性を確認できない）
リリースプロセスにおいては適切な通知とリリースドキュメントを用意する事が欠かせない

コンポーネントに含まれるクラスはすべてが再利用されるかすべてが再利用できないかのどちらかにすべき

CCP: 閉鎖性共通の原則
Common-closure principle
コンポーネントを変更する理由が複数あるべきではない
単一責任の原則（SRP）をコンポーネント向けに言い換えたもの

同じ理由、同じタイミングで変更されることが多いクラスは1つのコンポーネントにまとめておくべきCRP: 全再利用の原則
Common-reuse principle
コンポーネントのユーザに対して、実際には使わないものへの依存を強要してはいけない
インターフェイス分離の原則（ISP）を一般化したもの

1つのクラスだけを再利用するということはめったになく複数のクラスと組み合わせて使われることがほとんどのためそうしたクラス群は1つのコンポーネントにまとめる

補足：コンポーネント凝集性のテンション図

バランスを取る必要がある
https://qiita.com/NagaokaKenichi/items/65c149ba92580fce5be2

ソフトウェア設計における原則
コンポーネントの場合
結合性

ADP: 非循環依存関係の原則
Acyclic dependencies principle
コンポーネントの依存グラフに循環依存があってはいけない

コンポーネント間で循環依存がある場合コンポーネント単独でのデプロイ・リリースができず不整合が発生する

SDP: 安定依存の原則
Stable-dependencies principle
安定度の高い方向に依存すること

安定度が高い = 変更しづらい
多数のコンポーネントから依存されたコンポーネントは（変更することの影響が大きいので）変更しづらいSAP: 安定度・抽象度等価の原則
Stable-abstractions principle
コンポーネントの抽象度は、その安定度と同程度でなければいけない

安定度の高いコンポーネントは抽象度も高くあるべきで安定度の高さが拡張の妨げになってはいけない

SDP × SAP = コンポーネント版の DIP

おまけ：パターン紹介

クリーンアーキテクチャ
モジュール・コンポーネントに関する良いとされる原則について見てきた
これまで様々に提唱されてきた設計のパターンは基本的にこの原則を実現するための方法論であるアーキテクチャのルールはどれも同じである！
― Robert C. martin

https://itkonekt.com/2019/12/19/robert-c-martin-uncle-bob-2/

クリーンアーキテクチャ
クリーンアーキテクチャが主張するルールは２つだけ・関心事でレイヤーを分ける（境界を引く）・レイヤー間の依存性は一方向にする
これにより結果、以下の特性を持つシステムを生み出す・フレームワーク非依存・テスト可能・UI非依存
・データベース非依存・外部エージェント非依存まとめ良い設計には知識が必要→ まず「原則」を知る
クリーンアーキテクチャ等、設計パターンはその原則から自然に導かれるもの

実践上の注意点など
CleanArchitectureの書籍に色々示されているので、一度読んでみるのをオススメ