- 講演資料:Eight iOSを支えるアーキテクチャ
複雑な問題を単純な問題の群として切り分ける
「Eight」は、取り込んだ名刺の情報からビジネスネットワークを構築できる個人向け名刺アプリだ。名刺撮影や連絡先の管理、知り合いの最新情報を把握できるフィード、アプリをさらに便利に利用できる有料サービス「Eightプレミアム」など、多くの機能を持つ。そのため、画面に表示すべき“状態”の種類も多い。アプリ開発において、複雑な状態をうまく管理するには設計が重要である。
「本発表では、設計を『関心の分離によって、複雑な問題を単純な問題の群として切り分けること』と定義します。『Eight』の一機能である『フォローしているアカウントの一覧画面』を例に、関心の分離について説明します」(河辺氏)
この画面では、サーバーからフォローしているアカウントのリストを取得し、人物情報を扱うEntityにParseして、取得した情報をキャッシュに保存してからViewに表示する。このままでは問題が複雑であるため、コードも複雑になりかねない。そこで、この機能における関心ごとを整理すると、下図のように4つに分割できる。
これはつまり、適切な設計を行うことで、複雑だった問題を単純な問題に切り分けられたということだ。
設計をする際に役立つのが設計パターン(デザインパターン)だ。設計パターンを知ることで、再利用性の高い柔軟な設計ができ、かつ開発者同士の意思疎通が容易になる。iOS版の「Eight」ではMVVMパターンを採用している。これは、非同期処理を抽象化するために用いられているRxSwiftのbinding機構を、最大限に生かせるためだ。
MVVMパターンでは「View(ViewController)」「ViewModel」「Model」の3つが相互にやりとりをして処理を行う。各層の関心ごとをまとめると、以下の通りとなる。
View
すべきこと
- UIを定義する
- ViewModelにUIEventsを伝える
- ViewModelから受け取ったデータを反映する
すべきでないこと
- プレゼンテーションロジックを定義する
- 通信やデータ操作を行う
ViewModel
すべきこと
- UIEventsを監視し、Modelに処理を依頼する
- Modelから受け取ったデータをViewで利用するのに最適な形に加工する
すべきでないこと
- UIを定義する
- 通信やデータ操作を行う
Model
すべきこと
- データ構造を定義する
- データを永続化する
- データを操作する
すべきでないこと
- UIを定義する
- データをViewで利用するのに最適な形に加工する
シンプルなコードを実現するための設計ノウハウ
iOS版「Eight」では、ModelをさらにEntity、Repository、Request、UseCaseの4つに細分化している。それぞれが担う役割は以下の通りだ。
Entity
- データ構造を定義する構造体
Repository
- EntityのCRUD操作を提供する
- SQLiteやUserDefaults等のDataSourceを隠蔽
Request
- HTTPRequestを投げる処理を定義する
UseCase
- ビジネスロジックを記述する
河辺氏は前述の「フォローしているアカウントの一覧画面」を例に、各層がどのように動作しているかをサンプルコードとともに解説した(河辺氏が説明に使用したコードはこちらのスライドに掲載されている。興味を持たれた方はぜひ参照してほしい)。
まず、Entityでは構造体を用いてデータを定義する。一覧画面ではフォローしているアカウントのリストを表示するため、FollowingPersonという名前で構造体を作成し、Viewで表示するために必要なデータを持たせる。
次に、Requestでは「Responseの型(先ほどEntityで定義したFollowingPersonの配列)」「HTTP Method」「HTTP Methodを投げるPath」「Responseを受け取った際の処理」を定義する。RepositoryではProtocol(Interface)にCRUD操作のメソッドを定義し、実装クラスにCRUD操作の実処理を書いていく。
UseCaseでは先ほど定義したEntityやRepository、Requestを使ってビジネスロジックの記述を行う。このクラスでは、具体型ではなく抽象に依存するように実装し、Initializerで依存性を注入する。依存関係逆転の原則を適用し、変化しやすい具象ではなく安定した抽象に依存することで、変化に強い設計としているのだ。クラスの外から必要なものを注入することで、モックの差し込みが容易となりテストしやすいコードとなる。
ViewModelでは、Viewで表示するために必要なEntityを公開プロパティとして定義する。そして、「ViewからUI Eventを取得する」「Event受け取り時にModelに対して処理の依頼を行う」などの役割も担う。
Viewでは、画面起動のEventを通知する処理を行う。また、「ViewModelにEventを伝える」「ViewModelからデータを受け取りViewにデータを反映させる」などの処理もこのクラスが行っている。
「このように、iOS版『Eight』ではMVVMパターンを採用し、各層のすべきこと・すべきできないことを明確にして実装しています。また、変化しやすい具象への依存は避けて抽象へ依存することで、変化に強い設計をつくり上げているのです」
河辺氏は最後にこのように語り、本セッションを締めくくった。
お問い合わせ
Sansan株式会社