メインコンテンツへスキップ

ArcBlock Android App アーキテクチャ紹介

ArcBlock
AndroidArcBlock

現在 ArcBlock Android App が採用しているのは、コンポーネント化 + MVP の基本アーキテクチャです。以下では2つの部分に分けてそれぞれを紹介します。

Why コンポーネント化?

なぜコンポーネント化を使うのか?フロントエンド開発全体を見渡すと、コンポーネント化開発の思想は各フレームワークに深く浸透しており、フロントエンドの2つの著名なフレームワーク React、Vue はその最も成功した代表例です。

コンポーネント化の核心思想は、複雑なアプリケーションを異なるモジュールに分割し、各モジュールをできるだけ「高凝集、低結合」にすることで、コンポーネントの再利用性、柔軟性を高め、最終的に開発効率の向上を助けることです。

自分が以前手がけた App プロジェクトを分析すると、頭の中ですぐに App をコンポーネント化する構想が浮かびます:

  1. コア業務機能コンポーネント
  2. ログイン登録コンポーネント
  3. パーソナルセンターコンポーネント
  4. プッシュコンポーネント
  5. ……

コンポーネント化は、コードをより良く設計・組織化するのに役立ちます。これは、コードをより明確にするために、異なる業務モジュールのコードを異なるパッケージ名の下に配置する目的と同じです。ただ、コンポーネント化はこれをさらに一歩進めてくれます。

最も汎用的なログイン登録コンポーネントを例に取ると、開発設計の初期段階でこのコンポーネントを単独で開発し、その後依存の形でホスト App に使用させる。これはコード量の面では実際には以前すべてのモジュールを一括りにして開発していたのと大きな違いはありませんが、知らず知らずのうちに以下の2点を実現してくれています:

  1. 特定の機能モジュールの高凝集、低結合を保つ
  2. 機能モジュールの再利用性を高める

会社にフロントエンド App が一つしかないということは大いにあり得ないでしょう。この時、コンポーネント化の優位性が現れてきます。もしある日上司が、製品の方向性を素早く調整する必要があり、既存の A 製品をベースに素早く B 製品を開発してほしいと言ったとしましょう。コア業務モジュール以外、ログイン登録、パーソナルセンターなどのモジュールは A 製品と一致させる、という場合です。

この時、「半日かけて以前のコードをコピーして修正すれば同じことじゃないか」と疑問に思うかもしれません。コピーは簡単ですが、メンテナンスこそが最も頭を悩ませる問題です。なぜなら、コピーの形を採用すると、後々2つ以上のまったく同じコードを維持しなければならなくなり、それは間違いなく災難だからです。

コンポーネント化の実施は早ければ早いほど良いです。古いプロジェクトでコンポーネント化方案を試みる労力は、新たにラインを起こしてコンポーネント化されたバージョンを開発するのに劣らないほどです。ですから、コンポーネント化の様々な利点をすでに理解しているのであれば、プロジェクト開始の初期段階で完全で拡張可能なコンポーネント化アーキテクチャを構築するのが最善です。

私たちはまさにそうしました!下図は ArcBlock Android App 全体のアーキテクチャ図です:

Android App FrameWork Design Image

Why MVP?

なぜ MVP アーキテクチャを使用するのか?まず MVP がそれぞれ何を指すのかを見てみましょう:

js
MVP = Model + View + Presenter

MVP と言えば、MVC のアーキテクチャに触れないわけにはいきません。MVP が流行する以前、MVC は間違いなく最も人気のある Android 技術フレームワークでした。

Android の初期の MVC フレームワークの時代、Activity と Fragment のこの層は基本的に ViewController という2つの役割を担っていました。この方式の利点は、問題を特定する際に比較的便利なことで、基本的にどのページで問題が起きたかがわかれば、直接そのページに行って探せば良いというものです。しかし欠点も明らかで、簡単なページであれば良いのですが、業務がやや複雑なコードであれば、クラス全体のコード量が非常に膨大になり、後から加わったメンテナンス担当者が耐えられなくなってしまいます。

MVC Image

View と Model の様々な交差的な相互呼び出しも一つの隠れた問題であり、デバッグとテストの両方に困難をもたらしました。

次に MVP の呼び出し関係を見てみましょう:

MVC Image

2つの重要なポイント:

  1. View が Model を変更させたい場合、必ず Presenter に通知して実現させる必要があります。
  2. Model が View を更新したい場合も、必ず Presenter に通知して実現させる必要があります。

このようなモードは、View と Model が互いに変更し合う状況、つまり上記の MVC における View と Controller の相互呼び出しの状況を隔離します。

Android の MVP アーキテクチャの思想は、React Flux フレームワークの単方向データフローの思想といくつか似ている点があります。Flux では、以下のいくつかの役割があります:

  1. Action: View が発行するアクション
  2. Dispatcher: Action を受け取り分配して Store を更新する役割
  3. Store: ページのレンダリングに使用するために View が呼び出すデータを保存する役割
  4. View: ビューモジュール

MVC Image

View の更新は Store に依存し、Store の更新は Dispatcher が Action を分配することに依存します。View は Store を直接変更することは許されません。

Android MVP の Presenter の役割は Flux における Dispatcher の役割と類似しており、どちらも View と Model(または Store)の交差的な相互作用を断ち切り、データフローのロジックをよりシンプルで明確にすることを目的としています。

さらに、Android App が MVP フレームワークを採用した後は、ユニットテストも簡単になります。核心的なロジックはすべて各ページの Presenter の中にあるため、テストの重点をそこに置くだけで済みます。一方、Activity と Fragment は View のレンダリングを担当し、Model はデータのやり取りを担当するというように、分業が明確で、構造がすっきりしています。