〈完全なプログラミング〉を目指す会 2020

第五回 アーキテクチャ

omuomugin

アーキテクチャ

〈完全なプログラミング〉を目指す会 2020

の前に

〈完全なプログラミング〉を目指す会 2020

復習

〈完全なプログラミング〉を目指す会 2020

〈完全なプログラミング〉

とは?

〈完全なプログラミング〉を目指す会 2020

「読めば分かるコードを書く」
「必要十分なドキュメントを書く」

〈完全なプログラミング〉を目指す会 2020

余計なモノを
一切必要としない

ソフトウェアづくり

〈完全なプログラミング〉を目指す会 2020

その心は?

〈完全なプログラミング〉を目指す会 2020

コードは圧倒的に
人間によって読まれる

〈完全なプログラミング〉を目指す会 2020

故に〈完全なプログラミング〉は
圧倒的に はやい

〈完全なプログラミング〉を目指す会 2020

さらに

〈完全なプログラミング〉を目指す会 2020

品質の改善は
コストを削減する

〈完全なプログラミング〉を目指す会 2020

故に〈完全なプログラミング〉は
圧倒的に やすい

〈完全なプログラミング〉を目指す会 2020

はやい
やすい

〈完全なプログラミング〉を目指す会 2020

うまい
😋

〈完全なプログラミング〉を目指す会 2020

今回はアーキテクチャ編

〈完全なプログラミング〉を目指す会 2020

今日持ち帰って欲しいこと

〈完全なプログラミング〉を目指す会 2020

ベストな「How」は「Why」でしか規定できない
Mercari Bold Challenge "Why Microservices?" by @deeeet

see also ベストな「How」は「Why」でしか規定できない メルカリがマイクロサービスに移行した理由と、その軌跡

〈完全なプログラミング〉を目指す会 2020

すべての解決策は
「なぜ」適用するかが大事

〈完全なプログラミング〉を目指す会 2020

では本編

〈完全なプログラミング〉を目指す会 2020

よい設計は悪い設計よりも変更しやすい
我々が知る限り、この世のあらゆる設計原則は ETC (Easier to Change) 原則を特殊化したものとなっています
— 達人プログラマ第二版 Tips14

〈完全なプログラミング〉を目指す会 2020

変更のしやすさが最も大事

〈完全なプログラミング〉を目指す会 2020

なぜソフトウェアは
変更しにくくなってしまうのか

〈完全なプログラミング〉を目指す会 2020

ソフトウェアは「変化し続ける要求」と「戦略的ではない依存の追加や変更」によって腐っていく
— Design Principles and Design Patterns, 2000, Robert C. Martin

〈完全なプログラミング〉を目指す会 2020

ソフトウェアの複雑性は、「依存」と「曖昧さ」によって引き起こされる
— Philosophy of Software Design

〈完全なプログラミング〉を目指す会 2020

複雑なソフトウェアの3つの負

  • Change Amplification: 変更箇所が多すぎる
  • Cognitive Load: コードが理解できない
  • Unknown Unknowns: そもそも何を変更すべきかわからない
〈完全なプログラミング〉を目指す会 2020

変化し続ける要求に耐えながら
依存を完結に保つのが大事

〈完全なプログラミング〉を目指す会 2020

疎結合かつ凝集性を高く

〈完全なプログラミング〉を目指す会 2020

理想的な構造的な設計は、結合度を低くし、凝集性を高めることである
— Comparing Techiniques by Means of Encapsulation and Connersence, 1992, Meilir Page-Jones

〈完全なプログラミング〉を目指す会 2020

疎結合と凝集性はお互いに表裏の関係にある

〈完全なプログラミング〉を目指す会 2020

Connascence (コナーセンス)

  • 2つのソフトウェア要素 A, B があるときに一方を変更した際にもう一方も変更しないといけないような関係のこと
  • 結合度と凝集性両方のメトリクスとして 1992 年に提案された
  • e.g. パッケージ同士でコナーセンスがあるとそれは密結合になる
// Int -> String に変えた場合には ソフトウェア要素 B も変更する必要がある例
var a: Int // ソフトウェア要素 A 

a = 7  // ソフトウェア要素 B
〈完全なプログラミング〉を目指す会 2020

Connascence の強さ

〈完全なプログラミング〉を目指す会 2020

疎結合かつ凝集性を高く
=
境界外は「弱い」コナーセンスに
境界内は「強い」コナーセンスに

〈完全なプログラミング〉を目指す会 2020

強いコナーセンスは、構造的にはわからない

〈完全なプログラミング〉を目指す会 2020

プログラムの「意味」を理解して
はじめてコナーセンスを判断できる

〈完全なプログラミング〉を目指す会 2020

ちょっとまた別の話

〈完全なプログラミング〉を目指す会 2020

弱い凝集性

  • 情報的凝集: 決まった順番で処理される必要があるだけ
  • 連絡的凝集: 同じデータを利用しているものを集めただけ
  • 時間的凝集: 同時に実行されるものを集めただけ
  • 手順的凝集: 独立している処理が順番に並んでる
  • 論理的凝集: 分岐処理が1つのルーチンに閉じ込められてる
  • 偶発的凝集: たまたま一緒 (暗号的凝集とも呼ばれる)

— Code Complete 上 第7章 高品質なルーチン

〈完全なプログラミング〉を目指す会 2020

強い凝集性

  • 機能的凝集

ルーチンが処理を1つだけ実行する場合である。ここでの評価は、それらのルーチンがその名前が示唆するとおりの処理を行うと前提してのものである。他にも何かの処理を行うとしたら、凝集性は弱まり、名前も適切とは言えなくなる。
— Code Complete 上 第7章 高品質なルーチン

〈完全なプログラミング〉を目指す会 2020

「1つだけ」のサイズは?

〈完全なプログラミング〉を目指す会 2020

Software that fits in your head
— Dan North (creator of BDD)

〈完全なプログラミング〉を目指す会 2020

複雑な問題を完全に詰め込めるほど大きな脳を持った人はいない by Edsger Dijkstra
— Code Complete 上 第7章 高品質なルーチン

〈完全なプログラミング〉を目指す会 2020

サイズの決定権は、
「我々」に委ねられている

〈完全なプログラミング〉を目指す会 2020

強い凝集性は
構造的にはわからない

〈完全なプログラミング〉を目指す会 2020

プログラムの「意味」を理解して
はじめて凝集性の判断ができる

〈完全なプログラミング〉を目指す会 2020

全ては、プログラムの「意味」を
理解するところから

〈完全なプログラミング〉を目指す会 2020

もう1つだけ例を

〈完全なプログラミング〉を目指す会 2020

どっちの方が優れてると思いますか?

// ① 引数を1つずつ渡す
fun doSomething(a: Int, b: Int, c: Int, d: Int)

// ② 引数に必要なものを1つのオブジェクトに詰めて渡す
fun doSomething(obj: SomeObj)

〈完全なプログラミング〉を目指す会 2020

これらの意見はどちらも短絡的で、ルーチンのインターフェイスが表す抽象概念とは何かという最も重要なポイントを見逃している。
ルーチンは3つの要素が渡されることを期待していて、それらがたまたま同じオブジェクトによって提供されることが抽象化であるというなら、3つのデータ要素を個別に渡すべきだろう。
しかし、常に特定のオブジェクトが存在し、ルーチンがそのオブジェクトを使って何かをすることが抽象化であるというなら、3つのデータ要素を公開した時点で、抽象化を崩壊させることになる。
— Code Complete 上 第7章 高品質なルーチン

〈完全なプログラミング〉を目指す会 2020

(再掲)

全ては、プログラムの「意味」を
理解するところから

〈完全なプログラミング〉を目指す会 2020

小休憩がてら偉人のお言葉を

〈完全なプログラミング〉を目指す会 2020

パターンがより最悪の自体を招いたケースをある。
人々が本を読んで紹介されているパターンにワクワクしてまるで適用すればするほど良いソフトウェアになる魔法のように感じてしまった。
本来であれば、それらのパターンがどこで使用されるべきか、それらを使用する正しい方法は何か、そしてそれらをどのように適応させるかを理解する必要があるにも関わらず。
— Software Engineering Radio EP 215: Gang of Four - 20 Years Later

〈完全なプログラミング〉を目指す会 2020

あるプラクティスがなぜワークするのかを理解することなく、耳かきをしながらプロジェクトが無事に成功することを願っているだけである。
カーゴカルト な ソフトウェアエンジニアは、「我々はいつもこのやりかたでやってきた。」、「我々の会社の標準はこの方法であり。」と言って意味のないようなプラクティスを正当化する。
— Cargo Cult Software Engineering, March/April 2000 IEEE, Steve McConnell

〈完全なプログラミング〉を目指す会 2020

カーゴカルト

  • 飛行機を見たことがない島の原住民が、島でも飛行機を飛ばそうと植物のつるとやココナッツの殻、椰子の葉といった現地の材料を使って再構築しました。
  • 当然、飛行機の形をしたものが出来上がっただけで、飛ぶことはない
〈完全なプログラミング〉を目指す会 2020

カーゴカルト

彼らは中身を伴わない、形を真似ただけだったのです。人類学者はこれを「カーゴカルト」と呼んでいます。
我々はしばしば、この島の島民と同じ行動をとろうとします。
このカーゴカルトの罠に誘い込まれ、はまってしまうのは簡単です。目に映りやすい特報に投資し、それを作成することで、何らかの魔法のような結果を呼び込めると期待してしまうのです。
— 達人プログラマ 第2版 Tips 87

〈完全なプログラミング〉を目指す会 2020

すべての解決策は
「なぜ」適用するかが大事

〈完全なプログラミング〉を目指す会 2020

では「意味」をどうやって分析するか

〈完全なプログラミング〉を目指す会 2020

ドメイン駆動設計のアプローチ

  • ドメインエキスパートとの対話を通した 「ドメインの分析」
  • 理解したドメインを元にした 「戦略的設計」
  • 戦略的設計を実現するための 「戦術的設計」

※詳細には立ち入らないので、気になった人は一緒に話しましょう

〈完全なプログラミング〉を目指す会 2020

DDD に対する誤解

  • 例えばレイヤードアーキテクチャを DDD だと思っている人がいる
  • しかし DDD本 のあとに出た IDDD本 では ヘキサゴナルアーキテクチャを利用して説明している

戦略的、そして戦術的に設計したドメインモデルは、特定のアーキテクチャに依存するのではなくアーキテクチャ的に中立であるべきだ。
— 実践ドメイン駆動設計

〈完全なプログラミング〉を目指す会 2020

レイヤードアーキテクチャのような
戦術的設計だけを適用する DDD を
「軽量DDD」と呼び、DDD ではしばしば
アンチパターンとされている

〈完全なプログラミング〉を目指す会 2020

ドメイン分析

〈完全なプログラミング〉を目指す会 2020

ドメイン分析

  • ドメインエキスパートとの対話を通してドメインを理解すること
  • またその成果物として共通言語である「ユビキタス言語」を定義すること
〈完全なプログラミング〉を目指す会 2020

ユビキタス言語

  • ユビキタス言語は、ただの言葉のことを指しているわけではない
  • コードにも多大なる影響を及ぼす

ユビキタス言語が注目するのは、その業務自体が、どのような考えのもとでどのように動くのかということだ
— 実践ドメイン駆動開発

〈完全なプログラミング〉を目指す会 2020

インフルエンザワクチンを患者に投与する

〈完全なプログラミング〉を目指す会 2020

あなたなら
どんなコードを書く?

〈完全なプログラミング〉を目指す会 2020
// どうでもいいからさっとコード書こうぜの人

//...
patient.setShotType(ShotTypes.TYPE_FLU);
patient.setDose(dose);
patient.setNurse(nurse);
//...
〈完全なプログラミング〉を目指す会 2020
// 「インフルエンザの注射を患者に打つ」まで分析できた人

//...
patient.giveFluShot();
//...
〈完全なプログラミング〉を目指す会 2020
// 「ナースが患者に、インフルエンザワクチンを適量投与する」まで分析できた人

//...
Vaccine vaccine = vaccines.standardAdultFluDose();
nurse.administerFluVaccine(patient, vaccine);
//...
〈完全なプログラミング〉を目指す会 2020

業務やモデルの理解がコードに現れる
理解したことしか表現できない

〈完全なプログラミング〉を目指す会 2020

ジョシュアツリーの法則 覚えてますか?

〈完全なプログラミング〉を目指す会 2020
〈完全なプログラミング〉を目指す会 2020

名前を言えるようになったとたんに、いたる所でそれを見るようになりました
– Robin Williams ノンデザイナーズ・デザインブック

〈完全なプログラミング〉を目指す会 2020
  • 名前を知らなければ 知覚することすら出来ない
  • 森羅万象、名前を与えることで初めて、それについて考えることが出来るようになる
〈完全なプログラミング〉を目指す会 2020

で?対話ってどうやるの?

  • 口で言うのは簡単だが、実践するのは難しい
  • 多くの企業ではこの業務は Senior, Staff Engineer の役割
    • ※ Staff は Senior の上級職
〈完全なプログラミング〉を目指す会 2020

Example Mapping

〈完全なプログラミング〉を目指す会 2020

実際にスライドの例を見てみよう

〈完全なプログラミング〉を目指す会 2020

Take Away for Example Mapping

  • 具体例をベースに
    • 「真の要求」を聞き出す
    • 誰も気づいてなかったルールを発見する
    • 対話を通して共通の仕様の認識を作っていく
  • 結果的に最初の「良い感じに表示したい」からいくつものルールが定義できた
〈完全なプログラミング〉を目指す会 2020

戦略的設計

〈完全なプログラミング〉を目指す会 2020

若かりしころすべての業務で統一されたモデルを作ることとアドバイスされた。しかし DDD でわかったことは統一されたモデルは大規模なシステムにおいて不可能か費用対効果に見合わないことがわかった。
— ドメイン駆動設計

〈完全なプログラミング〉を目指す会 2020

ECサイトにおける「商品」

  • 購入者が一覧で閲覧する「商品」
  • 購入者が購入しようとしてる「商品」
  • 配達者が配達する「商品」
  • 在庫管理者が在庫管理している「商品」

それぞれでの「商品」の意味が異なる

〈完全なプログラミング〉を目指す会 2020

「商品」の意味が異なる
=
「商品」のコンテキストが異なる

〈完全なプログラミング〉を目指す会 2020

境界づけられたコンテキスト

境界を越えてモデルを扱うと様々な意味を含んでしまうことになる
結果としてモデルが複雑になり、腐っていってしまう

〈完全なプログラミング〉を目指す会 2020

どうやって境界を分ける?

〈完全なプログラミング〉を目指す会 2020

ドメインを
分析するしかない

〈完全なプログラミング〉を目指す会 2020

境界の分け方を
支援してくれるツールはある

〈完全なプログラミング〉を目指す会 2020

Context Map Patterns

〈完全なプログラミング〉を目指す会 2020

パターン

  • Open / Host Service
  • Conformist
  • Anticorruption Layer (腐敗防止層)
  • Shared Kernel
  • Customer / Suplier
  • Partnership
  • Published Language
  • Seprate Ways
  • Big Ball of Mud
〈完全なプログラミング〉を目指す会 2020

戦術的設計

※ 詳細には立ち入らないです!

〈完全なプログラミング〉を目指す会 2020

必ずしも DDD本 で
紹介されているものだけじゃない

〈完全なプログラミング〉を目指す会 2020

思いつく限りあげてみよう

〈完全なプログラミング〉を目指す会 2020

集約とRepositoryパターン

〈完全なプログラミング〉を目指す会 2020

Layered Architecture

〈完全なプログラミング〉を目指す会 2020

ヘキサゴナル (Port and Adapter) アーキテクチャ

〈完全なプログラミング〉を目指す会 2020

CQRS と Event Sourcing

〈完全なプログラミング〉を目指す会 2020

Clean Architecture

〈完全なプログラミング〉を目指す会 2020

Humble Object Pattern

〈完全なプログラミング〉を目指す会 2020

DTOやDPO

※ DTO = Data Transfer Object
※ DPO = Domain Payload Object

〈完全なプログラミング〉を目指す会 2020

Transaction Script と Domain Modeling

〈完全なプログラミング〉を目指す会 2020

Service Oriented Architecture (SOA)

〈完全なプログラミング〉を目指す会 2020

RESTとRPC

※ RPC = Remote Procedure Call

〈完全なプログラミング〉を目指す会 2020

マイクロサービス、モジュラモノリス

〈完全なプログラミング〉を目指す会 2020

Dependency Injection

〈完全なプログラミング〉を目指す会 2020

GoF の Design Pattern

〈完全なプログラミング〉を目指す会 2020

Design By Contract

〈完全なプログラミング〉を目指す会 2020

防御的プログラミング

〈完全なプログラミング〉を目指す会 2020

REP, CCP, CRP原則

※SOLID原則と共に紹介されるパッケージにおける原則

〈完全なプログラミング〉を目指す会 2020

ADP, SDP, SAP原則

※SOLID原則と共に紹介されるパッケージ間の関係における原則

〈完全なプログラミング〉を目指す会 2020

SOLID原則

〈完全なプログラミング〉を目指す会 2020

DRY, KISS, YAGNI

〈完全なプログラミング〉を目指す会 2020

あなたはいくつ知ってましたか?

〈完全なプログラミング〉を目指す会 2020

まだまだあるし
これからも増え続ける

〈完全なプログラミング〉を目指す会 2020

最後にもう一度

〈完全なプログラミング〉を目指す会 2020

すべての解決策は
「なぜ」適用するかが大事

〈完全なプログラミング〉を目指す会 2020

付録

〈完全なプログラミング〉を目指す会 2020

Books

  • Domain-Driven Design, Eric Evans
  • Implementing Domain-driven Design, Vernon, Vaughn
  • Philosohy of Software Design, John Ousterhout
  • Code Comple 上下, Steve McConnell
  • 達人プログラマ第2版, David Thomas, Andrew Hunt
  • Agile Testing Condensed, Janet Gregory, Lisa Crispin
  • Fundamentals of Software Architecture, Neal Ford, Mark Richards
  • etc...
〈完全なプログラミング〉を目指す会 2020

Articles

〈完全なプログラミング〉を目指す会 2020

Papers

  • Design Principles and Design Patterns, 2000, Robert C. Martin
  • Cargo Cult Software Engineering, 2000, Steve McConnell
  • etc...
〈完全なプログラミング〉を目指す会 2020

Presentations

〈完全なプログラミング〉を目指す会 2020

EOF

〈完全なプログラミング〉を目指す会 2020