俺的Androidアプリ開発の基本方針 ver 2016.Q3

# 前提

@eaglesakura が務めているTopgate社は受託案件が多いので、この方針が絶対ではない。受注元によっては好き放題できるし、受注元によっては条件が厳しくなる。

また、弊社のAndroidアプリ開発は1人～数人で行われることが多い。そのため、この方針は更に大規模な開発では通用しない可能性があることも承知している。

その辺りは [以前の記事](http://qiita.com/eaglesakura/items/3f552dc5971d39fa9466) でも書いたとおり。

ここに書いた方針はその時々の状況（公式ツールやSupport Library、流行り廃り）によって変化する。が、こういう構成になったのはその時時の理由があるわけなので、明文化することで後々「なぜこういう構成にしなければならなかったのか」ということを思い出せるようにもしておきたい。

# 環境整備

## ソースコード管理

制限が無いのであれば、githubで管理する。githubのissueはRedmineに比べると機能的に不十分である（特に期限が設定できないことと、ガントチャート化できないこと）が、重複した管理(github + Redmine)は管理コスト増加やミスを誘発するので、githubのissueを適度に使うこととしている。

期限の設定、特に「今日やること」「早めに対応すること」については専用タグ `Next` 等を用意することで対応している。

## コーディング規約

基本的にAOSP規約を使用する。

メンバ変数頭に`m`をつけたり（ハンガリアン記法的）なあたりでだいぶ論争が起きているが、ありがたいことにこれは「AndroidのFrameworkで使われている記法」なのである。なので、複数の協力会社とアプリを開発する際に、「Androidの基本なのでAOSPで」という強い力で投下でき、規約を統一しやすい。

複数会社の社内規約に従うと、IDEの設定やフォーマッタの差分でひどい目に遭うので、統一しやすいことは正義である。

ちなみに個人的なことを言えば、ハンガリアン基本でもそうでなくても統一さえしてくれればそれで良いと思ってる（更に限定的なことを言えば、常にIDEを使ってコードを読むとも限らないので、頭に`m`をつけてくれるとそれはそれで助かることも多い）

## gitは基本的にコマンドラインで扱う

DIFF等のグラフィカルな方が良い場合を除き、基本的にコマンドラインから操作する。

コマンドを代行してくれるGUIツールは沢山あるが、使うと大抵の場合コメントの入力が適当になる、ignore忘れでのゴミファイルが混入するなどの弊害が大きい。

個人差が大きいので、gitに慣れているのであれば好きなツールを使うと良い。

## リポジトリ構成

リポジトリのrootに必ずrootとなるbuild.gradleを配置している。そのため、Android Studioでプロジェクトをimportするとgitにある全てのファイルがプロジェクトツリーの表示対象となる。

ASだけで全てのファイルを監視下におけるので、Explorer等の利用を最低限にできる。

# テスト

## テスト優先での開発

基本的に、コードの動作確認はUnit Testによって行われてから実機検証を行うべきだと思っている。特にファイル操作やDB等は手作業でチェックするよりもUnit Testを書いたほうがよっぽど動作確認がし易い。

ただし、全てのコードにテストを書いても骨が折れるという現実があるので、その辺のしきい値は開発者ごとに適度に任せる。

### ミスしたコードには可能な限りテストを追加する

Unit Testに合格していても、もしくは「このくらいならテストしなくても動くだろう」と思って実行しても、失敗するときは失敗する。考慮ミスは発生する。その場合、たとえ簡単な修正（ぬるぽチェックミスとか）であっても、テストパターンを追加する。

テストが増えることは、心の安息にも繋がる。

# 自動化基本方針

## 準備

**絶対にかつ最初に**UnitTestを行う準備だけは行う。

準備とは、例えば何も実態のないTestClass.javaが一つだけあり、かつ必ずテストが合格する状態を許容する。テストが無い状態は、心理的にも「テストを書かなくても良い」という状態を招きやすい。

また、最初に「CIによってテストが行われる」ことさえ保証しておけば、後々テストを増やしていく際の心理コストを最小限にできる。

```lang:java
// 最初はこんな感じでも、あとからコードを追加していくだけなのでそこそこ役立つ
class TestClass {
    @Test
    public void stub(){
    }
}
```

## ビルド自動化

自動ビルドはCircle CIで行う。クラウド上に環境が構築でき、かつ一般的な攻撃に対するセキュリティを我々開発者が気にする必要がない。正しく権限を設定すれば、正しい開発者にのみ環境が開放される。

毎日サーバーから送られてくるアクセスログやアラートに怯えずに済む。

ローカルPCに構築したJenkinsを使っても良い。メモリを潤沢に利用でき、もし何か問題が起こってもローカルPCにログインしてGUIとターミナルを駆使してメンテしてしまえばよいのだ。VirtualBox等のVM上に構築しておけば、環境を壊してもロールバックや物理的な引っ越しが楽に行える。

どちらを使うか、もしくは両方使うかはプロジェクトごとに適宜決めればいい。Circle CIでメモリ警告が出始めて、死ぬ気で使用メモリ量を調整したりメモリ量を毎度毎度増やしてもらうより、サクッとUnitTest用のローカルJenkinsを用意したほうが楽かもしれないぞ。

## JUnit4を利用する

古来からのAndroid Unit Test標準はJUnit3だったが、この頃は環境が整備されてきたので、JUnit4を使用したほうが書きやすい。

## 基本的にはPC Test側で行う

Androidアプリ開発ではPC上で行うUnitTestと端末上で行うUnitTestの2種類がある。前者はPC Test、後者はDevice Testと便宜上読んでいる。

PCで実行したほうがテストのビルドも実行も高速に行える。そのため、可能な限りPC Testが行えるようになる。設計は「Unit Testを行えること」を前提として、「可能な限りPC Testで行える」ように意識する。

Androidの機能に依存する部分はDIによって差し替える、テストデータを噛ませる等のテスタビリティを確保した代替案を考える。

それでも不可能ならばDevice Test側に行わせる。例えば、通信周りを確実にテストしたいならば、Device Testを行ったほうが良い。

## UIのUnitTestはCI必須ではない

UI周りのテスト環境は整備されているので、昔に比べたら気が狂いそうになることはない。ただし、CIで回そうと思うと途端にメンドウになる。エミュレータが毎度無事に起動してくれなかったり、何故かたまに失敗したり。

そして重要なビルド（納品前とか）に限って、ローカルPCで合格しているものがCIで謎のエラー（エミュレータ起動しないとか）になるというジンクスがある。これはただの恨み言である。

CIで実行されている場合、致命的なもの以外は合格にしてしまう、等は許容されると思っている。CIで実行されているか、開発マシンで実行しているかは、BuildConfig等に環境を書き込めば良い。

ちなみに、思い出話であるが、一時期Device Test用に専用機をつないでいた事があった。しかし、いつの間にか開発用端末としてUSBケーブルごと持ち去られていた。持ち去った奴はちゃんと元の場所に戻そうな。

# ライブラリ

便利なライブラリでも、導入する・しないは費用対効果を考えなければならない。費用とは「自分たちで開発した場合の開発期間」と「導入することでアプリが肥大化する量」を指す。

ただし、maven等のビルド済を配布していない場合についてはビルド成果物のみを含める等、可能な限りアプリの本質に関係のないソースコードをリポジトリに（submoduleを含めて）混入しないようにする。

## Multi Dexの可否

AndroidのMulti Dexは肥大化するアプリに対する最後の希望であると同時に、敵だ。ビルド時間の増大は開発のイテレーション（特にリリース直前、デスマ的案件）の精神状態を悪化させる。最悪の場合、1回のassembleに4~5分の時間を要する。

ビルドの度にコーヒーが淹れられるし、カップ麺も食えるだろう。

残念ながら、そこまで胃腸は強くない。

もしどうしても、Multi Dexが必要なのであれば、FacebookやTwitterをやる時間にでも充てよう。仲間とのふれあいは、心の平穏をもたらす有意義なものとなるだろう。ただし、それを実践することによってキミの席が無くならないということを、僕は保証できない。

しかし最悪の場合、金のチカラで全力で殴れば全ての問題は解決する。Money is JUSTICE!!（適当）

# 読んでおくと良い参考記事

特にAndroid系で開発を共にする人には一読しておいて欲しい参考記事たち。

 * 公式
    * [Android Developers Blog](http://android-developers.blogspot.jp/)
    * [Android/Fragment](https://developer.android.com/training/basics/fragments/index.html)
    * [Material Design](https://material.google.com/)
    * [Managing the Activity Lifecycle](https://developer.android.com/training/basics/activity-lifecycle/index.html)
 * 参考記事
    * [猿でも分かる! Dependency Injection: 依存性の注入](http://qiita.com/hshimo/items/1136087e1c6e5c5b0d9f)
    * [【Android】Fragmentを使うときのコツとか色々](http://qiita.com/HideMatsu/items/ddf640899cbe1b2027ed)
    * [Gitをインストールしたら真っ先にやっておくべき初期設定](http://qiita.com/wnoguchi/items/f7358a227dfe2640cce3)
    * [Android Studioの超高速コーディングを支える技術（テクニック）](http://qiita.com/yuya_presto/items/813c19513c2771815b28)
    * [Androidのプロセス間で大量データを連携する (Binder & Pipe)](http://qiita.com/arenahito/items/f232c22a6ebac1a215bc)
    * [gradle.propertiesに定義した値をAndroidManifest.xmlから参照する](http://qiita.com/shts/items/5a0ceab7334c5ad8f4f9)
    * [Androidの新しいGoogleサインインAPIについて](http://qiita.com/syarihu/items/1c67816ad926f08d76d8)
    * [控えめに言ってBindingAdapterが最高だからみんな使おうぜって話](http://qiita.com/tacksman/items/c99cefadcb7d2b4d9ef6)
    * [https://github.com/wasabeef/awesome-android-ui](https://github.com/wasabeef/awesome-android-ui)
 * 自分で書いたやつ
    * [脱Android Annotationsのために、onActivityResultの処理を楽にするライブラリを作った](http://qiita.com/eaglesakura/items/3900327d79bcdac34d91)
    * [小規模開発のgit-flowの導入を楽にするブランチルールと拡張スクリプト配布](http://qiita.com/eaglesakura/items/4fa17bf1f2b6683e6520)
    * [Eclipse+Ant勢にオススメする、Android Studio+Gradleに移行すると手に入る便利機能](http://qiita.com/eaglesakura/items/51ac46f08c5ec526cee4)
    * [Android案件を見積もる場合に考えておくことリスト](http://qiita.com/eaglesakura/items/3f552dc5971d39fa9466)
    * [さよならButterKnife. 僕はAPTの無いキミが好きだったよ](http://qiita.com/eaglesakura/items/7366886cfbbd5ba74cfe)
    * [楽で安全な非同期処理 / Androidアプリを開発する際の俺的設計](http://qiita.com/eaglesakura/items/8c96788012107ffcb7ab)
    * [Activity,Fragmentの分割と協調動作の具体例 / Androidアプリを開発する際の俺的設計](http://qiita.com/eaglesakura/items/2ab707755f5a504d9cf9)
    * [Daggerは嫌だが、DIは試してみたかった / Androidアプリを開発する際の俺的設計](http://qiita.com/eaglesakura/items/33bfc0eb65050826deeb)
 * ツール系
    * [svg2android](http://inloop.github.io/svg2android/)
        * SVGからAndroid用ベクタアセットに変換できる
        * importで崩れる場合は試してみる
        * それでもダメな場合はラスタライズする

# 最後に

Androidアプリ開発は楽しいぞ！