現場で選ばれているiOSアーキテクチャ

## はじめに

ナビタイムジャパンでは、アプリの継続的な開発・運用をスムーズに行うために「設計」を重視しています。本記事では、その「設計」を実現するアーキテクチャをいくつか紹介し、実際に現場で使われているアーキテクチャについて考察していきたいと思います。

### アーキテクチャとは？

アーキテクチャとは、アプリを綺麗に開発・継続的に運用していくための設計方法です。この設計方法を考えずに開発すると以下の問題点が発生してしまいます。

* クラスが肥大化し、コードを追いにくくなる
* ロジックの煩雑化、再利用性の低下
* チーム開発における役割分担がしにくい
* 属人化が進み、引き継ぎにくい
* テストがしにくい
* 機能の追加、改修が困難
* etc…

チームでのアプリ開発はもちろん、個人でアプリを開発する時も、開発するアプリに規模や特性に合わせて適切にアーキテクチャを選ぶことが、アプリを継続的に開発・運用していく上で非常に重要です。ただし、アーキテクチャは手段に過ぎず、固執することなく常に設計について考えることが大切です。

## アーキテクチャのご紹介

どのようなアーキテクチャがあって、どのように選べばいいのかをご紹介していきます。

### MVC (Model View Controller)

iOS開発において、`MVC`というとAppleが推奨している`Cocoa MVC`が一般的です。

![iOS_Architecture_CocoaMVC.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/315364/c8a3d032-84ee-14b6-18a1-6c05378c1da8.png)

`Cocoa MVC`では`View`がユーザーの入力を受け付け、`Controller`にアクションを渡します。そして`Controller`が`Model`にデータの更新を依頼します。最後に`Model`が`Controller`に処理の完了を通知し、`Controller`が`View`を更新します。

* `View`：表示、入出力
* `Controller`：入力にもとづく`Model`と`View`の制御
* `Model`：データの保持、通信、ビジネスロジック

`Cocoa MVC`は`UIKit`をそのまま素直に使えば簡単に実装できますが、`Controller`が`View`と密結合しており、`View`のライフサイクルにも影響されるため、テストは容易ではありません。また、`Controller`は`View`と`Model`の仲介を行うので、処理が集中しがちで肥大化しやすいです。このため`Massive View controller`と言われることもあります。

ところで、`Cocoa MVC`はAppleによって改良されたもので、原初の`MVC`とは構造が異なります。原初`MVC`は元々`SmallTalk`という元祖オブジェクト指向のプログラミング言語の開発環境のために考案されたデザインパターンです。

![iOS_Architecture_MVC.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/315364/74b8b840-e68e-a0a1-0034-dcff3a396ba7.png)

`Cocoa MVC`では`Controller`が`View`と`Model`を分離し仲介を行いますが、原初`MVC`では`Model`が`View`に通知し、`View`が`Model`の更新された状態を取得して表示を更新するというオブザーバパターンを採用しています。このため`View`と`Model`の間に依存関係が生じてしまい、`View`で表示用にデータを加工することも必要になります。

### MVP (Model View Presenter)

![iOS_Architecture_MVP.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/315364/9f056aca-4050-7e65-6646-90f81c622a98.png)

`MVP`は`View`と`Model`、そして両者を仲介し、プレゼンテーションロジック（UIのビジネスロジック）を担当する`Presenter`で構成されるアーキテクチャです。`MVC`とは異なり、入力を受け付けるのが`Controller`ではなく`View`になり、`MVP`では`UIViewController`は`View`に分類されます。このため`Presenter`は`View`のライフサイクルやレイアウトに依存せずに、プレゼンテーションロジックのみ担当し、`import UIKit`が必要ありません。また、`View`と`Presenter`はデリゲートやインターフェイスを通してやり取りを行うため、`View`のモックがしやすく、`Presenter`のテストが容易になります。

`MVP`には`Supervising Controller`と`Passive View`の2種類があり、前者の`Supervising Controller`ではデータバインディングにより`View`が`Model`を監視し、データ更新があれば表示も更新します（上図の`View`と`Model`にデータバインディングの関係が追加されます）。`View`が`Model`を監視することで、データを加工せずにそのまま表示するシーンでは、`Presneter`の負担を軽減できますが、`Model`が`View`のレイアウトに依存してしまいます。一方、後者の`Passive View`では、`View`と`Model`のやり取りは全て`Presenter`を介しますので、`View`と`Model`が完全に分離されますが、その分`Presenter`の負担が増えてしまいます（これは`Cocoa MVC`での`Controller`に似ています）。

### MVVM (Model View ViewModel)

![iOS_Architecture_MVVM.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/315364/a417c745-5189-bece-2db3-00f1552d75d7.png)

`MVVM`は元々Microsoftの`WPF (Windows Presentation Foundation)`および`Silverlight`アーキテクチャです。`MVP`と似ていますが、`MVP`ではデリゲートやインターフェイスで処理を移譲・更新処理を行うのに対して、`MVVM`ではデータバインディングで`View`と`ViewModel`を紐付けます。

データバインディングでは、イベントを発行・購読することで、直接的な依存関係がなくても、アクションに対応した処理を行って表示を更新することができます。データバインディングは`MVP (Supervising Controller)`での監視よりもさらに密な考え方で、UIとデータオブジェクトを紐付けて、同一のデータをやり取りできるようにしています。双方向データバインディングでは、UIを変更すればデータも書き換えられ、データが更新されればUIも変更されます。

iOSでは、データバインディングを実現するために、リアクティブプログラミング(`RP`)を実装したフレームワークである`RxSwift`や`ReactiveSwift`などのライブラリが使われますが、`RP`の習得コストが高く、個人開発者はともかくチームで開発する場合は、全員が`RP`について理解していることが必要のため、簡単に導入できないというデメリットがあります。

### Clean Architecture

ここまで紹介してきた`MVC`, `MVP`, `MVVM`はGUIアーキテクチャと呼ばれるもので、UIに関するロジック（プレゼンテーション）とシステムに関するビジネスロジック（ドメイン）を分離する※のが目的です。しかし、プレゼンテーション層から分離されたロジックに関するルールはないため、サーバ通信やデータの永続化などのロジックは全て`Model`に詰め込まれ肥大化してしまいます。
※`Presentation Domain Separation（PDS）`

一方、`Clean Architecture`はシステムアーキテクチャと呼ばれ、UIだけに止まらず、システム全体の構造を示すものです。`Clean Architecture`ではドメイン駆動開発（`DDD`）やユースケース駆動開発（`UCDD`）を意識して、ビジネスロジックをUIやフレームワークから引き離して、それぞれの層ごとに役割と責任を分離しています。

![iOS_Architecture_CleanArchitecture.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/315364/1c719ea8-c2b3-4283-9266-b69dcbda9605.png)
※ 画像は[The Clean Code Blog](https://blog.cleancoder.com/uncle-bob/2012/08/13/the-clean-architecture.html)を参考

`Clean Architecture`は以下の層で構成され、中心には変化の少ないドメインを、外側には変化の激しい層を配置し、中心に向かって一方向の依存性しか持ちません。

* フレームワーク・ドライバ
	* DB、UI、デバイス、Web
* インターフェイスアダプター
	* Gateway、Presenter、Controller
* アプリ固有のデータ・ロジック
	* Use Case
* アプリ非依存のデータ・ロジック
	* Entity

`Clean Architecture`はシステム全体の構造を、各層に役割と責任を持たせて整理していることから、特定のフレームワークやライブラリに依存しません。また、各層に分割したことでUIやデータの保存処理が頻繁に変化してもビジネスロジックには影響しなく、全ての層でテストを導入することもコストが低いです。

このように、`Clean Architecture`は変更に強く、再利用可能で、テストもできるため、「Clean」なアーキテクチャです。しかし、層が多くなるため必然的にコード量が多くなってしまい、プロトタイプや小規模なアプリケーション開発にはあまり向いていませんが、一定規模以上のプロダクトで効力を発揮します。

### VIPER

![iOS_Architecture_VIPER_banner.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/315364/3a899f86-e76f-f2a1-8895-a14f4d6f6690.jpeg)
※ 画像は[iOS Project Architecture: Using VIPER](https://cheesecakelabs.com/blog/ios-project-architecture-using-viper/)より引用

`VIPER`は上で述べた`Clean Architecture`をiOS向けに再設計したアーキテクチャです。もちろん`Clean Architecture`がもとになっているので、システムアーキテクチャであり、単一責任の原則にもとづいて各層を分割し責任を持たせています。`View, Interactor, Presenter, Entity, Router`の頭文字を取って`VIPER`と呼びます。また、`VIPER`では各層でプロトコルを定義し、それに準拠して実装することでテストも行いやすいです。

![iOS_Architecture_VIPER.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/315364/4b0e76b0-ebf1-4fb1-41d3-c6a1b13e2d02.png)

* `Router`
	* 「画面遷移」と「依存関係の解決」を担当
	* `View`が画面遷移まで担当する必要がなくなる
* `View`
	* `UIView` & `UIViewController`
	* 「画面の更新」と「`Presenter`へのイベント通知」を担当
* `Presenter`
	* `View`から受け取ったイベントをもとに「プレゼンテーションロジック」を担当
	* `View`に画面の更新を依頼
	* `Interactor`にデータの取得を依頼
	* `Router`に画面遷移を依頼
	* `import UIKit`禁止
* `Interactor`
	* 「データに関するロジック」を担当
	* データ取得が完了したらデリゲート経由で`Presenter`に返す
	* `import UIKit`禁止
* `Entity`
	* 「データ構造の定義」を担当
	* `struct`でデータを定義
	* `Interactor`のみアクセス可
	* `import UIKit`禁止

`VIPER`では役割を細かく分割するため、ファイル構成もやや複雑になってしまうが、[Generamba](https://github.com/strongself/Generamba)というコード生成ツールを活用すれば必要なファイルを適切な構成で作成できます。

## 現場で選ばれているアーキテクチャ

ここまでiOSの代表的なアーキテクチャについて紹介してきましたが、では実際の現場ではどのアーキテクチャが選ばれているのか、社内のアプリを対象にアンケートを取りました。以下がその結果です。

![iOS_Architecture_AdoptionRatio.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/315364/096898dc-153a-3d35-2540-92b06a2c3ce8.png)
![iOS_Architecture_AdoptionTransition.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/315364/e12af560-ee98-a5d6-a004-28d6ee5d6164.png)

`MVC`と`MVP`がそれぞれ約3割ずつを占めており、`MVVM`が約2割弱、少数派として`VIPER`やその他のアーキテクチャがありました。実際、数年前に開発が始まったアプリでは`MVC`が多く、3年以内の新規アプリやリニューアルしたアプリでは`MVP`や`MVVM`、`VIPER`などのアーキテクチャが採用されています。その背景として、アジャイル開発やテスト自動化の重視が考えられ、よりテストがしやすく、しっかりと役割分担ができ、継続的な開発を支えるために適切なアーキテクチャが選ばれています。

`MVVM`よりも`MVP`が選ばれているのは、上でも述べた通り、データバインディングの学習コストが高いため、比較的導入がしやすく、かつテストも行いやすいからです。また、`MVP+Clean Architecture`や`MVP+Coordinator`など、`MVP`に＋αしてGUIアーキテクチャの弱点を補うような使い方もあります。また、`MVVM`では`RxSwift`などのデータバインディングライブラリを使うと、ライブラリへの依存性が生じてしまうので、ステータス監視でノーバインディングな使い方もあります。

`VIPER`を選ぶアプリもありますが、厳密な分割が必要で、学習コストもやや高いため、実際には`MVP`や`MVVM`が多く選ばれている傾向があります。

## まとめ

本記事では、iOS開発でよく話に上がるアーキテクチャを紹介し、実際の現場で選ばれているアーキテクチャについて考察をしてきました。近年のアジャイル開発やテスト自動化の潮流に合わせて、選べれるアーキテクチャに変化が見られます。しかし、導入にともなう学習コストやアプリの規模との相性も関係し、「これを選べば正解」なアーキテクチャはなく、プロジェクトのメンバーやプロダクトの規模に合わせて、適切なアーキテクチャを選ぶべきと言えます。

また、冒頭でアーキテクチャは「アプリを綺麗に開発・継続的に運用していくための設計方法」だと述べましたが、アーキテクチャはあくまで手段に過ぎず、使い方を間違えても、それに囚われすぎてもダメで、常に「設計」を意識しながら、適切にアーキテクチャを活用していくことが重要です。

## 参考
* [Model-View-Controller](https://developer.apple.com/library/archive/documentation/General/Conceptual/DevPedia-CocoaCore/MVC.html)
* [【完全保存版！】iOSエンジニアとして働く上で知っておきたい14のこと](https://techacademy.jp/magazine/11766)
* [iOSアプリ設計大全集 2016](https://qiita.com/tattn/items/d4b95af0b60c3849243a)
* [iOSをMVC,MVP,MVVM,Clean Architectureで実装してみた](https://medium.com/@rockname/clean-archirecture-7be37f34c943)
* [Webアプリケーション開発者から見た、MVCとMVP、そしてMVVMの違い](https://qiita.com/shinkuFencer/items/f2651073fb71416b6cd7)
*  [StackOverFlowの「MVPとMVCの違い」についての回答を読んでみた](https://qiita.com/takahirom/items/597c48ece57b4623cdee) 
* [怖くないiOSでのMVVM](https://medium.com/@r.izumita/怖くないiosでのmvvm-f3530cdc0216)
*  [まだMVC,MVP,MVVMで消耗してるの？ iOS Clean Architectureについて - Qiita](https://qiita.com/koutalou/items/07a4f9cf51a2d13e4cdc#domain-layer)
* [iOS Clean Architecture - 騒音のない世界 BLOG](http://noiselessworld.hatenablog.jp/entry/ios-clean-architecture)
* [iOS Project Architecture :  Using VIPER 和訳 - Qiita](https://qiita.com/YKEI_mrn/items/67735d8ebc9a83fffd29)
* [VIPERアーキテクチャ まとめ - Qiita](https://qiita.com/hicka04/items/09534b5daffec33b2bec)