Slide 1

Slide 1 text

©MIXI MIXI 25新卒技術研修 ソフトウェアアーキテクチャ研修

Slide 2

Slide 2 text

22 ©MIXI 講師紹介 登内 雅人 とのうち まさと 2020 年度新卒入社 • 業務:開発本部 たんぽぽ室 AIモデリング G • サッカー映像解析、アナリスト支援アプリ開発、 FC東京アプリ開発、みてねでの画像解析 • ML系の研究開発、MLOps、Backend、Frontend • Python、Go、Flutter • 趣味:サッカー観戦、格闘技、将棋、個人開発 Docbaseマイページ github pages: https://github.com/tonouchi510

Slide 3

Slide 3 text

3 ©MIXI はじめに ソフトウェアアーキテクチャ研修は今年からの取り組みです。 セクションごとに質問の時間を挟むので、疑問点があれば質問してください。 ※サンプルコードや解説は厳密性より分かりやすさを優先しています。 また、ソフトウェアアーキテクチャ研修と⾔いつつ、設計に関する概念を全般的に触 れていきます。 ⾊々話すと思いますが、以下の観点を持って返ってもらえると幸いです。 ● アーキテクチャとは何か、なぜ学ぶ必要があるか ● 設計の考え⽅‧向き合い⽅について、何を⽬的とするべきか

Slide 4

Slide 4 text

4 ©MIXI ⽬次 ● ソフトウェアアーキテクチャとは ● アーキテクチャを学ぶ必要性 ● モノリシックアーキテクチャ ● マイクロサービスアーキテクチャ ● モノリス vs マイクロサービス?? ● 疎結合を実現するための⽅法論の紹介 ● ドメイン駆動設計(DDD)の解説 ● DDD実践演習

Slide 5

Slide 5 text

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

Slide 6

Slide 6 text

6 ©MIXI アーキテクチャとは 対象の構造や、対象を構成する部品と部品同⼠の関係を⽰す設計図。 システム全体のアーキテクチャ(インフラ構成)の場合 ● Webサーバー ● APIサーバー ● 認証基盤 ● データベース ● APIゲートウェイ ● クラウドサービス ● etc ソフトウェアアーキテクチャではこの部分の構造の設計⽅針を定義する

Slide 7

Slide 7 text

7 ©MIXI ソフトウェアアーキテクチャとは ソフトウェアの構成要素とそれらの関係を定義したもの。 ソフトウェアの構成要素 ● 各機能を実現するためのサービス‧モジュール‧クラス ○ 例:ユーザ管理、在庫管理、商品検索、決済 ● 認証‧認可 ● DB操作 ● 外部サービス連携 ● etc ソフトウェアを組み⽴てるときには様々な要素が必要となる

Slide 8

Slide 8 text

8 ©MIXI ソフトウェアアーキテクチャとは ソフトウェアアーキテクチャと聞いてよく出てくる⽤語 ● クリーンアーキテクチャ ● レイヤードアーキテクチャ ● オニオンアーキテクチャ ● ヘキサゴナルアーキテクチャ ● モノリシックアーキテクチャ(モノリス) ● マイクロサービスアーキテクチャ ※あとでまた触れます。

Slide 9

Slide 9 text

©MIXI アーキテクチャを学ぶ必要性

Slide 10

Slide 10 text

10 ©MIXI アーキテクチャを学ぶ必要性   ⾮機能要件を実現するため なぜソフトウェア開発において、アーキテクチャ‧設計が重要か? ● 機能要件 ○ ユーザやシステムが「何をできるか」に関する要件。機能そのもの。 ● ⾮機能要件 ○ システムが「どのように動作するか」など機能に限らない要件(品質や性能等)。 ○ 実⾏時の品質:パフォーマンス‧スケーラビリティ、可⽤性‧信頼性、セキュリティ ○ デプロイ時の品質:デプロイ‧ロールバックの容易性 ○ 開発時の品質:保守性(メンテナンス‧機能改修、新機能開発の容易性) ソフトウェア開発では、単にエンジニアを増やせば 開発速度が上がるわけではないという現実がある 「ユーザアカウントを作成でき る」、「注文できる」など。

Slide 11

Slide 11 text

11 ©MIXI アーキテクチャを学ぶ必要性 https://www.oreilly.com/library/view/accelerate/9781457191435/ 実際、Accelerateという、2000社以上の開発組織の調査 結果をまとめた⽂献がある。 ‧横軸:エンジニアの数 ‧縦軸:1⽇のデプロイ数 エンジニアが単に増えるだけではパフォーマンス(⽣産 性)は上がらず、鈍化することさえある。 High Performersは⼈数とデプロイ数をほぼ線形を維持。 => High Performance組織としての⼟台が必要。 パフォーマンス向上には、「プロセスの改善( DevOps的な話)」や「組織作り(心理的安全性)」なども重要。 ただし、それだけではどうにもならない問題もある => 技術での解決が必要

Slide 12

Slide 12 text

12 ©MIXI アーキテクチャを学ぶ必要性 素朴な疑問: ● 開発速度の観点でいうと、アーキテクチャとか設計考えた⽅が落ちるのでは? ○ 少なくとも設計考えて会議して議論してっていう⼯程が増える ○ ⼤変そうなので機能要件だけ考えて作った⽅が早いのでは? => 1回作りきって終わりのソフトウェアはそう => スケールし、継続的な改修が必要なソフトウェアの場合、規模拡⼤とともにそうも ⾔えなくなる

Slide 13

Slide 13 text

13 ©MIXI 機能要件の実現のみを意識した実装 機能要件しかなければ、極端なことを⾔うと、クラスを定義せず、⼀つの関数でIf⽂ とFor⽂だけで組み⽴てたコードでも良いことになる。 ただ機能を追加していくだけの コード。 機能要件は実現できても、 人間にとって理解しづらい。 ※あくまで疑似コードです。

Slide 14

Slide 14 text

14 ©MIXI 密結合と疎結合 ソフトウェアアーキテクチャや設計の⽂脈においては、”ソフトウェアの構成要素同⼠ の結合度合い”が重要な設計の観点となる。 ● 密結合(⼀般的に良くない状態) ○ クラスやモジュールが互いの内部構造や具体的な実装に依存している状態 ■ 例:他のクラスの変数を直接参照したり、インスタンス⾃体を変数に持つなど ● 疎結合(⼀般的に良い状態) ○ クラスやモジュールが互いの内部構造や具体的な実装に依存していない状態 ■ 「インターフェースや抽象のみへの依存」、「集約」など

Slide 15

Slide 15 text

15 ©MIXI 密結合した実装の例 例:「家族アルバム みてね」のようなアルバムサービスを想定 仕様:アプリのユーザはアルバムの作成と参加が可能 => コード上では機能要件は満たしている UserクラスがAlbumクラスに依存している => 例えば Albumのコンストラクタが変更されたら `create_album` が壊れる可能性がある ※以降もあくまで疑似コードなので、プログラムとしての正しさは仮 定してません。

Slide 16

Slide 16 text

16 ©MIXI 密結合した実装の例 Albumの仕様変更:`follower_scope`を追加(参加者のアクセス権制御) ● 定数定義が変わったら依存先が壊れる ○ 1 がフル権限になったら`create_album`が壊れる ● オブジェクトがどこでどう変更されるかが分からない ○ UserがAlbumのインスタンスを持っていて、やろうと思えばメンバ変数にも直接アクセス‧変更できる ○ バリデーション(整合性チェック)の実装が分散しやすい ■ そうなると別の場所ではバリデーションをやり忘れたり、バリデーションの変更漏れも起きやすい ■ ※本来はAlbumクラスにscope変更のメソッドを⽣やすなど、⼀箇所にできると良い

Slide 17

Slide 17 text

17 ©MIXI 密結合の特徴 これらの例では、規模も⼩さく仕様もシンプルなのでミスも起こらないと思うが、規 模が拡⼤すると、仕様も複雑になり、把握できない部分も増えていくため、より影響 が⼤きくなる。 密結合の特徴を整理すると以下の通り ● 他のモジュールの変数やメソッドにアクセスし放題で、開発はしやすい ● ⼀⽅で、変更時の影響範囲が広く、それらを適切に把握できないとバグを⽣む ● つまり、あるモジュールの開発‧改修を⾏う際に依存先のモジュールに関する知識も 必要になってしまう

Slide 18

Slide 18 text

18 ©MIXI 密結合について (リアルに⾟さをイメージしてもらうため) 密結合した100億⾏のコードで出来たシステムを想像してみてください。 あなたの配属先事業ではそのシステムを扱います。 数ヶ⽉後に新機能のリリースが迫っていて、そこを担当してもらいます。 さらに、新機能は仕様書だけで数⼗ページあります。 => どれくらい絶望的な状況か理解していただけたでしょうか?

Slide 19

Slide 19 text

19 ©MIXI アーキテクチャを学ぶ必要性 規模が⼤きくなると遅くなる原因 ● コード量‧機能量が多いことによる認知負荷増 ○ どのコードや機能がどこに依存しているのかわからなくなる ○ (メンバーの離職等により)誰も把握していないコードも増える ○ => 時間とともに、もはやそのソフトウェアを⼗分に理解することが不可能になる ● 障害やバグの数も増える ○ つまり、本質的な機能改修に取り組める時間がどんどん失われていく ● 組織の⼈数が増えることによるコミュニケーションコスト増 ○ リリースなどの調整先が増える、コンフリクトも増える ※特に前スライドのように複雑なものに複雑なものを追加する時は顕著になる

Slide 20

Slide 20 text

20 ©MIXI アーキテクチャを学ぶ必要性 https://www.oreilly.com/library/view/accelerate/9781457191435/ 以上を踏まえると、このグラフが起こりうる現実 としておかしくないと理解してもらえるはず。 ● 既存のエンジニア ○ 勤務時間における会議や障害‧バグ対 応、コンフリクトの割合が増える ○ 本質的な業務に取り組めない ● 新規参⼊エンジニア ○ 読まなければいけないコードが多すぎ て把握しきれない ○ ⼀⼈⽴ちできるまで時間を要する アーキテクチャを学ぶ必要性: ● エンジニアの増加に対するパフォーマンスの最⼤化を⽬指す ● 機能改修の速さはビジネス観点では ”競合優位性(参⼊障壁)” となる 要点

Slide 21

Slide 21 text

21 ©MIXI (再掲)⽬次 ● ソフトウェアアーキテクチャとは ● アーキテクチャを学ぶ必要性 <= ここまで終了 ● モノリシックアーキテクチャ ● マイクロサービスアーキテクチャ ● モノリス vs マイクロサービス?? ● 疎結合を実現するための⽅法論の紹介 ● ドメイン駆動設計(DDD)の解説 ● DDD実践演習 質問あれば受け付けます。

Slide 22

Slide 22 text

22 ©MIXI 補⾜:エンジニア組織のパフォーマンス計測 組織の開発のパフォーマンスを測るのは実際にはかなり難しい。 デプロイ数で計測するというのは⽅法の⼀つ。 有名なものとしては、Four Keysがある。 リファクタリング‧リアーキテクチャのKPIに設定し、そこの改善を⾒ると⾯⽩そう。 コードがコミットされてか ら本番環境で正常に機能す るまでの時間 リードタイム コードを本番環境にデプロ イまたはリリースした頻度 デプロイ頻度 変更失敗時にサービス復元 までにかかる時間 平均修復時間(MTTR) リリース後に障害や不具合 等により修正を⾏う必要が ⽣じた割合 変更失敗率

Slide 23

Slide 23 text

23 ©MIXI ソフトウェアアーキテクチャとは(再掲) ソフトウェアアーキテクチャと聞いてよく出てくる⽤語 ● クリーンアーキテクチャ ● レイヤードアーキテクチャ ● オニオンアーキテクチャ ● ヘキサゴナルアーキテクチャ ● モノリシックアーキテクチャ(モノリス) ● マイクロサービスアーキテクチャ ここから、まずマクロレベルの設計の話として、モノリスとマイクロサービスについ ての概要と、アーキテクチャ選定に関する考え⽅の解説をします。 こちらはあくまで⼀つの モノリス or サービスの 内部の構造の話 まずこちらを扱う

Slide 24

Slide 24 text

©MIXI モノリシックアーキテクチャ

Slide 25

Slide 25 text

25 ©MIXI モノリシックアーキテクチャ ⼀般的な説明:  「コードベースが単⼀」、「全ての機能が同⼀プロセス内で動作」、「各機能が密結合(※)」 普通に作ったら⼤体こうなる DB API Web UI Adapter Adapter Business Logic Business Logic Business Logic Business Logic Business Logic Business Logic 外部 サービス 後で補足します。

Slide 26

Slide 26 text

26 ©MIXI モノリシックアーキテクチャ ⼩規模アプリケーション開発の場合 ● テストがしやすい ○ サーバー間通信などもなく、E2Eテストも簡単 ● デプロイしやすい ○ 複雑なコンポーネントに分かれていない、シングルバイナリ ● スケーリングが簡単 ○ アプリケーションを複数インスタンスで実⾏するだけ ● 開発もしやすい ○ コードベースが単⼀(やろうと思えば全てのクラス‧メソッドにアクセスできる) ○ DBも単⼀(全てのデータを参照できる、整合性の担保も簡単) 全てが⼀箇所であることからくる利点

Slide 27

Slide 27 text

27 ©MIXI モノリシックアーキテクチャ ⼤規模アプリケーション開発の場合 ● テストが⾟い(実⾏時間等) ○ ⼀部の機能を修正しただけなのに全体のテストが動く ● デプロイが⾟い ○ ⼤⼈数で同じコードベースを触るので競合が増える ● スケーリングが⾟い ○ 異なるリソース要件の機能が混在するため ● 開発がしづらい ○ コードベースがデカすぎて⼀⼈のエンジニアが理解できるキャパを超えてしまう ○ 古い技術スタックに縛られる(依存する範囲が広いため) ● 信頼性低下 ○ バグや障害を起こしやすく、発⽣時に特定しづらくなる ○ 依存箇所が多いライブラリのアプデ難易度も上がる メリットだった部分が 全て反転してくる アプリケーション開発において、規模が拡⼤するとあらゆる問題が出現してくる

Slide 28

Slide 28 text

©MIXI マイクロサービスアーキテクチャ

Slide 29

Slide 29 text

29 ©MIXI マイクロサービスアーキテクチャ ⼀般的な説明(※): アプリケーションを⼩さく、独⽴したサービスの集合体として設計‧開発するアプローチ。 サービスごとに独⽴したコードベース‧基盤‧データベースを持ち、独⽴してデプロイされる。 サービス: ● 特定の機能を提供し、個別 にデプロイできるソフトウェア コンポーネント ● 外部からはAPI経由でのみ アクセス可能(疎結合) ※ただし、次のセクションで話しますが、 定義にとらわれる必要はありません

Slide 30

Slide 30 text

30 ©MIXI マイクロサービスアーキテクチャ マイクロサービス(の理想状態)では、以下のような恩恵が受けられる。 ● テストが効率的 ○ 変更したサービスだけテストすれば良い ● デプロイがしやすい ○ 他のサービスの開発者の作業に影響されない ● スケーリングが効率的 ○ サービスごとに、リソース要件に合わせてスケーリングできる ● 開発‧メンテナンスがしやすい(保守性) ○ ⾃分の担当するサービスに関する知識だけあれば良いので、認知負荷が低い ○ 依存範囲が狭いため、技術スタック‧ライブラリの更新がしやすい(サービスごとに可能) ● 信頼性向上 ○ コードベース、DB、インスタンス等が分かれているため、障害発⽣時の 影響を限定できる、原因の特定がしやすい あらゆる事柄を個別の サービス単位で考えらえる ようになる恩恵

Slide 31

Slide 31 text

31 ©MIXI 基本的にはこういうイメージで考えてもらえるとわかりやすいかも。 マイクロサービスアーキテクチャ このリポジトリ渡されて開 発任されるの、どっちが良 いですか? このリポジトリ渡されて開 発任されるのと、

Slide 32

Slide 32 text

32 ©MIXI マイクロサービスアーキテクチャ マイクロサービスアーキテクチャの⽋点 ● マイクロサービスを理想通り実現するためには多くの専⾨知識が必要 ○ 様々な設計パターンに関する知識 ○ 分散システム特有の問題への対処 ● サービスへの適切な分割を考える難易度が⾼いこと ○ 他サービスの開発に影響しない分割(疎結合)をする必要がある => 具体的にマイクロサービスの構築で考えなければいけないことをみていきます

Slide 33

Slide 33 text

33 ©MIXI マイクロサービスアーキテクチャ 「サービス間通信はどうするか?」 サービスに分かれることになるので、サービス間でやり取りが必要となることがある。 せっかくサービスで分かれているのに、これまで通り同期APIで呼び出していては可⽤性が 上がらない。 例えば「家族アルバム みて ね」の例でいうと、写真アップ ロード時に AIによる写真の解 析処理が動くが、解析処理の 遅延や失敗でアップロード機 能自体を利用不可にしたくな い。 => 非同期通信にする => (可⽤性を上げたければ)出来るだけ⾮同期のメッセージング基盤等でやり取りする設計   に変える必要がある。

Slide 34

Slide 34 text

34 ©MIXI マイクロサービスアーキテクチャ 「サービス間でのデータ整合性はどうするか?」 サービスごとにDBが分かれることにより、様々な問題が⽣じる。特に複数サービスにまたがっ たデータの整合性維持は難しい問題。結果整合性で考えていくことになる(※サーガ)。 ※単⼀DBではトランザクションのACID特性により整合性を担保できる。 在庫修正だけ失敗すると配送してな いのに在庫数が減ってデータの整合 性が壊れることに 注文キャンセルの例:

Slide 35

Slide 35 text

35 ©MIXI 結果整合性とは 分散システムにおいて、⾼いパフォーマンスや可⽤性を優先するために⽤いられる 整合性担保の⽅法。 通常のRDBなどで保証されている「強い整合性」では、トランザクション処理によって データの更新が即時にすべてのテーブルで反映されます。 ⼀⽅で、「結果整合性」では、⼀時的な不整合‧不⼀致を許容しつつ、最終的には全体が ⼀貫性を持った状態に落ち着くことを保証する整合性モデルです。

Slide 36

Slide 36 text

36 ©MIXI 結果整合性の⾟み マイクロサービスではサービス間のデータ整合性は結果整合性を前提としているのでそれに伴う 問題の考慮は当然必要になってくる。 ⾮同期更新なので、DB研修で習ったような「ダーティリード」、「ノンリピータブルリー ド」、「ファントムリード」に類似するような問題が発⽣し放題。その他の問題も多い。 ● 注⽂処理は成功しているのに在庫情報が変わっていない(更新遅延) ● 在庫確認してから注⽂処理を確定し、その後在庫を引き落とそうとしたらなかった ● 決済で処理が失敗したが、在庫の修正前(確定前)の値を読んでしまう (対処できるものもあるが) これらが致命的になるデータの場合は、単⼀のサービスに含める必要がある。  多くの場⾯でトランザクションの分離性よりもパフォーマンスが重要視されるようになってきていると   はいえ、データの整合性は事業の存続に関わる重⼤な問題であり、正確に判断するための知⾒が必要。

Slide 37

Slide 37 text

37 ©MIXI マイクロサービスアーキテクチャ 「そもそもどうやってサービスに分割するか?」 ⼀般的なシチュエーションとしては、事業がスケールし、密結合が⾟く感じるようになってか ら、マイクロサービスへの移⾏を検討するようになる。 ただし、単に特定の機能をサービスに切り出しても、アーキテクチャ図上の⾒え⽅が変わるだけ で実態は変わるわけではない。  「サービスに切り出した」 => 「疎結合」  ではなく  「疎結合」 => 「サービスに切り出せる」

Slide 38

Slide 38 text

38 ©MIXI マイクロサービスアーキテクチャ 先ほどのアルバムアプリの例を再掲 この状態で単にUserを別のコードベースに切り出しても、当然`Album`周りで`Undefined Error`が 出まくるだけ。まずはAlbumクラスへの依存を解消してからでないと切り出せない。 依存の多いクラスは全ての依存を解消して初めて切り出せる。この作業だけでも⼤変。

Slide 39

Slide 39 text

39 ©MIXI マイクロサービスアーキテクチャ 加えて、⾒かけ上のエラーがなくなっても密結合が解消されるわけではない 本質的に疎結合を実現してからでないと以下のような状態に陥る可能性がある ● 切り出したサービスで、処理の途中で元のサービスのデータが必要になり、 何度もやり取りが発⽣する ● 切り出したのに、元のサービスの知識が必要 ● お互い共有ライブラリのロジックに依存している ● サービス間通信のインターフェースが曖昧で頻繁に変わる このように、せっかく切り出しても独⽴して開発できない状態になってしまう。

Slide 40

Slide 40 text

40 ©MIXI マイクロサービスの失敗 ここまで聞くと、マイクロサービス化はかなり難易度が⾼いことがわかる => 実際、マイクロサービス化 / サービス切り出しの失敗例は数多くある 失敗例 ● 組織の構造にあっていない ○ サービスごとに担当する⾃⽴したチームがいなければ、サービスだけ分かれていても効果が薄い ● 内部構造をそのままにサービスへの分割を⾏ってしまっている ○ 先ほども説明したように、モノリスに課題を感じているからといって、単にサービスに切り出すだ けでは問題は解決しない(それどころか悪化する可能性も) ● マイクロサービス化が⽬的になってしまっている ○ アーキテクチャはあくまで⾮機能要件を実現するための⼿段  失敗すると、頑張ってサービス分割してもメリットを享受できずにデメリットだけ追加される可能性も...  => しっかりとした⽬的と知識を持って進めることが⼤事。

Slide 41

Slide 41 text

41 ©MIXI ⼀旦休憩 質問あれば受け付けます。 質問終了後、トイレ休憩も挟みます。

Slide 42

Slide 42 text

42 ©MIXI 補⾜:サーガ ● マイクロサービスにおいて、複数サービスでデータを⼀貫性を持って更新するための⽅法 ● ⾮同期メッセージングによる⼀連の「ローカルトランザクション」と「補償トランザク ション」の組み合わせで整合性を維持する仕組み ○ 補償トランザクション:処理失敗時に、途中までコミットしてしまった操作を戻すト ランザクション処理 ● ACDのみ保証、Cは結果整合性のみ保証 ○ 「I(分離性)」はサポートしないので注意 コレオグラフィベースとオーケストレーションベースの2種類がある。

Slide 43

Slide 43 text

43 ©MIXI 補⾜:コレオグラフィベース サーガ XXX サービス API YYY サービス API ZZZ サービス API ABC サービス API それぞれで非同期にローカルトランザクションが実行される(結果整合)。 XXX サービス API YYY サービス API ZZZ サービス API ABC サービス API ここで処理が失敗 補償トランザクションのパブリッシュ 補償トランザクション 打ち消すための トランザクション実行 打ち消すための トランザクション実行 ● サーガの参加サービス⾃⾝が⾃律的に連携し合う ● 失敗した場合の補償トランザクションのリクエストも各サービスが担う

Slide 44

Slide 44 text

44 ©MIXI 補⾜:オーケストレーションベース サーガ XXX サービス API YYY サービス API ZZZ サービス API サーガ オーケストレーター ABC サービス ● サーガに参加する各サービスへの制御を中央集権的に担う ● リクエストや補償トランザクションの管理

Slide 45

Slide 45 text

©MIXI モノリス vs マイクロサービス??

Slide 46

Slide 46 text

46 ©MIXI モノリス vs マイクロサービス?? ここまで、モノリスとマイクロサービスという2つのアーキテクチャパターンの概要を 解説しました。 対⽐する事柄なのでよく⽐較されることもある ● 結局のところどっちの⽅が優れているのか? ● どちらを採⽤すれば良いか? モノリスは悪・善? マイクロサービスは悪・善? => 「モノリス vs マイクロサービス」という構図はそもそも間違い

Slide 47

Slide 47 text

47 ©MIXI モノリス vs マイクロサービス?? そもそもどちらか⼀⽅ではなく、基本的には共存することが多い。どちらも活かす。 スケールするプロダクト開発では、以下のような流れになるのが⼀般的。 ● 初期フェーズ: ○ まずは、⼩規模少⼈数で利点が多い”モノリス”で開発を始める ● 組織規模拡⼤後: ○ 必要に応じてマイクロサービスも検討するようになる ○ 分割する必要のあるものからサービスに切り出されていく このように、モノリスとマイクロサービスが共存している状態になるはず。 特定のアーキテクチャスタイルやデザインパターンを採⽤した からといって、全てそれに従わなければいけないわけではない。

Slide 48

Slide 48 text

48 ©MIXI モノリス vs マイクロサービス?? 課題感(その1): ● モノリス⾟いのでマイクロサービスにしたい。 ● でもサービス間のデータ整合性の問題が⽣じるのは厳しいかも。 対処法:  => データ整合性の重要度が低い部分だけ切り出せば良い ● ここでも、マイクロサービスアーキテクチャを採⽤したら何でもかんでも細かく サービスに切り出さなければいけないわけではない ● サービスに切り出してより⾟くなるのは本末転倒 ● 利点が⽋点を上回ると判断した部分だけサービスに切り出せば良い

Slide 49

Slide 49 text

49 ©MIXI モノリス vs マイクロサービス?? 課題感(その2): ● 他サービスのデータを参照したいが、毎回サービス間通信を挟むのは⾟い。 ● パフォーマンスや可⽤性に問題が⽣じてしまう。 対処法:  => データのコピーを持てば良い 他サービスの必要となるデータをあらかじめ⾃サービス内に同期しておき、そこを参照す るよう変更する。こうすることでサービス間通信が不要になる。 ※これ⾃体はマイクロサービスで⼀般的な設計パターン

Slide 50

Slide 50 text

50 ©MIXI モノリス vs マイクロサービス?? 課題感(その3): ● 他サービスのデータを同期するのも同期遅延による不整合が怖い。 ○ 例:注⽂管理サービスで在庫管理サービスのデータのコピーを同期しているが、同期 遅延で在庫管理サービス側のDB(正規)が空なのに注⽂受付してしまった。 対処法:  => Read権限のみ許可して直接他サービスのデータを参照すれば良い 他サービスのDBに依存するのでもちろん可⽤性の観点では低下するが、同期遅延の⽅が問題に なると判断すれば検討の価値がある。マイクロサービスだからといって必ずしもDBを分離する 必要はない。 ※ロジックまで密結合になりすぎないように注意

Slide 51

Slide 51 text

51 ©MIXI モノリス vs マイクロサービス?? 課題感(その4) ● マイクロサービスを⽬指すほどのモチベはないが、事業拡⼤に伴ってエンジニア を増やしても⽣産性が上がらないのは厳しい... 対処法:  => コード上の疎結合さえ実現できていれば、上記⽬的は達成できる可能性が⾼い  => モノリスでも可(モジュラーモノリス) エンジニアの増加に対する⽣産性向上の観点でいえば、サービスまで分けずとも、モ ジュール分割によって分担したり認知負荷の軽減ができれば⽣産性向上は⾒込める。 そこを優先して他の要件‧サービス切り出しのメリットは妥協するとか。 どこを達成したいか、どこを優先するかという考え⽅が⼤事。

Slide 52

Slide 52 text

52 ©MIXI モノリス vs マイクロサービス?? ここまでまとめ: ● ここまで話したように、モノリス/マイクロと⾔ってもやり⽅は⾊々あり、どっちが良 い悪いではなく、トレードオフであり、適宜使い分けるものです。 ● 特定のアーキテクチャスタイルやデザインパターンを採⽤するからといって、定義通 りに作る必要はなく、全ての箇所で従わなければいけないわけでもありません。 ○ => そこを⽬指すと⼿段が⽬的化してしまう ● アーキテクチャはあくまで⼿段であり、⾃分たちのチームの課題がどこにあって、何 を解決したいかが重要です。 ○ 解決するための⼿段をみて、それを実⾏する利点が⽋点を上回れば実⾏すれば良い

Slide 53

Slide 53 text

53 ©MIXI (再掲)⽬次 ● ソフトウェアアーキテクチャとは ● アーキテクチャを学ぶ必要性 ● モノリシックアーキテクチャ ● マイクロサービスアーキテクチャ ● モノリス vs マイクロサービス?? <= ここまで終了 ● 疎結合を実現するための⽅法論の紹介 ● ドメイン駆動設計(DDD)の解説 ● DDD実践演習 質問あれば受け付けます。

Slide 54

Slide 54 text

54 ©MIXI 補⾜:マイクロサービスを検討する場⾯ モジュラーモノリスでも⼗分という話もしたが、例えば以下の場⾯など。他にもあるかも。 ● 機械学習モデルを動かすモジュールなど、リソース要件が⼤きく異なるもの ○ 元々ステートレスな処理でありサービスへの切り出しも容易 ● 技術スタックを新しくしたい場合 ○ 例:Perlで作られた古いシステムに新しい機能を追加したいが、現在ではPerlのエンジニア は市場にほとんどいない。 ○ => このような場合は致命的であるのである程度デメリットを許容してでも、別サービスとし て切り出し、既存の技術スタックに縛られずに作る⽅が良いかも ● 横展開する汎⽤的なシステムを作る場合 ○ 例えば、あるプロダクトにポイント機能を追加したいとして、社内の他のプロダクトにも同 様にポイント機能を提供する可能性がある場合、独⽴して動くサービスとして開発しておく と使いまわせて良いかも? ● 外注する場合など。別組織なので独⽴して開発できるものを任せられると効率的

Slide 55

Slide 55 text

©MIXI 疎結合を実現するための⽅法論

Slide 56

Slide 56 text

56 ©MIXI 設計に関する各種⽅法論 ここから、具体的に疎結合を実現するための⽅法について解説していきます。 本当に多くのものが提唱されてるので、その内⼀部を独断と偏⾒で以下に整理してみます。 カテゴリ 具体例 主な目的や役割 アーキテクチャスタイル クリーンアーキテクチャ, オニオン アーキテクチャ, マイクロサービス, モ ノリス ソフトウェア全体の構造・依存関係の流れ、分 割の方針を決める 設計思想・アプローチ オブジェクト指向, ドメイン駆動設計 (DDD), CQRS 設計や実装、分割に関する思想・指針。人間が 理解しやすい実装への指針。 設計原則 SOLID原則, DRY, YAGNI クラス・モジュールの内部構造や依存のあり方 に関するもの 設計指標 モジュール結合度, モジュール強度 (凝集度), LCOM 設計の品質を評価する軸、設計改善の指針に なる 設計パターン Repository, Factory, Saga, Entity 具体的な実装方法についてのテンプレート

Slide 57

Slide 57 text

57 ©MIXI モジュール強度(凝集度)‧結合度 良い設計かどうかを判断する基本的な指標。⾼強度‧疎結合が⼀般的に良い設計とされる。

Slide 58

Slide 58 text

58 ©MIXI SOLID原則 オブジェクト指向の⽂脈で良く出てくる。変更に強く、拡張しやすく、理解しやすいソフトウェ アを作るためのガイド。

Slide 59

Slide 59 text

59 ©MIXI 設計の⽅法論に関する注意点 これらの考え⽅を参考にするだけでも良い設計に近づける。ただし以下に注意。 ● これらの指標や原則に従うことを⽬的化するべきではない ○ 全てのモジュール強度最強‧結合度最弱にすることが必ずしも良いわけではない ○ 必要以上にやりすぎてしまうとかえって書きづらく、読みづらくなり本末転倒 ● 設計の⽅法論はパターンやテンプレートとして使うべきではない ○ 重要なのは⽂脈、背景、⽬的(これを知った上で使うと効果的) ○ パターンにとらわれるとやりすぎという状態に陥ってしまいがち ■ マイクロサービスで例えると、必要以上にサービスに切り出してしまっている状態 ● 単にこれに従うだけでは良い疎結合が達成できるわけではない ○ そもそも「単⼀機能‧責務」とは何?どれくらいの範囲か? ○ これだけだとどういうまとまりで開発を分担すれば良いか分からない => まずは全体の構造やモジュール分割の⼤⽅針が必要。

Slide 60

Slide 60 text

60 ©MIXI アーキテクチャスタイル 有名なものとしては、「レイヤードアーキテクチャ」、「オニオンアーキテクチャ」、「クリー ンアーキテクチャ」、「ヘキサゴナルアーキテクチャ」の4つが挙げられる(以下、⼀部解 説)。 ● Domain(ビジネスロジック)から Infra層への依存を排除。 ● => Domain層が純粋なビジネス ロジックに集中できる ● Domain層にInfra層のインター フェースを定義し、Application層 からはそこに依存させる(依存関 係逆転の法則)。

Slide 61

Slide 61 text

61 ©MIXI オブジェクト指向 データ構造とそのデータに対する操作(振る舞い)を⼀つのまとまりとして扱い、それらの関係 からシステムを構築する⽅法論。 ある役割(機能)を持った”モノ”ごとにクラスを分割するという、モジュール分割に関する指針 の側⾯も。 => ⼈間が理解しやすい分割の概念が⼊る 概念 説明 クラス オブジェクトの「設計図」に値するもの。プロパティ(属性)とメソッド(振る舞 い)を定義。 オブジェクト クラスから生成された「実体」。状態と振る舞いを持つ。 カプセル化 データと振る舞いを一つのクラスにまとめ、内部を隠蔽する。 継承 既存のクラスを元にして、共通処理を再利用・拡張できる。 ポリモーフィズム 同じインターフェースで異なる振る舞いを実現する。差し替え可能。

Slide 62

Slide 62 text

62 ©MIXI ドメイン駆動設計(DDD) ソフトウェアが解決すべき問題領域(=ドメイン)を中⼼に据えて、ソフトウェアを設計‧実装 する⽅法論。 オブジェクト指向の最終到達点と⾔われることもある。 DDDにおいては、「オブジェクト(モノ)」ではなく「ドメイン(ユビキタス⾔語)」に抽象化 することで、現実世界のモデリングとソフトウェアへの落とし込みを⽬指している。 どちらの概念もコードに意味を伝えさせる⽅法論。 ● ドメイン(特定の業務領域‧問題領域)の例 ○ ECなら「注⽂‧⽀払い‧配送」 ○ 銀⾏なら「⼝座‧取引‧残⾼」 ○ SNSなら「投稿‧フォロー‧通知」

Slide 63

Slide 63 text

63 ©MIXI 設計パターン適⽤の失敗例 ここまで話した設計概念を”なんとなく取り⼊れる”だと失敗する。 ● DRY(Don’t repeat yourself)やりすぎて逆に⾟い ○ 重複を減らすためといって、なんでもかんでも共通化するべきというわけではない ● 機能的強度を⽬指して、機能を細分化しすぎてしまい逆にコードを把握しづらい ○ SNSの例:「フォローリクエストできる」「フォローリクエストを承認できる」を別 機能として別クラスで実装する? ○ やりすぎると、ファイルやクラスが別れすぎて逆にコード追いづらいことも ○ ⼈間が把握しやすいことが⼤事なので、その意図であえて下げる判断も⼤事 ● 何らかのアーキテクチャスタイル採⽤しているのにドメイン層に知識が全くない ○ データを持つクラスが定義されているだけ => ドメインモデル貧⾎症 ○ ドメインルール、ビジネスロジックがドメイン層に集約させるべき => しっかりとした⽬的と設計概念への理解が重要

Slide 64

Slide 64 text

64 ©MIXI ここまでまとめ(前半) ● これらのように、設計に関する⽅法論は数多く提唱されています。先駆者たちの これまでの研鑽が反映された指針として、⾮常に参考になるので、興味あると 思った部分はもっと深ぼって学んでみてください ● ⼀⽅で、あくまで⽅法論の⼀つであり、それに従うことを⽬的にするべきでは ありません。⽬的はあくまで⾮機能要件であるべきです。 ● ほとんどの⾮機能要件の実現は、疎結合化によって達成できます ○ ただし、必要な疎結合のレベルは⽬的の⾮機能要件によって変わる ○ 加えて、「どこをどのレベルの疎結合にするべきか」は各々の開発チームごとに 異なるという認識が重要 ○ ⽣産性向上のためには、⼈間にとって意味のあるまとまりを持った疎結合が⼤事

Slide 65

Slide 65 text

65 ©MIXI (再掲)⽬次 ● ソフトウェアアーキテクチャとは ● アーキテクチャを学ぶ必要性 ● モノリシックアーキテクチャ ● マイクロサービスアーキテクチャ ● モノリス vs マイクロサービス?? ● 疎結合を実現するための⽅法論の紹介 <= ここまで終了 ● ドメイン駆動設計(DDD)の解説 ● DDD実践演習 質問あれば受け付けます。その後休憩に⼊ります。

Slide 66

Slide 66 text

©MIXI 演習問題

Slide 67

Slide 67 text

67 ©MIXI 演習問題 ここまでの内容を振り返るために、アーキテクチャに関するケーススタディ的な例題 をいくつか出してみます。 扱うテーマ的に、明確に回答があるわけではないですが、少し時間を取るので考えて みてください。

Slide 68

Slide 68 text

68 ©MIXI 演習問題1 問:あなたは密結合しているシステムのマイクロサービス化に着⼿しようとしています。 「システムのコアとなる機能やロジックが集約された”巨⼤クラス(密結合)”」から、「あまり 使われておらず他との依存が少ない⼩規模なクラス」まで様々な機能やクラスが存在します。 ここで、どちらのクラス‧機能からサービスの切り出しに取りかかるべきでしょうか?

Slide 69

Slide 69 text

69 ©MIXI 演習問題1 問:あなたは密結合しているシステムのマイクロサービス化に着⼿しようとしています。 「システムのコアとなる機能やロジックが集約された”巨⼤クラス(密結合)”」から、「あまり 使われておらず他との依存が少ない⼩規模なクラス」まで様々な機能やクラスが存在します。 ここで、どちらのクラス‧機能からサービスの切り出しに取りかかるべきでしょうか? 回答例: ● ⼩さく依存の少ないクラス(すでに疎結合) ○ 切り出しやすい。ただし、更新頻度が少ないためそもそも開発効率を上げる意味がない ○ 第⼀歩としての成功事例を作るためならあり ● あらゆる機能改修に関わってくる巨⼤クラス(ゴッドクラス) ○ 今後の開発の効率化に繋がり、切り出す効果は⾼い ○ ただし、依存先が多いため、疎結合化するにも全体の把握と多くの調整が必要

Slide 70

Slide 70 text

70 ©MIXI 演習問題2 問い:あなたはある会社から新規サービスの開発案件を受注しました。 その会社では、エンジニアが⾜りないのでひとまず外注して開発を進めたいということだった が、納品後の機能改修やメンテナンスは⾃社内で継続的に⾏うということだった。 あなたは技術⼒に⾃信があったので、納品先での今後の開発効率やサービスのスケールまで考慮 し、マイクロサービスアーキテクチャを採⽤した。この判断は正しいでしょうか?

Slide 71

Slide 71 text

71 ©MIXI 演習問題2 問い:あなたはある会社から新規サービスの開発案件を受注しました。 その会社では、エンジニアが⾜りないのでひとまず外注して開発を進めたいということだった が、納品後の機能改修やメンテナンスは⾃社内で継続的に⾏うということだった。 あなたは技術⼒に⾃信があったので、納品先での今後の開発効率やサービスのスケールまで考慮 し、マイクロサービスアーキテクチャを採⽤した。この判断は正しいでしょうか? 回答例: 例えば納品先が基本エンジニア⼀⼈体制ならオーバースペック。 また、納品先でマイクロサービスに関する知⾒が無ければむしろ負債化するリスクもある。 サービスまで切り出さずとも、モノリスで内部が疎結合であれば⼗分な場合も多い。 その辺りの背景を汲み取った上で判断が必要。

Slide 72

Slide 72 text

72 ©MIXI 演習問題3 問:あなたの開発チームでは出前サービスを開発しています。 ここで、競合サービスを作っている他社のエンジニアから、出前サービスでは「注⽂管理」、 「配達」、「決済」で、ロジックを明確に分けて考えることが可能なのに、このシステムでは密 結合になっているためリファクタが必要と指摘されました。どうするべきでしょうか?

Slide 73

Slide 73 text

73 ©MIXI 演習問題3 問:あなたの開発チームでは出前サービスを開発しています。 ここで、競合サービスを作っている他社のエンジニアから、出前サービスでは「注⽂管理」、 「配達」、「決済」で、ロジックを明確に分けて考えることが可能なのに、このシステムでは密 結合になっているためリファクタが必要と指摘されました。どうするべきでしょうか? 回答例: 競合他社と事情(組織構成‧技術スタックなど)が同じとは限らないため、⾃社でも分割が最適 とは限らない。 例えばその競合他社とは類似していても強みとする機能が異なる場合、機能改修や更新頻度は変 わることになる。開発頻度が低いモジュールをあえて分割しても効果は薄い。 補⾜:外部の⼈から「このソフトウェアは密結合だ」と⾔われても、内部の⼈達が問題に感じて いないならその組織にとっては必要⼗分。あくまで開発を担当するチーム内で基準を持つべき。

Slide 74

Slide 74 text

74 ©MIXI 演習問題4 問:SNSなどで、AI〇〇アプリ(もしくは機能)がバズっており、⼀定規模の市場が望めること がわかった。あなたは同じようなアイデアを持っていたため、⾃⾝でもアプリ(もしくは機能) の開発をすることを考えた。この時、どのような設計を考えるべきでしょうか?

Slide 75

Slide 75 text

75 ©MIXI 演習問題4 問:SNSなどで、AI〇〇アプリ(もしくは機能)がバズっており、⼀定規模の市場が望めること がわかった。あなたは同じようなアイデアを持っていたため、⾃⾝でもアプリ(もしくは機能) の開発をすることを考えた。この時、どのような設計を考えるべきでしょうか? 回答例: 機能要件だけでも実装し、とにかく早くリリースすることを優先するのもあり。 トレンド的なものだと、競合も同じように考えやすいので、速さが正義になる可能性も。 この場合は、設計とか考えている場合ではなく、ビジネスチャンスを逃さないためにもとにかく 先にリリースしたい。 密結合 = 絶対悪ではない。速度を優先させるために意図して選択することもありうる。 ※注意:密結合の⽅が早いかどうかは状況による

Slide 76

Slide 76 text

76 ©MIXI (再掲)⽬次 ● ソフトウェアアーキテクチャとは ● アーキテクチャを学ぶ必要性 ● モノリシックアーキテクチャ ● マイクロサービスアーキテクチャ ● モノリス vs マイクロサービス?? ● 疎結合を実現するための⽅法論の紹介 ● ドメイン駆動設計(DDD)の解説 ● DDD実践演習 ⼀旦休憩を挟みます。

Slide 77

Slide 77 text

©MIXI 疎結合を実現するための⽅法論 ドメイン駆動設計(DDD)の紹介

Slide 78

Slide 78 text

78 ©MIXI ドメイン駆動設計の背景 ● ここまで話してきたように、ソフトウェア開発は複雑で⾊々な問題を抱える。 ● ドメイン(業務領域‧問題領域)⾃体が本質的に複雑であることが要因の⼀つ。 ○ ⼈間の⾏う⼊り組んだ業務や活動をプログラムに落とし込む作業なので、当然と⾔え ば当然。 ● 何もしないとソフトウェアはどんどん密結合し複雑になっていってしまう。 ○ ビジネスルールがコードのいたるところに散在してしまう ● そこからさらに複雑なドメインが現れたら、⼿も⾜も出せなくなる。 ○ ※例えば、AI等による技術⾰新で業務フローやユーザ⾏動に重⼤な変化が起きたとし ても、そのレベルの変更をソフトウェアに反映させるのは不可能になっているかもし れない => 次から次に機能を満たすコードを作成するだけでなく、「ドメインに対する理解」と「モデ リング」にしっかりと取り組むことが重要

Slide 79

Slide 79 text

79 ©MIXI ドメイン駆動設計の⽤語集 ● ドメイン(Domain) ○ システムが解決しようとする業務領域‧問題領域のこと ○ 例:ECサイト(注⽂管理‧在庫管理)、SNS(投稿、フォロー、リアクション)など ● ドメインエキスパート ○ その業務の専⾨家 ■ 医療システムであれば医者、看護師、医療事務 ○ ⼀般ユーザ向けアプリであれば、ユーザの⾏動や背景を深く理解している⼈ ■ PO、PMなど ● ユビキタス⾔語 ○ 開発者とドメインエキスパートなどの参画者が共通して使う⾔葉 ■ コミュニケーションにおける⾔語の認識のズレが起きるのを防ぐ ○ モデル、クラス名、関数名など、コード上でもそのままその⾔語が使われる ※toBの業務システムとtoCのビジネスで若⼲解釈に違いはある。今回は主にtoC向けに解説。

Slide 80

Slide 80 text

80 ©MIXI ドメイン駆動設計の概要 (その名の通り) ドメインを深く理解し、それを中⼼にシステムを組み⽴てる設計思想。 ※開発プロセスやコミュニケーション等にまで踏み込んだ思想であるが今回は省略。 DDDを取り⼊れることにより、ソフトウェアは以下のように変わる ● ドメインモデルに責務が集中する ○ プログラムで動作するドメインのルールや振る舞いが全て書かれている ○ => つまり、コードがドキュメントになる(常に最新版を担保) ● ドメインモデルによるモジュール分割 ○ 変更に強く、意味のある単位での疎結合化

Slide 81

Slide 81 text

81 ©MIXI 基本的な流れ ● ドメインモデリング ● 実装 ● レビュー‧ドメインの理解 これを繰り返していくことで、ドメイン モデルが洗練されていく。 ※今回は省略してますが、このサイクル ⾃体もDDDにおいてはかなり重要な側⾯ を持ちます。 ドメイン駆動設計の流れ ドメイン モデリング レビュー・ ドメインの理解 実装 イテレーション

Slide 82

Slide 82 text

82 ©MIXI ドメインモデリング ドメインエキスパートの中にある知識を、必要な性質を取捨選択して抽象化し、ソフ トウェアで扱えるようにするための作業(設計にあたる)。 モデリングの流れの例 ● ドメインエキスパートと対話し、ドメインについて理解を深める ○ どういった概念‧ルール‧関係があるのかを整理する ● 名詞や動詞に注⽬しながら⽤語を洗い出す(ユビキタス⾔語) ● UMLなどでモデルと関係を整理する ● モデルをドメインオブジェクトと対応づける ○ ドメインオブジェクト:モデルをソフトウェアで動作するモジュールとして表現 オブジェクトには、振る舞いと守るべきルールがある。単なるデータスキーマではな く、ドメインモデルにそういった知識を反映させていくことが重要。 なんとなくクラスを定義 するのではなく、こういっ たモデリングをしっかり やろうというのが DDDで す。

Slide 83

Slide 83 text

83 ©MIXI ドメインモデリング 先ほどのアルバムサンプリアプリをモデリングした例(UML) 左:ユースケース図、右:ドメインモデル図 ※今回はシンプルすぎるので図にする必要もないが、複雑な例では図が役に⽴つこともある これで実装に進めるフェーズに。

Slide 84

Slide 84 text

84 ©MIXI DDDの実装 ドメインモデリングが完了したら、それを元に実装することになります。当然です が、モデリングした結果と実装が乖離してしまっては意味がないので、正しくコード に落とし込む必要があります。 DDDでは、ドメインモデルを実装に落とし込み、システムを構築するための設計パ ターンも提唱されています。重要な概念を紹介していきます。

Slide 85

Slide 85 text

85 ©MIXI ドメイン駆動設計のパターン(構成要素) ドメインの知識を表現するための構成要素 エンティティ 値オブジェクト 集約 ドメイン サービス 仕様 アプリケーションを実現するための構成要素 アプリケーション サービス リポジトリ ファクトリ 利用して 組み立てる ● モデリングした知識を⼀箇所に集中させる ● それを活⽤してアプリケーションを組み⽴てる

Slide 86

Slide 86 text

86 ©MIXI 値オブジェクト(Value Object) ライフサイクルのないオブジェクト。値に関する知識を表現する。 ● こういった何らかのルールがあるものは、プログラミング⾔語のプリミティブ型(Int, Float, Stringなど)ではなく、独⾃の型として定義して知識を組み込むのが良い ● 必要に応じて、振る舞い(メソッド)を定義することもある 値オブジェクトの例 ルール 住所 都道府県・市区町村・番地など 名前 姓と名から成る メールアドレス 特定のフォーマットがある 座標 (x, y)の数値の組み合わせで表現される

Slide 87

Slide 87 text

87 ©MIXI 値オブジェクト(Value Object) アルバムアプリのコード例(再掲): ● follower_scopeに関するバリデーションを利⽤側で書いている。 ● 他にもアクセスする関数‧メソッドがあればその都度バリデーションの記述が必要。 ● Albumクラスを⾒ても、follower_scopeに関するルールが書かれていない

Slide 88

Slide 88 text

88 ©MIXI 値オブジェクト(Value Object) 修正コード例(擬似コード): ※便宜上Go⾔語に変わってます。 ● FollowerScope型を定義し、コンストラクタにルール(バリデーション)を記述 ○ FollowerScopeのインスタンスが存在している時点でバリデーション通っていることが保証される ため、他の場所でバリデーションする必要がなくなる(※Goの場合は紳⼠協定が必要) ● このように、値オブジェクトに意味‧ルールを持たせた⽅が⼀箇所にまとまり、把握しやすい

Slide 89

Slide 89 text

89 ©MIXI エンティティ(Entity) ライフサイクルのあるオブジェクト。⼀意に識別するためのIDを持つ。 状態の変化を得ても、IDにより同⼀性が判断される。 エンティティでは、ルールに加えてこういった振る舞いを定義することが多い。 エンティティの例 ライフサイクル ユーザー アカウント登録し、退会までシステムに存在し続ける。 注文 リクエストを受けてから生成され、 ”ステータス=完了”までの状 態変化がある。 商品 登録後、価格や在庫の変動などの状態変化がある。取扱い 対象商品から除外されて役目を終える。

Slide 90

Slide 90 text

90 ©MIXI エンティティ(Entity) 先ほどのUserクラス、Albumクラスに識別⼦(ID)を追加すれば、エンティティに該当する。 ただし、UserクラスにAlbumクラスの振る舞いが書かれてしまっていたので直す。 ChangeScopeは、アル バムの属性に対する変更 操作なのでここに移動 仕様の⾃然⾔語で書かれた通りではなく、どのドメインモデルに対する操作‧振る舞いかとい うことを意識してメソッドを定義することが⼤事。 ※UserクラスにはUserモデルに関する振る舞いを書く

Slide 91

Slide 91 text

91 ©MIXI 集約(Aggregate) ⼀貫性を保つべきエンティティや値オブジェクトをひとまとめにしたもの。 ● 集約パターンにおける実装上の制約 ○ 集約ルート(Aggregate Root)を外部とのやりとりの唯⼀の窓⼝とする ■ 内部のオブジェクトには直接外からアクセスさせない ○ 他の集約のオブジェクトを直接参照することを禁⽌(IDのみ許可) ■ 先ほどの例だと、UserクラスがAlbumクラスのコレクションを保持している が、これを禁⽌する ● => 集約を境界としてモジュール分割される(疎結合化)

Slide 92

Slide 92 text

92 ©MIXI 集約(Aggregate) 修正コード例: ● Album、Userそれぞれを集約ルートとして捉え、Id以外の変数を⾮公開に ● 便宜上、それぞれのクラスのID型を作成 ● Album、Userそれぞれで、互いのIdのみ保持するよう変更 ● => ここまでいけば、Userクラス開発担当者はAlbumクラスに関する知識が不要になる

Slide 93

Slide 93 text

93 ©MIXI その他 ● ドメインサービス(Domain Service) ○ エンティティや値オブジェクトに属さないドメイン知識に関するロジック(関数)を表現 ○ ※例えば、存在確認‧重複確認のメソッド(Exists)は、エンティティ⾃⾝の振る舞いとし て定義するのは違和感であるため、ドメインサービスとして実装する。 ● リポジトリ(Repository) ○ データの永続化や読み込みのためのインターフェース ○ DDDにおいては「集約」を保存‧取得する役割 ○ そのため集約単位で設計するのが基本 ● ファクトリ(Factory) ○ 複雑なドメインオブジェクトの⽣成処理をカプセル化するための要素 ○ コンストラクタで記述するのでは重すぎる⽣成処理の場合はファクトリを使う ● 仕様(Specification) ○ 複雑なドメインオブジェクトのバリデーションルールをカプセル化するための要素

Slide 94

Slide 94 text

94 ©MIXI ドメインモデルを隔離するための⽅法 アーキテクチャスタイルを採⽤し、全体の構造と依存の⽅向を整理する => ここではオニオンアーキテクチャを採⽤(Domain層からInfra層への依存を無くせるため) ● Domain層 ○ ドメインオブジェクトを実装 ○ ドメイン知識がこの層に集中する ○ リポジトリのインターフェースもここで定義 ● Application層 ○ ドメインオブジェクトとInfra層(DIP)を 活⽤し、ユースケースを組み⽴てる ● Infrastructure層 ○ ドメインオブジェクトの永続化‧取得を担う ■ I/O両⽅ドメインオブジェクト(DAO返さないよう注意) ○ リポジトリ、ファクトリなどの実装がある

Slide 95

Slide 95 text

95 ©MIXI オニオンアーキテクチャ どうやってコード上でオニオンアーキテクチャを実現するか?(Go⾔語の例) サンプルリポジトリ: => https://github.com/tonouchi510/golang-ddd-layout Go⾔語の特徴 ● パッケージ単位のアクセス制御⽅式 ○ パッケージ外部では public のみアクセス可能で、パッケージ内部では他オブジェクト の private 変数‧メソッドにもアクセスできる => 集約の実装にも適している ○ 各レイヤ(層)をパッケージで分けることで、他の層から内部データにアクセス不可 能にできる ● 静的型付け⾔語である ● => 設計上のルールを、紳⼠協定でなく、コード(仕組み)で担保できる

Slide 96

Slide 96 text

96 ©MIXI オニオンアーキテクチャ こういったアーキテクチャスタイルを採⽤した時には、各レイヤ(層)をまたぐ際に、データを 別のオブジェクトに詰め直す処理がある。 ● リポジトリ(インフラ層) ○ 内部では使⽤するORMライブラリのデータ構造を扱うことになるが、返却時はドメインオブ ジェクトに詰め直す => 他の層でDB操作をさせないため ○ ⼊⼒もドメインオブジェクトにすることで保存前のバリデーションが不要に ● アプリケーション層 ○ 内部ではドメインオブジェクトを触っても良いが、上位層に返却する時にはDTO(ロジック を持たない構造体)に詰め直す必要がある ○ 意図しない場⾯でドメインオブジェクトに対する操作が⾏われないため ⾯倒な部分で敬遠されがちだが、紳⼠協定でなく仕組みで防ぐために重要なこと。 今ならAIがほぼ⾃動⽣成してくれるはず。

Slide 97

Slide 97 text

97 ©MIXI オニオンアーキテクチャ オニオンアーキテクチャを利⽤することで得られる利点を以下に整理します。 ● 依存が整理される、各層の責務も明確になる ○ どんなユースケースがあるか知りたければアプリ ケーション層を、どんなドメインモデルが存在し てどういうルールや振る舞いがあるのか知りたけ ればドメイン層を⾒れば良い ○ 実装の際にも、どこに実装すれば良いかを迷わず に済むようになる ● ドメイン層が⼀番下でどこからも依存しない ○ インフラ層への依存も取り除かれるため、純粋な ドメインモデルの実装に集中できる ○ ドメインモデルのテストも容易になる

Slide 98

Slide 98 text

98 ©MIXI ドメインモデルで逆に困る場⾯ Userデータの取得に関するユースケースを考える。 ここで、参加アルバムのIDだけ取得しても表⽰に困るので、”JoinedAlbumIds”ごとに Albumデータも取得する。 => N+1問題 ● DBに保存されているデータを取り出して返すだけなので、本来ドメインモデルの操作 も、バリデーションも必要ない ● ドメインモデルを経由していたら⾮効率 ● => ドメイン層をスキップすれば良い(CQRS) (何度も話しているが)DDDを採⽤したからといって、全てDDDの原則に従わなければい けないわけではない。必要に応じてドメイン層はスキップしても良い。

Slide 99

Slide 99 text

99 ©MIXI CQRS Command Query Responsibility Segregation(CQRS)とは ● Command(更新系の処理)とQuery(参照系の処理)で責務を分離するパターン ○ Command:複雑なビジネスロジックが絡み、整合性などの要件がある ○ Query:パフォーマンス含め、更新系と異なる要件がある ■ パフォーマンス、ページング、並べ替えなど ■ 参照のみなのでドメインモデルの操作やバリデーションは本来不要 ○ => Queryはドメインモデル介さずに実装する 補⾜:CQRSパターン採⽤する⽅はHasuraおすすめしときます。 ● Query系APIは⾃動⽣成(ただしGraphQLに限る) ● ⼈間はCommand系の実装に集中できる ● 興味あれば調べてみてください

Slide 100

Slide 100 text

100 ©MIXI DDDも銀の弾丸ではない ● DDDに限らず、設計の理論やパターンを学ぶと⼤きな期待感を抱いてもらえるかも。 ● ⼀⽅で、実際のプロジェクトでやろうとするとひどい現実が降りかかってくることも ○ 組織上の問題もあれば、技術的な問題も ■ 技術への適合、時間の制約、ドメインに対する理解不⾜などで諦めが必要な場⾯も ○ 指針が⽰されているとはいえ、どう実装するか悩む場⾯もまだ出てくるはず ■ どこの層、どのオブジェクトが適切か?など ○ => 経験も必要になってくる部分 ● 結局リファクタリングは必要 ○ 最初にしっかりドメインモデリングしてから実装するとはいえ、最初から完璧なドメ インモデルを得られることはほぼない。ドメインに対しては継続的な学習が必要。 ○ ドメインモデルは開発のサイクルを通じて洗練させていくもの 銀の弾丸ではないが、設計やリファクタにおける⼤きな指針として活⽤してください。

Slide 101

Slide 101 text

101 ©MIXI ドメイン駆動設計 まとめ 少なくとも、今回話した内容を取り⼊れることで、機能要件のみを満たすコードを作成するだけ のコードよりも、はるかに意味を伝えてくれて、可読性の⾼いコードになると思います。 ※左と右、どちらの書き⽅が読みやすいですか?

Slide 102

Slide 102 text

102 ©MIXI (再掲)⽬次 ● ソフトウェアアーキテクチャとは ● アーキテクチャを学ぶ必要性 ● モノリシックアーキテクチャ ● マイクロサービスアーキテクチャ ● モノリス vs マイクロサービス?? ● 疎結合を実現するための⽅法論の紹介 ● ドメイン駆動設計(DDD)の解説 <= ここまで終了 ● DDD実践演習 質問あれば受け付けます。その後休憩に⼊ります。

Slide 103

Slide 103 text

©MIXI DDD実践演習

Slide 104

Slide 104 text

104 ©MIXI 「家族アルバム みてね」のドメインモデリングをしてみよう ここまでの内容をもとに、DDDを実践してみましょう! 「家族アルバム みてね」を題材としてみます。 周りの⼈と議論しながら考えてみてください。

Slide 105

Slide 105 text

105 ©MIXI 1. ドメイン(業務領域‧問題領域)の理解をする ドメインエキスパートとの対話であったり、書籍や⽂献、ネットなどから情報を集め るのが⼀般的な⽅法。 今回はリリース済みのアプリであり、公式サイトがあるのでそこから学ぶ。 => https://mitene.us/

Slide 106

Slide 106 text

106 ©MIXI 2. ユースケースを洗い出す このアプリでユーザは何ができるのかというところを列挙してみる。 何度も出てくる単語‧概念があったり、⾔語化してみることで様々な気づきがあるこ ともあります。

Slide 107

Slide 107 text

107 ©MIXI 3. ユビキタス⾔語による統⼀‧整理 議論におけるコミュニケーションエラーを減らすために、この段階でユビキタス⾔語 を定義しておくと良い。 ユースケースの洗い出しで出てきた単語や概念を整理し、⽤語を統⼀する。 めんどくさいので省いちゃいがちだが、今だと議事録からAIがドキュメント化してく れるかも?

Slide 108

Slide 108 text

108 ©MIXI 4. モデリングの対象を決める いきなり全てのモデリングを⾏うのは⼤変。対象を絞ってから⾏う。 スモールから始めるのもありだが、基本的に事業において最も重要なコアドメインを 中⼼にモデリングを⾏うのが効果が⾼い。 ここでも、まずコアドメインを⾒つけてみることとする。 ここまで議論した中で最も頻出した単語‧概念がコアドメインである可能性が⾼い。

Slide 109

Slide 109 text

109 ©MIXI 5. UMLの作成 前ステップで決めたコアドメインに対して、モデリングを⾏う。 モデルにどういう情報が必要か?他のモデルとどういう関係があるか?などの観点で 整理し、UMLを作成する。集約(モジュール境界)も意識しながら設計すると良い。 UMLではモデルの持つデータや関係、振る舞いなどは表現できるが、モデルの持つ ルールは別途記述しておく。 ※補⾜: ドメインモデルはDBスキーマとは異なる。必要なデータを考える際、エンジニアだとついDBの ことを意識してしまいがちだが、ドメインモデリングは出来るだけ現実世界を反映させるように ⼼がける。

Slide 110

Slide 110 text

110 ©MIXI 6. コードに落とし込む ● 解説したDDDの実装パターンを活⽤し、ドメインモデルを実装する ● それを使って、最初に列挙したユースケースを組み⽴てていく 興味がある⼈は取り組んでみてください。

Slide 111

Slide 111 text

111 ©MIXI まとめ ⾊々と幅広く解説しましたが、本研修では以下を持ち帰ってもらえると幸いです。 ● スケールするプロダクト開発におけるアーキテクチャや設計の重要性 ● 設計の⽅法論に対する向き合い⽅(何のためにやるかの⽬的が⼤事) ※特に今回の講義では⽣産性の観点からこれらを述べました また、今回話した各テーマについては、本研修ではあくまで概要を触れただけなの で、より深く知りたいと思った⽅は書籍などで体系的に学んでみてください。とにか く議論したり実践することで学べることも多いと思います。 各部署に配属後、既存機能のリファクタや、新機能開発の設計の際の指針として役⽴ ててもらえると幸いです。

Slide 112

Slide 112 text

112 ©MIXI