「関心の分離」と「疎結合」 - ソフトウェアアーキテクチャのひとかけら

18.4K Views

April 01, 23

スライド概要

profile-image

「持続可能なソフトウェア」の探求がライフワーク。C#、.NET、WPFあたりが住処。Microsoft MVP for Development Technologies(2017/01〜)。

シェア

またはPlayer版

埋め込む »CMSなどでJSが使えない場合

関連スライド

各ページのテキスト
1.

「関心の分離」と「疎結合」 ソフトウェアアーキテクチャのひとかけら Atsushi Nakamura

2.

About Me 中村 充志 / Atsushi Nakamura • • • • リコージャパン株式会社 金融事業部所属 Enterprise系のITアーキテクト JavaからC#へ渡り歩く 趣味はXamarin • Blog http://www.nuits.jp • Blog(英語)https://blog.nuits.jp • Twitter @nuits_jp Copyright 2017 @nuits_jp

3.

「関心の分離」と「疎結合」 Today’s Goal

4.

Today’s Goal 1. ソフトウェア アーキテクチャの概略を理解いただく 2. 特に理解いただきたいこと 1. 関心(関心事)の分離 2. カプセル化 3. 密結合と疎結合 4. 疎結合を実現する代表的な手段 Xamarin.Forms Navigation Overview Slide 4

5.

「関心の分離」と「疎結合」 アーキテクトとは?

6.

アーキテクトとはなにか? class Class Model IT アーキテクチャ ≒ システム アーキテクチャ アプリケーション アーキテクチャ (≒ソフトウェア アーキテクチャ) 設計・構築する インフラストラクチャ アーキテクチャ ITアーキテクト インテグレーション アーキテクチャ Copyright 2017 @nuits_jp Slide 6

7.

アーキテクトとはなにか? class Class Model IT アーキテクチャ ≒ システム アーキテクチャ アプリケーション アーキテクチャ (≒ソフトウェア アーキテクチャ) 設計・構築する インフラストラクチャ アーキテクチャ ITアーキテクト インテグレーション アーキテクチャ Copyright 2017 @nuits_jp Slide 7

8.

「関心の分離」と「疎結合」 ソフトウェア アーキテクチャといえば何を思い浮かべますか? Copyright 2017 @nuits_jp

9.

ソフトウェア アーキテクチャといえば何を思い浮かべますか? 1. MVC 2. MVP 3. MVVM 4. MVPVM 5. クリーン アーキテクチャ 6. レイヤー アーキテクチャ 7. オニオン アーキテクチャ などなど これらはソフトウェア アーキテクチャの類型的なパターン群です Copyright 2017 @nuits_jp Slide 9

10.

ソフトウェア アーキテクチャとは何か? ソフトウェアアーキテクチャでは、ソフトウェア システムの構成に関する一連 の重要な判断を網羅しています。これには、システムを構成する要素とイン ターフェイスの選択、要素間のコラボレーションとして指定される動作、この ような構成と動作の要素のより大きなサブシステムに対する構成、この構成の 指針となるアーキテクチャスタイルが含まれます。また、機能性、ユーザビリ ティ、復元性、パフォーマンス、再利用性、理解できること、経済的な制約、 テクノロジの制約、トレードオフ、および外観への配慮も必要です。 by Philippe Kruchten, Grady Booch, Kurt Bittner, Rich Reitman Microsoft 「アプリケーション アーキテクチャ ガイド2.0」より引用 Copyright 2017 @nuits_jp Slide 10

11.

ソフトウェア アーキテクチャとは何か? アーキテクチャは、システムを大きなレベルで分解したもので、決定事項の変 更は困難です。システムには複数のアーキテクチャが存在し、アーキテクチャ にとって重要な事項はシステムの運用中に変化します。要するに、重要な要素 は、すべてアーキテクチャということになります。 by Martin Fowler Microsoft 「アプリケーション アーキテクチャ ガイド2.0」より引用 Copyright 2017 @nuits_jp Slide 11

12.

ソフトウェア アーキテクチャとは何か? ソフトウェアアーキテクチャとは、抽象化と問題の分割によって複雑性を減ら すことを主に念頭に置いたものである。ただし、今までのところ、「ソフト ウェアアーキテクチャ」という用語に関して、万人が合意した厳密な定義は存 在しない Wikipedia「ソフトウェアアーキテクチャ」より引用 Copyright 2017 @nuits_jp Slide 12

13.

とは言え、おおよその共通認識はある Copyright 2017 @nuits_jp Slide 13

14.

ソフトウェア アーキテクチャとは何か?かみ砕くと… 1. ソフトウェアアーキテクチャとは システムアーキテクチャのうち、ソフトウェア領域のアーキテク チャである この時「システム」とは「IT」だけではなく、それらを取り巻く 社会やビジネスを含めた「仕組み」を指すことも多い ※ 元来「System」とは制度・組織・体系・系統などのこと Copyright 2017 @nuits_jp

15.

ソフトウェア アーキテクチャとは何か?かみ砕くと… 2. ソフトウェア アーキテクチャとは 1. ソフトウェアにおける重要な決定事項全てである 2. その中でも特につぎの2点が重要 1. ソフトウェア全体を、どのように分割するか 2. 分割した部分同士を、どのように相互作用させるか Copyright 2017 @nuits_jp

16.

ソフトウェア アーキテクチャとは何か?かみ砕くと… 3. ソフトウェアアーキテクチャを構築するのはなぜか? • 「システムの実現をサポートする」 • 「持続可能なソフトウェア」を • 「バランスよく」構築するため 4. ソフトウェアアーキテクチャのバランスとは? 1. Quality(機能・非機能) 2. Cost 3. Delivery(開発期間) 特にアーキテクチャは非機能要求から受ける影響が大きい Copyright 2017 @nuits_jp

17.

「関心の分離」と「疎結合」 Again, today’s Goal Copyright 2017 @nuits_jp

18.

Today’s Goal 1. ソフトウェア アーキテクチャの概略を理解いただく 2. 特に理解いただきたいこと 1. 関心(関心事)の分離 2. カプセル化 3. 密結合と疎結合 4. 疎結合を実現する代表的な手段 Xamarin.Forms Navigation Overview Slide 18

19.

Today’s Goal 1. ソフトウェア アーキテクチャの概略を理解いただく 2. 特に理解いただきたいこと 1. 関心(関心事)の分離 2. カプセル化 3. 密結合と疎結合 4. 疎結合を実現する代表的な手段 Xamarin.Forms Navigation Overview Slide 19

20.

「関心の分離」と「疎結合」 関心(関心事)の分離 Copyright 2017 @nuits_jp

21.

Separation of Concerns さて、アーキテクチャとは「どう分割し、どう結合するか」が重要 だとお話ししました。 その観点で非常に重要な概念として Separation of Concerns(SoC):関心(関心事)の分離 という考え方があります。 プログラムは異なる関心事は、異なる部分に分離せよという設計原 則です。 Copyright 2017 @nuits_jp

22.

MVC, MVP, MVVM, MVPVM, … たとえば、MVC・MVP・MVVMなども、ある「何かと何か」の関心 を分離するための仕組みです。 Binding & Command Update Notification Notification Copyright 2017 @nuits_jp Slide 22

23.

MVC, MVP, MVVM, MVPVM, … MVC・MVP・MVVMなどはつぎの二つの関心事を分離するものです。 • プレゼンテーション • プレゼンテーション以外 Binding & Command Update Notification Notification プレゼンテーション Copyright 2017 @nuits_jp その他 Slide 23

24.

なぜプレゼンテーションを分離するのか? いくつか明確な理由があります。 1. プレゼンテーションは専門性が高い →プレゼンテーションのみを分業できる仕組みを用意したい 2. 一般的にコードによるテストが困難である →プレゼンテーション以外はコードによるテストを行いたい こう言った理由から、プレゼンテーションとそれ以外を分離して設計する 考え方を「Presentation Domain Separation(PDS)」と言います。 Copyright 2017 @nuits_jp Slide 24

25.

MVC, MVP, MVVM, MVPVM, … is PDS Presentation Domain Separation:PDS Copyright 2017 @nuits_jp Slide 25

26.

MVC, MVP, MVVM, MVPVM, … is PDS 目的 Presentation Domain Separation:PDS 手段 Copyright 2017 @nuits_jp Slide 26

27.

PDS is SoC Separation of Concerns:SoC Presentation Domain Separation:PDS Copyright 2017 @nuits_jp Slide 27

28.

PDS is SoC 目的 Separation of Concerns:SoC Presentation Domain Separation:PDS 手段 Copyright 2017 @nuits_jp Slide 28

29.

プレゼンテーション以外の関心は? Copyright 2017 @nuits_jp Slide 29

30.

ところで 多くのソフトウェアのプレゼンテーションと、それ以外の比率は プレゼンテーション < それ以外 です。 Binding & Command Update Notification Notification その他 プレゼンテーション Copyright 2017 @nuits_jp Slide 30

31.

これらの概念だけでは足りない 目的 Separation of Concerns:SoC Presentation Domain Separation:PDS 手段 何かがここに必要! 何が必要なのか? Copyright 2017 @nuits_jp Slide 31

32.

ケースバイケースで銀の弾丸はない Copyright 2017 @nuits_jp Slide 32

33.

とはいえ参考となるものは存在する 1. Domain Driven Design(ドメイン駆動設計) 2. レイヤー アーキテクチャ 3. クリーン アーキテクチャ 4. Microsoft アプリケーション アーキテクチャ ガイド2.0 など Copyright 2017 @nuits_jp Slide 33

34.

ここからはモデルケースを見ながら進めます Copyright 2017 @nuits_jp Slide 34

35.

題材 【要求】 • 端末の位置情報を利用し、周辺のレストラン一覧を表示する • レストラン情報は「リクルートWEBサービス」のグルメサー チAPIを利用させていただく https://webservice.recruit.co.jp/hotpepper/reference.html • コンソールアプリケーションとして実装する 【制限事項】 • Unit Testの実装例はごく一部に限らせていただきます 【ソースコード】 https://github.com/nuitsjp/SoC-and-Loosely-Coupled Copyright 2017 @nuits_jp Slide 35

36.

関心の分離方針 全体としてはレイヤー アーキテクチャを採用 Presentation • プレゼンテーション層 • ユーザーインターフェース(コンソール)を実現する Usecase • ビジネスロジック層 • ユースケース単位でクラスを分割 • 今回は「周辺のレストランを探す」ユースケースのみ Integration • プログラム外との統合するための層 • 現在地座標の取得と、指定座標のレストラン情報の取 得の2種類に分割 Copyright 2017 @nuits_jp Slide 36

37.

それではコードを見てみましょう! Copyright 2017 @nuits_jp Slide 37

38.

現在の構造 class Class Model Presentation RestauranListConsole Usecase FindRestaurants + FindNearbyRestaurantsAsync(): GourmetSearchResult Integration GourmetSearchResult GourmetService + GeoCoordinator SearchGourmetInfosAsync(): GourmetSearchResult Copyright 2017 @nuits_jp Slide 38

39.

NGポイント:関心の未分離 Copyright 2017 @nuits_jp Slide 39

40.

NGポイント:関心の未分離 class Class Model Presentation RestauranListConsole Usecase FindRestaurants + FindNearbyRestaurantsAsync(): GourmetSearchResult Integration GourmetSearchResult GourmetService + GeoCoordinator SearchGourmetInfosAsync(): GourmetSearchResult Copyright 2017 @nuits_jp Slide 40

41.

関心をカプセル化する Copyright 2017 @nuits_jp Slide 41

42.

めざす姿 class Class Model Presentation RestauranListConsole ③ Usecase Restaurant FindRestaurants + FindNearbyRestaurantsAsync(): IList<Restaurant> ② Integration GourmetInfo GourmetService + GeoCoordinator SearchGourmetInfosAsync(): IList<GourmetInfo> ① GourmetSearchResult Copyright 2017 @nuits_jp Slide 42

43.

現在の構造 class Class Model Presentation RestauranListConsole Usecase Restaurant FindRestaurants + FindNearbyRestaurantsAsync(): IList<Restaurant> Integration GourmetInfo GourmetService + GeoCoordinator SearchGourmetInfosAsync(): IList<GourmetInfo> GourmetSearchResult Copyright 2017 @nuits_jp Slide 43

44.

NGポイント:密結合 Copyright 2017 @nuits_jp Slide 44

45.

NGポイント:密結合 class Class Model Presentation RestauranListConsole Usecase Restaurant FindRestaurants + FindNearbyRestaurantsAsync(): IList<Restaurant> Integration GourmetInfo GourmetService + GeoCoordinator SearchGourmetInfosAsync(): IList<GourmetInfo> GourmetSearchResult Copyright 2017 @nuits_jp Slide 45

46.

NGポイント:密結合 class Class Model new FindRestaurants + FindNearbyRestaurantsAsync(): IList<Restaurant> GourmetService + SearchGourmetInfosAsync(): IList<GourmetInfo> use • クラスとクラスが直接依存関係にある • 各レイヤー間が密結合状態となっている Copyright 2017 @nuits_jp Slide 46

47.

NGポイント:密結合 class Class Model Presentation RestauranListConsole Usecase Restaurant FindRestaurants + FindNearbyRestaurantsAsync(): IList<Restaurant> Integration GourmetInfo GourmetService + GeoCoordinator SearchGourmetInfosAsync(): IList<GourmetInfo> GourmetSearchResult Copyright 2017 @nuits_jp Slide 47

48.

なぜ密結合が悪いのか? 一般論 • 利用者側が、依存先の影響を強く受ける • 結果、保守性・拡張性が低下する Copyright 2017 @nuits_jp Slide 48

49.

NGポイント:密結合 class Class Model Presentation RestauranListConsole Usecase Restaurant FindRestaurants + FindNearbyRestaurantsAsync(): IList<Restaurant> Integration GourmetInfo GourmetService + GeoCoordinator SearchGourmetInfosAsync(): IList<GourmetInfo> GourmetSearchResult Copyright 2017 @nuits_jp Slide 49

50.

NGポイント:密結合 class Class Model Presentation RestauranListConsole Usecase Restaurant FindRestaurants + FindNearbyRestaurantsAsync(): IList<Restaurant> Integration GourmetInfo GourmetService + GeoCoordinator SearchGourmetInfosAsync(): IList<GourmetInfo> GourmetSearchResult Copyright 2017 @nuits_jp Slide 50

51.

閑話:Unit Test Copyright 2017 @nuits_jp Slide 51

52.

テストが難しいクラス class Class Model テストコード テスト対象 Copyright 2017 @nuits_jp 依存先 Slide 52

53.

テストが難しいクラス class Class Model テストコード テスト対象 Copyright 2017 @nuits_jp 依存先 Slide 53

54.

テストが難しいクラス class Class Model テストコード テスト対象 依存先 • 依存先がテストを困難にする要素を持っている • 時間 • 位置情報 • ネットワーク • 大量の再依存クラス • など Copyright 2017 @nuits_jp Slide 54

55.

依存先を置き換え可能にする class Class Model テストコード «interface» 依存先 テスト対象 依存先 Copyright 2017 @nuits_jp テスト用の偽物 Slide 55

56.

依存先を置き換え可能にする class Class Model テストコード «interface» 依存先 テスト対象 依存先 Copyright 2017 @nuits_jp テスト用の偽物 Slide 56

57.

依存先を置き換え可能にする class Class Model テストコード Driver «interface» 依存先 テスト対象 依存先 Copyright 2017 @nuits_jp テスト用の偽物 Slide 57

58.

依存先を置き換え可能にする class Class Model テストコード «interface» 依存先 テスト対象 依存先 テスト用の偽物 Stub Fake Mock Copyright 2017 @nuits_jp Slide 58

59.

閑話終了 疎結合を目指す Copyright 2017 @nuits_jp Slide 59

60.

疎結合を実現する class Class Model FindRestaurants + «interface» IGourmetService FindNearbyRestaurantsAsync() + 利用者がインターフェースにのみ 依存している状態を目指す SearchGourmetInfosAsync() GourmetService + Copyright 2017 @nuits_jp SearchGourmetInfosAsync() Slide 60

61.

疎結合の実現 その1 インターフェースの抽出 Copyright 2017 @nuits_jp Slide 61

62.

インターフェースの抽出結果 class Class Model FindRestaurants + FindNearbyRestaurantsAsync() «interface» IGourmetService use + SearchGourmetInfosAsync() new 利用箇所の依存性は分離できたが インスタンス生成箇所がクラスに 依存している。 GourmetService + Copyright 2017 @nuits_jp SearchGourmetInfosAsync() Slide 62

63.

解決方法は二つ 1. Dependency Injectionパターン 2. Service Locatorパターン Copyright 2017 @nuits_jp Slide 63

64.

解決方法は二つ 1. Dependency Injectionパターン 2. Service Locatorパターン Copyright 2017 @nuits_jp Slide 64

65.

インターフェースの抽出結果 class Class Model FindRestaurants + FindNearbyRestaurantsAsync() «interface» IGourmetService use + SearchGourmetInfosAsync() new 利用箇所の依存性は分離できたが インスタンス生成箇所がクラスに 依存している。 GourmetService + Copyright 2017 @nuits_jp SearchGourmetInfosAsync() Slide 65

66.

疎結合の実現 その2 依存性の注入 Copyright 2017 @nuits_jp Slide 66

67.

疎結合の実現 class Class Model FindRestaurants + FindNearbyRestaurantsAsync() «interface» IGourmetService use + SearchGourmetInfosAsync() injection Program GourmetService new Copyright 2017 @nuits_jp + SearchGourmetInfosAsync() Slide 67

68.

Unit Testを書いてみよう! Copyright 2017 @nuits_jp Slide 68

69.

Dependency Injection 面倒ですよね? Copyright 2017 @nuits_jp Slide 69

70.

Dependency Injection Containerを使おう! Copyright 2017 @nuits_jp Slide 70

71.

「関心の分離」と「疎結合」 まとめ Copyright 2017 @nuits_jp

72.

まとめ ① 1. ソフトウェア アーキテクチャとは 1. 重要な決定事項の全てがアーキテクチャ 2. 特にその中でも次の2点が重要 1. 全体をどう部分に分割するか 2. ソフトウェア内部と外部、部分と部分をどう結合し、どう 相互作用させるか Copyright 2017 @nuits_jp

73.

まとめ ② 1. 関心の分離 分割する際「関心の分離(SoC)」を実現すること 2. カプセル化 分割された対象は、依存先の関心を内部にカプセル化すること 3. 密結合と疎結合 分割された対象間は、密結合しないよう疎結合を保つこと 4. 疎結合を実現する代表的な手段 インターフェースを活用し疎結合を実現すること その際、結合はDependency Injection Patternなどを利用すること Copyright 2017 @nuits_jp

74.

まとめ ③ これらを実践するにあたり、いくつかのツールを紹介した • Unit Testの実施 → Unit Test Frameworkを利用しよう • Unit Test時のMockについて → Mock生成をサポートするライブラリを使おう • Dependency Injection Pattern → Dependency Injection Containerを使うと良い Copyright 2017 @nuits_jp Slide 74

75.

Thank You! Any Questions?