読者です 読者をやめる 読者になる 読者になる

クックパッドのiOSアプリ開発を加速させるスクリプト群

こんにちは、技術部モバイル基盤グループの茂呂(@slightair)です。

今回は、ちょっと地味ではありますが、クックパッドのiOSアプリ開発を支えているスクリプト群について書きたいと思います。

日々iOSアプリ開発を行うとすれば、Xcodeまたはその他のお気に入りのエディタでコードを書き、ビルドと実行を繰り返して開発を進め、アプリが完成したらサブミット、めでたくリリースという流れになると思います。 場合によってはこうした開発の所々をサポートするツールを使うこともあるでしょう。クックパッドでもいくつかのツールを使っていますし、場合によっては自作することもあります。

ツールを導入することで解決できることであればそれでよいですが、もうちょっと気の効いたことをして欲しい、リリースフローなど自分たちのアプリ開発の進め方の都合で発生する繰り返しタスクを省力化できないか、というような比較的小さな問題を解決するために、僕たちは今回紹介するようなスクリプトを用意しています。

開発支援系

アプリ開発を支援するスクリプト群を紹介します。

利用ツールのバージョンチェック

クックパッドのiOSアプリ開発では CocoaPods, Carthage, clang-format, SwiftLint, SwiftFormat などのツールを使っています。 数が多い上にこれらのツールの更新頻度はバラバラで、バージョンによって動きが違ったりします。複数人でアプリを開発しているので、環境によって期待している効果が得られないと困ってしまいます。そのため、各開発者の環境に期待しているバージョンがインストールされているかチェックするスクリプトを用意しています。

ライブラリ群のインストール

クックパッドのアプリは CocoaPods と Carthage を併用しています。 CocoaPods は Objective-C で書かれた静的リンク可能なライブラリ群を、Carthage は Swift のライブラリ群をインポートするために使っています。 何故このように使い分けているかというと、CocoaPods で導入しているライブラリの一部が静的ライブラリであって use_frameworks! が使えないからです。 またフレームワークが増えるほどアプリ起動に時間がかかってしまう問題を防ぎたいというのも理由です。

CocoaPods と Carthage のコマンドを叩き、Carthage がチェックアウトしたライセンスファイル群を CocoaPods の acknowledgements.plist にマージするスクリプトを用意しています。

また、Carthage にはこの記事を書いている時点では更新のあったライブラリだけをビルドし直す仕組みがなかったので、ビルド時間を抑えるために更新が必要なライブラリだけをビルドするスクリプトを用意していました。 この問題への対応はすでに PR が出てマージされているので、新しいバージョンではこの処理は必要なくなりそうです。

前述のツール群のバージョンチェックとあわせて make でこの操作を実行できるようにしています。 各開発者は手元へ最新のコードを fetch した後に make コマンドを実行することで、チームで期待されている開発環境にそろえて開発に取り掛かることができるようになります。

コードフォーマッタ

コードフォーマッタに clang-format と SwiftFormat を使っています。 直接これらのツールを使ってもよいのですが、ちょっとした工夫をしています。

clang-format はオプションで format をかけたい範囲を指定できるので、開発者が変更を入れた箇所にだけフォーマッタをかけるスクリプトを用意しています。ファイル単位でも良いのですが、PRを出した時に変更とは関係のないフォーマッタによる修正が混ざるとレビューする側がつらくなってしまうので、こうしています。

また、フォーマッタにかけるのを git の commit hook などに仕込むこともできると思いますが、意図的にしていません。これは、フォーマッタによって自動的に変更されたコードを開発者に確認してもらいたいからです。

リリースフローに関係するタスク補助系

クックパッドのリリースフローに含まれるタスクのうちスクリプトで解決しているものを紹介します。

アプリのバージョンを繰り上げる

アプリのバージョンを変更するというただそれだけのスクリプトを用意しています。特に面白みのないものですが、Extension を複数持つアプリだとそれに対応する info.plist がいくつもあるので地味に面倒な作業であることがわかると思います。クックパッドではこの部分の変更作業を複数人で回しているので、スクリプトで行えるようにしているのは作業する人によって微妙に違う内容になってしまうのを避ける目的もあります。

開発に関わった人ごとのマージコミットをリストにする

リリースフローに、次にリリースしようとしているバージョンのコードに自分がいれた変更が正しく含まれているか各開発者が確認する手順があります。このチェックリストをつくるスクリプトがあります。 単純に git のコマンドを利用してマージコミットのリストを作るだけのものですが、このような単純な作業こそスクリプトにしやすく、単調で間違いやすいタスクなので、スクリプトで片付けるようにしています。

開発環境の計測系

開発に直接関わるものではなく、開発環境がどういう状態であるか計測するためのスクリプトもあります。

Swift 移行率の計測

毎日リポジトリの master ブランチに含まれる iOS アプリのコードのうち Swift のコードの割合がどれくらい変化しているか計測・記録し、グラフに描画するようにしています。 単純な興味もありますが、Objective-C のコードが残っていると Swift の便利な機能が使えない場面が多くでてきてしまうので、必要に応じて Swift への書き換えを進めています。この進行具合が可視化されると、少しだけやる気がでたり達成感が得られます。

ビルド時間の計測

アプリのビルドにどれくらい時間がかかっているのか、バージョンを重ねるたびに変に伸びたりしていないか計測しています。ビルドに時間がかかっているということは、それだけ開発者を待たせてしまい生産性を下げていることになるので、状況を把握するために記録しています。ここで計測している時間をもとに、ライブラリの選定や場合によっては直接的な対策を行います。特に Swift を採用してからは書き方によってビルド時間が変に長くなってしまうこともあるので xcprofiler などを使って具体的な場所を特定したりもします。


これらのスクリプトはだいたい Ruby で書かれています。 Makefile などから呼び出されているスクリプトもありますが、最近は fastlane をよく使っているので、fastlane action として実装し直そうという動きもあります。今回紹介したようなスクリプトの中で汎用的な action として分離できるものがあれば、公開していきたいと考えています。

クックパッドではiOS/Androidに詳しいモバイルアプリ開発エンジニアはもちろんのこと、このようなモバイルアプリ開発をより効率よくするために活躍できるエンジニアを募集しています。

/* */ @import "/css/theme/report/report.css"; /* */ /* */ body{ background-image: url('http://cdn-ak.f.st-hatena.com/images/fotolife/c/cookpadtech/20140527/20140527163350.png'); background-repeat: repeat-x; background-color:transparent; background-attachment: scroll; background-position: left top;} /* */ body{ border-top: 3px solid orange; color: #3c3c3c; font-family: 'Helvetica Neue', Helvetica, 'ヒラギノ角ゴ Pro W3', 'Hiragino Kaku Gothic Pro', Meiryo, Osaka, 'MS Pゴシック', sans-serif; line-height: 1.8; font-size: 16px; } a { text-decoration: underline; color: #693e1c; } a:hover { color: #80400e; text-decoration: underline; } .entry-title a{ color: rgb(176, 108, 28); cursor: auto; display: inline; font-family: 'Helvetica Neue', Helvetica, 'ヒラギノ角ゴ Pro W3', 'Hiragino Kaku Gothic Pro', Meiryo, Osaka, 'MS Pゴシック', sans-serif; font-size: 30px; font-weight: bold; height: auto; line-height: 40.5px; text-decoration: underline solid rgb(176, 108, 28); width: auto; line-height: 1.35; } .date a { color: #9b8b6c; font-size: 14px; text-decoration: none; font-weight: normal; } .urllist-title-link { font-size: 14px; } /* Recent Entries */ .recent-entries a{ color: #693e1c; } .recent-entries a:visited { color: #4d2200; text-decoration: none; } .hatena-module-recent-entries li { padding-bottom: 8px; border-bottom-width: 0px; } /*Widget*/ .hatena-module-body li { list-style-type: circle; } .hatena-module-body a{ text-decoration: none; } .hatena-module-body a:hover{ text-decoration: underline; } /* Widget name */ .hatena-module-title, .hatena-module-title a{ color: #b06c1c; margin-top: 20px; margin-bottom: 7px; } /* work frame*/ #container { width: 970px; text-align: center; margin: 0 auto; background: transparent; padding: 0 30px; } #wrapper { float: left; overflow: hidden; width: 660px; } #box2 { width: 240px; float: right; font-size: 14px; word-wrap: break-word; } /*#blog-title-inner{*/ /*margin-top: 3px;*/ /*height: 125px;*/ /*background-position: left 0px;*/ /*}*/ /*.header-image-only #blog-title-inner {*/ /*background-repeat: no-repeat;*/ /*position: relative;*/ /*height: 200px;*/ /*display: none;*/ /*}*/ /*#blog-title {*/ /*margin-top: 3px;*/ /*height: 125px;*/ /*background-image: url('http://cdn-ak.f.st-hatena.com/images/fotolife/c/cookpadtech/20140527/20140527172848.png');*/ /*background-repeat: no-repeat;*/ /*background-position: left 0px;*/ /*}*/