TL;DR
PoC(検証)のための新規iOSアプリ開発で、iOSアプリ開発初心者がアーキテクチャにMVPを採用した理由と、MVPを実装するする上で気づいたことを共有するものです。
結論
- アーキテクチャの検討に当たっては、①開発要件に合うものの中で、②経験があるor経験がなくても最も理解しやすそうな、設計パターンをサクッと決定するのがよさそうです
- MVPのアーキテクチャパターンにおいては、プレゼンテーションロジックの分離が重要で、その際に活用できるのがProtocol
この記事の効能
- 新規のiOSアプリ開発でアーキテクチャを決定する一助になるかもしれません
- MVPの実装において筆者が大切だと思った、「プレゼンテーションロジックの分離」について理解が深められます
MVPの選定
手順
今回はデザイナーさんが作成してくださったワイヤーフレームがあったのでそれを参考にしながら行いました
- 開発する画面を列挙する
- 各画面や画面間で管理する状態を書き出す
- 上記のステップでまとめた開発要件を元に設計パターンを考える
- 管理すべき状態
- 画面をまたぐもの
- セッション(ログイン)情報
- サインアップ画面
- IDとパスワードが不正の状態(validationに利用)
- カート画面
- カート内のアイテム
- 合計金額
etc.
今回の前提条件
a. ページ間にまたがる状態はログインの有無だけで、状態管理が複雑でない
b. 検証用のiOSアプリで1+α人程度での小規模な開発
c. 開発者はiOSアプリ開発初心者
選択肢
MVC, MVP, MVVM, Flux, Redux
上記の全てについて一通り把握し検討を行いましたが、前提条件のaにあるように複雑な状態管理がないことから、MVCとMVPに絞りました。また他の設計パターンでは、導入に当たって外部のライブラリを使用すべきであったことも選定対象から外れた理由となりました。(例:MVVMにおけるRxSwiftなど)
MVCとMVPの2つの中から選定した理由としては、①決済などテストすべき項目を扱うためテストしやすい方がいい、②MVCから発展したものだからMVPの方が使いやすい(はず)になります。
アーキテクチャパターン選定のまとめ
結構時間をかけて真剣に設計パターンの検討を行いましたが、後から見返すとやってみないと分からないことも多いなと思います。また、実際に開発を進めて考えていく中でやっと理解が進むものもあります。結論として、アーキテクチャの検討に当たっては、①開発要件に合うものの中で、②経験があるor経験がなくても最も理解しやすそうな、設計パターンをサクッと決定してしまうことが良さそうかなと思っています。(BFFの設計も考えたことがあり、その経験も踏まえて。)
今回に関して言うと、ページをまたがる複雑な状態管理が必要なく、少人数での開発という開発要件で、比較的単純な(だと感じた)MVPを採用しました。
MVPにおけるプレゼンテーションロジック分離の重要性
MVPについて
MVPの中にも、データの流れによってPassive ViewとSupervising Controllerという2つの方式があります。
Passive ViewはViewとModelのデータのやり取りにおいて必ずPresenterを経由するもので、データの流れが理解しやすく、全てのプレゼンテーションロジックのテストが可能です。一方でSupervising Controllerは、Model→Viewの流れにおいて、更新の通知により変更を知らせることができ、Presenterを挟まない分冗長なデータの流れを回避することができます。
今回は、テストが容易な点と開発の簡潔な点を重視してPassive Viewを採用しました。
それぞれの詳しい図解と解説は以下の記事が分かりやすかったです。(ただ、Supervising Controllerについては以下の記事ではData bindingになっていますが、参考文献のようにオブザーバー同期を使うものもあります)
StackOverFlowの「MVPとMVCの違い」についての回答を読んでみた
Passive Viewにおける各コンポーネントの役割
コンポーネント | 役割 |
---|---|
Model | コマンドを受けて自身を更新(Presenterからのみアクセスされ、Viewとは直接の関わりをもちません) |
View | ユーザーの入力を受け、Presenterに伝える(Presenterからの描画指示に従うだけで、完全に受け身な立ち位置になります) |
Presenter | ViewからのコマンドをModelに送る・Modelからの変更を受け取り、Viewを更新(すべてのプレゼンテーションロジックを受けもちます) |
(参考文献より) |
補足:プレゼンテーションロジックとは
「View(ユーザーの入力など)やModel(データの変更など)の変更から、画面の更新・遷移を行うロジックのこと」
Protocolの活用によるプレゼンテーションロジックの分離
実装している中で、プレゼンテーションロジックがViewに紛れていることに気付きました。今回はiOSアプリでよく用いられるViewControllerというファイルにViewの役割を持たせたのですが、ViewControllerのファイルの中に直接プレゼンテーションロジックを書き込んでいたのです。これはひとえに、各コンポーネントの役割を完全に理解できていなかったことが原因であると考えます。そこで以下の記事を見つけ、Protocolの活用法に気づくと共に、リファクタを行なってプレゼンテーションロジックをViewControllerから取り除きました。
MVP VS MVVM in iOS using swift
実装に当たっては、上記の記事よりもPresenterの役割が分かりやすいコードがあったのでそちらを参考にしました。
以下が参考にしたコードです。(参考文献で扱われているコードです。)
ポイントは、protocolの定義において、ユーザーからの入力(SearchUserPresenterInput)と、画面更新・遷移(SearchUserPresenterOutput)を分けて行うことで、それぞれの役割を明確にしている部分です。
MVPにおいてPresenterを実装するということ
簡単なことではありますが、気づくのに時間がかかったポイントを挙げます。
**「全てのプレゼンテーションロジックを受けもつPresenterを実装する」**ということは、
- プレゼンテーションロジックは全てPresenterから呼び出されるべき(=Viewが呼び出すことはなく、また当然Viewに直接プレゼンテーションロジックを記述することもない)
- ユーザーからの入力はInputProtocol、画面の描画はOutputProtocolで定義し、OutputProtocolの実装自体はViewControllerで継承して行うのがよい
ということであると理解しました。
(追記)この記事にいただいたご質問・ご意見
MVPは難しくないの?
参考文献では、MVCの責務を再分割したもの(MVCの三要素を60°回転したもの)であると言及されていたため、そこまで複雑なものではないと考えていました。
また以下の記事でも、MVVMやReduxと比べれば、規模を小さく開発できると考えられます。
手を動かしてMVPパターンを体験する
自分としては、記事で説明したようにPresenterを正しく理解できないなどのポイントはあるものの、小規模開発にも適したパターンであると考えます。今回、iOSアプリ開発が初めてであったことを考えると、MVC(Cocoa MVC)の習得にも学習コストは存在するので、MVPとそれほど差異はないのではないかと考えています。
MVCとの違いは?
MVCに対するMVPの利点として挙げられるのは、テストの容易性と作業分担のしやすさになります。これはPresenterという役割を作り、プレゼンテーションロジックを取り出したことによるものかと思われます。
特にPassive Viewの場合は、データの流れが単一なので実装に迷うことがないというメリットもあると、実装する中で感じました。
AndroidにもMVPはある?
あるようです。
Architecture of Android Apps
また、Androidには公式のアーキテクチャガイドがあるようで、素敵だなと思いました。
アプリ アーキテクチャ ガイド
参考
iOSアプリ設計パターン入門
iOSアプリ開発に限らず、設計パターンを学びたい方に損得抜きで強くおすすめです。歴史的経緯も含めた設計パターンの丁寧な解説、さらに各設計パターンのサンプルコードで構成されています。