Help us understand the problem. What is going on with this article?

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

More than 1 year has passed since last update.

はじめに

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

アーキテクチャとは?

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

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

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

アーキテクチャのご紹介

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

MVC (Model View Controller)

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

iOS_Architecture_CocoaMVC.png

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

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

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

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

iOS_Architecture_MVC.png

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

MVP (Model View Presenter)

iOS_Architecture_MVP.png

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

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

MVVM (Model View ViewModel)

iOS_Architecture_MVVM.png

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

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

iOSでは、データバインディングを実現するために、リアクティブプログラミング(RP)を実装したフレームワークであるRxSwiftReactiveSwiftなどのライブラリが使われますが、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
※ 画像はThe Clean Code Blogを参考

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

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

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

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

VIPER

iOS_Architecture_VIPER_banner.jpeg
※ 画像はiOS Project Architecture: Using VIPERより引用

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

iOS_Architecture_VIPER.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というコード生成ツールを活用すれば必要なファイルを適切な構成で作成できます。

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

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

iOS_Architecture_AdoptionRatio.png
iOS_Architecture_AdoptionTransition.png

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

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

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

まとめ

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

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

参考

navitime_tech
株式会社ナビタイムジャパンの技術に関する情報を発信します。 ※ご意見、お問い合わせは公式サイト (https://www.navitime.co.jp/) からお願いします。
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away