Slide 1

Slide 1 text

実践 Clean Architecture Scala 福岡 2019 @yoshiyoshifujii Scala 福岡 2019 1 / 46

Slide 2

Slide 2 text

Yoshitaka Fujii @yoshiyoshifujii Chatwork 株式会社(5 ヶ月目) Scala 歴 5 年目 Scala 関西 Summit スタッフ(4 年目) 登壇 ScalaMatsuri2016 Scala でドメイン駆動設計に真正面から取り組んだ話 ScalaMatsuri2017 Serverless Architecture をScala で構築するぞ Scala 福岡2017( 懇親会LT) Scala とサーバレス相性いいよ アミノ酸とプロテイン 自己紹介 実践 Clean Architecture Scala 福岡 2019 2 / 46

Slide 3

Slide 3 text

Clean Architecture 達人に学ぶソフトウェアの構造と設計 ­ 2018/07/27 実践 Clean Architecture Scala 福岡 2019 3 / 46

Slide 4

Slide 4 text

著者 Robert C. Martin ( アンクル・ボブ) 1970 年からプログラマ cleancoders.com の共同創業者であり、ソフトウェア開発者向けの学習用動画をオンラインで提供している TheCleanCoder (邦訳:CleanCoder─ プロフェッショナルプログラマへの道) CleanCode (邦訳:CleanCode─ アジャイルソフトウェア達人の技) UMLforJavaProgrammers (邦訳:Java プログラマのためのUML ) AgileSoftwareDevelopment (邦訳:アジャイルソフトウェア開発の奥義) ExtremeProgramminginPractice (邦訳:XP エクストリーム・プログラミング実践記─ 開発現場からのレポート) Robert C .Martin, 角 征典, 高木 正弘. Clean Architecture 達人に学ぶソフトウェアの構造と設計 (Japanese Edition). Kindle 版. 実践 Clean Architecture Scala 福岡 2019 4 / 46

Slide 5

Slide 5 text

The Clean Architecture [2012/08/13] The Clean Architecture ­ The Clean Code Blog https://blog.cleancoder.com/uncle­bob/2012/08/13/the­clean­architecture.html [2013/07/13] アーキテクチャの目的は意図であり、フレームワークではない ­ InfoQ https://www.infoq.com/jp/news/2013/07/architecture_intent_frameworks [2015/01/05] 持続可能な開発を目指す ~ ドメイン・ユースケース駆動(クリーンアーキテクチャ) + 単方向に制限した処 理 + FRP ­ Qiita https://qiita.com/kondei/items/41c28674c1bfd4156186 [2015/12/22] まだMVC,MVP,MVVM で消耗してるの? iOS Clean Architecture について ­ Qiita https://qiita.com/koutalou/items/07a4f9cf51a2d13e4cdc [2016/03/16] DDD + Clean Architecture + UCDOM Full 版 ­ Speakerdeck https://speakerdeck.com/yoskhdia/ddd­plus­clean­architecture­plus­ucdom­fullban https://github.com/yoskhdia/cleanArchSample [2018/11/07] ドメインオブジェクトを中心としたClean Architecture のためのレイヤー構成 ­ Qiita https://qiita.com/j5ik2o/items/7817055b35b2ff34f2e9 [2018/12/17] 実装クリーンアーキテクチャ ­ Qiita https://qiita.com/nrslib/items/a5f902c4defc83bd46b8 実践 Clean Architecture Scala 福岡 2019 5 / 46

Slide 6

Slide 6 text

アジェンダ 1. なぜ Clean Architecture か 2. ポリモーフィズム 3. SOLID 原則 4. コンポーネントの原則 5. Clean Architecture 実践 Clean Architecture Scala 福岡 2019 6 / 46

Slide 7

Slide 7 text

1. なぜ Clean Architecture か 実践 Clean Architecture Scala 福岡 2019 7 / 46

Slide 8

Slide 8 text

1. なぜ Clean Architecture か あらゆるソフトウェアシステムは、 「方針」 と 「詳細」 に分割できる 方針 は、ビジネスのすべてのルールや手順、システムの本当の価値 詳細 は、DB 、WEB 、フレームワークなど方針に影響を与えるものではない ソフトウェアをソフトに保つために、できるだけ長い期間、多く選択肢を残す 残すべき選択肢とは、 重要でない詳細 方針と詳細を慎重に区別し、方針が詳細に依存せず、詳細の決定を延期・留保できる方針をデザインする 優秀なアーキテクトに求められる 実践 Clean Architecture Scala 福岡 2019 7 / 46

Slide 9

Slide 9 text

1. なぜ Clean Architecture か レイヤー化アーキテクチャ、ヘキサゴナルアーキテクチャも目的は同じ「関心事の分離」 フレームワーク非依存、テスト可能、UI 非依存、データベース非依存、外部エージェント非依存 ドメイン駆動設計によるモデル分析の結果を中心で表現し、詳細を後から選択する 叫ぶアーキテクチャ アプリケーションのアーキテクチャが「ヘルスケアシステム」「会計システム」と叫ぶか ドメインとユースケースは相互関係 実践 Clean Architecture Scala 福岡 2019 8 / 46

Slide 10

Slide 10 text

1. なぜ Clean Architecture か レイヤー化アーキテクチャ、ヘキサゴナルアーキテクチャも目的は同じ「関心事の分離」 フレームワーク非依存、テスト可能、UI 非依存、データベース非依存、外部エージェント非依存 ドメイン駆動設計によるモデル分析の結果を中心で表現し、詳細を後から選択する 叫ぶアーキテクチャ アプリケーションのアーキテクチャが「ヘルスケアシステム」「会計システム」と叫ぶか ドメインとユースケースは相互関係 優れたクリーンなアーキテクチャと設計により 長期的に利益をもたらすシステムを構築する 実践 Clean Architecture Scala 福岡 2019 8 / 46

Slide 11

Slide 11 text

Clean Architecture を実践するうえで 理解しておきたい原則を見ていく 実践 Clean Architecture Scala 福岡 2019 9 / 46

Slide 12

Slide 12 text

2. ポリモーフィズム 実践 Clean Architecture Scala 福岡 2019 10 / 46

Slide 13

Slide 13 text

2. ポリモーフィズム ポリモーフィズム(英: Polymorphism )とは、プログラミング言語の型システムの性質を表すもので、 プログラミング言語の各要素(定数、変数、式、オブジェクト、関数、メソッドなど)について それらが複数の型に属することを許すという性質を指す。ポリモルフィズム、多態性、多相性、多様性とも呼ばれる。 ポリモーフィズム ­ Wikipedia 実践 Clean Architecture Scala 福岡 2019 10 / 46

Slide 14

Slide 14 text

2. ポリモーフィズム ポリモーフィズム(英: Polymorphism )とは、プログラミング言語の型システムの性質を表すもので、 プログラミング言語の各要素(定数、変数、式、オブジェクト、関数、メソッドなど)について それらが複数の型に属することを許すという性質を指す。ポリモルフィズム、多態性、多相性、多様性とも呼ばれる。 ポリモーフィズム ­ Wikipedia abstract class Animal { abstract String talk(); } class Cat extends Animal { String talk() { return "Meow!"; } } class Dog extends Animal { String talk() { return "Woof!"; } } 実践 Clean Architecture Scala 福岡 2019 10 / 46

Slide 15

Slide 15 text

2. ポリモーフィズム OO 言語が安全で便利なポリモーフィズムを提供しているということ ソースコードの依存関係は ( たとえどこにあっても) 逆転できる 依存関係逆転の原則 (DIP) このパワーを使って、DB やUI をビジネスルールに依存させることができる ビジネスルールを独立してデプロイできる 独立してデプロイできるなら、別々のチームで開発する独立開発可能性がある 実践 Clean Architecture Scala 福岡 2019 11 / 46

Slide 16

Slide 16 text

3. SOLID 原則 実践 Clean Architecture Scala 福岡 2019 12 / 46

Slide 17

Slide 17 text

3. SOLID 原則 目的 以下のような性質を持つ中間レベルのソフトウェア構造を作ること 変更に強いこと 理解しやすいこと コンポーネントの基盤として、多くのソフトウェアシステムで利用できること 「中間レベル」とはモジュールレベル コードレベルより上に適用する 実践 Clean Architecture Scala 福岡 2019 12 / 46

Slide 18

Slide 18 text

3. SOLID 原則 単一責任の原則(SRP :Single Responsibility Principle ) モジュールは、たったひとつのアクターに対して責務を負うべき オープン・クローズドの原則(OCP :Open Closed Principle ) 拡張に対しては開いていて、修正に対して閉じていなければならない 変更の影響を受けずにシステムを拡張しやすくする システムを分割して、依存関係を階層構造にする リスコフの置換原則(LSP :Liskov Substitution Principle ) クラスA はクラスB を使っていて、そのB をC に置き換えた際にA の振る舞いが変わらない場合、C はB の派生形である 置換可能性に少しでも違反すると、特別な仕組みだらけになる インターフェイス分離の原則(ISP :Interface Segregation Principle ) 必要としないお荷物を抱えたものに依存していると、予期せぬトラブルの元につながる 依存関係逆転の原則(DIP :Dependency Inversion Principle ) ソースコードの依存関係が抽象だけを参照しているものが、最も柔軟なシステムだ 実践 Clean Architecture Scala 福岡 2019 13 / 46

Slide 19

Slide 19 text

4. コンポーネントの原則 実践 Clean Architecture Scala 福岡 2019 14 / 46

Slide 20

Slide 20 text

4. コンポーネントの原則 再利用・リリース等価の原則 (REP) 再利用の単位とリリースの単位は等価になる コンポーネントを形成するクラスやモジュールは凝集性のあるグループ コンポーネントには一貫するテーマや目的があり共有するモジュールを集める Maven 等にリリースする際の凝集性は一貫性がないとだめ 閉鎖性共通の原則 (OCP) 同じ理由、同じタイミングで変更されるクラスをコンポーネントにまとめること 変更の理由やタイミングが異なるクラスは、別のコンポーネントに分けること 単一責任の原則(SRP) をコンポーネント向けに言い換えたもの 全再利用の原則 (CRP) コンポーネントのユーザに対して、実際には使わないものへの依存を強要してはいけない インターフェイス分離の原則(ISP) を一般化したもの 不要なものには依存しないこと 実践 Clean Architecture Scala 福岡 2019 14 / 46

Slide 21

Slide 21 text

3 つの原則は、相反するところがある バランスをうまくとるのがアーキテクトの腕の見せどころ 再利用・リリース等価の原則(REP )と閉鎖性共通の原則(CCP ) は、包含関係 ひとつのコンポーネントを大きくする方向に働くもの 全再利用の原則(CRP )は、これらとは相反する原則 コンポーネントを小さくする方向に働くもの 4. コンポーネントの原則 実践 Clean Architecture Scala 福岡 2019 15 / 46

Slide 22

Slide 22 text

5. Clean Architecture 実践 Clean Architecture Scala 福岡 2019 16 / 46

Slide 23

Slide 23 text

フレームワーク非依存 テスト可能 UI 非依存 データベース非依存 外部エージェント非依存 5. Clean Architecture 実践 Clean Architecture Scala 福岡 2019 16 / 46

Slide 24

Slide 24 text

依存性のルール 円の中央に近付くほどソフトウェアのレベルが上がる 円の外側は 詳細 。内側は 方針 。 ソースコードの依存性は、内側だけに向かっていなければ ならない 円の外側にあるものから内側にあるものに影響を及ぼさな い 5. Clean Architecture 実践 Clean Architecture Scala 福岡 2019 17 / 46

Slide 25

Slide 25 text

Entities 最重要ビジネスルールをカプセル化したもの メソッドを持ったオブジェクトでも、データ構造と関数で も可 最も一般的で最上位レベルのルールをカプセル化したもの 特定のアプリケーションの操作に変更が発生しても、影響 を受けない 5. Clean Architecture 実践 Clean Architecture Scala 福岡 2019 18 / 46

Slide 26

Slide 26 text

Use Cases アプリケーション固有のビジネスルールが含まれている システムの全てのユースケースがカプセル化・実装されて いる エンティティに入出力するデータの流れを調整 エンティティに最重要ビジネスルールを使用するように指 示を出す このレイヤーの変更はエンティティに影響を与えない データベース、UI 、フレームワークなどの外部の影響を受 けない 5. Clean Architecture 実践 Clean Architecture Scala 福岡 2019 19 / 46

Slide 27

Slide 27 text

Interface Adapters ユースケースやエンティティに便利なフォーマットから変 換する層 変換する先としては、データベースやウェブなど 逆に、外部のフォーマットから内部のフォーマットに変換 もする 5. Clean Architecture 実践 Clean Architecture Scala 福岡 2019 20 / 46

Slide 28

Slide 28 text

Frameworks & Drivers 最も外側の円 フレームワークやツールで構成されている データベースやウェブフレームワークなど 通常、このレイヤーにコードは書かない 書くとしても円の次の内側とやり取りするグルーコード 5. Clean Architecture 実践 Clean Architecture Scala 福岡 2019 21 / 46

Slide 29

Slide 29 text

4 つの円について 概要を示しただけ 4 つ以外にも必要なものはあるだろうとのこと この4 つ以外を認めないというルールはない ただし、依存性のルールは常に適用される ソースコードの依存性は常に内側に向ける 円の内側に近付くと、抽象度と方針のレベルが高まる 円の外側は、具体的な詳細で構成される 5. Clean Architecture 実践 Clean Architecture Scala 福岡 2019 22 / 46

Slide 30

Slide 30 text

境界線を越える 円の境界線をどのように越えるべきかの例 Controller とPresenter は、内側のレイヤーのUse Case と通 信している Controller ­> Use Case ­> Presenter 依存関係は、すべて内側のUse Case に向いている 依存関係逆転の原則(DIP )を使う インタフェースや継承を整理して制御の流れと逆転するよ うにする 依存性のルールに違反しないようにポリモーフィズムを活 用する 5. Clean Architecture 実践 Clean Architecture Scala 福岡 2019 23 / 46

Slide 31

Slide 31 text

典型的なシナリオ ユーザーからの入力データを、Controller に渡す Controller は、POJO なInput Data にデータを詰め込む Input Boundary を経由して、Use Case Interactor に渡す Use Case Interactor は、Entities のダンスを制御する Data Access Interface を使用してDatabase とI/O する Output Data をPOJO として生成し結果を詰め込む Output Data は、Output Boundary インタフェースを経由し て、Presenter に渡す Presenter は、Output Data をViewModel(POJO) に詰め込み 直す 5. Clean Architecture 実践 Clean Architecture Scala 福岡 2019 24 / 46

Slide 32

Slide 32 text

この典型的なシナリオをベースとして、 実践的な Scala のコードに落とし込んでいきます ↓ コードは ↓ https://github.com/yoshiyoshifujii/scala­clean­architecture­example 実践 Clean Architecture Scala 福岡 2019 25 / 46

Slide 33

Slide 33 text

題材 サンプルコードで扱うドメインは、 OAuth 2.0 RFC­6749 http://openid­foundation­japan.github.io/rfc6749.ja.html 最近、業務で触ってる https://creators­note.chatwork.com/archive/category/OAuth 「認可コードによる認可」 部分のユースケースをコード化 あくまで、サンプルコードであり、プロダクションコードとは異なります。( 当然ですが…) 実践 Clean Architecture Scala 福岡 2019 26 / 46

Slide 34

Slide 34 text

プロジェクト構成 実践 Clean Architecture Scala 福岡 2019 27 / 46

Slide 35

Slide 35 text

プロジェクト構成 build.sbt lazy val `infrastructure` = (project in file("modules/infrastructure")) lazy val `entities` = (project in file("modules/entities")).dependsOn(infrastructure) lazy val `usecases` = (project in file("modules/usecases")).dependsOn(entities) lazy val `adapters` = (project in file("modules/adapters")).dependsOn(usecases) lazy val `main` = (project in file("modules/main")).dependsOn(adapters) 実践 Clean Architecture Scala 福岡 2019 27 / 46

Slide 36

Slide 36 text

プロジェクト構成 build.sbt lazy val `infrastructure` = (project in file("modules/infrastructure")) lazy val `entities` = (project in file("modules/entities")).dependsOn(infrastructure) lazy val `usecases` = (project in file("modules/usecases")).dependsOn(entities) lazy val `adapters` = (project in file("modules/adapters")).dependsOn(usecases) lazy val `main` = (project in file("modules/main")).dependsOn(adapters) infrastructure は、レイヤー化アーキテクチャのインフラ層ではなく、要件が変化しても依存し続ける層。すべての 層が依存できる汎用的な技術基盤。 entities は、その名の通りエンティティ。 usecases も、そのまま。 adapters も、そのまま。 main は、究極的な詳細が入るところ。依存関係は、このmain プロジェクトに注入する。 sbt のマルチプロジェクトで、依存の方向性を強制する 実践 Clean Architecture Scala 福岡 2019 27 / 46

Slide 37

Slide 37 text

依存するライブラリ entities https://github.com/j5ik2o/scala­ddd­base "com.github.j5ik2o" %% "scala-ddd-base-core" % version DDD の集約とリポジトリを良い感じに抽象化したcore ライブラリ Slick(JDBC) 、SkinnyORM(JCBC) 、Redis などボイラープレートとなりがちな具象部分を提供してたり https://github.com/septeni­original/sbt­dao­generator を使ってDAO を自動生成して組み合わせたり ボイラープレートが増えがちな詳細部分の作業を減らしてくれる めちゃオススメ 実践 Clean Architecture Scala 福岡 2019 28 / 46

Slide 38

Slide 38 text

依存するライブラリ 今回のサンプルでは、このライブラリが主な依存であり、他は特に依存させていない。 Akka HTTP にするのか、Play Framework にするのか、MySQL にするのか、DynamoDB にするのか… 実践 Clean Architecture Scala 福岡 2019 29 / 46

Slide 39

Slide 39 text

依存するライブラリ 今回のサンプルでは、このライブラリが主な依存であり、他は特に依存させていない。 Akka HTTP にするのか、Play Framework にするのか、MySQL にするのか、DynamoDB にするのか… 詳細について検討するのは、 方針を実装してからで良い。 実践 Clean Architecture Scala 福岡 2019 29 / 46

Slide 40

Slide 40 text

パッケージ構成 実践 Clean Architecture Scala 福岡 2019 30 / 46

Slide 41

Slide 41 text

Entities ユビキタス言語やValueObject でパッケージを切っている 共通的なValueObject 以外は、ユビキタス言語でグルーピ ングしてパッケージングしている 当初はフラットに並べておき、後から説明がつくあたりで パッケージングしていくのが良い パッケージ構成 実践 Clean Architecture Scala 福岡 2019 30 / 46

Slide 42

Slide 42 text

Use Cases usecases パッケージ直下に、 InputBoundary 、 OutputBoundary 、UseCaseInteractor 、を定義して いる 抽象度が高い作りなので、別のプロジェクト、パッケ ージに切り出すのも有り ユースケースのアクターごとにパッケージを切る OAuth クライアントを管理するアクターのユースケー スを、 admin 認可フローを実施するアクターのユースケースを、 authorization usecases パッケージ の下を見ると、このシステムが何 か叫んでいるようにしたい パッケージ構成 実践 Clean Architecture Scala 福岡 2019 31 / 46

Slide 43

Slide 43 text

Use Cases gateway は、アプリケーションロジックなので、 usecases プロジェクトに置いている Repository っていうと、レイヤー化アーキテクチャとかだ ったら、ドメイン層に置いていた Clean Architecture では、ビジネスロジックを entities 、アプリケーションロジックを usecases としているの で、永続化するとかどうこうはアプリケーションロジック と判断した パッケージ構成 実践 Clean Architecture Scala 福岡 2019 32 / 46

Slide 44

Slide 44 text

Adapters Framework や、DB など、詳細な部分との変換処理が入る ところ Controller 、 Presenter をそれぞれ、 controllers 、presenters にまとめる gateway には、Repository の具象を置く Contoroller は、仮にAkka HTTP でWeb を作ると決めた のであれば、 akka.http.scaladsl.Route を返すよう なメソッドを持つ Presenter は、POJO なViewModel を定義して返す Controller で、Response の形式、仮にJSON を返却す る場合、 Circe ( キルケー) などのJSON Library にPOJO な ViewModel からコンバートするような処理を持つ パッケージ構成 実践 Clean Architecture Scala 福岡 2019 33 / 46

Slide 45

Slide 45 text

Adapters adapters プロジェクトは、さらに細分化しても良い 仮に、AWS Lambda などのFaaS にデプロイするようなモ ジュールである場合、adapters のような詳細なライブラ リとの依存の強いプロジェクトはファイルサイズが巨大に なりがち。 依存ごとに細かくプロジェクトを分けることも考えられる が、詳細については、後で良い なるべく、決定を遅らせていく 仮にここをあとからごちゃごちゃ変えても、方針は影響を 受けない パッケージ構成 実践 Clean Architecture Scala 福岡 2019 34 / 46

Slide 46

Slide 46 text

境界を越えるあたりの実装をみていく 実践 Clean Architecture Scala 福岡 2019 35 / 46

Slide 47

Slide 47 text

典型的なシナリオで述べた以下について表している Controller は、POJO なInput Data にデータを詰め込む Input Boundary を経由して、Use Case Interactor に渡 す InputData は、型パラメータとして任意の型を扱う Controller からは、InputBoundary を経由してInputData を渡 して終わるので、Unit を返す InputBoundary trait InputBoundary[InputData] { def execute(arg: InputData): Unit } 実践 Clean Architecture Scala 福岡 2019 36 / 46

Slide 48

Slide 48 text

典型的なシナリオで述べた以下について表している Use Case Interactor は、Entities のダンスを制御する Output Data をPOJO として生成し結果を詰め込む UseCaseInteractor は、InputBoundary を継承している UseCaseInteractor は、OutputBoundary を保持している UseCaseInteractor は、InputData を受け取りdance して OutputData を返す dance を同期でするか非同期でするかとか、そういった中 身は詳細なので、Higher Kind で返却される OutputData は、OutputBoundary に渡される UseCaseInteractor trait UseCaseInteractor[F[_], InputData, OutputData] extends InputBoundary[InputData] { protected val outputBoundary: OutputBoundary[F, OutputData] override def execute(arg: InputData): Unit = outputBoundary.onComplete(dance(arg)) protected def dance(arg: InputData): F[OutputData] } 実践 Clean Architecture Scala 福岡 2019 37 / 46

Slide 49

Slide 49 text

典型的なシナリオで述べた以下について表している Output Data は、Output Boundary インタフェースを経 由して、Presenter に渡す OutputBoundary を継承するのは、Presenter OutputBoundary を経由して、Presenter にOutputData が渡 される F[_] は詳細なので、Higher Kind に抽象化されて渡されて いる OutputBoundary trait OutputBoundary[F[_], OutputData] { def onComplete(result: F[OutputData]): Unit } 実践 Clean Architecture Scala 福岡 2019 38 / 46

Slide 50

Slide 50 text

UseCase の実装例 class AuthorizationAuthorizeUseCase[F[_]]( override protected val outputBoundary: OutputBoundary[F, AuthorizationAuthorizeOutput], private val clientRepository: ClientRepository[F], private val reservedAuthorizationRepository: ReservedAuthorizationRepository[F] )(implicit ME: UseCaseMonadError[F]) extends UseCaseInteractor[F, AuthorizationAuthorizeInput, AuthorizationAuthorizeOutput] { override protected def dance(arg: AuthorizationAuthorizeInput): F[AuthorizationAuthorizeOutput] = ... } Use Case 1 つにつき、1 クラス インターフェイス分離の原則(ISP ) 余計な依存を持たない コンストラクターにOutputBoundary やRepository の抽象を受けとる 実際に注入するのは、main プロジェクト Airframe でコンストラクターインジェクションすると良さげ 実践 Clean Architecture Scala 福岡 2019 39 / 46

Slide 51

Slide 51 text

UseCase の実装例 sealed trait UseCaseError case class UseCaseSystemError(cause: Throwable) extends UseCaseError case class UseCaseApplicationError(message: String) extends UseCaseError type UseCaseMonadError[F[_]] = MonadError[F, UseCaseError] UseCase では、Entities の操作をした結果、ApplicationError と判断されるものと、何らかのシステム異常による SystemError を扱う このUseCaseError は、Presenter でパターンマッチし、WEB であれば、4xx エラーや5xx エラーに変換される 同期か非同期かとか、Either かTry といった詳細について、UseCase を表現する際に気にしない 詳細を決める際に、注入するため、Tagless Final Style で実装する ただし、前述の通り、UseCase では、エラーを扱う必要があるため、MonadError で型を制約する 実践 Clean Architecture Scala 福岡 2019 40 / 46

Slide 52

Slide 52 text

UseCase の実装例 override protected def dance(arg: AuthorizationAuthorizeInput): F[AuthorizationAuthorizeOutput] = for { clientId <- ME.pure(ClientId(arg.clientId)) // arg.clientId について検査が必要かどうかは、ClientId のassert で表明する client <- clientRepository.resolveById(clientId) reservedAuth <- client .reservedAuthorization( // OAuth クライアントから予約済み認可を生成する responseType = arg.responseType, redirectUri = arg.redirectUri, scope = arg.scope, state = arg.state ).toM[F] // EntitiesError からMonadError[F, UseCaseError] に変換する _ <- reservedAuthorizationRepository.store(reservedAuth) } yield AuthorizationAuthorizeOutput( redirectUri = Some(reservedAuth.redirectUri.value), scope = Some(reservedAuth.scopes.toStringList), state = reservedAuth.state.map(_.value), refKey = Some(reservedAuth.id.value), clientId = client.id.value, clientName = client.name.map(_.value) ) 実践 Clean Architecture Scala 福岡 2019 41 / 46

Slide 53

Slide 53 text

Entities ­ ビジネスロジック def reservedAuthorization(responseType: String, redirectUri: Option[String], scope: Option[Seq[String]], state: Option[String]): EntitiesValidationResult[ReservedAuthorization] = (assertResponseType(responseType), assertRedirectUri(redirectUri), assertScope(scope), assertState(state)) mapN { case (_responseType, _redirectUri, _scope, _state) => ReservedAuthorization( id = ReservedAuthorizationId(RefKeyGenerator.generate.value), status = Status.Active, responseType = _responseType, clientId = this.id, redirectUri = _redirectUri, scopes = _scope, state = _state, createdAt = ZonedDateTime.now, updatedAt = None ) } EntitiesValidationResult は、Type エイリアス assertXXX で事前条件を確認している 実践 Clean Architecture Scala 福岡 2019 42 / 46

Slide 54

Slide 54 text

EntitiesValidationResult case class EntitiesError(message: String) type EntitiesValidationResult[A] = ValidatedNel[EntitiesError, A] ValidatedNel のあたりは、Either にするとか、Invalid を貯めて返却したいといった要件やシステム上の決めに対して合わせ て型を決める 今回の例では、事前条件を確認した結果、エラーとなる原因を貯めて一括で返却するとした このあたりの選択は、方針として、先に決める必要がある 実践 Clean Architecture Scala 福岡 2019 43 / 46

Slide 55

Slide 55 text

まとめ あらゆるソフトウェアシステムは、 「方針」 と 「詳細」 に分割できる Clean Architecture を学び実践すると、方針と詳細を慎重に区別し、方針が詳細に依存せず、詳細の決定を延期・留保でき る方針をデザインできそう 方針をどんどんコードに落として検証、検査、議論し価値を実現 方針ができたら、詳細を作り、プラガブルにソフトなアーキテクチャを実現する 実践 Clean Architecture Scala 福岡 2019 44 / 46

Slide 56

Slide 56 text

参考 https://blog.cleancoder.com/uncle­bob/2012/08/13/the­clean­architecture.html https://www.infoq.com/jp/news/2013/07/architecture_intent_frameworks https://qiita.com/kondei/items/41c28674c1bfd4156186 https://qiita.com/koutalou/items/07a4f9cf51a2d13e4cdc https://speakerdeck.com/yoskhdia/ddd­plus­clean­architecture­plus­ucdom­fullban https://github.com/yoskhdia/cleanArchSample https://qiita.com/j5ik2o/items/7817055b35b2ff34f2e9 https://qiita.com/nrslib/items/a5f902c4defc83bd46b8 https://www.slideshare.net/AoiroAoino/purelyfunctionalplayframeworkapplication https://github.com/aoiroaoino/more­abstract­repository https://github.com/radusw/tagless­free­monix­samplep https://xuwei­k.hatenablog.com/entry/20140618/1403054751 実践 Clean Architecture Scala 福岡 2019 45 / 46

Slide 57

Slide 57 text

一緒に働くエンジニアを募集しています! https://corp.chatwork.com/ja/recruit/ 実践 Clean Architecture Scala 福岡 2019 46 / 46