クリーンアーキテクチャーをざっと理解できる短いコードを書いた

クリーンアーキテクチャーは沢山インターフェースやクラスが登場し、その関係をざっと把握するのが難しいです。
そこですべての要素が入ったなるべく短いコードを書いてみました。XCodeのPlaygroundなので、そのまま実行できます。[githubのリポジトリはこちらです。](https://github.com/TokyoYoshida/CleanArchitecturePlayground)なお、今回はざっと理解することを優先するため、クリーンアーキテクチャーについての詳しい説明は割愛します。参考記事をご覧ください。

このコードは、Uncle Bobの書いた[Clean Architecture 達人に学ぶソフトウェアの構造と設計](https://booklog.jp/item/1/4048930656)と、次の記事を参考に書いています。

参考記事：
実装クリーンアーキテクチャ: https://qiita.com/nrslib/items/a5f902c4defc83bd46b8
Laravelで実践クリーンアーキテクチャ: https://qiita.com/nrslib/items/aa49d10dd2bcb3110f22

## クリーンアーキテクチャーの概要図

この２つの図が有名かと思います。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/116010/810baac1-c7d0-9ebb-870a-ab328a7c9206.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/116010/1c1b5df4-478e-1f76-599a-d70b872f24cb.png)
引用：[Clean Architecture 達人に学ぶソフトウェアの構造と設計](https://booklog.jp/item/1/4048930656)

## 概要図と今回のコードとの対応
サンプルコードに現れるインターフェース、クラスをなるべく本家の図と同じ位置に同じ色で配置しています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/116010/2d962e97-536f-d7f3-eee2-b84b48e258a5.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/116010/88252681-dc0d-42a7-16ce-51a52424e8ca.png)

この図で、本家と違うのが`SomeView`が`UserController`にも依存しているところです。理由は、本家はMVC1を前提としていますが、Webフレームワークなどで使われているMVC2に寄せたほうが理解がしやすいと判断したためです。このあたりは[『クリーンアーキテクチャの Presenter が分かりにくいのは MVC 2 じゃないから』](https://qiita.com/os1ma/items/c02af5b7783b58165c8d)という記事に解説があります。

## コード

実際のコードです。簡単な説明がコメント行に入っています。

```swift:クリーンアーキテクチャーのコード
// 【Frameworks & Drivers】アプリケーションフレームワークやドライバなど実装の詳細にあたる部分

// DB ORMやDAOなどDBとのやり取りをするAPI。このサンプルでは何もしない
class SomeDB {
    static func executeQuery(sql: String, bindParam: [String]) {
        // Dummy ここで実際にユーザーを登録する
    }
}

// UI　UIKitやRailsの表示部分など画面表示をするためのAPI
class SomeView {
    var userController: UserController
    var viewModel: UserCreateViewModel

    init(userController: UserController, viewModel: UserCreateViewModel) {
        self.userController = userController
        self.viewModel = viewModel
        self.viewModel.bind { userName in
            print("登録：" + userName + "さん")
        }
    }
    
    func start(){
        userController.createUser(userName: "test user")
    }
}

// 【Interface Adapters】Application Business RulesとFrameworks & Driversの型の相互変換

// Controllers 入力をUserCaseのために変換する（入力のための変換）
class UserController {
    var userCreateUseCase: UserCreateUseCaseInputPort
    
    init(userCreateUseCase: UserCreateUseCaseInputPort) {
        self.userCreateUseCase = userCreateUseCase
    }
    
    func createUser(userName: String) {
        let input = UserCreateInputData(userName: userName)
        userCreateUseCase.handle(input: input)
    }
}

// GateWays Frameworks & Driversからのデータを抽象化する
class UserDataAccess: UserDataAccessInterface {
    func save(user: UserEntity) {
        SomeDB.executeQuery(
            sql: "REPLACE INTO USER (USER_NAME) VALUES (?) ",
            bindParam: [user.userName]
        )
    }
}

// Presenters データをViewに適した加工する（出力のための変換）
class UserCreatePresenter: UserCreateUseCaseOutputPort {
    var viewModel: UserCreateViewModel

    init(viewModel: UserCreateViewModel) {
        self.viewModel = viewModel
    }

    func complete(output: UserCreateOutputData) {
        let userName = output.userName
        self.viewModel.update(userName: userName)
    }
}

class UserCreateViewModel {
    typealias CallBackType = (String)->Void
    var userName: String
    var callBack: CallBackType?
    init(userName: String) {
        self.userName = userName
    }
    
    func bind(callBack: @escaping CallBackType) {
        self.callBack = callBack
    }
     
    func update(userName: String) {
        self.userName = userName
        self.callBack?(userName)
    }
}

// 【Application Business Rules】 アプリケーションのビジネスルール

// UseCaseと上位層との遣り取りをするためのオブジェクト
protocol UserDataAccessInterface {
    func save(user: UserEntity)
}

protocol UserCreateUseCaseOutputPort { // Output Boundaryともいう
    func complete(output: UserCreateOutputData)
}

struct UserCreateInputData {
    var userName: String
}

struct UserCreateOutputData {
    var userName: String
}

// Use Cases ユースケースを表す
protocol UserCreateUseCaseInputPort {  // Input Boundaryともいう
    func handle(input: UserCreateInputData)
}

class UserCreateInteractor: UserCreateUseCaseInputPort {
    var userDataAccess: UserDataAccess
    var presenter: UserCreateUseCaseOutputPort
    init(userDataAccess: UserDataAccess, presenter: UserCreateUseCaseOutputPort) {
        self.userDataAccess = userDataAccess
        self.presenter = presenter
    }

    func handle(input: UserCreateInputData) {
        let userName = input.userName
        
        let user = UserEntity(userName: userName)
        userDataAccess.save(user: user)
        
        let output = UserCreateOutputData(userName: user.userName)
        presenter.complete(output: output)
    }
}

// 【Enterprise Business Rules】 ドメイン層
// Entities ビジネスルールをカプセル化したもの
struct UserEntity {
    var userName: String
}

// Entry Point　このサンプルの実行開始ポイント
let viewModel = UserCreateViewModel(userName: "")
let userDataAccess = UserDataAccess()
let presenter = UserCreatePresenter(viewModel: viewModel)
let useCase = UserCreateInteractor(userDataAccess: userDataAccess, presenter: presenter)
let userController = UserController(userCreateUseCase: useCase)
var ui = SomeView(userController: userController, viewModel: viewModel)

ui.start()
```

## まとめ

短い、といいながら140行ほどになってしまいました。また、なるべく簡単にするために`userName`だけを持つ`class`ばかりとなってしまい、それぞれの`class`の必要性がつかみにくくなってしまったのが残念です。

コードと図を書いていて気がついたのは、`UseCase`が依存するインターフェースはすべて`UseCase`と同じレイヤーに配置されているということです。このあたりに[依存性逆転の原則](https://ja.wikipedia.org/wiki/%E4%BE%9D%E5%AD%98%E6%80%A7%E9%80%86%E8%BB%A2%E3%81%AE%E5%8E%9F%E5%89%87)がしっかり守られていると感じました。