リファクタリングから始めるiOS Clean Architecture (Presentation層＆Usecase)

[株式会社LITALICO](http://litalico.co.jp/)でアプリエンジニア（iOS/Rails）を担当しています、shuyuheyです。
『[LITALICO Advent Calendar 2016](http://qiita.com/advent-calendar/2016/litalico)』7日目の記事です。

# まえがき
このエントリでは、iOSアプリをリファクタリングしながら、徐々にClean Architectureを適用していく過程で気づいたことをまとめます。
まだまだリファクタリングは途中ですし、アーキテクチャ適用の中でも手探りな部分がありますので、ご意見を頂けますと大変嬉しいです！

# 当初のアプリの状態
当初のアプリでは、次のようにロジックがまとめられていました。

  - Managers
    - サーバAPIへアクセスする
    - レスポンスをModelへパースする
    - パースしたModelの一部を、インスタンス変数で管理する
    - シングルトンとして実装
  - Model
    - JSONオブジェクトの変換先
    - Himotokiで実装
  - ViewControllers
    - 表示の際のロジックはすべてViewControllerにまとめてある

例えば、ユーザの情報を表示する画面の処理の流れは次のとおりです。

 1. `UserViewController`が`UserManager.shared`のユーザ情報取得メソッドを呼び出す
 2. `UserManager`はサーバにAPIリクエストし、コールバックで`UserModel`を返す
 3. `UserViewController`は`UserModel`を使って、画面にユーザ情報を表示する

![image](https://qiita-image-store.s3.amazonaws.com/0/56528/8137d96c-928a-1765-1122-734600443529.png)


一見、流れとしては良いように見えます。しかし、この時の実装では、`ViewController`にビジネスロジックが集中していたほか、データは`Manager`が管理していたりと、オブジェクトの責務がはっきりしていませんでした。そのため、機能を追加するときにどこにロジックを書くべきか、都度悩んでいました。
また、ゆくゆくはテストを書いていきたいので、オブジェクト間のインタフェースは出来る限りシンプルにしたい。
そこで、その2つの要求を満たす、Clean Architectureを選択しました。

Clean Architecture については、以下の記事を参考にしています。このエントリでは、Clean Architectureの説明はあまりしませんので、気になる方はこの記事を読んでみてください。

- [まだMVC,MVP,MVVMで消耗してるの？ iOS Clean Architectureについて](http://qiita.com/koutalou/items/07a4f9cf51a2d13e4cdc)
- [持続可能な開発を目指す ~ ドメイン・ユースケース駆動（クリーンアーキテクチャ） + 単方向に制限した処理 + FRP](http://qiita.com/kondei/items/41c28674c1bfd4156186)


# リファクタリングから始める

さあやってみようと思いたちましたが、前述の課題以外にも細かい問題が当初のアプリにはありました。経緯は割愛しますが、とにかく`ViewController`に継ぎ足し継ぎ足しでロジックが追加されていたり、1つの`Manager`に依存している`ViewController`の数が多いことも有り、一気に適用するとおそらくかなり多くの機能がデグレするだろうな、という感覚がありました。

そこで、リファクタリングでロジックを分割していきながら、できる範囲でちょっとずつClean Architectureを適用してく戦略を取りました。

適用していく順番としては次のような順序です。

1. `Model`を`Entity`にリネーム
2. `ViewController`から表示用ロジックを`Presenter`に分離
3. `ViewController`および`Presenter`からビジネスロジックを`UseCase`に分離
    - この時点で`ViewController`と`Presenter`は`Manager`に依存していない状態を目指す
4. `Translator`を実装し、`Entity`を`Model`に変換する
    - この時点で`ViewController`は`Entity`に依存していない状態を目指す
    - また、`Model`固有の表示/ビジネスロジックは`Model`に移す
5. `Repository`を実装し、`UseCase`と`Manager`の結合を疎にする
6. `Manager`を`DataStore`に変更、`DataStore`を`Entity`ごとに分離

次節からは、それぞれの適用タイミングで感じたこと、気づきをまとめていきます。なお、現時点では4の途中まで手を付けていますので、今回は3までの示唆を書いていきます。

## `Presenter`の実装
はじめは、とにかく愚直に分離をしていきました。しかし、そのうちかなり冗長な記述をしてしまっているのではないか？と感じるようになりました。これなんかすごいやり過ぎ感が溢れていますね。これを`Presenter`に実装しようとしていました。

```swift
func numberOfSectionsInCollectionView() -> Int {		
    if haveForYouContent {		
       return 2		
    }		
    return 1		
}
```

また、`TableViewController`で、表示する`Entity`によって使う`Cell`を変更する、というロジックは表示ロジックではありますが、`Presenter`に分離する程のものかな？など、どんどん疑問が増えはじめ早くもリファクタリングがしんどくなり始めていました。そこで、再度考え直し、`Presenter`は実装しないことにしてみました。

Clean Architectureにおける`Presenter`は、`Controller`とセットで考えられます。`Controller`は、`View`からのイベント（ボタンのタップやテキストの入力）をうけとり、`UseCase`へと通知します。`UseCase`は、その結果を`Presenter`を通じて、`View`に反映します。　

![image](https://qiita-image-store.s3.amazonaws.com/0/56528/a4aa53ef-7282-b73d-4994-bfa43882fc11.png)


iOSにおいては、その両方の役目をそもそも`ViewController`というクラスが担当しており、そこから更にロジックを分離しようとしてしまうと、自信を持って責務を切り分けることが出来ず、冗長な記述をしてしまったり、結局`ViewController`からきれいにロジックが分離されなくなると思いました。

![image](https://qiita-image-store.s3.amazonaws.com/0/56528/03582eb7-7cd6-0d02-7943-8f42d29c348a.png)

そこで、`ViewController`の中で、`Presenter`に当たるロジックと`Controller`に当たるロジックを分離するために`extension`を使うことにしました。

後述の`UseCase`の実装で詳しく説明をしますが、`Controller`の責務に当たるビジネスロジックの呼び出しは、`UseCaseInputProtocol`を実装したインスタンスのメソッド呼び出しで実現し、`Presenter`の責務に当たる結果の受取と描画は`UseCase`から`UseCaseOutputProtocol`を実装した`ViewController`のメソッドを呼び出してもらうことにしました。

つまり、`ViewController`は、次のように記述されることになります。

```swift
class ViewController: UIViewController {
    var useCase: UserUseCaseInputProtocol = UseCase()

    override func viewDidLoad() {
        useCase.output = self
        useCase.getUser()
    }
}

extension ViewController: UserUseCaseOutputProtocol {
    func onSuccess(user: UserModel) {
        // 表示の処理
    }
}
```

これで、`Controller`の責務に当たる処理と、`Presenter`の責務に当たる処理を切り分けることができるので、どこにロジックを書くべきか、という点については迷いがなくなります。


## 3. `UseCase`の実装

前述したように、`Presenter`は、クラスとして実装するのはやめたので、`ViewController`からロジックを分離していきます。

`UseCase`は、次のように実装していきました。　

```swift
protocol UserUseCaseInputProtocol {
    var output: UserUseCaseOutputProtocol? { get set }
    func getUser()
}

protocol UserUseCaseOutputProtocol {
    func onSuccess(user: UserModel)
}

class UserUseCase: UserUseCaseInputProtocol {
    var output: UserUseCaseOutputProtocol?

    func getUser() {
        // 取得処理
        output.onSuccess(user: user)
    }
}
```

最初のうちはこれで良さそうだったのですが、リソースごとに`UseCase`をまとめようとしてしまうと`ViewController`によっては、使用しないメソッドを実装する必要がでてくるようになりました。

例えば、`UserUseCase`が、ユーザ情報の取得・更新などをするとします。すると、取得だけをすればいい画面でも`UserUseCase`を利用しようとすると、更新用のメソッドも実装する必要が出てきてしまいます。

そこで、`UseCase`は、アクションごとに`protocol`を分けることにしました。

```
protocol GetUserUseCaseInputProtocol {
    var getOutput: GetUserUseCaseOutputProtocol? { get set }
    func getUser()
}

protocol GetUserUseCaseOutputProtocol {
    func onSuccess(updated user: UserModel)
}

protocol UpdateUserUseCaseInputProtocol {
    var updateOutput: UpdateUserUseCaseOutputProtocol? { get set }
    func updateUser(user: UserModel)
}

protocol UpdateUseCaseOutputProtocol {
    func onSuccess(updated user: UserModel)
}

class UserUseCase {
    var getOutput: GetUseCaseOutputProtocol?
    var updateOutput: UpdateUseCaseOutputProtocol?
}

extension UserUseCase: GetUserUseCaseInputPtorocol {
    func getUser() {
        // 取得処理
        output.onSuccess(user: user)
    }
}

extension UserUseCase: UpdateUserUseCaseInputPtorocol {
    func updateUser(user: UserModel) {
        // 更新処理
        output.onSuccess(updated: user)
    }
}

```

これで、利用する`ViewController`は必要なアクションに応じた`UseCase`を利用できるようになりました。

`ViewController`で使うときは次のようになります。


```swift
class ViewController: UIViewController {
    var useCase: GetUserUseCaseInputProtocol = UseCase()

    override func viewDidLoad() {
        useCase.getOutput = self
        useCase.getUser()
    }
}

extension ViewController: GetUserUseCaseOutputProtocol {
    func onSuccess(user: UserModel) {
        // 表示の処理
    }
}
```

また、更新処理も合わせて利用する場合は、次のように書くことが出来ます。使うアクションを`Protocol`で分けることによって、useCaseの宣言時に、この`ViewController`がどのような操作をリソースに対して行うのかを宣言することができるので、見通しが良くなったと感じています。

```swift
class ViewController: UIViewController {
    var useCase: protocol<GetUserUseCaseInputProtocol, UpdateUserUseCaseInputProtocol> = UseCase()

    override func viewDidLoad() {
        useCase.getOutput = self
        useCase.updateOutput = self
        useCase.getUser()
    }
}

extension ViewController: GetUserUseCaseOutputProtocol {
    func onSuccess(user: UserModel) {
        // 表示の処理
    }
}

extension ViewController: UpdateUserUseCaseOutputProtocol {
    func onSuccess(updated user: UserModel) {
        // 表示の処理
    }
}
```

今回は触れませんでしたが、テストを書く際に、`Protocol`を分けたことでモックの実装がしやすかったという効果もありました。テストについてはまた別の機会に書きたいと思います。

# まとめ

適用の目標としては、まだ半分の手順も出来ていませんが、ここまでの示唆をまとめてみました。
リファクタリングをちょっとずつやり始めてから4ヶ月ほどで、ほとんどの`ViewController`から`Manager`が取り除かれつつありますが、まだまだ先は長いなという印象です。

ただし、徐々にアーキテクチャを適用していくことで、コードのロジックが分散しにくくなっているな、という感覚があります。新しい機能を追加するときに、アーキテクチャに沿って実装していくためとっちらかりにくいのだと思います。

アプリのアーキテクチャを変更するのは、結構コストが大きいですが、リファクタリングの過程で、順序を決めてじわじわ適用していくと、比較的低コストでやっていけるのではないかと思います。

次回は、[litalico-takamasa-mizukami](http://qiita.com/litalico-takamasa-mizukami)がKotlinについて書くみたいです！よろしくお願いします！