クックパッドアプリはみんなが寝ている間にサブミットされる

こんにちは、技術部モバイル基盤グループの茂呂(@slightair)です。 先日のiOSDCは大盛況でしたね。とても楽しく、実りあるカンファレンスでした。この記事で僕は ididblog! ということにしようと思っています 😋

クックパッドからは @giginet と僕の二人が登壇しました。発表を聞きに来ていただいた方はありがとうございました。 @giginet詳解Fastfile という発表中でさらっと話された、”毎週自動的にリリースされる”という言葉が気になった方はいるのではないでしょうか。実はこのリリースフローについての話もプロポーザルに出していたのです(もっともっと細かくリリースをしてユーザーに最速で価値を届けるためのリリースフロー)。

この記事ではこのリリースフローについての話をしたいと思います。

クックパッドアプリの開発体制

クックパッドアプリの開発体制は人数の変動はあるものの、ここ数年で大きく変わっているものはありません。 この記事にあるように、モバイルアプリを専門で開発するようなチームはなく、有料会員獲得やレシピ投稿、検索結果の向上などを目的とした部署に所属するエンジニアがそれぞれの目的に合わせた機能追加・修正のPRを出しマージして定期的にリリースする、というスタイルを続けています。

開発環境のメトリクスとして記録している数字を見ると、最近では各リリースごとにだいたい10数人のコミットが含まれているようでした。この数字にはアプリのコードを書くエンジニアだけでなく、テストエンジニアや画像リソースなどを変更するデザイナー、更新文言やアプリの説明文などを編集するディレクターの数も含まれます。

以前のリリースフロー

基本的には前述の記事で説明しているように開発期間やテスト期間などの日を細かく決め、その期間で各チームが開発を行い、コードフリーズ後に動作確認を行ってサブミット、審査が通ればリリース、というフローを回していました。1イテレーションはだいたい2週間のペースです。ひとつのイテレーションが終わると開発関係者で集まって振り返りを行い、課題や改善点が見つかれば次のイテレーションで解決するというのを繰り返すことで、不具合を抑え安定したペースでリリースし続ける状況を維持していました。このフローは僕たちの組織構造にも合っていて長年うまくいっていたリリースフローなのですが、問題もありました。

ひとつめはリリースマネージャーの負担が大きいことです。リリースマネージャーというリリースに責任を負う人物を立てて、問題なくリリースが行えるように部署間の施策の調整をしたり、スケジュールの調整を行う役目を担ってもらっていました。次のリリースに入るはずの機能がマージできていないときに関係者をつっつくような役目も持っていたので、とにかく細かい作業や人間の間の調整で忙殺されてしまうのです。リリースマネージャー役を関係者間で交代するようにしたり、リリース作業とリリース進行役を別の人間で分担するようにもしてみましたが、手順がまとめられていても人によってケアの仕方に差がでたり関係者が増えることによる負担は増加する一方でした。

ふたつめはだいたい2週間に一度のリリースのペースを守ろうとしていてもばらつきが起きていたこと、場合によってリリース間隔が開いてしまっていたことです。ある部署の大事な施策の開発が遅れているのでリリーススケジュールを遅らせたい、広範囲にわたる変更があるので他の部署の開発は次のリリースでは我慢してもらいたい、というようなリリースごとの特別対応が求められるケースがたびたび発生していました。そのような調整作業をまとめているリリースマネージャーがさらに疲弊してしまったり、想定のリリーススケジュールが守られず期待していたタイミングで機能を提供できない、価値検証がうまく行えない、タイミング次第では検証に基づく変更を反映するのに時間がかかりすぎてしまうというチームが出てしまう状況でした。

つまり、リリースマネージャーを立てて様々なケースに融通が利くようなフローにしていた結果、当事者間の調整コストが高まって色々な問題を引き起こしていたのです。

新しいリリースフローは「機械に人間が合わせる」

当事者間の調整でみんなが苦しんでいるのがわかったので、この「調整」を無くすことはできないだろうかと考え始めました。もう調整はしない!

そこで僕たちは可能な限りサブミット・リリース作業を自動化する仕組みを構築し、人間が動かなくても自動でアプリがサブミットされる状況を作ることにしました。 タイミングが来ると自動でサブミットを行うジョブが実行されるのでそれに合わせて開発するスタイルです。人間たちの準備が整ってからサブミットを実行するのではなく、機械のペースに人間が合わせて行動するということです。開発が間に合わなかったら次のリリースには入れられるように頑張ってね、という感じになります。

具体的にはこのようなルールで運用しています。

  • リリース予定日は毎週月曜日と仮定する
  • バージョン番号には 年.リリース予定日の週番号.パッチ番号.0 を採用する
    • 基本的に再サブミットを行わないのでパッチ番号は 0 になる
  • 毎週金曜AM2:00にサブミットジョブを実行し、その時点のmasterブランチの内容をビルド、サブミットする
  • サブミット後に開発関係者各自で動作確認を行いリリース判定を行う、あわせてAppleの審査を通過したらリリースを行う
    • もし致命的な不具合が見つかったり、バイナリの変更が必要な理由で審査に落ちたらそのバージョンのリリースをあきらめ、次のバージョンで問題を解決する
    • ある程度の不具合を許容する。リリースサイクルが早いので次の機会で確実に直せればよいと考える。
  • master ブランチには確実にリリース可能なコードのみをマージする。もしマージ後に問題が発覚すれば即リバートする。

「機械に人間が合わせる」というコンセプトでリリースフローを設計したので、ある意味ドライな意思決定がされるようになった部分もありますが、思い切った変更により自動化できる箇所が増え、開発者の負担を減らしたり毎週というリリースサイクルでも回せるようになりました。

このリリースフローに切り替えてから、毎週金曜日に出社したり仕事を始めようとするとサブミットが終わっている状況になっています。早いときは審査が終わっている場合もあります。ジョブの実行を金曜の早朝に設定している理由は、なにかサブミット作業で問題が起きたときに金曜日中に対応できるようにするためです。

f:id:Slightair:20180913183311p:plain

自動化しているもの、機械がやってくれること

以下のタスクを自動化しています。実際のサブミット作業だけでなく、このリリースフローを安定して回したり当事者間のコミュニケーションを促進する施策を実行します。

  • 更新文言(fastlane/metadata/ja/release_notes.txt)の変更があるか確認
    • AppStoreReviewガイドラインの最近の変更(2.3.12)のため、毎回同じ更新文言を出さないようにしている
    • 各チームから文言を決めるissueに書き込んだり、PRを出してもらう形にしている
    • サブミットジョブの終わりでテンプレートファイルを用いてリセットする。diffがなかったらサブミット失敗として扱う。
  • リリースに含まれるコミットをしたメンバーをリストにしたリリース前確認issueをGHEに作成する
  • git タグを作成する
  • アプリをビルド、サブミットする (fastlane deliver)
  • アプリのバージョンを更新しリポジトリにpushする
  • GHEへ次の次のマイルストーンを作成する
  • groupad(社内Wiki)に次のバージョンのリリース内容を記述するページを作成する
  • サブミットしたアプリと同等のバイナリをRC版としてビルドし、haneda(社内アプリ配信サービス)にアップロードする

一連の作業は fastlane と Jenkins で実現しています。人間がやる作業はアプリを開発したりメタデータを更新すること、動作確認をして全員の確認がそろったらリリースボタンを押すだけです。

アプリの品質管理について

新しいリリースフローに移行する前は、開発後にコードフリーズを行いテストをする期間を設けていました。この期間で開発者が動作確認するのはもちろんですが、テストエンジニアが自動シナリオテストを実行したり重要な機能の動作確認を集中的に行い、不具合を含んだアプリがリリースされてしまうのを防ごうとしていました。この方法ではテストエンジニアがアプリの品質に対して集中的に責任を持って守れる一方、アプリが持つ機能の詳細や新規機能、修正内容を把握した上で動作確認を行う必要があり、情報のキャッチアップにも動作確認にも時間がかかってしまっていました。スケールもしません。

そのため新しいリリースフローに移行すると同時に、開発するチーム単位でも品質をコントロールできるようにする取り組みも始めています。これはリリースサイクルを早めるためにも必要な試みで、機能を開発するチームが自分たちの担当する部分の品質をコントロールしてリリース可否や不具合対応方針を決められる体制のほうが健全であり、結果的にスピードも出るだろうという考えです。

ある程度の不具合を許容すると前節で書きましたが、正確には不具合を見つけたとしてもすべてを解消してからリリースすることを目指すのではなく、不具合とどう向き合うのかも含めて機能を開発しているチームがアプリの品質をコントロールし動けるようにする、ということです。

リリースフローを運用してみて

新しいリリースフローに移行してからだいたい1ヶ月くらい、リリース回数でいうと4,5回行ったところですが、今の所大きな事故はなく、うまくいっています。以前と違いAppleの審査時間が短くなったのもこのリリースフローが成立する理由のひとつです。うれしいですね。

移行してからリジェクトもいくつかありましたが、メタデータリジェクトが多く、この場合は修正してリリースを行っています。 一度だけサブミット後にバイナリに変更が必要な状況になり、どうしてもということでリリース延期を行わずイテレーション内の再サブミットを実行しています。可能な限りこのような特別対応は無いほうがよいと思っていますが今後はどうなるでしょう、様子をみていくつもりです。リリース前確認もすりぬけて致命的な不具合を含んだ状態でリリースしてしまい、1週間は待てないのでそれを修正するための緊急リリースをしたいということもいつかは起こってしまうはず。どういう対応が必要になってくるかはこれから見えてくると思います。

単純にリリース回数が多くなっただけではないということを繰り返し社内でも伝えていますが、調整をしたがる声が時々出てしまっています。難しいですね。気持ちもわかるし、このやり方が定着するにはもう少し時間がかかりそうです。

まとめ

iOSDC では発表できなかった、クックパッドアプリの新しいリリースフローの取り組みについて紹介しました。機械に人間が合わせるというコンセプトをもとに、自動化できるところはとことん自動化し機械にまかせることで、リリースサイクルを早めたり開発関係者の負担を下げられるような努力をしています。このリリースフローが今後もうまく続けられるかどうかはもう少し経ってみないとわかりませんが、なかなかおもしろい取り組みなのではないかと考えています。

/* */ @import "/css/theme/report/report.css"; /* */ /* */ body{ background-image: url('https://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('https://cdn-ak.f.st-hatena.com/images/fotolife/c/cookpadtech/20140527/20140527172848.png');*/ /*background-repeat: no-repeat;*/ /*background-position: left 0px;*/ /*}*/