中規模Androidアプリ開発の過程に生じた問題と対策の紹介
Upcoming SlideShare
Loading in...5
×
 

中規模Androidアプリ開発の過程に生じた問題と対策の紹介

on

  • 10,858 views

 

Statistics

Views

Total Views
10,858
Views on SlideShare
8,742
Embed Views
2,116

Actions

Likes
12
Downloads
26
Comments
0

11 Embeds 2,116

http://nil-one.jp 1924
http://nil-one.com 91
http://localhost 55
https://twitter.com 32
http://nilone.lolipop.jp 6
http://www.nil-one.com 2
http://192.168.33.10 2
http://www.nil-one.jp 1
http://74.207.252.251 1
http://jenkins.nil-one.com 1
http://twitter.com 1
More...

Accessibility

Categories

Upload Details

Uploaded via as Apple Keynote

Usage Rights

© All Rights Reserved

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Processing…
Post Comment
Edit your comment
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n

中規模Androidアプリ開発の過程に生じた問題と対策の紹介 中規模Androidアプリ開発の過程に生じた問題と対策の紹介 Presentation Transcript

  • NilOne中規模Androidアプリ開発の過程に生じた問題と対策の紹介 NilOne Ltd. http://nil-one.jp/ contact@nil-one.com
  • 本書の内容 弊社(NilOne)が中規模(10人月程度)のAndroidアプリ(ソーシャルゲーム)開発を通し て直面した問題と、それを解決するために行った対策を紹介します。これを読んだ方が同様の 問題に直面した際の解決の糸口になれば幸いです。 直面した問題の発生原因は大きく分けて以下の2つですので、何れかに該当する方は本書の内 容が参考になる可能性が高いです。 開発対象のアプリの規模が大きくなっていったこと 端末のローカルDB(SQLite)を活用したこと h※Androidアプリを対象にしていますが、iOSアプリであっても同様の問題に直面した場合にと るべき対策の方向性は同じになると思います。※本書では行った対策の概要を示すだけに留めています。紹介しているツールの具体的な設定方 法などは各ツールのHP等を参考にしてください。※図を簡略化するため、端末とサーバとの通信の際に行う双方向の認証などの詳細ステップは省 略しています。 NilOne
  • 会社紹介社名 NilOne Ltd.設立 2011年4月1日代表 窪田豊事業 iOS,Androidアプリ制作(制作の依頼を承っています)ML contact@nil-one.comHP http://nil-one.jp/紹介 RadialMenuというスマートフォン向けの新しいメニューUIのデモアプリ (Android)を公開しました。(Google Play「RadialMenu」ページ) h NilOne View slide
  • 開発効率向上編∼効率良く品質の高いアプリを開発する NilOne View slide
  • プロジェクトの分割 問題 Eclipse上に作成したのAndroidプロジェクトの規模(サイズ)が大きくなるにつれ、ビルド や端末への転送時間が長くなり開発効率が落ちていく。 対策 Androidプロジェクトをまとまった機能(画面)単位に切り出す。 解説 サイズが大きくなったAndroidプロジェクトをまとまった機能単位で切り出し、新たにプロ ジェクトを作成します(図中AppA∼AppC)。こうすることで、その時の開発対象の機能を h 保持したプロジェクトのみをビルドや転送の対象にすることが可能になり、プロジェクト全体 の規模増大による開発効率の低下を防ぐことができます。この時、切り出し元のプロジェクト は各プロジェクトの共通機能置き場として使用するため、外部ライブラリ化して各プロジェク トから参照します。 外部ライブラリ プロジェクト 共通機能は を分割 各機能をプ App Appに集約 ロジェクトにし サイズが大 て切り出しきくなったタイ ミングで App AppA AppB AppC NilOne
  • プロジェクトの分割 解説(つづき) 結合テストなどのアプリの全体の流れを確認する必要のある段階になったら、切り出したプロ ジェクトを全て外部ライブラリ化し、全てのプロジェクトを統合するプロジェクト(図中 AppAll)を新たに作成してそこに集約します。 外部ライブラリ 外部ライブラリ 外部ライブラ App リ化する App 外部ライブラリ 外部ライブラリ 外部ライブラリ AppA AppB AppC AppA AppB AppC h 全てを統合す るプロジェクト AppAll を作成参考) Android Developers「Managing Projects from Eclipse with ADT」 (Androidプロジェクトを外部ライブラリ化する方法が記載されています。) NilOne
  • 単体テスト 問題 開発中の機能の動作確認をするために、端末にアプリを転送しなければならないため時間が かかる。 単体テストでの動作確認を試みたが、Android標準の単体テストツールは端末へア プリを転送する必要があるため問題の解決にはならないし、Eclipse上で単体テスト用のJava プロジェクトを用意し実行しても、テスト対象にAndroidSDKのコードが含まれていると 「java.lang.RuntimeException: Stub!」という例外が発生し実行できない。 対策 Android用単体テストツールのRobolectoricを使用してEclipse上で単体テストを行う。 解説 h AndroidSDKのコードはDalvik仮想マシンで動作させることを前提として開発されているた め、JVM環境で動作させようとすると上記の例外が発生してしまいます。これを解決するた めに、AndroidSDKのコードをインターセプトして、JVM環境でも例外が発生しないように するツールであるRobolectricを使用します。 NilOne
  • 単体テスト 解説(つづき) Robolectricを使用して単体テストを行うにはAndroidSDK、Robolectric、JUnitのjarにパス を通したJavaプロジェクト(図中AppTest)を作成し、その中に単体テスト用のコードを書き JUnitとして実行します。 単体テスト用の AppTest Javaプロジェクトを 作成 h App参考) Robolectric NilOne
  • DIコンテナ 問題 開発中UIの動作確認のため、UIに対して実データを供給するコード(以降、本番用コード)と ダミーデータを供給するコード(以降、スタブ)の切り替えを行いたいが、切り替える箇所ごと にコードを修正する必要があるため時間がかかる。 対策 DIコンテナを使用し、本番用コードとスタブの切り替えを一箇所で行う。 解説 例えばUserというオブジェクトの一覧を表示するListViewを開発している場合、使用するオ h ブジェクトに、静的に作成したダミーのUserオブジェクトと、サーバから得たデータを基に 構築したUserオブジェクトとを、様々な場面(画面レイアウト変更時やバグ発生時など)に おいて切り替えたい場合があります。 供給 実データ User1 User1 この2つを ListView 簡単に切り替え User2 ダミーデータ たい User3 DummyUser1 NilOne
  • DIコンテナ 解説(つづき) その場合には、RoboGuiceというAndroid用のDIコンテナを使用し、本番用コードとスタブ を一箇所で切り替えます。この例の場合には、データを供給するコードのインターフェースを 定義し、その実装として本番用コードとスタブの2つを作成します。 データの 供給を担う実装 のインター DataProvider フェース ダミーデータ 実データを供給 を供給する する DataProviderの h 実装クラス DataProviderImpl DataProviderStub UIの実装はDataProviderインターフェースに対して行い、そのインターフェースに対する実 装(DataProviderImplとDataProviderStub)の切り替えをRoboGuiceの機能を使用して 行います。 このような設計にすることで、DataProviderImplに対する単体テストがやりや すくなるという大きなメリットもできます。参考) Roboguice NilOne
  • ローカルDB活用編∼サーバの運用コストを抑えつつ運用を容易にする NilOne
  • SQLiteの活用 問題 サーバの運用コストが、アプリから得た収益を吸収してしまう。 対策 必要最低限のデータ(他のユーザと共有する必要のあるデータなど)のみサーバで管理し、 それ以外のデータ(マスターデータやユーザデータ)は端末のローカルDBで管理すること で、サーバの運用コストを下げる。 解説 サーバの運用コストを下げるために有効なのは、端末とサーバとの通信回数と通信1回当りの h データ量をできる限り少なくすることで、そのために端末のローカルDB(SQLiteを使用) を最大限に活用します。 ただ、このような構成にした場合、次ページ以降に記載したいくつ かの問題が発生します。 共有データ の送信 端末 サーバ マスターデータ 共有データ ユーザデータ の受信 共有データ NilOne
  • SQLiteの暗号化 問題 root化された端末を所持している悪意のあるユーザにSQLiteの内容を改ざんされる 可能性がある。 対策 SQLiteを暗号化する。 解説 アプリで使用するSQLiteは、一般の権限を持つ他のアプリやユーザ(図中一般ユーザ)からは 読み書きできないようにすることができますが、root化された端末(図中rootユーザ)におい h ては読み書きができてしまいます。これを防ぐために、SQLCipherという暗号化ツールを使用 してSQLiteの内容を全て暗号化します。 一般ユーザ rootユーザ 一般ユーザ rootユーザ 暗号化 le! ! ! cessib ac ut block block b le! essibl e! unr eadab acc S SQLite ?SQLite? NilOne
  • SQLiteの暗号化 解説 ここで注意が必要なのは、何かしらのORMライブラリを使用している場合で、そのライブラリ とSQLCipherの組み合わせが正常に動作するかを確認する必要があります。弊社の場合は、 「ORMLite」というORMライブラリを使用していましたが、SQLCipherと組み合わせて使用 するために「ORMLite」のソースコードを少しだけ修正する必要がありました。参考) SQLCipher ORMLite h NilOne
  • SQLiteファイルをサーバへ送信 問題 各ユーザ固有のデータ(ユーザデータ)をSQLiteで管理するようにした場合、アプリ全体の利 用状況を把握できない。 対策 一定のタイミングで端末がSQLiteをサーバへ送信し、サーバはそれを集計する仕組みを作る。 解説 ユーザデータを管理するDBは個々の端末に存在しているため、運用者からはアプリ全体の利用 状況を把握できません。これを解決するために、端末から一定の間隔でサーバに対してSQLite h のファイルを送り、サーバでは受け取ったSQLiteの中身を集計する仕組みを作ります。 集計 端末 SQLite サーバA SQLite SQLite SQLite SQLite SQLite SQLite SQLite SQLite SQLite 一定の間隔 サーバB でSQLiteを 送信 集計データ NilOne
  • SQLiteファイルをサーバへ送信 解説 これにより、(リアルタイムではないですが)アプリ全体の利用状況は把握できます。 また、 この対策を取ることにより、ユーザがSQLiteを何らかの原因により破損した場合に、(バック アップがサーバ側に保管されているため)復旧してあげるサポートをとることが出来るように なります。 ※「結局、送信されたSQLiteを保管しておく領域や集計のためのサーバを用意する必要がある じゃないか」という意見があるかもしれませんが、少なくてもこれらのサーバが障害で動かな くなったとしても直接的にサービスに影響しないため、運用コストは下がります。 h NilOne
  • トランザクション 問題 SQLiteとサーバのデータを同時に更新する処理が途中で失敗した場合、端末(SQLite)と サーバ間でデータの不整合が起きてしまう。 対策 SQLiteとサーバの更新を1つのDBトランザクション内で行う。 解説 例えば複数のユーザで構成される「チーム」がある場合、あるユーザがそのチームに参加した という情報はユーザ自身とチームメンバーが知る必要があるため、SQLiteとサーバの両方を更 h 新します。この時、SQLiteの更新は成功したがサーバの更新は失敗した場合、SQLiteではそ のユーザはチームに属していることになっているが、サーバではそうなっていないという不整 合が起きてしまいます。 ②更新失敗 端末とサーバ間 端末 サーバ でデータの不整合 ①更新成功 が起きる SQLite × NilOne
  • トランザクション 解説(つづき) これを防ぐために、サーバの更新が失敗した場合はSQLiteの更新は反映させない(ロールバッ ク)ようにする必要があり、これを実現するためこれら2つの処理を1つのDBトランザク ション内で行います。 ここで注意が必要なのは、SQLiteの更新をサーバの更新より前に行うことです。これが逆に なってしまうと、サーバの更新は成功しSQLiteの更新が失敗した場合に、サーバの更新はロー ルバックされないため、不整合の状態が発生してしまいます。 h NilOne
  • マスターデータの更新 問題 端末にマスターデータがあるため、更新が難しい。 対策 ①アプリをアップデートする 。 ②サーバーから間接的にマスターデータを更新する。 解説 ゲームのマスターデータをサーバで管理している場合は、サーバのDBを更新すれば良いです が、端末(SQLite)で管理している場合は①、②のどちらかの方法を行う必要があります。 h ①はマスターデータを修正する場合はアプリをアップデートするという対策ですが、マスター データの更新毎に、ユーザはアプリアップデートする必要が出てきてしまい、ユーザにストレ スを与えてしまいます。 NilOne
  • マスターデータの更新 解説 ②は端末がサーバからマスターデータ更新用のデータを受信し、端末がそのデータを使用して マスターデータを更新するという対策です。①とは異なり、ユーザにストレスを与えずにマス ターデータの更新を行えますが、ある程度の開発コストを要します。 ①更新用デー タの存在チェッ ク 端末 サーバ 更新用データ h (SQL相当) マスターデータ ②更新用データ ユーザデータ の受信 ③更新用データを使用してマスターデー タを更新 上記の対応以外に、端末側でマスターデータとユーザデータでSQLiteのファイルを分ければ、 マスターデータの更新はサーバからダウンロードしたマスターデータのSQLiteのファイルを更 新するだけで済むのですが、マスターデータとユーザデータをまたがったクエリを発行できな くなりパフォーマンスと開発効率が悪くなるため、弊社では上記の構成を取りました。 NilOne
  • おわりに以上で本書の内容は終了です。記載した内容(問題に対する対策)は、弊社が試行錯誤する過程で見出したものですが、更によい対策があると思っているので、お気づきの方はぜひご連絡ください。iOSやAndroidアプリではあまり品質が高くないものが多く見られますが、その原因の1つにスマートフォンアプリ特有の設計方法が確立されていない(情報がまり出回っていない)ことがあるのではと考え、本書を公開するに至りました。本書が少しでも品質の高いアプリ制作のための参考になれば幸いです。 NilOne Ltd. 代表 窪田豊 h NilOne