Quantcast
Channel: クックパッド開発者ブログ
Viewing all 726 articles
Browse latest View live

アプリのユーザーテストをGoogle Play ベータテストで行う

$
0
0

 こんにちは。検索事業部 ディレクターの五味です。クックパッドにレシピを探しに来るユーザーの体験向上を使命に、レシピ検索に纏わる技術・UIの改善、プラットフォームをまたいだサービス全体の編成に関わる仕事をしています。

 プロダクトのリリースや改善にあたり、ユーザーテストによる仮説検証は不可欠です。今回は、先日クックパッドAndroidアプリで初めて、Google Playのベータテスト機能を使ってユーザーテストを行った話をご紹介します。

ベータテストに踏み切った背景

 クックパッドアプリでのユーザーテストはこれまでも実施してきましたが、すべて通常版アプリにテストを内包する手法をとってきました。

 しかしあるプロジェクトで、これまでのユーザー導線を根底から変える規模の改変を含んだプロダクトのテストを行う必要が生じました。アプリ全体の体験から大きく異なるテストプロダクトを通常版アプリに統合することはコストが高すぎる上、メリットもありません。

 そこで、テスト版アプリを通常版と別バイナリとして配信でき、またその対象者も既存のアプリユーザーから募ることのできる、Google Playのベータテスト機能を利用してみることにしました。

既存アプリで大胆な価値検証ができた

 1つの仮説にとことん集中し、その仮説を満たす最低限の機能のみで構成されたプロダクトを実際のユーザーに配信して反応を測る。今回ベータテストを実施してもっとも良かった点は、そのような大胆な価値検証を、クックパッドという既存アプリで遂行できたことです。

 今回のテストは、従来であれば、新規の別アプリを作って検証する等の手段を取らざるを得ない内容でした。しかしその手法では、将来的に既存アプリをテストプロダクトでリプレイスする可能性がある場合、その際に生じるネガティブな反応の大きさを計り知ることができません。

 この検証は、ユーザーが普段使っているアプリがテスト版に置き換わるというGoogle Playベータテストの仕様によって可能になったものでした。

f:id:natsuki53:20160803091737p:plain

ベータテストの実施で考慮すべき点

 ここからはベータテストに興味をお持ちの方向けに、テスト実施の際に一考いただきたいポイントをご紹介します。この3項目は今回我々が苦慮した点でもあります。

1. オープン?クローズド?

 ベータテストにはGoogle Appsアカウントでテスターを管理できるクローズドベータと、テスター数の上限だけを設定するオープンベータの2種があります。テストの目的や要件をよく考慮し、状況に合った方式を選ぶことが大切です。

 今回のケースでは数千単位のテスターを必要としており、アカウント管理のコストを考慮すると、本来はオープンベータを採択するべき案件でした。しかし以下の理由から、敢えてクローズドベータを選択しました。

  • 仮説がきちんとターゲットに響くか確かめるため、テスト参加者を既存アプリの利用パターンから選出した方に限定したい
  • テストプロダクトがMVP検証のため既存機能を大幅に削ってあるため、注意事項をご理解いただいた上で参加いただきたい

 結果、テスト参加者は想定より大幅に少なくしか集客できませんでしたが、この施策段階では条件に合うユーザーにテストアプリを使っていただくことが、数を揃えるより優先度が高かったと考えています。

2. ベータテスト参加のユーザー体験

 サービスによって差異はあるとは思いますが、ユーザーはこのようなテストアプリを利用することに熟達していないという点を忘れてはいけないと思います。

 試しにアプリのベータテストに参加してみると、テスター募集からテスト参加、テスト版アプリのインストールまで、画面遷移は多く、導線も複雑です。Google Play Developer Consoleでの作業の簡単さと引き換えに、Google Play側の各画面は編集できる領域が少なく、使われる用語もユーザーにとってわかりやすくはないように思えます。

f:id:natsuki53:20160802185251p:plain

 テスト参加の敷居を下げ、多くのユーザーにテスターとなってもらうため、以下のような準備をしました。

・テスト参加ご案内ページ

 テストにスカウトしたユーザーに概要を知っていただくためのページです。参加規約や、テストアプリを入手するまでのフロー解説、お問い合わせ導線をまとめています。

f:id:natsuki53:20160802185310p:plain

・テスター専用FAQ

 事前にFAQを作成。テストアプリ内のわかりやすい場所に導線を設けました。テストを途中離脱したい場合の解説等も併記しています。

f:id:natsuki53:20160802185330p:plain

・ユーザーサポートチームの協力

 サポートチームに担当をつけてもらい、事前にテストアプリの機能表や想定問答集を共有。専用チャットルームも準備して密にコミュニケーションを取れる体制を作りました。

3: テスターの募集方法

 テストアプリの配信はGoogle Playに助けていただけますが、参加者確保はすべて自前で行う必要があります。今回はこの点になかなか苦戦しました。

 リクルーティング導線として、今回はAndroidアプリのスタートスクリーンにテスター募集のバナーを表示しました。しかしこの導線のパフォーマンスが予想以上に厳しく、3000人にバナーを表示しても、100名程度しか反応が得られませんでした。てこ入れ策として対象ユーザーにメール配信も行いましたが、そちらも思うほど効果がなく、最終的にテストアプリをインストールしていただけたのは200名弱という結果になりました。

f:id:natsuki53:20160802185351p:plain

今後に向けて

 今回のベータテストでの1番の収穫は、既存アプリで作り上げられている環境を制約とせず、新しい機能に集中した急進的なテストプロダクトを、実際に今のアプリを使っているユーザーに試用いただけたことです。

 テストにご参加いただいたのに利用反応がなくなってしまった方に、プロジェクトメンバーが直接電話インタビューを行い、リアルなご意見をいただいて悄気てしまう日もありました。しかしそこからのプロダクト改善は目覚ましく、そのようなネガティブな反応をいただけたのも、既存のクックパッドアプリから更新する形でテストアプリをお使いいただくことができたおかげだと思います。

 次はより多くのテスターに使っていただくなど、段階に合わせたテスト方法も検討していく必要があります。折しもGoogle社からオープンベータの機能増幅やテスター参加導線の強化がいくつか発表されていますので、それらもうまく取り入れ、より柔軟にテストを活用できるようにしていきたいと考えています。

 なおクックパッドでは、このようなサービス改善に一緒に取り組み続けてくださる方を、職種問わず募集しています 。ご興味のある方はこちらからどうぞ。


データベースドキュメント管理システム dmemo のご案内

$
0
0

こんにちは、みんなのウェディングに出向中の小室 (id:hogelog) です。

今回はクックパッドとみんなのウェディングで利用しているデータベースドキュメント管理システム dmemo を紹介します。

https://github.com/hogelog/dmemo

f:id:hogelog:20160808041022p:plain

dmemo を作成し導入した経緯

私は2016年3月頃からみんなのウェディングで Redshift, bricolage, embulk, re:dash 等を利用したデータ分析基盤の構築を進めています。 (みんなのウェディングのデータ分析基盤の現状 - みんなのウェディングエンジニアリングブログ)

社内の誰でも扱えるデータベース、データの集約・計算・加工、ダッシュボードの作成、クエリの共有などは上記ブログ記事でも書いたように Redshift, bricolage, embulk, re:dash 等を組み合わせることで実現できました。ですがそれだけでは DWH を社内の誰でも簡単に扱える状態とは言えません。たくさんのデータがあっても意味がわからなければ役にはたたないからです。

ソースコードを読み解くことでしかデータの仕様を理解できない環境では一部のエンジニアと周辺の人しか高度な分析をおこなえません。データの仕様のドキュメント化も進めていましたが、なかなか整備しきれるものではありません。

しかし実際のところデータベースに存在するスキーマ・テーブル・カラムなどのスキーマ情報はプログラムで自動的に取得できる情報です。スキーマ情報からはわからない「このテーブルはなんのためのテーブルなのか」「このカラムが取りうる値はなんなのか」といった情報のみを人が管理していけば良い、そんなツールを目指して作ったのが dmemo です。

dmemo の仕組み

dmemo は DBとして PostgreSQL を利用するごく標準的な構成の Rails アプリケーションです。

  • 接続可能データソース(データベーススキーマ情報の取得元)
    • Redshift
    • PostgreSQL
    • MySQL
  • Google OAuth 2.0 認証
  • バッチ実行によるデータソースとの同期処理

Dockerfile, Docker Imageも提供しているため、多くの環境ではDocker経由で稼働させるのが簡単でしょう。

ユーザ認証

ユーザ認証は Google OAuth 2.0 認証のみ提供しています。

接続先データソースなどの編集は Admin ユーザのみに許可されていますが、最初の Admin ユーザは DB を直接編集するか rake タスクから作成する必要があります。

$ ./bin/rake admin:activate EMAIL=konbu.komuro@gmail.com
 or
$ docker run --env-file .env.docker hogelog/dmemo ./bin/docker_admin_activate.sh konbu.komuro@gmail.com

データソースとの同期処理

dmemo はデータソースとなるデータベースのスキーマ・テーブル・カラムなどのスキーマ情報は半ば自動的に取得します。

Admin ユーザならば dmemo の Web 画面上からも実行できるのですが、基本的にはバッチ処理による同期を推奨します。

$ ./bin/rails r 'SynchronizeDataSources.run'
  or
$ docker run --rm --env-file .env.docker -t hogelog/dmemo ./bin/rails r 'SynchronizeDataSources.run'

みんなのウェディングとクックパッドでは上記処理を日次で実行し、実データと dmemo を同期させています。

Markdown による記述と履歴の保持

肝心のデータの仕様についてはデータベース・スキーマ・テーブル・カラムそれぞれに Markdown で説明を記述できるようになっています。データの現在の正しい仕様について誰でも恐れず更新していってほしいため、記述内容については差分を保持しています。*1

f:id:hogelog:20160808064011p:plain

辞書機能

データベースの説明にはドメイン固有の言葉がたくさん出てきます。

例えばクックパッドで文脈無しで「ユーザID」と言えば「main データベースの users テーブルの id カラム」のことです。このような説明を記述しておくため辞書機能を実装しました。

説明文の中に記述したテーブル名と辞書項目については自動的にリンクされるため、説明文における重複した記述を避けることができます。

HTML::Pipeline

余談ですが dmemo では Markdown 処理部分に HTML::Pipelineを利用しています。HTML::Pipeline は HTML を入力として Filter を通し HTML を出力するためのライブラリであり Markdown から HTML の変換も Filter として提供されています。HTML 構造を理解して処理するため文脈に応じた拡張文法の実装が容易であり dmemo のテーブル名・辞書項目の自動リンク機能も Filter の一つとして実装されています。

注意点

現在の dmemo は社内で設置し特定の Google Apps ドメインのユーザのみアクセスできる状態での動作を想定していおり、 Markdown 記述機能に関して一切の制限をかけていません。script タグなどもそのまま記述できるため、インターネットから不特定ユーザからアクセスできる状態で設置すると危険です。

OSS として開発したことによるメリット

実のところ dmemo はみんなのウェディングの DWH に感じた課題から、余暇にちょっとずつ開発していたソフトでした。2016年6月頃にはある程度の完成度に至り「意外とこれは本当に便利そうだし会社でも導入した方が良さそうだな」と感じていたのですが、まだ完成度に不安があったのと、日々の業務に追われみんなのウェディング社内には導入していませんでした。

そんな頃にふとクックパッドで DWH 基盤を構築している id:InoHiroid:mineroaokiもクックパッドのデータベースの仕様ドキュメント化に同様の課題を抱えていると聞き dmemo を紹介したところ、id:mineroaokiの「いいじゃないすか、そういうのが欲しかったんすよ」という一声により、あっという間にクックパッド社内に導入されてしまいました。*2

導入され運用が始まると手元で開発していた時には気づけなかった様々なフィードバックが届きます。例えば当初の dmemo はデータソースとの同期はオンラインでおこなう作りでしたが、 Redshift などに大量のテーブルが存在する場合同期処理の間アクセスができなくなる、デプロイの度にキャッシュが消えて特定巨大テーブルへのアクセスがタイムアウトするなど運用が辛いものでした。テーブル名の自動リンク、辞書機能などもまったく発想になかった機能もフィードバックから実装に至りました。

OSS として広くフィードバックを受けながら開発しているというにはまだちょっと狭いかもしれませんが、とりあえず会社の枠は超えた改善が実現できました。

まとめ

クックパッドとみんなのウェディングでは dmemo を利用しデータベースの暗黙知を組織内で共有し、誰でも簡単に使えるデータ分析基盤の構築を進めています。

クックパッドでは id:mineroaokiを中心としたプロフェッショナルなチームにより世界一使われている料理とレシピのサイトのデータ分析基盤が構築されており、みんなのウェディングでは id:hogelogid:takai_naotoらによりもう少し小規模なデータとチームでスピード感を持ってデータ分析基盤を構築しています。

クックパッド、みんなのウェディングどちらでも興味のある方は是非お声掛け下さい。実際に運用している dmemo の画面を見てみたいとか、そんなカジュアルな見学もいつでも歓迎しています。もちろん本格的な採用情報への応募もお待ちしております。

*1:日付つき但し書きが大量に書かれた仕様書、よく見かけますけど読むのは辛いですね

*2:実際のところクックパッド社内にも導入させてやろうという目論見のもと開発していましたし、紹介しました。業務でバリバリに使われるOSSを個人で開発したかったので、狙い目だったのです

新サービスを使い続けてもらうために工夫した2つのこと

$
0
0

こんにちは。くらしのきほんグループのエンジニアの長田です。

私たちのチームでは、「くらしのきほん」という普段の暮らしの楽しさや感動を再発見するサービスを提供しています。 くらしのきほんでは、料理をはじめとした日々の暮らしを丁寧に送るためのコンテンツを提供しています。

また、くらしのきほんのサービスの一部として、「わたしのきほん」という、ユーザーが普段の生活の中で大切にしている事を言葉で投稿するサービスをスマートフォンWebで提供しています。

この記事では、わたしのきほんを使い続けてもらうために工夫したことと、その効果についてご紹介します。

わたしのきほんとは

わたしのきほんは、TwitterやFacebookのように自分の近況を投稿するのではなく、自分が今までの人生の中で出会った、素敵だと思う言葉を投稿するサービスです。

投稿の例としてはこんなものがあります。

f:id:osadake212:20160809181103p:plain

このサービスの1番面白いポイントは、「投稿を重ね、言葉を振り返ることで、自分の輪郭がはっきりしてくるところ」です。

日々の生活を送る中で、大切にしていることや信条のようなものは誰しもが持っていると思うのですが、それを言語化する機会はありません。ブログやSNSで自分を発信していたとしても、それは近況報告だったり、心からの言葉ではなかったりします。

わたしのきほんは、ブログやSNSにあるようなタイムラインやシェア機能を設けておらず、自分の書いたものだけが常に見られるようになっており、他の人の目をあまり気にすることなく投稿できるようになっています。

なので、サービスを使うたびに「ああ、自分ってここに気をつかってるんだ」という再確認ができ、自分という人間の輪郭がよりはっきりしてきます。

わたしのきほんを使い続けてもらうために

わたしのきほんは投稿サービスなので、どんどん投稿をして欲しいのですが、自分が大切にしている言葉をずっと投稿し続けていくのは難しいです。例えば、投稿することを思いつかなくなってきて、投稿できなくなってきた人や、ただ投稿し続ける動作に疲れてしまった人などがその例だと思います。

そのようなユーザーは、自分一人で投稿し続けることに限界を感じているのではないかという推測をし、他の人との接点をもつと、より投稿しやすくなるかもしれないという仮説をたてました。

当初は自分の言葉を振り返ることを主目的にしていたので、SNS的な要素はできるだけシンプルにしていたのですが、上に書いたような課題を解決するためにも、他人とのつながりをもう少し強化して、投稿のモチベーションを上げてもらう改善を試みました。

モチベーションを上げてもらうためにやった2つのこと

改善は日々行っているのですが、その中から2点だけ、その内容と効果について紹介させていただきます。

トップページからいいねできるようにして、いいねUUが1.6倍に

この改善の目的は、ユーザーが書いたきほんに、より多くのいいねをつけてもらうためでした。

自分が投稿したものに対していいねがつくと嬉しいですよね。それは、わたしのきほんでも例外ではなく、ユーザーにもっと喜んでもらうために、いいねを増やすことにしました。

そこで、既にくらしのきほんトップページに表示していた、スタッフがピックアップしたユーザーの投稿に、いいねボタンを配置し、くらしのきほんに訪れたユーザーが、すぐにいいねできるようにしました。

[左: いいねボタンなし, 右: いいねボタンあり] f:id:osadake212:20160809220926p:plain

トップページにはその他のコンテンツも表示していることもあり、情報量を少なくする目的で、当初はいいねボタンを置いていませんでしたが、毎日訪れてくれるコアユーザーにとっては、いいねがすぐできるほうが嬉しいですし、初めて訪れるユーザーにとっては、わたしのきほんというサービスがどんなサービスかをより説明できると考え、いいねボタンを置きました。

結果としては、これまでいいねの機会を逃していたユーザーを獲得することができ、いいねのUUが1.6倍になりました。

スタッフがピックアップしたものをユーザーに通知して、投稿数が1.2倍に

投稿した言葉がいいねされると嬉しいということは、自分が書いたきほんが他の人にも共感して欲しい、という承認欲求があるということです。 とはいえ、ユーザー同士のつながりを過剰に強化することで、いわゆるSNS疲れのような状態になってしまうのも防ぎたいと考えていました。

そこで、スタッフがピックアップしたことをユーザーにお知らせする機能を追加しました。 スタッフからの通知であれば、ユーザー同士のつながりではないので、SNS疲れの心配もないですし、ピックアップされるとくらしのきほんトップに掲載されるため、投稿のモチベーションになります。

f:id:osadake212:20160809181109p:plain

結果としては、通知によりユーザーの投稿のモチベーションを上げることができ、投稿数が1.2倍になりました。

おわりに

この記事では、くらしのきほんのサービスである、わたしのきほんについてのご紹介と、サービスを使い続けてもらうために工夫したこととその効果について紹介させていただきました。

開発者が意図していたことは必ずしもプラスに働いている訳ではありません。また、開発者の懸念が、よりユーザーの行動を制限している場合があります。

この改善を通して、サービスの使いやすさや分かりやすさはバランスが重要であることを再確認しました。 新規サービスの場合、開発者はサービスのヘビーユーザーなので、今日はじめて訪れるライトユーザーの気持ちになることを心がけ、サービスをバランスよく改善していくことが大切です。

このわたしのきほんの事例が、これから投稿サービスを開発する人にとって、何かのお役に立てれば幸いです。

海外のユーザーを向いたプロダクト開発の工夫

$
0
0

こんにちは、検索事業部の岡根谷です。クックパッドは日本だけでなく海外でもレシピサービスを展開しています。今回は自分がプロダクトオーナーとして行った「関連レシピ」の複数言語同時リリースの話をしたいと思います。

関連レシピとは?

レシピページの下にあり、ユーザーの行動から関心を汲んで自分にぴったりなレシピを見つけるのを助ける機能です。 「パスタ」で検索してジェノベーゼパスタに興味を持ってレシピを開いた人が、より自分にあったジェノベーゼパスタを見つけることができる、というようなシナリオを想定しており、たくさんのレシピを闇雲に探索するのではなく絞り込む方向に導くことで「作る」という行動に繋げたいという思いがあります。

チームメンバーは世界中に散らばっており、各国のエンジニアやコミュニティマネージャーと連携して、スペイン語、アラビア語、インドネシア語、英語、ベトナム語など複数の言語のAndroidアプリで同時リリースを目指しました。

f:id:m_okaneya:20160811074222p:plain

アラビア語版関連レシピ

言葉がわからない国のプロダクト開発をどう進めるのか

プロダクトオーナーとして自分が重要な判断を行えるためには、誰よりも詳しく正しく、そこに暮らすユーザーの困っていることとプロダクトの提供価値を語れる必要があります。

会ったこともない国のユーザーのことを現地の人以上に正しく理解できるのかと怯みますが、その自信が持てないと、現地メンバーの一つ一つの意見に左右されてプロダクトの方向性を見失ってしまいます。 現地感覚を持つメンバーの意見は大事ですが、それを鵜呑みにするのではなく最終的な決定は自分が自信と責任を持って行えるために、様々な方法を試みました。

1. わからなくてもとにかく自分自身が徹底的に使う

地味ですが、とにかく徹底的に使って自分自身が一番うるさいユーザーになる努力は絶対に必要だったと感じています。開発中のアプリを自分のスマホに入れて、仕事中にかぎらず通勤中の電車でも布団の中でもとにかく毎日徹底的に使い続けるうちに、ユーザーが一体どういう場面でこの機能に出会うとうれしいのかという大きなストーリーとともに、アラビア語であってもよいケースそうでないケースの感覚が持てるようになりました。

とはいえ文字情報の理解はさすがにきびしかったので、スマホではテキスト選択して自動翻訳できる Google Translateを、PCのChromeのブラウザでは語意までわかる Google Dictionaryの力を借りました。細かいことですが、ページ全体を翻訳するのではなくわからない部分だけを選択してツールで訳すことで、なるべくユーザーに近い画面を見ることを心がけました。

誰よりもプロダクトに詳しくなるために、自分にできる方法でとにかくプロダクトと親密になることが重要だと実感しました。

f:id:m_okaneya:20160812083505p:plain

2. プロダクトの提供価値を一枚の絵で示し、みんなの共通理解にする

距離的に離れたグローバルの開発では、そもそもこのプロダクトは何を目指すものなのなんだっけということすら目線がずれてしまいがちです。「関連レシピは、言葉に現れないユーザーの関心を汲んでぴったりなレシピを提案する絞り込みの機能である」という定義が全メンバーの共通の理解になるよう、ユーザーストーリーを一枚の図に表現して、hangoutを通じて各国のコミュニティマネージャーにプレゼンをしたり、各国の開発者が見る社内ブログにのせたりして、浸透に努めました。

プロダクトの提供価値がいつでも誰でも参照できる伝わりやすい形になっていることで、それに基づいた公正な判断ができるようになります。この画が示せるようになったことで、ユーザーに興味を持ってもらえるよう広く多様なレシピを出したい、いう中東地域からの提案があったときも、検索を広げる方向はこの機能の役割とずれるから別の方法で実現しようと一緒に納得して決めることができました。

f:id:m_okaneya:20160810210742p:plain

3. 現地のコミュニティマネージャーにチェックしてもらって判断する

自分自身で使い込むことも大事ですが、ネイティブの目で見てより高い品質を確保するために、リリース判断には各国のコミュニティマネージャーからフィードバックを得て判断する、という方法を取りました。 自由回答にならないよう、実際のユーザーに近い状況でのフィードバックが得られるように対象レシピと観点を細かに指定し、スプレッドシートで作業シートの形式にして依頼しました。

f:id:m_okaneya:20160810185311p:plain

この方法のよかったところは、作業シートの形式にすることで主観的なフィードバックが定量化できるようになり、「何割以上◎だったらリリースする」という統一の基準を設けてすべての言語のリリース判断や比較が行えたことです。一方で限界は、プロダクトの目的を丁寧に繰り返し伝えてやってほしいことを相当に細かく説明しないと、実際に使うユーザーに近い正直な感想は得られないということです。関連レシピという名前が先行して「自分が作りたいレシピが見つかるか」ではなく「似ているかどうか」に終始したフィードバックが多くなってしまったのは反省点です。 考えてみれば、日本の開発をしていても、正直なユーザーの視点を持つのは非常に難しいことです。なので、国を超えて他人にそれをやってもらうことの難しさは一際です。

質問の仕方は工夫の余地があると思いますが、作業を明確にすることで定性的な感覚を定量化する、というのはよかったです。

4. ヘビーユーザーの行動を追跡する

プロダクトリリース後は、この機能が一体どのような場面で頼られて使われているのかを理解するために、それを最もヘビーに使ってくれているユーザーの行動を追跡するということをやりました。この方法のよいところは、実際のユーザーの行動という絶対的な証拠に基づいて、各国のメンバーと話ができることです。「ユーザーはきっとこう振る舞う」「これはユーザーにとってこうにちがいない」という主観を排して客観的な理解が持てるので、同じ土台の上に立ってみんなでプロダクトをよりよくしていくための議論ができます。

f:id:m_okaneya:20160810210656p:plain

実際のユーザーの中でも特に高頻度に使ってくれている人たちの行動は、一人のスタッフの意見よりもCTR等の数字より何百倍も説得力があります。チーム全員の目線が揃うと同時に、自分自身のユーザー理解が進むという意味でも非常によかったです。分析する中で、通常の検索の場面だけでなく、自分が気に入って保存したレシピから似たような見た目や盛り付けのレシピを見つける時に便利に使われていることがわかりました。

このことから、「言葉にしにくい希望を汲んで」という仮説とプロダクトの実態は一致しているけれど、当初想定した今日の食事決めの場面よりも、お菓子作りやパーティーのような計画を必要とする場面でより便利に使われているという事実がわかりました。

5. 日本語でやってみる

自分の言語だったら実感が持てるのではないか...と考え、日本のクックパッドのデータで関連レシピを再現してみるというのもやってみました。自分の言葉で普段食べるもので確かめることで、自分自身の実感は深まりました。しかし、これは結局自分の言葉か相手の言葉かという立場を逆転させただけなので、各国のメンバーと共有することはできません。国を超えた開発をするには、いつまでも自分の土俵に引きこもうとするのではなく、どんな土俵であってもみんなが対等に力を発揮できるような土台工事をできるようになるのが重要だと学びました。

f:id:m_okaneya:20160810211732p:plain

※未公開のテストプロダクトです

まとめ

振り返ってみると、結局大事なことや苦労したことは日本のプロダクト開発と共通だということに気づきます。

ちがう言葉だからわからないということはなく、自分自身が徹底的に使い込み、チームメンバー全員でプロダクトの目的を共有し、そして一人ひとりのユーザーの行動に向き合うことで、プロダクトオーナーとして責任を持って判断ができるようになります。

そしてその中で気がついたのは、日々料理をする人が困ることやうれしいと思うことは、言葉や文化が違っても本質的には同じであるということです。言葉や文化の振れ幅を排除して普遍的なものに目を向けることで、日本のユーザーにも世界中のユーザーにも頼られる、毎日の料理を楽しくするサービスになれるのではないかと信じています。

最後に

世界にサービスを展開を進めているクックパッドでは、世界中の毎日の料理を楽しみにすることを目指して一緒に働く仲間を募集しています。興味を持った方は こちらへ!

Android/iOSアプリのテストの区分戦略

$
0
0

技術部の松尾(@Kazu_cocoa)です。

クックパッドのモバイルアプリ開発では、どのようなテストを書き、どのようなタイミングで、どのようなテストを実施するか?に関してエンジニア各位が意識を合わせるためにテストサイズを定義し運用してきました。ここでは、そんなテストサイズに関して簡単ですがまとめておこうと思います。

テストサイズとは

ソフトウェアテストに関わったことがある方なら テストレベルという言葉には出会ったことがあるかと思います。JSTQBでは、このテストレベルは"管理していくテストの活動のグループ"と定義しています*1。 そうでない方も、俗に言う単体テスト/統合テストなど聞いたことがあるかと思いますが、その区分がここで示しているテストレベルとなります。

一方、このテストレベルは世の中で広く使われているため、社内における共通認識を構築するにあたり個々人の認識を合わせる上で手間がありました。そこで、 私たちの開発スタイルに合うようにいくつかの指標を定義し、そこに沿ってテストを区分する方法をとりました。その結果、その区分に対して妥当な表現としてテストサイズ、という言葉をとりました。この区分はGoogleのTest Sizeの影響も受けています。

なお、テストレベルに関しては安定したリリースを継続するためのテストとテストレベルの話として記事を書いたことがあります。当時はまだこのサイズに対する定義も試行錯誤の段階だったのでサイズという表現を用いてませんでした。

以下では、今回の話の対象と区分、その実例に軽く触れながらどのような定義を用いているのか載せていきます。

対象

  • モバイルクライアントアプリ
    • サーバ側は対象外

テストサイズと区分け表

テストサイズをsmall/medium/large/Enormousに区分します。その中で、いくつかの依存する要素に対してどのような関係を持っているのかをまとめます。

featureSmallMediumLargeEnormous
networknolocalhostlocalhost/yesyes
system accessnopartial/yesyesyes
OS(APIs)noyesyesyes
Viewnopartialyesyes
external systemnononoyes
time per a test< 100ms< 2s< 120s< 500s
  • yes: 基本、mock/stubしない
  • no: mock/stubする
  • partial: テストしたい事を安定させるためのmock/stubはOKだが、基本はしない
  • localhost: localhostに向けた通信

基準

テストサイズを区分する上で、以下の要素を考慮に入れています。

  • 依存性 : OSへの依存、ライブラリへの依存など。依存性が高いほど、複雑な系を対象にする。
  • 実行時間 : テストの実行時間
  • 実施環境: ネットワークアクセスなどなどのテスト時に依存する周辺環境

これらは私たちの開発スタイルであったり、テスト容易性を考える上で特に重要な性質を持ってきています。

区分け表で使っている要素

  • network connection
    • モバイルアプリの通信環境
    • API Clientを置き換えるか、localhostを起動するか、など
  • system access
    • DB/Shared preferenceなど、データの書き込みがあるかどうかなど
  • OS APIs
    • OS固有のシステムへのアクセスがあるかどうか
  • View
    • Viewが実際に描画されるかどうか、など
  • External system
    • アプリ間連携とか含む
    • Pushとその模倣など

各種内容

実際にS/M/L/Eの4つのサイズに区分した例を出しました。その中で、それらを実際の業務でどのように使い分けているのかを例も交えながら取り上げていきます。

Small Test

内容

  • RUN FAST!!

実施頻度

  • PR毎

検出したいこと

  • 小さなロジック単位で、意図した通りにメソッドが動作さすること

検出しないこと

  • Viewが正しく表示されるか
  • ネットワークなどの周辺環境の変化に対する確認はできない

  • RoboletricやJVM上で実施されるテストコード
    • 社内では、基本的に何もアノテーションをつけない場合このテストサイズとしてテストが実行されます
  • XCTest/OCMock系を使ったテストコード

Medium Test

内容

  • OS提供のAPIや機能、描画へ依存するが一定のシナリオ実施までは行わないテスト
    • Intentの受け渡しによりViewが正しく起動するとか
    • ActivityやCustom Viewの単純な表示確認とか
    • 通信は基本mock/stubサーバ、localhostへの接続

実施頻度

  • PR毎、もしくはmasterにマージされる毎

検出したいこと

  • 幾つかの要素に対して依存性を持った要素の、主にロジック面で不備がないか
  • Androidに依存する箇所の動作を確認できる
    • intentの受け渡しが正しくできているか
    • 特定のviewの表示要素がクラッシュなく表示されているか
    • sharedpreferenceなどへの書き込みが正しくできているか
    • RoboletricでShadowにされているところ全般
  • iOSへの依存に関しても同様

検出しないこと

  • 画面遷移含んだ複数Viewの遷移が正しくできていること
  • 通信のタイムアウトエラーなどの、OSの外部環境に依存する振る舞いの変化など

  • AndroidTest、Espressoを使ったテストコード
    • @MediumTestアノテーションを付与する
  • XCTestを使ったテストコード

Large Test

内容

  • 一定のシナリオ(画面遷移)が期待通り実施されるか確認
  • その時の通信などの処理も確認

実行頻度

  • 任意、もしくはリリース毎

検出したいこと

  • Viewからの、一連の操作に対する内部処理が正しく動作しているかを確認する

検出しないこと

  • テスト対象となる単アプリ以外を含めた連携の確認
  • 実際の通信を行った上での、タイムアウトエラーなどによる表示の変化

  • EspressoやUIAutomator v2を使い、ある一定の操作を実際の描画含めて行うテストコード
    • @LargeTestアノテーションを付与する
    • 別途、社内では、Android TVに対する画面遷移含むテストの独自アノテーションを定義し実施しています
  • XCUITest / UIAutomation / EarlGrey
    • EarlGrey用のスキーマを用意
  • Appium(一部)

Enormous Test

内容

  • リリースする成果物や、アプリ関連携が正しく動作するか確認する
  • ある一定のシナリオを、リリースと同等の状態で実施する
  • OS側の設定を変化させた時のアプリの動作を確認する

実行頻度

  • 任意、もしくはリリース毎

検出したいこと

  • 複数のアプリを跨いでアプリが期待した通りに動作するか
  • システム設定に依存した箇所の表示の変化
  • リリース物そのものに対する画面網羅、画像取得、その差分検出して問題ないかどうか
  • 性能劣化がないか
  • 多機種試験

不可能

  • 表示の網羅

  • Appium
  • 手動テスト

Tips

テストサイズが小さいうちはDIなどの技術を用いてテスト容易性を上げる、依存性を下げるなどするかと思います。一方で、テストサイズが大きくなるとテストが不安定になる要素や私たちアプリ固有の依存を持つ箇所が目立つようになります。また、動きを観測することで数値計測が必要になることも多々あります。その場合に対して、私たちは必要な補助ツールを用意し、適宜対応しています。その一例を載せています。

直接テスト実施には関係ありませんが、テストをするために必要な情報を取得したり、忘れがちなところを補助するツールも作り実行頻度を調整して適用しています。

最後に

安定した開発サイクルを保ちサービス開発に集中できるようにするために、安定した・必要な時間内に終えることができるテストの実現は現在まだ必要とされる環境です。そのためには、開発のボトルネックとなっている箇所を様々な技術(skill, technology, knowledge)を用いて対応していくことが必要です。

弊社ではこのような取り組みを共に実施し、より良いサービスを提供し続ける為にエンジニアを募集しています。ご興味のある方は、是非とも覗いてみてください。

OpenSTFでAndroidのCIを2倍早くする

$
0
0

はじめまして!技術部モバイル基盤グループの加藤(@k0matatsu)です。
業務の一部でCIお兄さんとしてJenkins氏のメンテナンスなどを行っています。

今日はf:id:komatatsu:20160815174157j:plainf:id:komatatsu:20160815174215j:plainにする話をしたいと思います。
CI待ち時間1/2で PR/レビューのサイクルの速さ2倍(当社比)です。

※ ビルド所要時間のボトルネックは環境やジョブ内容によって異なるため効果には個人差があります。

当社のAndroid CI環境

さて、開発効率を2倍にする前に、まずは当社のCI環境がどうなっているか説明が必要ですね。
当社のAndroid向けCI環境は幾つかの試行錯誤を経て、現在はAmazon Web Service(AWS)を使って構成されています。
下図のように、Amazon EC2(EC2)インスタンス上に構成管理ツール:itamaeを使って作成されたJenkinsのmaster/slave構成を擁し、その中でAndroid向けSlaveが2台稼働しています。

f:id:komatatsu:20160815173846j:plain

Jenkins Slave上では、Instrumentation Testの実行にはAndroid Emulator PluginとARMエミュレーターを使いテストを実行しています。
EC2上ではハードウェア仮想化が出来ないためIntel x86 Emulation Acceleratorが利用できず、 またAndroid Emulator Pluginによるエミュレーターの起動にも時間が掛かっており、エミュレーターの起動とInstrumentation Testのエミュレーター上での実行時間がボトルネックになっていました。

現構成での解決策と問題点

そのため、今ではテストをSmall/Medium/Large/Enormousの4サイズに分け、そのサイズごとに実行タイミングを変えることで開発サイクルとCIの流れを最適化しました。
テストのサイズ分けについて、詳しくは先日のAndroid/iOSアプリのテストの区分戦略をご参照ください。
その中から、今回はCIに関係の深いSmall/Medium/Largeのみ言及します。

サイズ実行されるタイミング内容
Smallプルリクエスト毎JVM Test
Mediumプルリクエストのmasterへのマージ時Instrumentation Test
Large任意Espresso Test

テストサイズにより実施するテストを分けたことによってプルリクエスト時にはエミュレーターを起動しなくて良くなったため、テストにかかる時間が大幅に短縮されテスト以外の処理と合わせても5min/pr程度に収まる様になりました。

ですが、マージの度に実行するInstrumentation Testには今まで通りの時間がかかります。 このため、マージが頻繁に発生する場合はキューが詰まるという問題が発生し、Slaveを追加してジョブの並列度をあげることで全体のスループットをあげる方法(別名:札束で殴る)で解決せざるを得ない状況でした。
しかしこの方法は根本的なエミュレーターの準備と利用に時間がかかるという課題を解決できていないので1つのslaveによる実行時間が短くなることはなく、1回のビルドにかかる時間以上に開発効率が上がらないという限界があります。
この問題を根本から解決するにはARMエミュレーターを捨てるほかありませんでした。

OpenSTFの登場、そしてビルド所要時間1/2へ...

そんな折に燦然と姿を現したのはOpenSTFでした。 OpenSTFはブラウザからAndroidの実機を遠隔操作することが出来るオープンソースのツールです。 f:id:komatatsu:20160815173900j:plain

端末操作だけでなく、ログの取得やブラウザ経由のアプリのインストールなど様々な機能を持っており主に検証用途で利用されています。 当社でも試験的に導入しており、誰も使ってない検証用端末を繋いで簡単な動作確認などはOpenSTF上で出来るように環境構築していました。
OpenSTFの空き端末を使ってテストを実行出来るようになればこの問題を解決できるんじゃないですか?私はそう思いました。

OpenSTFでテストを走らせる

OpenSTFでテストを実行するためには、まず端末を利用状態にして確保する必要があります。 その後、確保した端末の接続用のIPとPortを取得し、adb connectする事でインターネット越しにテストを実行することが可能になります。 f:id:komatatsu:20160815173918j:plain

最新のversion2.0.1ではAPI機能が開放されており、APIを使って端末を利用状態にしたり、adb connectに必要な情報が取得出来るようになっています。

さっそく簡単なスクリプトを書いて挑みます。

DEVICE_SERIAL=`ruby stf.rb device | sed -e 's/"//g'`
DEVICE_INFO=`ruby stf.rb connect ${DEVICE_SERIAL} | sed -e 's/"//g'`
IP_PORT=(`echo $DEVICE_INFO | tr -s ':' ' '`)
export ADBHOST=${IP_PORT[0]}
export ANDROID_ADB_SERVER_PORT=${IP_PORT[1]}
adb tcpip ${IP_PORT[1]}
adb connect ${DEVICE_INFO}
adb devices

例に出てくるstf.rbはOpenSTFのAPIを叩くための簡単なRubyスクリプトです。APIドキュメントの一部をラップしています。
stf.rb deviceはAPIを叩いて端末を利用状態にし、その識別文字を取得する処理です。
同じく、stf.rb connectは上記の処理で取得した識別文字を使って接続に必要なIPとPortを取得します。

ネットワーク越しに端末に接続するadb connectを使うには、環境変数ADBHOSTANDROID_ADB_SERVER_PORTにそれぞれIPとPortを設定して置く必要があります。
その上で上記のようにadb tcpip {Port}でadb-serverのPortを設定し、adb connect {IP:Port}とすることで接続することができます。

また、初めて接続する際にはOpenSTF側にADBキーの設定が必要になります。 OpenSTFを開いた状態で上記のスクリプトを実行すると下図の様にADBキーの保存を促す画面が出ますので忘れずに保存しておきましょう。 f:id:komatatsu:20160815173602j:plain

ここまでで準備は完了です。
あとは思うがまま、Jenkins Slaveから./gradlew connectedAndroidTestしましょう!

まとめ

このように、OpenSTF連携を行うことでエミュレーターにより実行時間がかかる問題が解消し当社CIのビルド所要時間は半分になりました。
今回はエミュレーターと起動時間と、エミュレーター上でのInstrumentation Testの実行時間が主なボトルネックとなっていた為、エミュレーターを捨てOpenSTF上の実機を使うことで課題を解決しました。
同様にエミュレーターがボトルネックになっているケースでは有効な対策だと思います。

CIのメンテナはJenkinsおじさんなどと揶揄され、つらそうというイメージを持つ方も少なくないかもしれません。
ですが僕はCI待ち時間が半分になったのを確認した瞬間に最高の達成感を味わう事が出来ましたし、日々開発を頑張っている他のメンバーの待ち時間を減らすことが出来たのは誇りでもあります。
このように開発者の役にたっている事が実感できる基盤業務に興味がある仲間を募集しています。
めざせ、5min切り!
ありがとうございました。

謝辞

OpenSTFの開発は以下のお三方とコントリビューターの方々によって支えられています。
sorccuさん
guntaさん
vbanthiaさん
コントリビューターの皆さん
ありがとうございました。

開発速度を上げるための Pull-Request のつくり方

$
0
0

こんにちは、投稿開発部の森川 (@morishin127) です。クックパッド、お料理アルバムみんなのお弁当の iOS アプリの開発等に携わっています。

クックパッドでの開発は GitHub Enterprise 上で行われており、書いたコードをプロダクトに取り込む前には基本的に第三者のコードレビューが必須です。コードレビューはプロダクトの品質向上に貢献していますが、往々にして結構な時間と労力がかかるものです。Pull-Request を出してレビューをしてもらい指摘の修正を繰り返していると、場合によってはマージに数日〜1週間ほどかかってしまうこともあります。自分の開発速度を速めるため、また周りのエンジニアの開発速度を下げないためにレビューしやすい Pull-Request を出すことは重要です。この記事ではレビューしやすい Pull-Request のために心がけていることを紹介したいと思います。

説明文は構造化してひと目で分かるように

Pull-Request の説明文では Markdown が使えます。見出しや箇条書きのスタイルを利用することでかなり読み易くすることができます。例えば次のような形式で書くことが多いです。

#目的
<実装の目的を一文ぐらいで>
#やったこと
-<実装の技術的な内容を>
-<箇条書きで>
-<書く>

UI の変更前後を視覚的に

Before / After のスクリーンショット

UI に変更のあった Pull-Request では説明にスクリーンショットを用いることが多いと思いますが、このとき変更後のものだけでなく変更前の画像も比較できるようにしておくと非常にレビューがし易いです。スクリーンショットを横に並べる場合は下記の Markdown のようにするとシュッとした感じになります。

before | after
---- | ----
<imgsrc=""width="320"/> | <imgsrc=""width="320"/>

f:id:morishin127:20160816192651p:plain

長い画面のスクリーンショット

余談ですが、モバイルアプリではスクロールビューのように画面に収まらない長いビューのスクリーンショットを撮りたい場合があります。iOS 実機を使っている場合は Tailorというアプリでスクロールしながら撮った複数のスクリーンショットを結合したりしています。ただ開発中はシミュレータを使用していることも多く、PC内に保存した画像を同様に結合できる手段が欲しかったためそのためのスクリプトを書いて使ったりもしています(雑ですが)。重なり部分を判定していい感じに結合してくれます。

morishin/image-stitcher
https://github.com/morishin/image-stitcher

アニメーション GIF で動作確認

実装した機能の動作の様子は静止画では伝わらないことも多いので動作の様子を撮影したアニメーション GIF を積極的に貼っています。撮影はかつてオープンソースだったGifzoを社内用にアレンジしたものが使われています。実機の画面を撮影したい場合は QuickTime Player の機能で iPhone の画面を Mac に映しそれを先述のツールで撮影しています。

f:id:morishin127:20160816193322g:plain

変更は数百行までに

やはり大きな変更のレビューには時間がかかる上に問題点の発見も困難になります。プロダクトの内容や言語にも依りますが、 iOS アプリの開発においては 500 行を超えるとかなりレビューがしんどく感じます。大きな変更を加える場合は feature ブランチを切り、数百行以内に収まるように分割した Pull-Request を feature ブランチに向けて出すのが良いでしょう。複数の Pull-Request に分けるとレビューしてもらうものが増え時間がかかるように思えますが、変更が大きい Pull-Request は敬遠され中々レビューされなかったり(よくある)、問題点があっても発見されづらくなるリスクがあるため、適度に分割することが開発効率の向上に繋がります。

Dokumi による事前レビュー

クックパッド iOS の開発では CI 上で Dokumiというツールが動いていて、機械的な静的解析で分かるような問題点は Dokumi が Pull-Request へのコメントという形で指摘してくれます。こういったツールもコードレビューの負担を減らしています。Dokumi についての詳細は過去の紹介記事をご覧ください。 Dokumi (日本語) - クックパッド開発者ブログ

まとめ

サービス開発では品質の保持と同時に開発・検証のサイクルを速く回すことも求められます。前者を保証するためにコードレビューという作業は必要ですが、開発速度のボトルネックになることもあります。このコードレビューを速く回すためにもレビュワーに負担のかからないレビューし易い Pull-Request をつくるよう心がけましょう。

「プログラミングElixir」から分散系の世界へ踏み込もう

$
0
0

テストエンジニアしてます、技術部の松尾(@Kazu_cocoa)です。

今回は、2016年8月19日に発売されますプログラミング言語であるElixirの入門書、プログラミングElixir(以下、本書)に関して少し書こうと思います。

プログラミングElixir

プログラミングElixir

私はここ1年以上、Erlang/Elixirを学びながら業務/私事で使っていました。

業務では主にAndroid(Java)/iOS(Objectvie-C/Swift)/Rubyを使っています。その傍、 社内向けWebアプリケーションをElixir x Phoenixフレームワークを使い構築したり、HTTPリクエストをrecord/play/proxyするテストツールとしてhttp_proxyを実装していたりしました。

f:id:kazucocoa:20160819101724p:plain (社内向けWebアプリケーションのコード分布)

そんな折、翻訳者の笹田さんから恵贈いただきましたので、簡単ですがElixirについてここで書いてみます。

私がElixirを学びはじめたわけ:分散と並行処理

私は、大学の頃にソフトウェアの信頼性や、分散系の問題であるThe Byzantine Generals Problemをかじっていました。そのため、分散系や複雑系に対して技術的な興味を持っていました。また、私は数年前に負荷ツールとしてTsung、XMPP Serverとしてejabberdに出会っていました。(当時はErlangをしっかり使ったわけではありませんが。)

また、数年前からマイクロサービスのような系をサービス開発においても考える必要が出てきました。マイクロサービス時代を乗り越えるために、Rack::VCRでらくらくアプリケーション間テストサービス分割時の複雑性に対処する: テスト戦略の話クックパッドにおける最近のMicroservices事例にあるようなところです。このため、今後何らかのサービス開発するにあたり分散系を対象としたシステムに触れる可能性が高まるであろうと感じていました。

そんな時、分散系や並行処理、信頼性に関する知見をElixir/Erlangから学べそうだと感じたため学んでみることにした、というのがきっかけです。

私のElixir学習の入り口: Programming Elixir

海外ではProgramming Elixirの第1版が2014年10月15日に発売され、その後Elixirのバージョンアップとともに内容に変更が加えられてきました。そして、Elixir1.2をベースにしたものが約2年の時を経て翻訳され、プログラミングElixirとなって世に出てきたことになります。

私の学び始めも、このProgramming Elixirや幾つかの書籍、exercism.ioから始まりました。私は原書を1.0の頃に購入したきりだったので、Elixir1.2で新たに追加された with構文など、私が読んだことのない内容までが書籍として収まっている状態を見て新鮮さも感じました。

ところで、Elixirは2016年8月19日現在、すでに1.3.2がリリースされ、masterブランチでは1.4系に向けて開発が進んでいます。そのため、幾つかの関数単位では変わっている箇所も見られますが、多くの内容は本書においては問題にならないはずです。

プログラミングElixirについて

本書について

Elixirを学ぶにあたり、基本的な構文の話は当然ながら、Erlang/OTPやマクロ、その周辺のエコシステムの話は避けては通れません。

この書籍は、Elixirの基本的な構文から入り、プロジェクトを作りながらそのエコシステムを学び、OTPとしてGenServerなどの代表的な作り、さらにはマクロまで、ちょうど良い具合に内容が発展しながら話が進んでいきます。

第1部では、変数の束縛の話から始まり、1.2から導入された with構文に関するまでの構文や構造に関して網羅しています。その中で無名関数や高級関数などの話もされます。再帰表現による繰り返し処理やパターンマッチ、制御フローのような基本的なことがらから、末尾最適化などの話もかじることができます。

第2部では、周辺のエコシステムの話が主になります。mixと呼ばれるビルドツール、ExUnitと呼ばれるテストフレームワークやテストコードがドキュメントになるDocTestsなどです。Elixir1.3からはテストコードに構造を持ち込むためのExUnit.Case.describe/2なんかも加わっているのですが、Elixir1.2では扱われません。このようなところは、若干の差があります。

また、Elixirを用いて mixを使った簡単なプロジェクトを作りながら、Erlang/OTPの資産を学ぶこともできます。その中から、GenServerやTask、Agentはもちろんのこと、スーパーバイザやその木を構成するといった、プロセスの監視/再起動戦略や分散系の構築などの入り口に触れることができます。:observerといった標準のモニタリングツールの話もあります。(ここでいう プロセスは、 ErlangVMにおけるプロセスを意味します。)

ここまで読み進めるとざっとElixirのエコシステム含む全体がどんなものか学ぶことができると思います。また、簡単なライブラリであれば自身で作成し、hex.pmにアップロード・公開することができます。

第3部ではマクロの話やプロトコルによる機能拡張の話など、少し踏み込んだ話になってきます。Lispを学んだことがある人であれば、Elixirのマクロのとある側面では構文に親しみを覚えるかもしれません。私もex_parameterizedという、パラメータ化テストを支援するようなマクロを実装してみました。

このように、本書は大きく3部に分かれています。

こういう人におすすめ

私は英語で学んでいたのですが、本書を読むとやはり日本語訳されているだけあってElixirを理解することに集中することができると感じました。もとの書籍の完成度もさることながら、それが母国語で読めるというのはやはり新しいものを理解する第一歩の手助けとしてとても大きいものがあります。

本書はElixirに興味はあるけれど入り口をどこにおこうか悩んでいる方、Web上で少し学んだけれど理解を整理して腹に落とし込みたい人におすすめします。一方で、この書籍を全くプログラミングに触れたことがない状態で読むには少し難しいかもしれません。

関数型プログラミングを全く知らない状態で読む場合も、少し読み進めるにあたり負荷がかかる場面があるかもしれません。ただ、新しい考え方を学ぶきっかけになるかもしれませんので、読んで損はないかと思います。

Elixirに対してさらに興味を持った人へ

Erlang/Elixirに触れると、"Let it crash"という言葉をよく目にします。これは、処理がクラッシュしたらそのままにしておけ、という意味です。ただ、これは好き勝手にクラッシュさせて良いということではありません。実際は例外をちゃんと考える必要もありますし、プロセスのモニタリングも頭に入れながらプログラムを組む必要があります。また、例外発生時の影響を局所的にするために、スーパーバイザなどを使ったプロセスの設計も考慮する必要があります。

この書籍をざっと学んだ後に、そのようなより発展したことを書籍を使い学びたい場合、以下を参考にすると良いと思います。プロセス間の参照渡しや値のコピー、性能に関すること、Erlang/OTPとの付き合い方などを少し詳しく学ぶことができます。

最後に

簡単ですが、本書の概要や学ぶことができること、さらに学びを深めるために、という形で話をまとめてみました。

初めに書きました私のきっかけであった分散、並行処理への理解は、学び始めの狙い通り深めるきっかけになりました。例えば、並行プロセスとメッセージパッシングによる分散系の構築とそれらを使った処理を実現できること、それらの耐障害性を高めるための仕組みなど。ナインナインの稼働率を実現する、培われたErlangVMとそれらをWebアプリケーションでも活用するElixirの工夫と言ったところです。私個人は、Elixirから入りErlangを学んだことは、プログラミング言語の構文を単に学ぶというよりは、分散系に対する設計レベルで考え方を学ぶことができました。

Elixirは言語としても、そのような分散系の構築や非同期処理を少ない実装で実現できる面白さも経験することができます。本書も日本語で手に取りやすい形になったので是非とも手にとって、案外、分散系も手軽に扱えるものだと体験してみてください。

最後になりますが、本書を翻訳されました笹田さん、鳥井さんには重ねてお礼申し上げます。

プログラミングElixir

プログラミングElixir


画像の認識・理解シンポジウムMIRU2016に参加してきました

$
0
0

こんにちは。人事部の小久保です。

8月1日(月)〜4日(木)の4日間、画像の認識・理解シンポジウムMIRUに研究開発部のメンバーと参加してきました。今回は、MIRUの内容やなぜ参加してきたのかについてご紹介したいと思います。

MIRUとは

今回で19回目を迎える画像の認識・理解シンポジウムで、画像の認識と理解技術に関する国内最大の会議です。

具体的には、研究者や技術者、学生が基礎から応用までさまざまな最新の研究発表をし、討論をする場となっています。今回は静岡の浜松で開催されました。

各自の発表内容は1枚のポスターにまとめられたものが展示されており、それぞれポスターの前で紹介する形になっています。発表やデモセッションに加えて、特別講演も別会場で行われました。

f:id:bonami:20160822155720j:plain

クックパッドの取り組み

クックパッドは今回初めてMIRUに参加したのですが、企業展示という形でブースで発表をしました。

f:id:bonami:20160822155746j:plain:w500

毎日午前中には、スポットライトセッションという形で、ブースで紹介している内容を30秒間宣伝できる時間もありました。

f:id:bonami:20160822155757j:plain:w500

なぜクックパッドが学会に参加するのか?

以前からクックパッドには研究開発グループという形で、研究を専門に担当しているチームがありましたが、7月から研究開発部という組織に変わり研究開発により力を入れていくことになりました。具体的には、画像や言語を中心とした機械学習や料理に関する研究を行っています。

そこで、研究開発をすることはもちろんなのですが、学会での活動も積極的に実施をしていくため、今回MIRUに参加をしました。

各研究室の取り組み

クックパッド以外にも多くの研究室が料理に関する研究を発表していましたので、いくつかご紹介します。

・東京大学 相澤研究室
東京大学の相澤研究室では食事記録アプリのログを分析するため、料理名を一般 化する研究を発表していました(例えば、「シュリンプエッグサンド」を「サンドイッチ」にする)。また、画像認識の精度を上げるため、個々人にパーソナライズした認識エンジンを作る研究も発表していました。

・電気通信大学 柳井研究室
電気通信大学の柳井研究室では、画像認識・画像変換をモバイルで実行するための研究をしていました。機械学習のモデルからC言語のコードを自動で作って、これを高速に動かすために行列の計算を並列化していました。また、Twitterの画像つき投稿を使って、「博多ラーメン」などの細かいカテゴリに画像を分類したデータセットを紹介していました。

・名古屋大学 村瀬・井出研究室
名古屋大学の村瀬・井出研究室では料理の撮影をサポートするため、料理の写真の魅力度を測る研究をしていました。料理を様々な角度から撮った画像のデータセットを作って、どのような特徴がその魅力度に関わるのかを発表していました。

・京都大学 美濃研究室
京都大学の美濃研究室ではレシピナビゲーションシステムを研究していました。カメラで現在の調理行動を認識し、次の手順をナビゲーションしてくれるものでした。発表では実際にトマトやアボカドを調理することで、ナビゲーションの様子を見ることができました。

・大阪府立大学 吉岡・井上研究室
大阪府立大学の吉岡・井上研究室ではレシピ動画を自動要約するシステムを研究していました。ヘッドマウントカメラを使って調理中の手元の動きを撮影し、画像から抽出した手の領域から現在の調理行動を識別する実験をしていました。

どれも非常に高度な内容で、私達も大変勉強になりました。

まとめ

今回MIRUに参加されてる方々とお話する中で、クックパッドって機械学習の取り組みしてたの?!と驚かれることが多くあったのでもっと認知されるような活動が必要だなと実感しました。

ただ、参加をしたことで新たに一緒に共同研究をやりたい、クックパッドのデータを使いたいと言ってくれる研究室もあったので参加してよかったなと思っています。

なお、できたてほやほやの研究開発部へJOINしていただけるメンバーも絶賛募集中です!!今なら研究開発部の立ち上げから経験することができます。ご興味がある方はぜひご応募ください。お待ちしております。

新サービス立ち上げ時の重要指標のデザイン

$
0
0

こんにちは、株式会社ビットジャーニーに出向中の出口 (@dex1t) です。ビットジャーニーでは、社内情報共有ツール Kibela*1のサービス設計やプロダクトマネジメントに責任を持ちつつ、エンジニアとして開発全般に携わっています。

今回は、新サービスの立ち上げ時にどのような考えで重要指標*2を設計し、それを実際の開発のなかでどう使っていくかという話をします。

なぜ検証をするのか

そもそもなぜ新サービス立ち上げ時に、重要指標や検証といった考えが必要になるのでしょうか。それを考えるにあたって、クックパッド的なサービス開発の流れを改めて整理してみます。

企画と検証は表裏一体

サービス開発といえば、企画・開発・検証をぐるぐる回すというのが一般的だと思います。指標は検証段階で活用する道具です。企画で考えたことを確かめるのが検証段階であり、企画と検証は表裏一体です。 したがって、指標の設計をするにあたっては、その前段階である企画段階について抑えておくのが重要です。

サービス企画には様々な方法論があると思いますが、「何を作るべきか定義する」ことは、どんな方法にも共通しているのではないでしょうか。クックパッド内でもやり方は様々ですが、私の場合は次のような流れで定義しています。

  1. 思想を定める
    • サービス価値、目指す世界観を定義する
  2. 体験を定める
    • サービス価値を実現するためにどんな体験が必要を定義する
  3. 機能を定める
    • 体験を提供するためにどんな機能が必要か逆算する

これらをフォーマット化したものが、この開発者ブログでも何度か紹介されている、アプリケーション定義ステートメントシートEOGSです。上記3点を抑えられれば、フォーマット自体は自分の慣れたものを使うのが一番だと思います。

思い込みを確かめる

ここで大切なのは、企画はあくまで開発者の思い込みであり、企画を具現化した後にはそれを確かめる必要があることです。先に挙げた3点で言えば、次のような確かめどころがあります。

  1. 提供している「体験」が、「思想/価値」を実現できているか
    • 例) 「今晩の献立がすぐに決まる」体験は、「毎日の料理を楽しみにする」という価値に繋がっているか
  2. 提供している「機能」が、「体験」に寄与しているのか
    • 例) 「人気順検索」機能は、「今晩の献立がすぐに決まる」体験に寄与しているのか
  3. 提供している「機能」は、意図通り「機能」しているのか
    • 例) 「人気順検索」機能は、どんな人にどれぐらい利用されているか

1.を定量的に正しく検証するのは難しく、定性的手法での検証が向いていると思います。本エントリは指標を使った定量的な検証の話なので、2.と3.について考えます。

指標をみる2大シーン

先の2.と3.の言い換えになりますが、指標をみる2大シーンとして次が挙げられます。

  • 機能が定めた体験に寄与しているか (線の検証)
  • 機能 (feature) が機能 (work) しているか (点の検証)

クックパッドにおけるレシピを探す体験を例にすると、次のようなイメージです。

f:id:dex1t:20160830043356p:plain

一般的に「検証」というと、CTRなどの比較によるA/Bテストを思い浮かべるのではないでしょうか。それはあくまで「点の検証」であり、ある機能の最適化はできても、その機能が体験全体にとって必要かどうかは判断が難しいところです。

サービスの立ち上げ時は、ある一点の機能だけを磨きこむことに集中するよりも、定めた体験がそもそも正しいのかをまずは確かめるべきだと私は考えています。これは、ほとんどの新サービスの場合、一機能の良し悪し以前に、定めた体験がユーザーの欲求に合致していないことが多いからです。そのため、サービスの立ち上げ時こそ、「線の検証」を重視すべきだと考えています。

何を測るのか

それでは先に挙げた、体験 (線) の検証をするためには、具体的に何をすればいいのでしょうか。

体験の定義としてのユーザーストーリー

体験 (線) を検証するためには、まずはその体験の定義が必要です。定義の表現方法には様々な手法があるかと思いますが、私のプロジェクトでは、複数のシナリオから成るユーザーストーリーを書いています。ユーザーストーリーとは、ざっくり言えば、開発者が頭のなかに描く「サービス上でユーザーはこう考えて、こう行動する」という妄想を文章にしたものです。

敢えて妄想と書いたのは、サービス開発初期はユーザー理解がまだ浅いことが多く、ストーリー自体の妥当性は低いと考えられるからです。あくまで妄想ですが、文書化やそのレビューを通して、ユーザーに期待する行動についての認識が、チーム内で統一される効果は得られます。チーム内での認識のブレは、新規サービス立ち上げ時に立ち向かうべき問題の1つです。これを解消できるのは大きな効果です。

ユーザーストーリーの構成

サービス開発初期のユーザーストーリーは、未検証であることは自体は仕方がありませんが、それでもあまりに現実味が無さすぎると使い物になりません。そのため、書き方には注意が必要です。ユーザーストーリーを構成するシナリオは、次の2つを分けて書くようにしています。

  • アクティビティシナリオ
    • ユーザーの心情と行動にフォーカスして書いたシナリオ
    • クックパッドではセリフ調で書くことが多いです
    • 例) (仕事帰りに) 今日の晩ごはんどうしよう。たしか冷蔵庫に茄子があったから消費したいな。へー茄子のチーズ焼きか。簡単そうだし美味しそう!帰ったら作ってみよう。
  • インタラクションシナリオ
    • 目的を達成するための、サービス上での具体的な操作を書いたシナリオ
    • 例) クックパッドiOSを開く、検索ボックスをタップ。茄子と入力し検索する。人気順検索の1位になっていた茄子のチーズ焼きのレシピをタップ。材料欄と手順欄をスクロールして確認し、MYフォルダに保存。

アクティビティシナリオを書く上での注意点は、具体的な操作名や機能名を出さないことです。つい「この導線をクリックする」のような表現を使いがちですが、普段の生活の中で導線やクリックといった言葉は使いません。結構書くのがしんどいのですが、ここでのシナリオに現実味が感じられない場合は、おそらく実装しても同じことが起きるでしょう。

このようにユーザーストーリーを書く上では、アクティビティとインタラクションを区別すること、そして何より、開発を進める中で深まったユーザー理解を随時ストーリーに反映し、妥当性を高めていくことが重要です。

どのストーリーを検証すべきか

ストーリーといっても、多くの場合サービス上には無数のストーリーが考えられます。サービス上の登場人物 (キャスト) が多ければ多いほど、ストーリーも増えていきます。例えば、私が今携わっている社内情報共有ツール Kibelaでは、社内ツールという性質上、「記事を閲覧する人」「記事を投稿する人」だけでなく、「Kibelaを社内で管理する人」といった、多様なキャストが存在し、そのそれぞれに提供すべき体験 (ストーリー) があります。

サービス立ち上げ初期は、全てのストーリーを網羅して検証することは難しいですし、検証だけに時間をかけることになると本末転倒です。そのため、このストーリーが欠けたらサービスが成り立たない、という一点にまずは集中して検証すべきです。

Kibelaの場合は、「記事を投稿する人」のストーリーにまずはフォーカスしています。情報共有ツールである以上、記事の投稿による情報共有が成立しないと元も子もないからです。このような考え方は、書籍『Lean Analytics』においてOMTM (One Metric That Matters) として紹介されています。書籍のなかでは、様々なサービスのOMTMが紹介されているので、指標を設計する上ではぜひ一読をオススメします。

どうやって測るのか

ここまでは設計の話でしたが、次は目指すべき体験 (ストーリー) に対する現状の達成度をどうやって測るかについてです。

これは、定めたインタラクションシナリオから、ユーザーの行動を抜き出し、それらを行動トラッキングツールで測ることで実現できます。クックパッドではそのツールとして、Mixpanelを使うことが多いです。具体的な方法については、データドリブンでユーザー体験を改善する試みのなかでご紹介していますので、よろしければご覧ください。

f:id:dex1t:20160830043937p:plain

重要指標を活用する

ここまでで体験を定め、ストーリーを通して指標化し、実際に数値として計測することができました。ここからは実際のサービス開発の中で、定めた指標をどう活用していくかについてお話します。

ダッシュボードでモニタリングする

サービス開発初期は、大胆なサービス設計の変更や、ユーザー層の変化など、指標に影響を与える要因が多く存在します。そのため、一度定めた重要指標は継続的にモニタリングしていくことが重要です。また、モニタリングする指標はダッシュボードとして、一箇所にまとめています。見るべき指標が色んなツール上にバラバラしていてアクセスし辛い状況だと、見ること自体が億劫になり、設計した指標も無意味になります。

Kibelaでは行動トラッキングツールとしてMixpanelを使っているため、ダッシュボードもMixpanel上に作りました。Mixpanelには、Platform機能というものがあり、これを使うとMixpanel APIを使って、Mixpanel上の値をよしなに操作した上で可視化しダッシュボード化できます。これがベストとは言えませんが、Kibelaでは見るべき指標をMixpanelに集約しているため、今のところ必要十分でした。

f:id:dex1t:20160830044006p:plain

意識せずに重要指標を見てしまう状況をつくる

詳しくは後述しますが、ここで定めた重要指標はチームの共通理解であるべきです。そのため、ダッシュボードを活用するのがチーム内でひとりだけだと不十分です。チームメンバーの日常の導線の中にダッシュボードを置き、意識せずに重要指標を見てしまう状況を作ることも大切です。

私のチームでは自分たちのサービスであるKibelaをドッグフーディングしているため、メンバーは常日頃Kibelaを見ています。手前味噌になりますが、Kibelaは社内ポータル的な使い方ができ、iframeで上記のダッシュボードをKibela内に埋め込んでいます。これで、毎日Kibelaを開く度に重要指標のグラフが目に飛び込んできます。

f:id:dex1t:20160830044019p:plain

また関連して、Statsbotを使って、重要指標のサマリーをSlackに定期的に流すといったこともしています。

f:id:dex1t:20160830054851p:plain

このようにして、サービスの健康状態をチーム全員が無理せず把握できるような状況を作っています。

毎週定例で分析し共有する

ここまで述べてきたような「体験 (線) 」は、「機能 (点) 」への変更の積み重ねによって変化が起きるものです。そのため、サービスのアップデート起因とは別に、定点観測的に分析をおこなっています。

Kibelaの場合は、毎週月曜日に定点観測しています。結果はドキュメントとしてまとめてチームメンバーに共有します。繰り返しになりますが、これも重要指標の理解を個人に留めずチームの共通理解にするための試みです。

f:id:dex1t:20160830044051p:plain

重要指標を軸にコミュニケーションする

基本的にサービス開発は、正解がない中での細かい意思決定の連続だと思います。そのため、チーム内で何らかの基準を持った上で、議論するのが大切だと考えています。ここで定めた重要指標はその際にも有用です。

タスクの優先順位付けや、製品仕様の決定、デザインの方向性の決定、カスタマーサポートの方針、などサービスに関係するあらゆることは常に重要指標を軸にして判断するようにしています。こうすることで、議論の方向性がブレず、意思決定の速度が上がると考えています。

まとめ

本エントリでは、新サービス立ち上げ時の指標設計とその活用方法についてご紹介しました。指標というテーマだったため、インタビューに代表される定性的な検証手法には触れませんでしたが、決して蔑ろにしているわけではありません。実際Kibelaでも、オンライン・オフライン問わずインタビューによる生の声は非常に重要視しています。定量と定性の両方の良さを組み合わせつつ、サービスの検証を進めていくことが重要だと考えています。

最後になりますが、クックパッドはもちろんビットジャーニーでも、デザイナー・エンジニアを募集しています。このようなサービス開発にご興味あるかたは、@dex1tまでお気軽にお声がけください!

*1:8/1にティザーサイト https://kibe.la/を公開したばかりのサービスです。現在、先行登録いただいた方にベータ版へのご招待を順次進めています。

*2:KPIやKGIといった用語とほぼ同義です

Ruby on Rails アプリケーションにおけるモンキーパッチの当て方

$
0
0

技術部の牧本です。 今日はモンキーパッチの話をします。

モンキーパッチとは何か

そもそもモンキーパッチ (monkey patch) とは何でしょうか? 端的に言えば、言語の組み込みクラスやライブラリ、その他外部ライブラリの挙動を、動的に拡張する仕組みをモンキーパッチと呼びます。 *1

例えば、Ruby のモンキーパッチのすごく単純な例として以下のようなものがあります。

moduleNilClassExtensiondefempty?trueendendNilClass.prepend(NilClassExtension)

インスタンスが空であるかどうかを判定するメソッドとしての #empty?StringArrayなど様々なクラスに存在しますが、 nilを唯一のインスタンスとする NilClassには本来は存在しません。 このモンキーパッチを導入することで、通常はメソッドがないことによる例外が発するはずの nil.empty?というメソッド呼び出しが、 trueを返すようになります

さて、このようなパッチが読み込まれたシステムでは、予想外の挙動が起きます。 例えば、 method_missingを用いてフォールバックするようにしているライブラリがあるとすると、 nilは本来 #empty?メソッドを受け取れないはずが、パッチが存在するためにフォールバックせず、挙動が変わってしまいます。

ここで例に挙げた NilClass#empty?メソッドを追加するモンキーパッチは、あとで述べるように、モンキーパッチとしては行儀の悪い部類です。

しかし、このパッチは、実はかつて実際にクックパッドに存在していたものです。

クックパッドの中心となるアプリケーションのレポジトリは最初に作られてから10年弱が経過しており、歴史的経緯から様々なモンキーパッチが存在します。 われわれは、これらのモンキーパッチとうまくやる方法を考えていく必要があります。

そこから得られた知見をもとに、本稿では Ruby on Rails アプリケーションにおける、モンキーパッチの当て方、そして、モンキーパッチの外し方について紹介します。

モンキーパッチの当て方

さて、あなたが Ruby でアプリケーションを書いていて、ライブラリなどの標準の挙動を変えるためにモンキーパッチを導入したいと考えたとします。 その際、まずは最初の原則を当てはめましょう。

最初の原則 - モンキーパッチを使わない

まず、本当にモンキーパッチを当てる必要があるかを考えましょう。 それが何らかの不具合に対する対策だとしたら、ライブラリを最新バージョンにアップデートすることで対応できませんか。 発想がモンキーパッチになってはいけません。 何らかの組み込みクラスの挙動を変えたい場合、クラスそのものを拡張する以外の方法は取れないか考慮するべきです。

冒頭述べた NilClass#empty?について言うならば、 nilが入る可能性がある変数に対し、 var.empty?と呼んだときに trueが返ってほしいのは理解できなくはないですが、Rails アプリケーションでは var.blank?というほぼ同等の代替手段があるので回避できるはずでした。 そういう観点ではこのモンキーパッチは入れるべきものではなかったと言えます。

それでもモンキーパッチを当てたいとき

とは言え、モンキーパッチを使わざるを得ない場面が起きるかも知れません。 よくある例として、外部のライブラリになんらかのバグがあるがそれが修正されたバージョンがリリースされていない場合、または、ライブラリのアップデートによる影響範囲が大きく別途検証が必要なためにすぐにアップデートできない場合などです。

以上のような理由でモンキーパッチを当てなければならない場合、最大限パッチをコントロールする必要があります。

パッチを隔離する

モンキーパッチを導入することを決めたとき、まず行なうべきはモンキーパッチ用のディレクトリを作成することです。 これによって、他のモジュールやクラスに影響を与えるコードを一箇所に集めることで一覧性を高め、読み込みのタイミングを統一します。

クックパッドでは #{Rails.root}/lib/monkey_patchesというディレクトリがよく使われており、このディレクトリをイニシャライザで requireしています。

# config/initializers/000_monkey_patches.rbDir[Rails.root.join('lib/monkey_patches/**/*.rb')].sort.each do |file|
  require file
end

アプリケーションから見えるインターフェースを変えない

モンキーパッチを当てる場合に気をつけることの一つに、パッチを当てたことによってアプリケーションコード (モンキーパッチを当てたライブラリを使う側のコード、 Rails の場合は appディレクトリ以下にあるコードなど) を変更させるべきではないうものがあります。 つまり、たとえライブラリにパッチを当てたとしても、新しいインターフェースを増やしたり、既存のインターフェースを変更させないということです。

これによって、モンキーパッチを外すときの労力がかなり下がります。

例えば、最初に論じた NilClass#empty?を追加するというパッチは、この原則に則しておらず、実際にパッチを除去する際に大きな労力を要しました。

パッチが不要になったときに外せるようにする

さて、影響範囲を最小限にするという観点では、パッチが不要になるタイミングで適切にキャッチアップしてパッチを削除することができるようになるべきです。

最低限やるべきは、なぜそのパッチを導入することになったかをコメントとして残すことです。 さらに、どういう状態になればパッチを外して良いかまで明記されていると、将来の自分やチームメンバーがそのパッチを外せるかどうかで悩むことを防げます。

より良い方法は、パッチが不要になったら開発者が自動的に気づけるようにすることです。 例えば、ライブラリの特定のバージョンの挙動に依存してパッチを当てざるを得なくなった場合、以下のようにライブラリをアップデートしたら例外が発生するようにして、もしパッチを消し忘れてもテスト実行時などに気づけるようにします。 *2

# lib/monkey_patches/nanika_ext.rbrequire'nanika/version'unlessNanika::VERSION == "2.2.0"raise"Consider removing this patch"endmoduleNanikaMonkeyPatch# monkey patches go here...endNanika.prepend(NanikaMonkeyPatch)

このように、大規模なアプリケーションにモンキーパッチを当てる際には細心の配慮をもって対応する必要があります。

モンキーパッチの外し方

さて、当てたモンキーパッチはいずれは外されなければなりません。 次に、どのようにモンキーパッチを外すのかについて論じていきます。

モンキーパッチを当てるときに注意を払えば、開発者はどのタイミングで外せるかを気づくことができるし、安全に外せるようになっているはずです。

モンキーパッチを外す作業は、外部ライブラリのアップデートや内部ライブラリの挙動を変更した場合の対応とほぼ同じです。 つまり、影響範囲を調べて、動作確認をして、問題なければリリースするという手順を踏みます。

先述の通り、ライブラリのインターフェースはパッチを当てた場合も外した場合も同じであることが期待されるので、基本的にアプリケーションのコードを変更する必要はないはずです。 しかしながら、実際はパッチによる副作用によって思わぬ場所で不具合が発生するかも知れないので、一度入れたパッチは細心の注意を払って外すべきです。

まとめ

本稿では、 Ruby on Rails アプリケーションにおけるモンキーパッチの当て方について記述しました。 先に述べたように、モンキーパッチを可能な限り使わず、使うときは最小限の影響範囲に留めて、なるべくふつうの Ruby、ふつうの Rails を使うことがアプリケーションの寿命を延ばす秘訣であると考えます。

*1:そもそもなぜ「モンキーパッチ」と呼ばれるようになったかについては、ある出典によれば、 Zopeの開発者内で使われ始めた用語であり、他のコードと衝突する可能性のあるパッチが ゲリラパッチ (guerilla patch) と呼ばれていたが、音が似ていることによって ゴリラパッチ (gorilla patch) に転じ、さらにそこから モンキーパッチ (monkey patch) になったとあります

*2:われわれのチームでは、これを「パッチに賞味期限を設定する」と呼んでいます

新規アプリのデザインで心がけたい5つのこと

$
0
0

こんにちは、株式会社トクバイ出向中のデザイナー 吉井です。

まだあまりご存知ない方も多いと思いますが、株式会社トクバイは2013年にクックパッドの新規事業としてスタートした「クックパッド特売情報」を分社化し、今年7月に設立されました。 それに伴いサービス名も「トクバイ」と改め、この夏Android / iOSの両アプリをリリース致しました。

※9月5日現在、iOSアプリはAppStoreのおすすめにフィーチャーされています!

f:id:hrtk441:20160905164635j:plain

トクバイは日々の特売品やチラシ、タイムセール情報など、リアルタイムで自分の近くのお店の買物情報を閲覧できるサービスです。

私はクックパッド特売情報の頃からデザイナーとして一連のサービス開発に携わっていますが、今日はその「トクバイ」も含め新規アプリをデザインする際、私が心がけている大きなポイントを5つご紹介します。

ユーザーをしっかりと理解する

f:id:hrtk441:20160905163720p:plain

まず基本中の基本ですが、価値を届けたいユーザーを知らないことには良いサービスは作れません。

そのなかで私個人としては、ユーザーと直接対話したことがあるかどうかで、実際のプロダクト開発に与える影響が格段に変わってくると考えています。

今回のトクバイの開発でも、「買い物」という行動はあまりに日常的で普遍的であるため、とりあえずなんか(我々が思うに)良さそうで便利なアプリにしよう、という感じでぼんやりしたままに進めてしまうと、結果なんだかよく分からないモノになってしまいかねませんでした。

また、レシピサービスであるクックパッドの内部に同居していたこれまでとも状況が異なります。

今まではレシピに紐付く形で買物情報が提示されていましたが、今回単体のサービスとしてクックパッドから切り離されることで、ユーザーのアプリの使い方が今までとは変わってくることが予想できました。

そこで私も含めた開発メンバーで、開発に入る前に実際に色んな属性のユーザーの方(クックパッド特売情報のユーザー)にお会いしてみるという試みをしました。

実際に10名以上のユーザーさんとお会いしてお話を聞いてみると、やはりそれぞれで持つ課題感が微妙に異なることが分かります。

子連れでゆっくり買い物できない、買いたいものがいつも決まらない、色んなお店の情報を比較して見たい...

ユーザーさんと直接対話することでより身近に課題感を感じられたことは、その後の開発プロセスにおいて具体的なイメージがつきやすくなるなど様々な好影響がありました。

本エントリでの詳細は省きますが、このあたりはプロダクトオーナーである弊社三浦のエントリも是非合わせてご参照ください。

最初にコアとなる価値を作りこむ

現在トクバイではスーパーに加え、ドラッグストアやクリーニング、ホームセンターなど、食品に限らない生活領域に関する様々なお店からも日々情報をお届けしています。

それが我々の持つコンテンツのひとつの強みではあるのですが、ただその情報を並べて表示するだけでは、他の競合サービスと何ら差別化が図れません。

そこで我々は前項で掴んだユーザー像をもとに、「複数のお店の情報から効率的に欲しい情報へアクセスできる」ことをコアとなる価値として設定し、それを実現するためのプロトタイプの作りこみを先に進めていきました。

特に「トップ」と呼ばれる複数店舗の情報を集約して表示する画面については、これまでのクックパッド特売情報にも存在しないものでありながら、上記のコア価値を体現する画面としてかなり多くの時間を割きました。

その名の通り起動して一番最初に開かれる画面でもあるので、アプリの「顔」となるべく相応しいものを、とメンバー間で議論を重ねに重ね、何度もプロトタイプを作り直しています。

ProttやFlinto for Macを用いてそれらを再度ユーザーさんや社内スタッフにも触ってもらいながら、率直な意見・感想を吸い上げ、組み立てては壊し...の繰り返しです。

f:id:hrtk441:20160905163700p:plain

苦しい時間が続くときもありましたが、粘り強く検証を繰り返すことでようやくひとつの形が見えてきます。

ここであまり固めきらずにある程度柔軟性を残した形で次のフェーズに移りますが、この部分の試行錯誤を早くから重ねておくことで、早期に足元が固められたような実感がありました。

我々のコアはこれだ、とチームで共通認識が持てるようになることで、その後の議論の不要な発散を抑えられ、腰を据えて開発を進めやすくなる効果があったと考えています。

早く全体像を捉える

f:id:hrtk441:20160905163713p:plain

コアが見え始めてきたら、次に思いつく限り、このアプリをリリースさせるために必要な画面の総量を洗い出します。

個人的に手法は何でもいいのですが、とにかく明確な画面単位、または機能単位で洗い出すようにします。 これも開発初期の早い段階で「今からやらなければいけないことの全体像を把握できている」という状態を作れていることが大事だからです。

そうして洗いだしたタスク量をもとにざっとマイルストーンを敷いていくわけですが、これを開発メンバー間にも見えるようにすることで、

  • 決まっていないことがいつまでに決まっていないとまずそうかが分かる
  • 時間をかけて考えるべき画面とひとまずそうでもない画面のバランス感が分かる
  • タスク消化がどれだけ遅れだすと後半の巻き返しで余裕がなくなるが分かる
  • 工期に対してできないこと、やらないこと(優先度)が早いうちに見極められる

など、自分のスケジュール管理の範囲を越えて様々なメリットが生まれました。

何か具体的な画面がなければ体験がどうこうという議論もしづらく、エンジニアも実装計画が立てにくくなります。

プロダクトの輪郭を浮かび上がらせていくことはデザイナーのひとつの職責であると思っているので、ここを率先して進めていくことが、大きなトラブルもなくリリースまで至れた一つの要因であったと考えています。

都合の良いケースだけで考えない

f:id:hrtk441:20160905163706p:plain

トクバイは、全国各地のお店から投稿いただいたチラシ情報を掲載することで成り立っています。

そのため各コンテンツに付随する情報量や、そもそもの投稿の有無はお店の裁量に委ねられる部分が多く、地域やお店の日毎の投稿状況によって、ユーザーさんに届くコンテンツの量や密度に少なからず差が出てしまうのが現状です。 (すべてのユーザーさんに均質な価値を届けられるよう、鋭意改善を重ねています)

デザイナーであれば心当たりがある方がいるかもしれませんが、要件を深く理解しないままついつい都合の良い理想的なデザインだけを作って、それだけで満足な気持ちになってしまったことはないでしょうか。

もちろんそういった状態を見越してデザインを作り上げていくことも大事ですが、足元を見ずに一部のケースでしか成り立たないものを作っていてはあまり意味がありません。

今回の開発でも、ここでいう「お店からの投稿が少ないなど、ユーザーの期待に反するがっかりなケースはなんだろう」と私個人が常に頭に置いておくことで、デザインのパターンを深く網羅的に展開できるようになりました。

複数のケースを想定する意識を強く持つことは、デザインを決定へ導くにあたって議論に深みを持たせ、実装面でも考量漏れによる工期遅延やデザインの練り直しなどのリスクが減らせるため、新規開発に限らず重要であると感じています。

また副次的な効果として、そういった「がっかりなケース」を減らしていくためにはどういう打ち手を仕掛けていくべきか、というネクストステップの手がかりが掴めてくるのも、この点を徹底していて良かった、と感じる点です。

シンプルな体験を追求する

デザインとはユーザーの体験をいかに心地よく設計できるかが一つの重要な要素であり、決してセンスよく、オシャレに、だけで語られるものではありません。

そのためトクバイのリリースバージョンでは、まずはシンプルでミニマムな、最低限ストレスのないユーザー体験を作っていく、ということに重点を置いて進めました。

例えば、Material Designに代表されるトランジションのアニメーションですが、確かに見ていて気持ち良く、新しいことを自由に試せる段階ではつい取り入れたくなることもあるかと思います。

しかしあれは本来ページ前後の関係を分かりやすくする、一連した体験を提供する、などの目的を持って設計されているものであり、「なんとなく今っぽいイカした感じのアニメーションをつける」ことが目的にすり替わっては本末転倒です。

トクバイの開発でも、写真がついたUIパーツをタップした時のトランジションについて、商品写真を拡大しながらシームレスに次ページへ遷移するといった演出を試みたタイミングがありました。

やや分かりにくいですが、プロトタイプ上だと下図のようなイメージです。

f:id:hrtk441:20160905163625g:plain

しかしこの内容でエンジニアに実装してもらったものを端末上で確認してみると、遷移時に微妙なチラつきが発生するなど細かな違和感があり、思っている品質に届かせるにはまだいくらかの調整が必要であると感じました。

工期に比較的余裕があればその後のブラッシュアップにも時間をかけるところですが、私の経験上このようなアプリ開発(特に新規)の現場においてそういったことは多くはないのではないかと思います。

勿論、今回の我々の場合も例外ではありませんでした。

局所的な調整に時間をかける余り、他の部分がおざなりになってしまい、アプリ全体を通した品質が犠牲になっては折角の苦労も意味を成し得ません。 上記のトランジションを検討した際にも、今後の開発量を見据えると今この調整に時間をかけるべきではないと判断し、単純にページングをするようなシンプルなトランジションに変更して進めました。

他にも「あったら便利そうな気がするけど仮説の検証が不十分な機能」「細かなビジュアルの作り込み」など、目指すべきユーザー価値を担保できない、あるいは明確に価値を向上させるものではない、と判断したものについては、初期の段階では適度に諦めて優先度を下げるようにしました。

細かな枝葉に拘ることよりも、まずは幹となるシンプルなユーザー体験を追求することを何よりも優先させ、アプリの持つ本質的な価値の向上を重視すべき、と方針づけたのです。

この方針をチームにも浸透させていくことで、チーム全体でひとつの方向を向いて、一丸となってスムーズに開発を進めることができたように思います。

最後に

デザイナーとして心がけた、としていくつかの内容をご紹介してきましたが、クックパッドの開発文化を受け継ぐトクバイでは、これらのマインドは私に限らず広くメンバーに備わっています。

トクバイアプリは開発期間が数ヶ月と、かなりのスピード感を持って進められたと感じていますが、それもこれらの共通理解が開発メンバーに根付いていたことがひとつの要因だったのかもしれません。

アプリもリリースしたばかりでまだまだこれからといった段階ですが、これからもユーザー視点を第一によりよい改善を重ねていきます。是非ご利用ください。

(★ダウンロードはこちら Google Play / AppStore)

なお、トクバイでは買い物の未来を楽しくするデザイナーを募集しています。 一緒に素敵なサービスを作っていきましょう。

クックパッド サマーインターンシップ2016の資料を公開します

$
0
0

技術部開発基盤グループの @moro です。

クックパッドでは、昨年に引き続き今年も、夏の技術職インターンシップを実施しました。 クックパッドのインターンシップは前後半に分けた構成になっていました。まず前半はWebサービス開発に必要な技術の中から6つの分野に関する講義や実習を行いました。さらに後半は、前半の座学に合格した方を対象に、メンターとなる社員と一緒に実際の開発現場に入り、具体的な問題解決に取り組んでもらいました。

f:id:moro:20160810112403j:plain

その中で、前半の講義に使った資料を公開します。


1日目 Git (@moro)

昨年に引き続き、講義初日はGit, TDD, Railsを1営業日で一巡りするという、忙しい構成でした。

Git編では、すでにGitを使っているエンジニアも多いだろうと想定して各コマンドの紹介などは最小限に済ませました。代わりに、Gitの内部構造を説明し「コミットを覚えておけばなんとかなる」感覚を掴んでもらうことを主眼に置きました。Gitあるあるである「rebase していたらわけわかんないことになった」に陥ったときにも落ち着いて復帰できるようになったと思います。

資料: https://speakerdeck.com/moro/about-git-at-cookpad-summer-intern-2016-day1

1日目 TDD (@moro)

引き続き、TDDの講義を行いました。 「時刻」を表すバリューオブジェクトを、ユニットテストに導かれながらボトムアップで実装していくというコースです。 こちらも、テスティングフレームワークRSpecの使い方や気の利いたAPIの説明などはインターネット情報にお任せしたうえで、「なぜTDDするのか」「何を考えてテストに駆動させるか」という 気持ちを伝えたい構成でした。

資料: https://speakerdeck.com/moro/about-tdd-at-cookpad-summer-intern-2016-day1

1日目 Rails (@moro)

ボリュームたっぷり1日目のラストは、Ruby on Railsを使ったWebアプリケーションの講義でした。 こちらも「特定バージョンのRailsの使い方」のみならず、Webアプリケーションフレームワークを使った開発の一般論や、HTTPやREST、RDBMS、End-to-Endなテストを書くトップダウンTDDといった内容も理解してもらえるような構成を心がけました。 ひたすらボリュームが多い講義でしたが、参加者はみなさん頑張ってついてきてくれました。すごい。

資料: https://speakerdeck.com/moro/about-rails-at-cookpad-summer-intern-2016-day1

2日目 Android (@101kaz& @kmats_)

Androidの講義では前日に作ったRailsアプリケーションのAPIを題材として、クライアントアプリを作りました。 Androidアプリのライフサイクルの話や、レイアウトの作成、サーバとの通信方法、DBを使った永続化など、Androidアプリを作る上で最低限必要な知識を説明しました。 今年は非同期処理にRxJava、レイアウトにDataBindingライブラリを利用するなどより実践的な内容になっています。 たった一日しかない中で、FragmentやRxJavaやDataBindingなどを使いこなし、実際の現場とほとんど変わらないスタイルでのAnroid開発はかなり難しいものがあったと思いますが、みなさんとても優秀だったので、想像を上回るスピードで課題をこなしていました。

資料: https://github.com/cookpad/cookpad-internship-2016-summer/blob/master/android/README.md

3日目 iOS (@slightair)

iOSの講義では、簡単なアプリの実装を進めながらiOSアプリ開発の基本を学んでもらいました。 架空のネット通販サービスで商品を注文するためのiOSアプリを題材に、講義形式の解説と自分のペースで実装を進める演習を用意しました。

午前中いっぱいとお昼ごはん後の1時間くらいで、画面の実装やAPIリクエストの送信など、iOSアプリ開発に必要な知識をひと通り説明しました。 1日しか時間がないのもあり、結構駆け足で説明してしまった所もあってすぐに演習課題に取りかかれるのか少し心配していました。 そんな心配をよそに、皆さんとても優秀で黙々と課題に取り組んでアプリの実装を進めていくことができていました。すばらしい。

ちょうど台風が関東に近づいていた日でもあり、はやめに切り上げる事になってしまったのは残念でしたね。 この日の感想を読むと「時間があるときに残りの課題もやりたい」と書いてくれた人が多かったので、それなりに楽しんでもらえたのかなと思ってます。ぜひ取り組んでみてください。

資料: https://github.com/cookpad/cookpad-internship-2016-summer/blob/master/ios/README.md

4日目 サービス開発 (@ryo_katsuma& @transit_kix)

「唯一コードを1行も書かない日」のサービス開発の講義では、前後半2パートの構成でした。

前半では、昨年に引き続きクックパッドでのサービス開発に対する考え方を講義形式で学んでもらい、 後半ではグループワークとして1人の社員の課題を解決するプロトタイプ作りとユーザーインタビューを行ってもらいました。

サービス開発において正解は誰も分からないものです。 そのためにもクックパッドでは、仮説を検証できるものを早く形にして、ユーザーの反応を見て「学びのある失敗」をしながら正解を探るアプローチを取っています。

今回も、たった1人の社員を満足させるためのプロトタイプであっても「これは私は使わない」「むしろこういうものが欲しい」など、全く想定していなかったフィードバックを参加者全員もらう流れになりました。

なかなか大変なグループワークだったと思いますが、学生のみなさんには「思い込みでつくるサービスがいかに意味がないか」「ユーザーのフィードバックがいかに大事か」など、普段ではなかなか体験できないであろうことを実感してもらえたかと思います。

資料: https://speakerdeck.com/katsuma/service-development-at-cookpad-2016-summer-internship

5日目 自然言語処理&機械学習 (原島純)

5日目は自然言語処理と機械学習の基礎を学んでもらいました。自然言語処理の講義では基礎解析からアプリケーションまで、その仕組みを大まかにお話ししました。また、それらがクックパッドでどのように使われているかもお話ししました。実習ではクックパッドのデータを使って、形態素解析器に触れてもらいました。

機械学習の講義では基礎知識から深層学習までをおおまかに学んでもらいました。こちらの実習でもクックパッドのデータを使って、機械学習のモデルを作ってもらいました。機械学習を初めて学ぶという方が多かったのですが、皆さん、素晴らしい成果を見せてくれて、大変驚きました。

資料: https://speakerdeck.com/junharashima/internship2016

6日目 プログラミングパラダイム (青木峰郎)

最終日の6日目は昨年に引き続き、プログラミングパラダイム……のはずが、それとはまったく関係なくJavaScriptコンパイラーを書くという課題をやってもらいました。

この課題のテーマはずばり、「すぐには役に立たないことをやる」。これまで言語処理系を実装したこともなかったエンジニアが、インターンに参加してくれたからと言って、すぐその日からプログラミングパラダイムについて一家言持って語れるなどということは正直ありえません。であればせめて3年後に語れるようになるための礎としてこの日を使ってもらうのがよいだろう、というのがこの講義の趣旨です。

さて、実際に講義をやってみて、去年も今年も多かった間違いが1つありました。それは、「プログラムを実行するコードを出力しなければいけないのにその場でプログラムを実行してしまう(インタープリターを作ってしまう)」という間違いです。この点はある意味コンパイラーの肝とも言える特徴なので、ここに悩んでもらえるのは講義をやった甲斐があるというものです。存分に悩んでいただければ幸いです。

なお、今年の反省として、流れを改善したことにより全体的に進捗がよくなってしまいました。来年は進捗をより絶望的にするために、もっと難易度を上げようと考えています。ネイティブコード出力とかがいいですかね?

資料: https://speakerdeck.com/aamine/cookpad-2016-summer-intern-programming-paradigm


今年もかなりのボリュームの講義でしたが、参加した皆さんは一生懸命取り組んでくれていました。 来年も、よりパワーアップして実施する予定です! お楽しみに!

(2016-09-06T19:07にスライド展開しました)

インターンシップ「サービス開発演習」の舞台裏

$
0
0

f:id:ryokatsuma:20160817121332j:plain

こんにちは、投稿開発部副部長の勝間(@ryo_katsuma)です。 普段はクックパッドのレシピ投稿周辺のサービス開発を行う部署のマネジメントやエンジニアリングを担当しています。

さて、クックパッドでは、8月10日から先日9月2日まで技術インターンシップを開催していました。 講義全体のまとめについては、先日公開されましたこちらの記事を参照ください。

今回は、私が担当した4日目の講義「サービス開発」について、どのような狙いを持って設計したか、また参加学生の皆さんがどのような反応だったかなど、舞台裏についてご紹介いたします。

昨年の振り返りと課題

技術インターンシップにおいて、サービス開発の講義は昨年度も私が担当しました。昨年度は日程の都合上、半日で「クックパッドにおけるサービス開発の考え方についての講義を行った後に、その実践編としてあるお題に対して仮説を立て、企画をまとめる」というかなりコンパクトな内容にする必要がありました。

学生の皆さんにとっては「企画をまとめる」という、普段は行わないような発想をする体験を提供できたかと思いますが、「とりあえず仮説をまとめる」に留まってしまったため、周囲からのフィードバックを得るということはできませんでした。 言い換えると、サービス開発におけるPDCAのサイクルを回す (= LeanStartup的に言うとBMLループを回す)まで体験できなかったので、学生の皆さんにとってやや消化不良な形になってしまったのは反省すべき点でした。

全体設計

昨年度の反省を元に、今年度のトライとして

  • 半日では時間が短すぎるので、最初のインターンシップ全体の設計から関わり、1日の枠を確保する
  • BMLループを少なくとも1周回すことを実現する

をテーマに設定しました。 また、このタイミングで、デザイナの倉光(*1)にも参加してもらい、主に2人で全体設計と当日の運営を進めていくことにしました。

フォーカスすべきポイント

設計を進める上で、あれもこれも、、とやりたいことは多くありますが、インターンの時間は有限なので、フォーカスすべき点は何か?を明確化する必要があります。 そこで昨年度の課題を元に議論を進めていきました。

正解は誰にも分からない

参加学生に最も理解してもらたいことは、サービス開発において「正解は誰にも分からない」ということです。講義を行っている自分たちはもちろん、社長ですら「何がユーザーに受け入れられるものか」は究極的には分かりません。そのためにも早く小さな価値ある失敗して、そこから学びを得て正解を探る必要があります。

動くものでユーザーの声を聞く

価値ある失敗から学びを得るためには、ターゲットユーザーから仮説検証を行うプロダクトの利用ログを分析する必要がありますが、そのためには1日で実装から本番環境にデプロイまで行うのはさすがに現実的ではありません。そこで、ターゲットユーザーに動くものに触れてもらい、直接意見を聞くことで同等の効果が期待できます。そのためにも、動くもの、つまりプロトタイプを作ることが大事になります。

このような議論を経て、「プロトタイプを元にユーザーインタビューを行う」を今回の演習で最もフォーカスするポイントとして設定することにしました。

どんどん諦める

限られた時間の中で上記の実現すべきことにフォーカスするためにも多くのことを積極的に諦めることにしました。

課題設定をしない

そもそも「誰の何の課題を解決するか」は非常に大事なテーマです。今回もここの領域は是非挑戦してもらいたいところではありますが、今回はここに時間をかけることを諦めます。代わりに、解くべき課題と、それに対する仮説をこちらであらかじめ設定することにしました。

f:id:ryokatsuma:20160905202347p:plain

今回は「子どもがもうすぐxx歳になるお母さんは、誕生日パーティを家族の思い出に残るものにしたいけど、何を作ったらいいか分からない」という課題を解決することを、実習における前提としました。

ちなみに、この課題は

  • 料理の領域に制限することで自分たちもフィードバックを返しやすい
  • 学生たち自身の経験則で進めることはできない
  • 対象ユーザーが社内で確保しやすい

などの理由からこの課題を設定しています。

1人のターゲットユーザー以外を考慮しない

課題が設定されていたとしても、その課題を持つできるだけ多くのユーザーを満足させることを考える時間もありません。

そこで、今回はターゲットユーザーは1人に絞り、ターゲットユーザー以外の人の考慮はしないようにしました。

f:id:ryokatsuma:20160905203530p:plain

実際の社内のスタッフをターゲットユーザーに見立て、事実を元にしたペルソナシートを用意することで「誰の課題解決をするか」を把握できる状態を狙っています。

プロトタイプの実装はしない

確保した時間から逆算すると、プロトタイプの準備にかけられる時間は2時間程度のみになることが分かりました。そこで、「エンジニアだからこそ実装しないと」の発想をやめてもらうためにも、InVisionを利用することで「手書きでプロトタイプを作る」という制限を課すことにしました。

f:id:ryokatsuma:20160905203915p:plain

これは今回用意した見本ですが、付箋とペンで描いた絵であっても「オムライスを検索してるんだな」は伝わるかと思います。

画面をいきなり作ることはしない

短期間でプロトタイプを作るとなると、「よくわからないからとりあえずそれっぽい絵を描く」ということになりがちですが、その際、結局「何をしたいかよくわからないもの」に仕上がりがちです。

そこで、今回は「実現したいユーザーストーリーをあらかじめ描き、それを元に絵を描く」という制限を設けました。

f:id:ryokatsuma:20160905204325p:plain

この例は、フリマアプリを利用を使う人のユーザーストーリーをユーザーの言葉で並べたものですが、例えばこのようなプロトタイプを作ることができるでしょう。

演習

事前リハーサル

今回は、事前に学生アルバイトのエンジニア2名を前にして講義の内容を聞いてもらい、画面をつくるためのユーザーストーリーシートも実際に書いてみてもらいました。これによって、伝わりづらかった点、魅力を感じてもらうために必要な点などいくつかの改善点が見つかり、この時点でいくつか改善点も見つかったものの大筋は問題が無さそうなことが確認できたので、安心して当日を迎えることができました。

当日のスケジュール

当日はこのようなタイムスケジュールで進めていきました。

  • 09:30-10:30 講義+全体説明
  • 10:30-12:00 方針決め+プロトタイプ準備
  • 12:00-13:00 昼食
  • 13:00-14:00 インタビュー準備
  • 14:00-14:30 インタビュー実施
  • 14:30-15:00 インタビューを踏まえた改善案まとめ
  • 15:00-16:00 全体発表
  • 16:00-18:30 振り返り

見ていただくと分かる通り、講師側も正直辛さを感じるスケジュールです。 しかし、結果として参加学生の皆さん全グループ時間内にプロトタイプを形にし、インタビューまで完了できていました。学生の皆さんは本当に素晴らしかったと思います。

インタビューを経て

一方で、全グループともプロトタイプはインタビュイーに満足してもらえませんでした。 多くのグループはパーティ料理の献立を簡単に探せるプロトタイプを作っていましたが、

  • 子どもの年齢で食べられるものは決まるので、年齢毎に検索できないと使えない
  • 具体的に調べたいというより、ぼんやりとインスピレーションを得たい
  • プロトタイプは悪くはないけど、使うかと言われると使わない

のような意見をインタビューでもらっていました。

これはサービス開発を長年行っている者の観点だと、一発で最高のプロダクトを作ることができるわけないので、ある意味当然の反応とも見なせます。ただ、参加学生の皆さんにとっては、非常に新鮮な反応だったようで

  • 自分たちでは最高のものができたと思っていても実際は全然受け入れられない
  • たった1人のためのものを作るのすら、全く正解に辿りつけていない

のような感想を持っていたようです。

演習を終えて

議論の活発化

今回、参加学生を見ていて最も印象に残ったことは、インタビューの前後で議論の熱量が大きく増えたことです。 最初は、どのグループも悩みながら半信半疑でプロトタイプを作っている印象でした。一方で、インタビューを通じて自分たちの仮説が持つ問題点がかなり明らかになったことで、どのグループも「どう改善すべきか?」の議論は活発に行われていました。発表会の後は手持ち無沙汰になってしまうことを危惧していましたが、結果としては終了ぎりぎりの時間まで全てのグループがプロトタイプを改良し続けていたのは非常に印象的でした。

評論的なフィードバックが不要に

今回のようなサービス開発系の発表のフィードバックはともすれば評論家のような話をしがちです。しかし、前述の通り、サービス開発における正解はユーザーの反応です。今回も、学生の皆さんは自分たちの課題について自ら気づいてくれることが多く、主催側の自分たちが細かなことを言う必要はほとんどありませんでした。

ゴールを見失いがち

一方、「誕生日パーティを家族の思い出に残るものにしたいけど、何を作ったらいいか分からない」課題を解決するという、そもその研修の目的を多くのグループが忘れてしまっていました。「すばやくパーティ献立を検索する」にフォーカスしてしまい、「家族の思い出に残るパーティを実現する」というゴールを見失った状態でプロトタイプを作ることに必死になっていたようです。(例えば、ゴールを達成するためにはデリバリーを注文することも手段になるはずです)

学生の皆さんへのフィードバックはこの点について言及しましたが、これは自分たちもともすれば陥りやすい罠です。目的から外れ手段に凝り過ぎてしまうことは、自分たちも油断するとよくやってしまいます。個人的には、学生さんたちの様子を見ることで、自分たちのサービス開発のフローを省みるいい機会になりました。

柔軟な発想

そんな中、思い出に残るという観点で「子どもと一緒に作れる」を軸に考えてくれていたグループがありました。

f:id:ryokatsuma:20160906095804p:plain

「パーティレシピを集めるための投稿ユーザーのモチベーションがうまく設計できていないことで、サービスを成立させることが難しそう」という理由で優秀賞には選定せずに「惜しかったで賞」という枠を選定しましたが、発想としては非常に素晴らしいものでした。このように柔軟な発想に出会えることもインターンを主催側の楽しみの1つです。

思ったよりいい感想を持ってもらえた?

今回は手を動かすことが大好きな学生エンジニアからエディタを取り上げることになったので、実施前は受け入れられるかどうか不安がありました。ただ、日報を見てみると

  • インタビューを通じて様々なことを気づくことができた
  • ユーザーが求めているだろうと自分が考えていたものが、インタビューしてみると全く価値がなかったのは衝撃的な体験
  • ここまでユーザーのことを考えたことがなかったので新鮮

など、前のめりなコメントも多く見受けられました。実際、自分たちで考えたものをリアルなユーザーに直接届け、感想を聞くという体験はなかなか得られないものではないかと思います。 また、後半に進んだ学生の中には、サービス開発を行う部署を希望してくれた人も何人もいました。

「サービス開発は難しい」ですが、同時に「だからこそおもしろい」と思ってもらえる機会を少しでも提供できたのかな、と期待しています。

まとめ

2016年度技術インターンシップにおけるサービス開発研修を舞台裏についてふりかえりを行いました。今年は、昨年度の反省を活かして、価値ある失敗を体験してもらうことに徹底的にフォーカスした設計を行いました。 準備はかなり大変でしたが、結果として昨年度の課題の大半は解決され、学生の皆さんにサービス開発の難しさと楽しさの2つの体験を提供できたかと思います。

最後になりますが、クックパッドではデザイナー・エンジニアを募集しています。このようなサービス開発にご興味あるかたは、募集一覧をご覧いただくか、または@ryo_katsumaまでお気軽にお声がけください!

(*1) 倉光はFablicさんと合同でのデザイナ向けイベントの運営や新卒研修でのサービス開発研修の講師を務めるなど、この領域において経験も実績も十分でした。
(*2) 念のため補足しておくと、ここではもちろんコードを書くことを否定しているわけではなく、早く動くものを用意しよう、ということのみを述べています。Webアプリケーションやモバイルアプリも早く形にできる環境であれば、InVisionなどのツールを使うよりも実際に実装したほうが望ましいです。

ECS を利用したオフラインジョブの実行環境

$
0
0

技術部の鈴木 (id:eagletmt) です。 クックパッドでは以前からアプリケーションの実行環境として Docker を利用していましたが、最近は徐々に Amazon EC2 Container Service (ECS) を利用し始めています。 去年の時点での Web アプリケーションのデプロイ手法 *1や、最近 ECS を利用してどう Web アプリケーションをデプロイしているか *2については紹介したことがあるので、今回は定期的なバッチ処理やジョブキューを介して非同期に実行されるようなオフラインの処理について、どのような環境を構築しているか紹介したいと思います。

Docker を使う前

Docker を利用し始めるより前から社内では kuroko2 *3というジョブ管理システムが稼動しており、複数のアプリケーションから利用されていました。 kuroko2 は定期的にジョブを実行するために必要な機能を十分そなえている一方で、複数のアプリケーション向けにワーカインスタンスをプロビジョニングする必要があること、ジョブを実行するワーカを柔軟に増減できないこと、といった欠点がありました。

Docker の導入

Docker を利用することにより、複数のアプリケーションから共通で使われつつもインスタンス側に必要なプロビジョニングを最低限に抑えることができるようになりました。 インスタンス側の構成はシンプルになり、新しくアプリケーションを追加するときに必要な手間も非常に小さく済みます。 プロビジョニングの手間だけでなく、API キーやパスワードのような秘匿すべきクレデンシャルがインスタンスに直接置かれることを防ぎ、ワーカインスタンスのインスタンスプロファイルにすべてのアプリケーションに必要な権限をつける必要がなくなり、共通のインスタンスを複数のアプリケーションで使い回しつつも権限が適切に分離できるようになりました。

社内では定期的なジョブを実行するときは kuroko2 を使うのが標準となっていたため、kuroko2 から Docker を利用するための機能追加やインスタンスの整備なども行いました。 これにより Web アプリケーションを動かすための Docker イメージを作ってあれば自動的に kuroko2 で実行する環境も手に入るようになり、アプリケーション開発者にとってオフラインのジョブ実行をする際の障壁が大きく軽減されました。

ECS の導入

Web アプリケーションのデプロイに ECS を利用し始めたのと同時に、オフラインジョブの実行にも ECS を利用し始めました。 Web アプリケーションのデプロイに使っているツールである hakoを使って、kuroko2 から hako oneshot awesome-app.yml -- bundle exec rake some:heavy:taskのようなコマンドを実行するようにしています。 hako oneshotは YAML の定義に従って ECS の RunTask API を呼び出すコマンドで、オフラインのジョブや bin/rails db:migrateのような単発のコマンドを実行するために使います。

直接 Docker を使っていたときと比較してよくなった点の一つに IAM ロールを利用できるようになったことがあります。 ECS ではインスタンス単位ではなくタスク単位で IAM ロールを利用でき、これにより AWS のアクセスキーを発行することなく AWS の API を利用したジョブを実行できるようになりました。

ジョブキューからの利用

先日の RubyKaigi 2016 で紹介されたように、現在 barbeque というジョブキューのしくみが整備されています。 barbeque からジョブを実行するときには社内では hako oneshotが使われています。 https://speakerdeck.com/k0kubun/scalable-job-queue-system-built-with-docker

barbeque へのエンキューは Web アプリケーションへのリクエスト起因であることが多いため、ジョブの実行回数、つまりジョブの実行に必要なリソースを事前に予想することが難しく、また時間帯によって刻々と変化するという特徴があります。 したがって、常に安定的にジョブを実行しつつコストを抑えるためには、オートスケールが重要になってきます。

オートスケーリング

ECS の導入によって、ワーカインスタンスのスケーリングが容易になりました。 ワーカインスタンスとして使うための ECS クラスタを作成し、そのクラスタのインスタンスはすべて AutoScaling グループで管理するようにしました。hako oneshotは RunTask API を使っていますが、この API はもし実行に必要なリソースがクラスタ内に不足していた場合にリソース不足を知らせるエラーを返すので、そのエラーが発生した場合は AutoScaling グループの desired capacity を引き上げ、再度実行を試みるようにしています。 この挙動は hako の定義ファイルで autoscaling_group_for_oneshotに AutoScaling グループを指定することで有効化できます。 https://github.com/eagletmt/hako/blob/v0.20.0/examples/hello-autoscaling-group.yml

一方、スケールインの実行は CloudWatch のメトリクスを定期的にチェックすることで行っています。 ECS はクラスタ毎にどれくらい CPU、メモリが使われているかの割合を自動的に CloudWatch に保存しているため、直近の実績値を参照することで現在必要なリソース量を見積もることができます。 クラスタが提供するリソースのうち P % を利用しているような状況を維持したい場合、現在のインスタンス数を N とすると n 台減らせるかどうかの閾値は (N - n) * 100 / N * Pになります。 リソース量の見積もりと閾値の計算を毎時実行し、見積もりが閾値を下回っていたら AutoScaling グループの desired capacity を下げることでスケールインを実現しています。

スケールインするときには、実行中のタスクが中断されないように注意しなければなりません。 AutoScaling にはライフサイクルフックというしくみがあり、AutoScaling によってあるインスタンスが terminating 状態になってから実際に terminate されるまでの間に終了処理を行えるようになっています。 ライフサイクルフックによって terminate が決定したときは AWS Lambda 経由でそのインスタンスに特別なタグをつけるようにしています。 各インスタンスは定期的に自分自身のタグをチェックし、もし特殊なタグがついていれば自分自身を DeregisterContainerInstance してサービスアウトし、その後ライフサイクルを継続させます。 もしそのインスタンス内でタスクが実行中であれば DeregisterContainerInstance は失敗するので、成功するまで DeregisterContainerInstance を実行し続けるようにしています。

今後の課題

ECS を利用しているとコンテナインスタンスのスケールアウトはしやすい一方で、スケールインをするには現状いくつかの工夫が必要になっています。 比較的短時間で終了するタスク専用のクラスタであれば DeregisterContainerInstance を成功するまで叩き続けるという方法でスケールインできるようになりましたが、 長時間実行が続くようなタスクが実行されてる場合や ECS の service を使っている場合など、すべての場合で自動的にスケールインすることはまだできていません。 このようなケースでもスケールインする方法を考える必要があります。

また、スケールアウトをするタイミングが現状は実際にリソースが不足したときになっており、一時的にジョブの実行が遅れることになります。 AutoScaling グループの desired capacity を変えてからインスタンスが起動してコンテナインスタンスとして登録されるまで3分ほどかかっています。 ジョブの実行ができるだけ遅れないようにするためには、インスタンスの起動を高速化する他に、リソースの使用状況の履歴から必要そうなときにあらかじめスケールアウトしておく方法があります。 しばらくはどういう状況のときに実際にリソースが不足してスケールアウトしているかを観察し、その結果をもとにスケールアウトする基準をどうするかを決めようと考えています。

まとめ

Docker や ECS をオフラインのジョブで利用するメリットと、実際にどう利用しているかについて紹介しました。 今後も ECS 自体の改善を注視しつつ、アプリケーション実行環境の利便性を高めながらもできるだけコストを抑えられるように改善していきたいと思っています。


エンジニア全体ミーティング Tech MTGのすゝめ

$
0
0

こんにちは。投稿開発部エンジニアの土谷(@taihaku0415)です。 Androidアプリcookpad.comの開発を中心に担当しています。

現在、クックパッドには100人弱のエンジニアが在籍しています。普段エンジニアはそれぞれの事業部に所属して、業務を行っています。スマートフォンアプリを専門に書くエンジニア、広告領域を担当するエンジニア、インフラや開発の基盤を構築しているエンジニアなど、多岐に渡ります。 そのため、クックパッドでは、業務をする上で必須なものから、他のチームの開発の知見や生産性を上げるためのtips(ツールの紹介や使い方など)まで、様々な情報を共有して、開発力や技術力の向上に役立てるための取り組みを行っています。

例えば、技術領域課題共有会では各部署・チームの課題を話し合う場が設けてあります。また、Groupadという社内ブログサービス上で、全社員(エンジニアにかぎらず全ての社員)が気軽に情報を発信しています。 それ以外にも、クックパッドの全てのエンジニアが顔を合わせて集まるエンジニア全体ミーティング、通称 Tech MTGを行っています。*1

今回の記事では、私も企画・運営に携わっているこのTech MTGに関してご紹介します。

Tech MTGとは

f:id:slippyvalley:20160916172744j:plain

クックパッドでは日本のオフィスにいる全てのエンジニアが集まって情報共有する機会を隔週で30分程度設けており、企画、運営もエンジニア自身で行っています。

なぜやっているか

目的

Tech MTGの主な目的はエンジニア全体での 情報共有です。

具体的には

  • 社内外で今話題の技術トピック
    • RubyKaigiやGoogle I/Oなどのカンファレンスの参加報告も含む
  • 新機能やサービスのリリース後の話
  • 事務的な連絡事項(e.g. 社内のインフラやツールに関する変更や、全エンジニアが知っておくべき周知事項)

を中心に各開発を担当しているエンジニアに発表してもらう、ということをしています。 また、人事部長や開発本部長から、今後のクックパッドのエンジニアリングの方向性についての発表もあります。 Tech MTGでは、開発担当者からサービスや機能の実際について生の声が聞け、質疑応答がその場でできます。

Tech MTGではなにが話されてるのか

では、Tech MTGではどんなことが話されているのでしょうか。ここではほんの一部ですが過去のTech MTGで発表された内容を紹介します。

Job Queue Systemに関する話

クックパッドのJob Queue SystemであるBarbequeについての発表がありました。このBarbequeについては、先日のRubyKaigi 2016でも開発担当者の国分が(@k0kubun)が発表しました。社内では、Barbequeが使えるようになった時に発表され、本格的に運用する前だったこともあり設計上の問題点についても他のエンジニアから指摘が入っていました。

speakerdeck.com

資料: https://speakerdeck.com/k0kubun/scalable-job-queue-system-built-with-docker

クックパッドのMicroservicesへの取り組みに関する話

クックパッドで取り組んでいるMicroservicesの事例に関して、社内で行われている様々な取り組みの事例もあげて説明してもらいました。詳しい内容はクックパッドにおける最近のMicroservices事例でも紹介されています。

speakerdeck.com

資料: https://speakerdeck.com/adorechic/how-microservices-are-linked-at-cookpad

Google I/Oの参加報告

社内の技術的取り組みに関する話以外にも、Google I/O 2016に参加したAndroidエンジニアに、Keynoteで気になった発表の内容を選んで説明してもらったり、サンフランシスコ・ベイエリアのスタートアップ系の企業に訪問して交流した話を紹介してもらいました。このように大きなカンファレンスの参加報告をしてもらうこともあります。

技術顧問によるテストの話

また、クックパッドの技術顧問の一人である@t_wadaさんにテストに関しての発表をお願いしたこともあります。その後TDD Bootcampというテスト駆動開発の勉強会も開催しました(参考: テストを使いサービス開発を駆動していくために取り組んでいること)。

法務部の社員からの話

発表の内容は、必ずしもエンジニアリングに関するトピックに限りません。
先日のTech MTGでは、法務担当の社員から、全てのエンジニアが知っておくべき法律についての発表がありました。

このように、Tech MTGでは技術的な話を中心に幅広いテーマを取り扱っています。

どのように運営されているのか

Tech MTGは、これまでは社内の有志数名によって運営されていましたが、今年の1月から技術本部長の成田 (@mirakui)と新卒2年目のエンジニアが中心になって行っています。

定例ミーティング(Tech MTG MTG)

Tech MTGがあった日に運営メンバーで集まって、振り返りと次回以降の発表内容の確認・検討を行っており、口頭で話した内容を、GitHubのIssueを利用してドキュメントに残していく方法でミーティングを進めています。 ミーティングでは、毎回同じアジェンダのテンプレートを使って各項目にチェックし、Tech MTGの準備に抜け漏れがないようにしています。

f:id:slippyvalley:20160916172847p:plain※定例ミーティングで使用しているアジェンダ(チェック項目)

振り返りでは、KPT (Keep, Problem, Try) フレームワークを使って振り返り行い、Problemで挙がった問題点を改善するためにTryの内容をissueに書き込んで次回改善されていたら閉じる、というように地道な作業をしています。

f:id:slippyvalley:20160916185310p:plain

また、準備期間をしっかりとれるように、約一ヶ月前には企画を固めて登壇者に依頼しています。 大きな機能のリリースや社内外のイベントに参加した社員(カンファレンスへの参加、社内勉強会など)がいないか、最近技術的にホットな話題とそれに精通している社員がいないか等から運営メンバー間でネタを出し合って、その中から多くの社員が興味を持ちそうで、業務にも役立つものを選んでいます。

まとめ

クックパッドのエンジニア全体ミーティング Tech MTGの目的、発表内容、どのように運営しているかについて紹介しました。 参加するエンジニアには業務時間を使って30分程度集まってもらい、登壇をお願いしている社員も準備に時間を割いてくれています。 なので、今後もTech MTGの登壇者・参加者が参加してよかったと思える、そんな情報共有の場にしていきたいと思っています。

最後になりますが、クックパッドではエンジニアを募集していますので、興味のある方は募集一覧をみていただくか、気軽に@taihaku0415までご連絡ください。

*1:ディレクターの知見共有会というのもあります

ユーザーをムフムフさせるための「お料理アルバム」デザインリニューアル

$
0
0

こんにちは、投稿開発部のデザイナー、木村です。主に、iOS/Androidのクックパッド App、また昨年から「お料理アルバム」というAppのデザインを担当しております。

今回は、お料理アルバムのデザインリニューアルを例に、既存サービスが持ってた課題をどのように解決していったかについて、デザインの観点を交えてお話したいと思います。

リニューアルの経緯

お料理アルバムは、毎日の料理写真をプライベートに記録する iPhone/Android Appです。多くのユーザーから「こんなアプリを待っていました!」「自動で写真をキレイに並べてくれて助かっています!」といった声を頂き、投稿された写真数は400万枚を超えるサービスに成長しました。

そんなお料理アルバムもリリースから1年半ほど経過し、さらにより多くのユーザーに喜んでいただくために、デザインのリニューアルを計画しました。

ゴールはユーザーの「ムフムフ」

リニューアルのゴールとして、初期段階からチームを貫いていたのが、表題にもなっている「ムフムフ」というキーワードでした。

「ムフムフ」とは、投稿開発部内での共通言語になっており、その定義は以下のようなものでした。

  • 記録したものを見返して達成感を感じる
  • 自己満足に浸る
  • 上達を実感する

今回は、「お料理アルバムを見返してユーザがムフムフすることで、料理を楽しいと感じてもらおう!」というゴールを目指して、リニューアルを進めました。

また、その定量的な指標として、ユーザーあたりの投稿数・MAUをはじめとした、数値目標もあわせて設定しました。

ムフムフを因数分解

つぎに、ユーザーはどんなことでムフムフするのか?ムフムフを因数分解し、現状のアプリに照らしあわせながら、それぞれの課題を解決するように再デザインを進め、最終的には右のスクリーンショットのようなデザインに落ち着きました。

変更の意図について、順を追って説明します。

並べて見返す楽しさを

既存のお料理アルバムでは、1日に複数枚写真を投稿すると、写真をタイル上にランダムにレイアウトするようにデザインされており、写真を投稿すれば投稿するだけフィードが賑やかになり、ムフムフしてもらえるだろうと考えておりました。

ですが、実際は多くのユーザーが、忙しい家事の合間に隙を見つけて写真を撮っているため、お料理の写真を1品ずつではなく、食卓というカタマリで撮影することが多いため、フィードにリズムがつきづらいことがわかりました。

このように、一度に投稿する写真の枚数が少ないと、結果、フィードのスクロール量が増え一覧性が下がってしまう問題がありました。

また、ユーザーが撮影する料理写真は、構図やスタイリングにこだわったフォトジェニックな写真よりも、食卓の様子をカジュアルに撮影した写真が多いため、見返したときに鑑賞に耐えられる最適なサイズも再度検討することにしました。

写真のレイアウトの改善は2段階で行いました。

まず、写真を複数枚アップロードした場合に小さく縮小したレイアウトから、横に最大2列、縦に積んでいくように変更したバージョンをリリースし、ユーザーの反響を見つつ、リニューアルを進めていきました。

大きすぎず小さすぎず、一目で記録量を実感しやすいレイアウトをいくつか検討し、最終的に写真は3カラムに、そして日付のラベルを取り払い、よりコンテンツに集中できるよう改善しました。

数字はシンプルに

既存のお料理アルバムでは、ユーザーが確認できる、投稿数をはじめとする数字が多岐にわたり、その数は11種類(!)にも及びました。

1ページ目では、その週に何品の料理を作ったかが見返せる設計になっていたのですが、多くのユーザーは1週間あたり2〜3枚の写真しか投稿していませんでした。

さらに2ページ目の指標となる数字を見るためには、ホーム上部を横スワイプせねばならず、殆どのユーザーに見られていないことも分かっていました。

そこで、ユーザーが確認できる数字を整理し、アプリを起動したファーストスクリーンでぱっと確認できるようなUIを検討しました。

写真リストを主役にし、数字は必要最低限になるよう、ナビゲーションバー内にレイアウトするA案や、最新の写真を大きく表示して、そのなかにさり気なく数字をレイアウトするB案をはじめ複数のアイデアの検討を進めました。

A案はナビゲーションバー内に展開するには数字の情報は多すぎて、煩雑な印象になってしまい、また、B案は、写真がメインになると、どうしてもそちらに注意が行き、数字に気が付かなかったり、その写真に限定した情報のように誤認してしまう懸念がありました。

最終的には、写真リストの上部に既存の数値エリアよりスペースを小さくしながら、3つの数字に絞ってアイコンと共にレイアウトするC案に落ち着きました。

細かなブラッシュアップ

上記のデザイン変更と平行して、細かなブラッシュアップも進めました。

一例として、ナビゲーションバーの白背景を取り払い、数字エリアの背景を全面にレイアウトするアイデアを提案しました。これにより、より画面に没入感が生まれ、写真エリアのスペースをより広げることで、写真の一覧性を向上させることがきました。

また、画面をスクロールし、数字エリアが画面外に移動した場合に、黒い半透明のナビゲーションバーが表示されることを想定していたので、チームメンバーへの提案時にその動画モックもあわせて共有しました。

文章や静止画だと伝わりづらい部分も、動画モックだと一目瞭然なので、開発のフェーズに合わせて最適な形でデザインを検証することで、その後の実装がスムーズになると思います。

ユーザーの声とどう向き合うか

デザインを大きく変えたことで、ユーザーからの「デザインが変わって、かわいくなった!」というポジティブな声もあれば、「前のほうがよかった」「見づらくなった」という声も届きました。

ユーザーの声をサービスに反映する場合は、サービスの価値に照らしあわせて、慎重に行うようにしています。お料理アルバムであれば、「本当に料理が楽しくなるのか?」「ムフムフできるのか?」という観点で、それらと向かい合うよう、気をつけました。

一例として、今回のリニューアルでは、ユーザーの声の中から「いつ作ったかわかりにくくなった」「日付を確認しづらくなった」という声があり、こちらが想定していたよりも、ユーザーにとって「その料理をいつ作ったか」という情報の優先度が高いことが分かりました。

それを受けて、写真リストに料理写真を邪魔しないデザインで日付を表記するよう改善したバージョンをリリースしました。

ユーザーへのフィードバックにかぎらず、サービスに関する判断は、常にそのサービスが本来持っている価値に立ち返ることで、ブレることなく進んでいけると考えています。

今後の対応

今回のリニューアルによって、MAU・リテンション・滞在時間などで、数値の上昇はあったものの、残念ながらユーザー一人あたりの投稿数で大きなインパクトは出すことはかないませんでした。

お料理アルバムチームでは、引き続き、ユーザーの「ムフムフ」を加速させるために、さらなる改善を日々検討しています。

一例として、お料理の成長を実感させるような価値検証を目的としたコレクションビューの提供を始めており、ユーザーからの反響も届いています。

まとめ

サービスの価値を改めて明文化し、初期段階からチーム内で共有することで、いつでもそこに立ち返られるため、デザインの議論・検討をする際もスムーズに進めることができました。

デザインを大きく変更する場合は、見た目のインパクトや受ける印象のみで判断しないよう、地に足を付けて、そのリニューアルをなぜやるのか、それをすることで、ユーザーにどんないいことがあるのかの裏付けが大事ではないかと考えております。

仮説検証とサンプルサイズの基礎

$
0
0

パートナーアライアンス部 森田です。有料会員の獲得施策や、それに関わるサービス内動線の最適化を担当しています。

記事の対象

  • 仮説検証を通じて何かを改善をしたいと思っている人
  • 仮説検証の際に「どれくらいのデータをを集めたら良いか」分からない人

はじめに

仮説検証とは「仮説を立て、それを証明するためのデータを集め、真偽を確かめること」です。今回は仮説検証を行う際の手順と、その検証に必要なサンプルサイズの考え方を説明します。サンプルサイズの話のみ関心があるかたは、前半を飛ばし「サンプルサイズの決め方」を読んでください。

目次


仮説検証のつくりかた

1. 仮説をたてる

仮説をたてます。知りたいことを言い切る形にすれば仮説になります。

例えば「クックパッドの利用者が有料会員になるきっかけは文字ではなく美味しそうな料理の写真である」や「クックパッド利用者は自分の閲覧したレシピを後から見返したい」などです。ただし、後者は仮説検証のための仮説としては少し不十分です。その理由は次に説明します。

2. 施策/KPIを考える

仮説は根拠の程度はあれど真偽は不明です。その真偽を確かめるために何のデータを集める必要があるか考えます。ここが一番の難所です。

「ユーザは自分の閲覧したレシピを後から見返したい」という仮説の真偽はどのようにすれば分かるのでしょうか。施策としては単純に閲覧履歴の提供が思いつきます。しかしKPIの設定で詰まります。

このようなときは「知りたいことを」をもう少し具体的にします。たとえば割合を決めたり、何かと比較したりします。例えば「全ユーザの5%がレシピを後から見直したいと思っている」や「閲覧履歴を利用したユーザは利用しないユーザに比べて利用時間が20%伸びる」などです。悩んだ場合は次に述べる「仮説検証後のアクションを決める」と合わせて考えることをおすすめします。

3. 仮説検証後のアクションを決める

実際にデータを集める「前」に、データを集めた後のアクションを決めます。このステップにより先の試作/KPIが十分かわかります。「こういう結果ならばこうする」というのが決められないようであれば、施策/KPIは不十分なのでやりなおしです。

サービスの改善のように、指標となるKPIの意味に主観が含まれる場合はとくに意識します。事後の解釈ではサンクコストによるバイアスがかかり、冷静な判断が難しくなります。たとえば「閲覧履歴の利用者は全体の5%」という結果がどのような意味を持つか、検証後に考えるようではいけません。

4. 対象を決める

施策もKPIも決まりました。次にその対象者を決めます。

最終的なサービスへの全体影響を知りたい場合は細かいことを考えず全体を分割してABテストなどでデータを集めます。

一方で、何かしらの価値の有無を確認したい場合、まずは「このユーザの行動が変わらないのであれば、価値自体が無いのだろう」と考える理想的なユーザを施策の対象とすることをおすすめします。なぜならば全体で価値の有無を検証をしてしまうと影響が希釈されて計測が難しくなることが多いためです。

先の「2. 施策/KPIを考える」と、この「4.対象を決める」では、相関関係と因果関係の問題に十分注意してください。たとえば先の「閲覧履歴を利用したユーザは利用しないユーザに比べて利用時間が20%伸びる」という仮説の検証は実はなかなか難しく、もしそのようなデータが取れたとしても「利用したユーザはもともと利用時間が長いユーザ」である可能性は非常に高いです。この問題に関しては今回の説明の範疇外のためこれ以上触れませんが、自明な答えがないためサンプルサイズを計算するよりも厄介です。大変ですが誰もが苦労していると思いあきらめましょう。

5. サンプルサイズを計算する

施策もKPIも対象も決まりました。あとは必要なサンプルサイズを計算するだけです。タイムイズマネー、時間は有限で貴重です。PDCAを回すためにも行き当たりばったりの計測ではいけません。


サンプルサイズの決め方

ここからはサンプルサイズの決め方を説明します。

私が業務で行う仮説検証はほぼ全て、ABテストとこの先で述べる仮説検定*1という考えのもとで行っています*2。そして、その際のKPIとしては「入会する/しない」や「利用する/しない」のような、単純な1,0を好みます。そのためここからは

  • A「入会率10%の現ランディングページ」
  • B「入会率(以下CVR)15%を期待する新ランディングページ(以下LP)」

という2つのページを「BはAよりもCVRが5%高いだろう」という仮説のもとABテストし、その結果を判断するのに必要なサンプルサイズnを、信頼区間の考えをもとに説明したいと思います。

検証としてABテストをするつもりがない場合でも、この先の説明を理解することで適切なサンプルサイズを決める事ができるようになると思います。

答えを先に

ここから先の説明は少し長くなります。少しでも理解しやすいよう、これから求めようとするサンプルサイズnとは何かを、さきに文章で表現します。注意すべき点として、求めるサンプルサイズnは「差があること」を確認するためのサンプルサイズであり、「Xの差があること」を確認するためのサンプルサイズではないという点です*3

確率p1と確率p2にX以上の差があるならばn個のサンプルサイズで明確な差がでるだろう。もし差が出ないのであればX以上の差は無いのだろう*4

サンプルサイズを決める二つの要素

今回のABテストに必要なサンプルサイズは「二つの平均値*5」と「必要な確度」できまります。そのためまずは「二つの平均値」と「必要な確度」がそれぞれ何を意味するかを説明します。続いて予備知識として「二項分布」の概念を説明をした後、「必要な確度」を分解して現れる「αとβ」を説明し、最後にサンプルサイズを計算します。

「二つの平均値」とは何か

今回で言えば10%と15%です。サンプルサイズの計算にはこの二つの値が必要です。理由については少し先の「β」で説明します。

「必要な確度」とは何か

確度とは下記の二つの確からしさです。

(1) AとBに差がない

(2) AとBに差がある

その上で、(1)であるにもかかわらず「差がある」とすることを「第1種の誤り」といい、その確率を「α」といいます*6

そして(2)であるにもかかわらず「差がない」とすることを「第2種の誤り」といい、その確率を「β」といいます。言い換えるとαは偽陽性の確率であり、βは偽陰性の確率です。

つまりサンプルサイズを決める要素の一つの「確度」とはαとβの二つであり、「必要な確度」とはαとβをそれぞれどの程度まで許容するかを意味します。

「AとBに差がない」とは何か

実のところ「AとBに差がない」とは「BはAで無いとは言えない」を意味します。消極的かつ回りくどい表現ですが、これには意味があります。実際のところいくらデータを集めても「完全に差がない」と言い切れません。そのため何かの差を判断する際にはまず、「BはAと等しいだろう」という前提に立ち、データを集め、「Bのデータを見る限り、確率的にAと等しい可能性が十分にある」状態ならば、それをもって「差がない」と結論します。いいかえると「Bの結果がAであるにしては逸脱している」かどうかで差の有無を結論するわけです。そして「Bのデータを見る限り、確率的にAと等しい可能性が少ない」場合には「差がある」と結論します。何を持って「逸脱」とするかはこのあとの「α」で説明します。

このような手法を「仮説検定」と言います。ここより先に続く説明は、この「仮説検定」という考えに基づき差の有無を結論します。「仮説検定」についてより詳しく知りたい方は「仮説検定 - Wikipedia」を読んでください。

二項分布

この後に続く「αとβ」の説明のために、予備知識として二項分布という概念を説明をします。

堅苦しい説明をすると、二項分布とは

確率pで成功する行為をn回施行した場合の成功数の確率分布

です。

たとえば、裏表がともに50%の確率で出るコインを100回投げた場合、表が出る数はぴったり50になるとは限りません。むしろ出るほうが稀です。では何回が何%の確率で出現するのでしょうか。それを表したものが下の図であり、二項分布です。

f:id:idwtstwof:20160923221813p:plain

縦軸が確率、横軸が表の数になり、面積を合計すると1(=100%)になります。これをみると平均を50として、だいたいが40−60の範囲に収まることがわかります。

同じ考えで、「入会する/しない」 をそれぞれ1と0で表し、入会する確率をpとした場合も、二項分布で表すことができます。下の図は200人(n)がCVR10%(p)のLPに接触したさいに、最終的な入会数がどのようにばらつくかを示しています。実装の都合上曲線になっていますが、実際は上の図のように階段状に分布しています。また、スライドを移動することでnを変更できます。nと分布の関係を確認してみてください。なお、赤く塗りつぶされた部分の説明は後ほどするため、気にする必要はありません。

n:

αとβ

予備知識の勉強を終え、ここからはαとβについて説明します。復習として、ぞれぞれの意味はこのようなものでした。

  • αとは「真実として差がないにも関わらず、差があると結論する」偽陽性の確率
  • βとは「真実として差があるにも関わらず、差がないと結論する」偽陰性の確率
α(偽陽性の確率)

αを入会数に当てはめて考えます。

200人がCVR10%の現LPに接触した場合の入会数は20人を中心にばらつきます。そして面積の(だいたい)95%が12人から28人の間におさまることが二項分布により示されています。この12−28の領域を「95%信頼区間」と呼びます。これは二つ目の図の赤で塗りつぶされていない部分に相当します。それはつまり赤い部分の面積は5%ということになります。

Bの入会数を計測し、その結果がこの赤い部分に該当する場合は「差がある」と結論すると決めたならば、それは「αを5%に設定した」事を意味します。

もしもBの真実のCVRが期待してたような15%でなくAと同様の10%である場合、Bの計測後の入会数は5%の確率で赤い部分になるため、その時は「真実として差がないにも関わらず、差があると結論する」ことになり、偽陽性の確率=α=5%となります。

なお、決めたと表現したように、αを何%するかは恣意的です。赤い面積が小さくなるようにαを設定すれば偽陽性の確率は減りますが、その分、本当に差がある場合も「差がない」と結論しやすくなります。一般的にはαを1%、5%、10%とすることが多いです。

β(偽陰性の確率)

続いてβの説明をします

αは一つの分布で完結する話でした。というのはαは比較して考える問題ではないからです。それに対してβは本当は存在する差を見逃してしまう確率であり、二つの分布が必要です。今回でいえばCVR10%(A)とCVR15%(B)の二つです。

まず先程の図に、CVR15%の分布をオレンジの線で加えます。また、入会数を入会率に置き換えた分布も合わせて示します*7。灰色の部分についてはすぐに説明するので気にしないでください。とはいえ察しの良い方のために言いますと、この灰色の部分がβです。

n:

復習になりますがβとは「真実として差があるにもかかわらず、差がないと結論する」偽陰性の確率です。今回の例にあてはめると「Bの真実のCVRは15%にも関わらず、n人が接触した結果の入会数をみて、Aと差がないと誤って結論する」確率です。この時に、何をもって「Aと差がない」とするかは先に述べたαで決まります。つまりβはαによって変わります*8

入会件数分布の灰色の部分は「CVR10%時に95%の確率で発生しうる人数の、CVR15%時の発生割合」を示しています。その割合(=確率)は右の山全体を100%とした時に39%となり、この39%がβです。βが39%とはつまり「Bの真実のCVRが15%の場合、200人のサンプルサイズでは39%の確率で『BはA(10%)と差がない』と結論する」事を意味します*9

しかしながら本当に差があるにも関わらず、39%の確率で差がないとしてしまうのであれば「(2) AとBに差がある」を十分な確度で結論出来ているとは言えません。ではこのβを5%にまで減らすにはどのようにしたらいいでしょうか。もしまだ試していなければ最後の図のスライドを動かしてn(サンプルサイズ)の値を増やしてみてください。するとnの増加に伴い、入会確率分布の山が鋭角になり、結果として灰色の面積が減っていくことがわかります。これはつまりβを小さくするにはnを増やせば良いということです*10

また、図を見るとわかるように、βは二つの分布の山の距離(平均値の差)により変化します。もしもB(オレンジの線)が15%でなく30%であれば山の距離はもっと離れ、それにともないβの値も変化します。このことから「適切なサンプルサイズ」を求めるには「二つの平均値」を事前に決める必要があることがわかります。

ここまでの話を整理するとこのようになります。

  • α = 恣意的な確率
  • β = f(α, 二つの平均値, サンプルサイズ)

このことからも、適切なβにするには、サンプルサイズを変化させれば良いことがわかります。

サンプルサイズの計算

今までの話を元に、αとβがともに5%となるようなnを計算します。考え方としては、Aの右側2.5%とBの左側5%の数値が一致するようなnを求めます。そうすれば過不足のない、必要十分なサンプルサイズを求めることができます*11

計算には二項分布の正規分布への近似を利用しています*12。計算のためのPythonコードは以下のようになります。

import sympy as sp
p = 0.1
diff = 0.5
n_s, p_s, diff_s = sp.symbols("n_s p_s diff_s")
a_mean = n_s * p_s
a_var = (a_mean * (1 - p_s))
a_sd = sp.sqrt(a_var)
b_p = p_ + p_s * diff
b_mean = n_s * b_p
b_var = (b_mean*(1 - b_p))
b_sd = sp.sqrt(b_var)
a_right = (a_mean + 1.96 * a_sd)
b_left = (b_mean - 1.65 * b_sd)
param = [(p_s, p), (diff_s, diff)]
print(sp.solve((sp.Eq(a_right.subs(param), b_left.subs(param))), n_s)[1])
=> 554.289654454896

これにより、555人という結果が得られました。この人数を先程の図に設定し、いい塩梅であることを確認してみてください。

まとめ

前半は仮説検証のつくりかたを、後半はその際に必要なサンプルサイズの考えかたを説明しました。「何のために何を計測するか」は最も大切な、かつ難しい問題です。しかし、もしそれを決めることが出来たならば、その時は十分なサンプルサイズを伴い正しく判断しなければいけません。また途中で述べたとおり、相関関係と因果関係にも十分注意してください。

サンプルサイズの話に関しては出来る限り誤った事を書かないように注意したつもりですが、私自身の統計や検定に対する理解不足から、説明や表現に間違いがあるかもしれません。その際は指摘していただけると助かります。

参考書籍

私が仮説検証に取り組み始めた当初、確率と統計に関して全くの無知でした。数学の知識も乏しく、参考書を読んでもなかなか理解できません。そんな時に出会った「入門統計学」と「伝えるための心理統計」の二冊は、混乱しがちな所を一から丁寧に書かれており、非常に助かりました。もし統計を一から学ぼうという方におすすめします。また、今回の説明にない「平均値の検定」などを行う際のサンプルサイズに関しては、永田靖さんの「サンプルサイズの決め方」で学ぶ事ができます。

入門 統計学 −検定から多変量解析・実験計画法まで− - 栗原 伸一

https://www.amazon.co.jp/dp/4274068552/

伝えるための心理統計: 効果量・信頼区間・検定力 - 大久保街亜, 岡田謙介

https://www.amazon.co.jp/dp/4326250720/

サンプルサイズの決め方 - 永田 靖

https://www.amazon.co.jp/dp/4254126654/

便利サイト

Optimizely社がサンプルサイズを計算するページを無償で提供しています*13www.optimizely.com

*1:紛らわしくて申し訳ありませんが、仮説検証と仮説検定は別です

*2:少し嘘です。実のところは私がABテストを行う理由は検定のためというよりも既存の情報(今回で言えばAのCVR)の季節変動や他の施策の影響を観測することが主目的です。Aが今まで10%だからといって、Bの計測中も10%であり続けるとは限りません。そしてまた、解釈や判断は検定よりもその背景にある信頼区間をもとに行っています。しかしながら適切なサインプルサイズを説明するには仮説検定の考えに沿う方が容易なため、今回は「ABテストの結果を仮説検定する」文脈で説明します

*3:差の大きさが重要な場合は、差の有無に加えて信頼区間による解釈が必要となり、場合によってはより多くのサンプルを必要とします

*4:ただしX未満の差の有無については依然として情報不足です

*5:一般的には平均値の差を以て「効果量(Effect size)」として説明されます

*6:今回の説明では触れませんが、p値を利用した帰無仮説の棄却については基準率の誤りに注意してください。Alex Reinhartさんの「The p value and the base rate fallacy — Statistics Done Wrong」(西原史暁さんが日本語に翻訳されています「【翻訳】ダメな統計学 (5) p値と基準率の誤り|Colorless Green Ideas」)が非常にわかりやすく、混乱するたびに読み返させていただいています

*7:二項分布における確率の信頼区間は正規分布で近似して計算しています。ただし、サンプルサイズが少ない場合及び確率が極端に低い(高い)場合の信頼区間には注意が必要です。気になる方はWikipediaの「 Binomial proportion confidence interval - Wikipedia, the free encyclopedia」や、ynomuraさんの「 統計学復習メモ18: 少数のベルヌーイ試行による発生確率の区間推定 (Weblog on mebius.tokaichiba.jp)を読んでください。実務ではRなどを使うことをおすすめします

*8:αが小さいほどβは大きくなります

*9:1-β(1-0.39)=61%を検出力(power)といいます

*10:鋭角になるということは、サンプルサイズの増加により、得られる結果が本来の値に近づく確率が増す事を意味しており、これを「大数の法則 - Wikipedia」と言います

*11:「なぜAは2.5%でBは5%なのか。Aも5%じゃないのか」と不思議に思うかもしれませんが、これは両側検定という考えをもとにαを設定している事に関係します。今回の説明の範囲外のため、気になる方は「両側検定」や「片側検定」といったキーワードで調べてみてください

*12:二項分布の正規分布への近似には条件があります。詳しくは「 二項分布 - Wikipedia」「 ポアソン分布 - Wikipedia」を読んでください

*13:今回の計算結果とOptimizely社の計算結果は異なります。どのような式を利用しているかは分かりませんでした。もしどこかに書いてあるならば教えてください

管理下にないウェブサイトを適切に改修するために

$
0
0

株式会社トクバイの根岸です。みなさん、SSSランキングの調子はどうでしょうか。僕は今朝家を出たときには766位でした。一睡もしてません。

さて、今回もブラウザ拡張を作ったよという話です。"外部サイト向けバナー・リンク"という、我々の管理下にないウェブサイトに設置するウィジェットなどの管理・改修をどのように行っているのかについて書きました。

外部サイト向けバナー・リンクについて

トクバイが運営しているクックパッド特売情報は、今日のチラシが見られる、お買い物をするひとたちのためのサイトです。閲覧できるチラシ情報自体は、基本的にはスーパーの店員さんによって管理がされています。 では店員さんがなぜチラシをアップロードするのかというと、単純な観点でものを言えば、販促のためです。 それでは、なぜ、販促ができるのかというと、様々な認知・再訪チャネルがクックパッド特売情報には存在し、お買い物をするひとたちがクックパッド特売情報にやってきやすいようになっているからです。 このチャネルはいくつもありますが、その中のひとつが"外部サイト向けバナー・リンク"という機能になります。

技術的には、iframeでcookpad.comからサーブしているコンテンツをウィジェットやバナーとして参照可能なように提供したり、適切な実装がなされているリダイレクタ(特定の店舗にチラシがあったらチラシの1枚目・無かったら店舗ページにリダイレクトする、みたいな)へのリンクを提供したりということをしています。これらをスーパーの店員さんが自社のウェブサイトに貼ることで、お買い物をするひとたちにチラシ情報が知られて、販売が促進するという形ですね。

運用上の課題

管理下にないウェブサイトに提供しているコンテンツを適切に管理・改修するには、求める内容によって様々な手法があると思います。結論を先に書いてしまいますが、我々は人力で頑張って管理するという方法を選択していました。バナーを貼ってみたのですがという連絡を受けて、目で見て、電話をかけて、このようにしてはどうでしょうかと営業さんからスーパーの店員さんにお話するのが適切だと考えています。これは、技術的な利用のされ方に対する判定とは独立して、お買い物をするひとたちにとって設置されたバナー・リンクが合目的かどうかを人間が判断する必要があるからだと僕は考えています。

さて、最近になって子会社化によるブランド変更に伴い、バナー・リンクを全面的に刷新することになりました。しかしあらためて全面的にチェックし直そうとすると、実はこれまで行っていたチェックでは問題があることに気づきました。

端的に言うと、技術的な部分のチェックが非常に複雑で、これまでは不十分だったということになります。

6種類の提供されているバナー・リンクが適切なリソースから提供されているかをチェックするには、その内容を判定するために、目のあたりに非人間的な正規表現が実装されている必要があります。もちろんhtmlの基礎的な知識も必要です。またぱっと見て、公式が提供しているバナーなので大丈夫かと思いきや、じつは少しだけ改変した画像にリンクを貼っているという状況もありました。そのようなもののチェック作業を繰り返していると人間は疲弊します。

そしてもちろん、機械的にチェック可能な部分に人間のリソースを割いてしまうことは、とてももったいないことです。より重要な、お買い物をする人たちのための判定が、上手くできなくなってしまうからです。

この、人力でチェックして案内に至るというプロセスの機械的なチェックの部分を、システムで解決するというのが今回のエントリーのテーマになります。

解決

普通に考えると脳髄眼球と管理下にないウェブサイトの間にはコントローラブルなシステムが入る余地がないように見えますが、もちろん、あります。ブラウザ拡張です。

実を言うとこのチェックには専任の担当者が以前いて、僕は例のごとくdotjsで管理機能を提供していました。機能としては、◯✕の判定を各リンクに対して判定しサイト右上にずらっと並べるという簡易なものです。ところが、dotjs scriptでこのチェック機構を担当者に渡して運用するのは問題がありました。

  • 開発が終了しました
  • 証明書周りでどうしてもインストールが煩雑になるため、エンジニア以外にはチーム内運用が難しいです
  • インストール後の修正の適用が難しいです

結果として営業チームでは担当者の離職に伴いロストテクノロジー化、眼球正規表現の時代に戻ってしまいました。申し訳ありません。

先程も申し上げたブランド変更に伴って全外部サイトの再チェックが走るにあたり、dotjs scriptをChrome拡張に書き換えました。多少ヒアリングして○△✕の3段階に変更し、どのステータスのバナー・リンクがどこにあるのかわかるようにしました。レポジトリ管理して、rakeタスクで公開フローを進められるようにする、という感じでメンテナンス性の向上も図っています。

また、業務にChrome拡張を利用する上で結構重要なtipsとしてChrome拡張は限定公開可能という点があります。覚えておいて下さい。

そんな感じで、現任の主担当者にドキュメントと、動作チェックのためのテストサイトを共有して、チーム内で運営してくださいね、よろしくお願いします。とお渡ししました。

結果

パッと作ったブラウザ拡張によって、結果として、膨大なドメイン知識が必要な状態から、✕って表示されたら直すのを進める、という一発アクショナブルな状態になりました。✕でました、はい管理しておきます、ご連絡しました、直りました!という感じで、ステータスを機械的に形式化したことによってチーム内に共通言語ができ、恊働がうまくいくようになりました。バナーっぽく見えるからメンテ不要に見えて、実はお手製の画像、というようなパターンも非常に簡単に認識出来るようになりました。一つのページのバナー・リンクのステータスが全て右上に出ているので、OKになるとオールグリーン感が出てわりとうれしいと言う声も聞きました。

あとはもちろん、新規の実装などで判定の基準が変わることもありますが、そう言った更新もすぐに反映されるようになりました。リリースしてしばらくは積極的に営業チームから状況を引き出して都度改善を入れていましたが、即時反映されるのでとても楽でした。

Chrome拡張、便利ですね。コンテンツの質を担保するために人手が入ることは、時には必要で、適切なことですが、機械でやるべきことは機械でやりたいです。頑張っている営業チームと、店員さん、サービスを使ってくれているお買い物をするひとたちに感謝しながら、みんなに便利そうなものを開発して、いい感じになっていくのを眺めているのは、とてもたのしいなと毎日思っています。

iOSアプリの継続的デリバリーへの取り組みについての勉強会を開催しました

$
0
0

f:id:gigi-net:20160913200616j:plain

技術部モバイル基盤グループの三木(@)です。

去る9月13日、「Cookpad Tech Kitchen iOSアプリの継続的デリバリーへの取り組み」と題して、iOSエンジニア向けの技術交流イベントを行いました。

このイベントでは、iOS開発の中でも特に大規模アプリの開発フローや、品質改善を支えるための技術をテーマに、弊社のエンジニアから3つの発表をしました。

この記事では、その様子についてお伝えします。

クックパッドiOSアプリの品質管理のための取り組み

まず、技術部品質向上グループの松尾(@)から、クックパッドiOSアプリ開発体制について紹介しました。

この発表では

  • どのような組織構造を元にアプリ開発が行われているか
  • 月1のリリースサイクルを実現するためのリリースフロー
  • テストサイズとテスト戦略
  • UIテストを中心とした自動テスト手法

などについての概略を紹介しました。

サイズごとのテストについては以下の記事でも解説しています。

CDC Testing on iOS

次に、私、三木より、Consumer-Driven Contract Testing(CDC Testing)と呼ばれる、クライアントとサーバーサイドアプリケーション間の関係性に着目したテスト手法をiOSアプリに組み込んだ知見について発表しました。

CDC Testingは、クライアントからのAPIサーバーへのリクエストを記録し、継続的に検査するテスト手法です。 これにより、APIの変更による連携の崩れを検出することができます。

サーバーサイドアプリケーション間のCDC Testingについて、当技術ブログにいくつか記事がありますので、ご興味のある方はあわせてご覧ください。

また、今回紹介した、iOSのユニットテスト内でPactを用いてAPI仕様を作成するためのライブラリ、Phakchiも公開しています。

クックパッドiOSアプリの開発フロー

最後に、投稿開発部森川(@)から、サービス開発に携わるエンジニアの目線から、 開発フローの中でどのように品質を改善していくかという手法について発表しました。

コードレビューやKPT会など、開発速度を上げるために行っている工夫についていくつか紹介しています。

また、今回の発表でお伝えしきれなかった内容について、以下の記事もあわせてご覧ください

開発速度を上げるための Pull-Request のつくり方 - クックパッド開発者ブログ

懇親会

上記の発表の後、懇親会を行いました。

懇親会では、他の弊社iOSアプリエンジニアも参加しながら、参加者と様々な意見交換や談話をしました。

多くの皆様にご参加いただけたおかげで、より深掘りした話をしたり、各社のiOS開発の知見を共有するなど、活発な情報交換が行えたと思います。

また、今回はAppleになぞらえ、リンゴをテーマにした料理も振る舞われました

f:id:gigi-net:20160913202255j:plain

まとめ

いかがでしたでしょうか。

クックパッドでは、今後もiOS開発をテーマに同様のイベントを行っていきたいと考えています。 次回は11月頃の開催を予定しています。詳細が決まりましたら、当ブログなどでお知らせします。

また、クックパッドでは、一緒にiOSアプリ開発を行っていくエンジニアを募集しています。ご興味のある方は是非遊びにいらしてください。

Viewing all 726 articles
Browse latest View live