Upgrade to Pro — share decks privately, control downloads, hide ads and more …

実践 Clean Architecture

実践 Clean Architecture

yoshiyoshifujii

January 19, 2019
Tweet

More Decks by yoshiyoshifujii

Other Decks in Technology

Transcript

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

    View Slide

  2. 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

    View Slide

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

    View Slide

  4. 著者
    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

    View Slide

  5. 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

    View Slide

  6. アジェンダ
    1.
    なぜ Clean Architecture

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

    View Slide

  7. 1.
    なぜ
    Clean Architecture

    実践 Clean Architecture
    Scala
    福岡 2019 7 / 46

    View Slide

  8. 1.
    なぜ
    Clean Architecture

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

    View Slide

  9. 1.
    なぜ
    Clean Architecture

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

    View Slide

  10. 1.
    なぜ
    Clean Architecture

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  14. 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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  18. 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

    View Slide

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

    View Slide

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

    View Slide

  21. 3
    つの原則は、相反するところがある
    バランスをうまくとるのがアーキテクトの腕の見せどころ
    再利用・リリース等価の原則(REP
    )と閉鎖性共通の原則(CCP

    は、包含関係
    ひとつのコンポーネントを大きくする方向に働くもの
    全再利用の原則(CRP
    )は、これらとは相反する原則
    コンポーネントを小さくする方向に働くもの
    4.
    コンポーネントの原則
    実践 Clean Architecture
    Scala
    福岡 2019 15 / 46

    View Slide

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

    View Slide

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

    View Slide

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

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  31. 典型的なシナリオ
    ユーザーからの入力データを、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

    View Slide

  32. この典型的なシナリオをベースとして、
    実践的な
    Scala
    のコードに落とし込んでいきます

    コードは ↓
    https://github.com/yoshiyoshifujii/scala­clean­architecture­example
    実践 Clean Architecture
    Scala
    福岡 2019 25 / 46

    View Slide

  33. 題材
    サンプルコードで扱うドメインは、 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

    View Slide

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

    View Slide

  35. プロジェクト構成
    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

    View Slide

  36. プロジェクト構成
    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

    View Slide

  37. 依存するライブラリ
    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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  42. Use Cases
    usecases
    パッケージ直下に、 InputBoundary

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

    View Slide

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

    View Slide

  44. 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

    View Slide

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

    View Slide

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

    View Slide

  47. 典型的なシナリオで述べた以下について表している
    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

    View Slide

  48. 典型的なシナリオで述べた以下について表している
    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

    View Slide

  49. 典型的なシナリオで述べた以下について表している
    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

    View Slide

  50. 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

    View Slide

  51. 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

    View Slide

  52. UseCase
    の実装例
    override protected def dance(arg: AuthorizationAuthorizeInput): F[AuthorizationAuthorizeOutput] =
    for {
    clientId について検査が必要かどうかは、ClientId
    のassert
    で表明する
    client reservedAuth .reservedAuthorization( // OAuth
    クライアントから予約済み認可を生成する
    responseType = arg.responseType,
    redirectUri = arg.redirectUri,
    scope = arg.scope,
    state = arg.state
    ).toM[F] // EntitiesError
    からMonadError[F, UseCaseError]
    に変換する
    _ } 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

    View Slide

  53. 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

    View Slide

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

    View Slide

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

    View Slide

  56. 参考
    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

    View Slide

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

    View Slide