はじめに
近年、iOSやAndroid向けのアプリケーション開発が盛んに行われ、これまでWebが中心であったソーシャルアプリ開発も、徐々にブラウザの枠を超えたところに手を伸ばしつつあります。ソーシャルアプリ開発のプロジェクトは、多くの場合、スモールスタートで始まりますが、開発を続けていくにつれて、コードが増え、端末が増え、人が増え、気がつけば、機能を実現するための実装と関係ない部分でのタスクが膨れあがっていきます。そんなコストを技術的に解決するためのしくみがあれば、もっと本質的な部分に時間を割くことができるはずです。
今回は、CI(継続的インテグレーション)ツールのJenkinsと内製のQA向けダウンロードツール、コードレビューツールのGerritを組み合わせた、継続的な開発をサポートするしくみ作りについて、ミクシィでのAndroidアプリケーション開発の事例を取り上げてご紹介します。
1人で始める継続的アプリ開発
mixiのAndroid向けクライアントアプリケーション開発は、メイン開発者である筆者と、デザイナー1名、企画者1名の3人で始まった、企画も開発も品質管理もノウハウのない状態からスタートしたプロジェクトです。あらかじめ決まった仕様やデザインはなく、期間の余裕がないなかプロトタイピングを繰り返しながら形にしなければならない一方で、単発ではない継続的な開発が予想されるアプリケーションとして、未来を見据えた構成が求められていました。
開発をめぐる状況は厳しいものでしたが、逆にしがらみを気にしないで一からアプリ開発のしくみを作る機会でもありました。そこで筆者は、ひとまず状況を整理し、可能な限り無駄を減らし、集中可能な環境を作るところから手を付けました。ここから、アジャイル開発に関する書籍を漁り、テスト駆動開発や、ベロシティを用いた工数予測など、良さそうなノウハウをつまみ食いする形で「1人アジャイル開発」を始めたのです。
開発が始まったころ、Jenkins(図1)というオープンソースの継続的インテグレーション(CI:Continuous Integration)ツールが話題になっていたので、さっそくAndroid開発におけるCIツールとして使用することにしました。
Jenkinsはプラグインが充実しており、Android Emulator Pluginを使えば、Android開発の自動ビルド&テスト環境を比較的手軽に構築できます。これにより、Subversionのリポジトリにコードをコミットすると、自動的にビルドが始まり、テストが実行され、結果が残る環境が整いました。手元でのテスト実行を忘れがちな自分でも、コミットするだけでリグレッションにすぐ気づくので、開発後期になって「実はマージミスで不具合が発生していた」といった状況に陥ることはありませんでした。
また、Jenkinsを覗けば常にプロジェクトの成果物が見えるため、開発者以外の人も簡単に開発の状況を確認できます。「実際に動かすことができる」プログラムが常に存在しているという認識を関係者間で共有できれば、開発の進捗について不必要に不安を持たれたり、進捗に関する話で割り込まれたりといった問題を最小限に抑えることができます。
複数の環境を一度にテスト
さらにJenkinsを活用して、さまざまなAndroidのバージョン、画面解像度、言語を掛け合わせたテスト実行環境を用意しました。これはJenkinsのMatrix Projectで構築できます(図2)。
ちょうどAndroid 2.3がリリースされたころ、新しいAndroid SDKをビルド環境に導入後、意気揚々とターゲットを追加してビルドを実行したところ、勢いよくテストが失敗したことがありました。Android本体で用いられているライブラリに変更があり、一部機能の互換性が失われていたのが原因でした。アプリにとっては致命的な不具合であったため、修正を行い、「Android 2.3対応」というアップデートをリリースしたのですが、リリース後、マーケットのレビューで「まだ日本では2.3対応の端末が出てないだろ」と突っ込まれてしまいました。新しい環境にもそれだけのスピードで対応できるということです。
独自ツールによるQAテストの効率改善
Jenkinsのおかげもあり、開発者が増えても開発そのものはスムーズに進みました。しかし、QAテストの段階で問題が起こりました。当初は、テスト担当者が各自のマシンでビルドを行い、検証用の端末にインストールしてテストしていましたが、複数人でこの作業を行うと「1人が修正したはずの不具合が、もう1人のビルドではなおっていない」という状況が発生したのです。
このため、テスト対象のビルドはすべてJenkins上で行うよう一本化し、同時に、JenkinsのAPIを用いて、現在有効なビルドの一覧と「ダウンロード、インストールされているビルドがどのビルドなのか」を判別できる検証用ツールを実装しました(図3)。
このツールの登場によって、前述の混乱がなくなったほか、ビルドに何らかの更新が発生してからQA担当者が修正確認を開始できるようになるまでの待ち時間がなくなりました。もともと、修正のたびに端末を持って人が行き来していたのですが、これも不要となりました。さらに、任意のバージョンをダウンロードして、アップデートした際の挙動を確認するといったことも簡単にできるようになりました。
コードレビューの効率化
開発者が1人増えた時点で、新しく学んだ知識や気づいたことを社内Wikiにまとめてもらったので、以降の環境構築やコーディングルール作成などはそれをベースとして進めましたが、既存コードを全部把握するには相当な時間がかかるため、コードレビューでそれを補いつつ細かいポリシーを適宜作り上げていくことにしました。しかし、レビューという仕事は開発後期にはボトルネックとなりがちです。本当は全員でペアプログラミングが実施できるとよかったのですが、なかなか踏み出せないまま、結局すぐに2人目のレビュアが誕生してマンパワーで解決する形となりました。それでも、自分で書いた場所以外のレビューにはやはり時間がかかることが多く、不安になります。良い手段はないだろうか、と考えていたころ、別の方面から「ソース管理のリポジトリをGitにしよう」という話が転がり込んできました。
そこで筆者たちは、Gitを導入するならばと、ツールも一新して、複数人でレビューできるしくみを考えることにしました。そのために目を付けたのがAndroidオープンソースプロジェクト(AOSP)で使われているGerritですEclipseのGit設定にもGerritサポートが含まれているなど、すでに使用しているツールとの全体的な統合が望めそうなのも決め手となりました。
Gerritの導入とJenkinsとの連携
Gerritは、オープンソースのGit向けレビューシステムで、AOSPのコードレビューのために作られました。デフォルトでログインユーザ全員がレビューを行えるようになっており、コードに行単位でコメントを書くこともできるため、細かい指摘も手軽にできます。また、レビューからリポジトリへのマージまでをWeb上で実行できます(図4)。
Gerritにおいて特徴的なのは、ReviewとVerifyという2つの概念が存在することです。Reviewはその名のとおりコードレビューを、Verifyは「コードのマージが正しく実行され、動作するかどうか」を指しており、デフォルトではこの2つに付けられたスコアがそれぞれ一定以上にならないとコードがマージできないようになっています。さらに、この2つのほかに独自のフラグを設定することもでき、たとえばEclipseのGerritでは、IP-Cleanという「知的財産権を侵害していないかどうか確認済み」フラグを持ったもののみがマージ可能、という設定がなされています。Review、Verify、その他のスコア付けの権限は、ユーザやグループ単位で管理することができ、たとえばReviewedフラグを立てられるのはReviewerグループに所属するメンバーだけ、といった設定を行うことができます。
小規模な開発チームとしては、Verifyは機械に任せてしまいたいところです。そこでJenkinsとの連携を考えます。Jenkinsには、Gerritのストリームを監視して、pushされたコードのビルドを自動的に行い、結果を報告するGerrit Trigger Pluginというプラグインがあります。この結果をVerifyに反映するよう設定すれば、Verifyの自動化が実現できます(図5)。
これによって、作業の終わったコードをGerritへpushするだけで、レビュー用のチケットが作成され、Jenkinsによってビルドされ、テストが通ることを確認できるので、それをレビュアがレビューするというフローができあがりました(図6)。さらに、これらの状況はGerritbotを利用して、すべてIRCに流すようにしました。「レビューしてよ」や「レビュー終わってマージしたよ」という情報がすべて自動で送られるため、チケットが来たのに気づかずスルーしてしまうことがなくなりました。
Gerritによって、複数人でのレビューや突っ込みがしやすくなったほか、マスターのリポジトリに対する変更手続きが1ヵ所に集約されたことで、マージそのものがレビューされないという問題もなくなりました。結果的にほとんどAOSPと同様のしくみになりつつあるため、Android本体の開発者にとっては、すぐに馴染める環境となっています。
開発プロセスもリファクタしよう
本稿では、ミクシィでのAndroidプロジェクトの開発プロセスとそこで使っているツールについてご紹介しました。最近では、弊社iOSプロジェクトでもJenkinsやGerritが試用されています。2012年の今日、スマートフォンアプリ開発は珍しいことではなくなりましたが、その開発プロセスにおけるデファクトスタンダードはまだ確立されていないように思います。プラットフォームそのものがまだ枯れ切ってない状況なので、その上で展開される開発プロセスもまだまだこれから成熟していく過程にあると考えています。
しかし、繰り返し作業を積極的に機械化していくことは、どんな場合でも有益です。「コードをコミットしたあとでテストする」という作業は、手動で行っていると絶対に忘れることがあります。「レビューのためにチケットを書く」という細かい作業も、見えづらいものですが確実に時間を消費しています。1人では小さく見積りがちな雑務も、100人規模のプロジェクトであれば100倍の時間を無駄にしていることになるのです。
筆者たちは、コードと同様プロジェクトそのものも、ツールを積極的に活用しながらボトルネックを見つけてはつぶすことで、常にリファクタリングできると考えています。本稿がみなさんの参考になれば幸いです。