アプリのアップデートに依存せずにアプリの画面を改善し続ける仕組み

検索事業部の日高(@kaa)です。
検索事業部では作りたいレシピが見つかることをひとつの目標に、レシピを探す行動を助けることに挑戦しています。 その中で、レシピ検索した際の結果画面でのコンテンツを改善していくための仕組みについて紹介します。

作りたいレシピが見つかるためへの色々なアイデア

レシピ検索結果画面でレシピを一覧で見せるだけでなく、作りたいレシピがより見つかるために考えられることはたくさんあります。

例えば

  • もし、入力ミスと思われる検索ワードだったら
    正しいと思われる検索ワードを提案、または正しいと思われるワードで検索し、元のワードも表示(Google検索のように)

  • あいまいな検索ワードだったら
    より具体的に検索できるよう検索ワードを提案。「さっぱり」だったら「冷しゃぶ」「さっぱり 麺」など。 (具体的なワードで検索するとレシピが決まりやすい傾向があります)

  • さらに小分類をもつワードなら
    「パスタ」だったら「ナポリタン」「カルボナーラ」「冷たいパスタ」といった具体的なワードを提案する。

  • 見つからない様子だったら
    もし検索結果をある程度の件数見て、まだ迷っているようなら、この食材でやってみるのはどう?といった方向性を変える提案

などなど、 それぞれのアイデアごとに、どのような検索ワードの時に、検索結果の一覧のどのあたりに出すべきかということを検討していく必要があります。 もちろん全てのアイデアに価値があるわけではありません。素早く効果を確かめ、もし駄目な場合も他の開発に影響なくクローズを行えるのが理想です。

アプリでの新機能・導線改善のよくある課題

  • アップデートの浸透具合により、コンテンツの効果判断できる時期が伸びがち(改善サイクルが遅い、段階リリースを利用するとさらに伸びる)
  • A/BテストのコンテンツのためのAPIなど、アプリ・サーバーに限らず一時的な実装が増えてしまう。
  • コンテンツ変更にアップデートが必要になってしまうので、スマホサイトで価値検証後、アプリに導入になってしまう。
  • Webで効果あった施策がアプリでも効果があるとは限らない。再度確かめる必要がなる

よくあるアプリでのA/Bテストとその課題

アプリで機能の価値評価を行なう際、A/Bテストを行なうことがあります。
基本的な流れとしては起動時などに設定用APIからフラグなどのデータを取得し、機能のONOFF、UIの切替を行ない数値検証をしていきます。 Google公式のFirebaseでもRemote configという機能が提供されるのでこれからさらに行われるようになると思います。

この場合も弱点として、フラグを処理する実装をしたバージョンからしか有効でない、機能自体はアプリに実装されていないといけないのでテストできるバリエーションが限られる、A/Bテストの結果を見てさらにテストを行ないたい場合、また次回アップデート待ちになりがち。
AパターンとBパターン、さらに手を加えたA'パターンまでアプリに実装されていないことにはWebと同じスピードで改善を続けていくことはできません。

また、クックパッドのandroidアプリでは新バージョンでの新たなクラッシュの検出のため段階的にリリースされていくようにしています。段階リリース中にクラッシュが検出された場合、その修正対応などによりアプリの全体公開の時期がずれこむこともあります。
段階リリース自体は素晴らしいのですがアップデートによる価値検証という目的ではサイクルが遅くなる要因となります。

アプリでの価値検証のスピードを上げるために

1.表示するコンテンツをAPIで指定できるようにする

検証したい価値ごとにアプリを実装していたのでは、アプリのアップデートに縛られてしまいます。 これには事前に考えられるコンテンツのデザインフォーマットを事前に用意しておくことで対応します。

コンテンツの表示方法がその機能固有になると、その実装したバージョンからしか検証ができません。
それではアイデアをすぐに試せないため今回はアプリのデザインルールに沿ったコンテンツのフォーマットを10パターン程度想定しました。
横スクロールのカルーセル型か、バナーか、一覧形式か、またはタイトル・サブタイトルになる要素、「もっと見る」的要素など各フォーマット共通に使われそうなものを整理。 画像があるのかないのか、あるなら画像サイズの自由度は、キャプション、バッジ的要素はあるのかないのか。
各コンテンツフォーマットのデザインに対してどんな利用シーンが起こりえるか想像力を働かせます。既存のデザインを見返し、どの要素が必須で、必須ではないcaptionなどの要素が空の場合でもデザインが破綻しないよう注意します。

今回は以下のようなテンプレートを用意しました。
上部には共通でlabel要素、アイコン、more(もっと見る等)の要素とその下に各フォーマットの情報。
これで全てではありませんが一例として。 f:id:futura24pt:20160729124517p:plain

各要素の名前も出来る限り汎用的に考えます、label,lead,caption,thumbなど。ここでもしrecipe_titleといった意味を持った名前を採用してしまうとそのフォーマットを別の用途で利用しようとした際に混乱を生んでしまいます。
ただ汎用性を高めすぎると使いにくかったり複雑な構成になりやすいため、今回はレシピを表示するrecipe_list,recipe_singleは別に用意しました。

価値評価後、最終的にはさらに適していると考えられるそのコンテンツの専用デザインを作成する可能性はありますが、評価段階では汎用的なもので進めます。
これらがアプリに実装された状態が出来てしまえば、APIの変更のみでコンテンツを入れ替え価値検証していくことが可能になります。

2.APIを検証したい機能ごとに用意しない

APIの種類が増えると表示速度の低下、通信エラーリスクの増加、コードの複雑化といった問題が起きますし、APIを叩く実装をしたバージョンでの動作に限定されます。 それでは価値検証したいコンテンツの評価に次バージョンを待たなくてはいけません。
また後々使わない可能性がある、しかし特定のバージョンでのみ利用しているAPIといったものができてしまうとサーバーサイドの実装もいつまでも残す必要ができてしまい、負債になってします。そのバージョンを利用するユーザーはアプリアップデート後も残ることになりますので。

運用していくために

仕様をドキュメント化する

あるデザインフォーマットのコンテンツを追加したい場合、コンテンツの各要素の指定方法がわからないといけません。 各要素の必須、任意なのかもまとめておきます。
この仕様さえ共有できてしまえば、価値検証時にアプリエンジニアの稼働がゼロで、アプリリリース時期に依存せず新たなコンテンツを提供していくことが可能です。もちろんバッティングしないよういまどういったコンテンツをレシピ検索結果に表示しているかの共有は大事ですが。
サーバーサイドとしてはどのようなJSONを出力すると望んだ表示ができるのか把握できることが望ましいので、サンプルのJSONと画面キャプチャも用意しておきます。

各デザインフォーマットをプレビューできるようにする

全デザインフォーマットが実運用で常に使われるわけではありません。 どのような表示が可能なのか、確認できるようになっていないと困ります。
クックパッドでは開発版ビルドでのみ各デザインフォーマットの確認ができるダミー画面を実装し、どのような表示が可能なのか見当できる画面を用意してあります。

各デザインフォーマットの対応バージョンを明記する

いくらデザインフォーマットを色んな想定したとしても、追加したいデザインはでてきます。
また、特定の機能のためのデザインを追加したくなることもあります。 もちろんそのデザインが実装されたバージョン以降からしか利用できませんので、どのフォーマットがどのバージョンから利用可能なのかまとめておきます。 これにより新しいコンテンツを配信した際、どの程度の数のユーザーがそのコンテンツを利用できることになるのか判断できます。
APIを一本化したことにより、もし古いバージョンのアプリを利用していて、最新版のアプリでしか対応していないコンテンツを受け取ってしまうとどうするか、という問題がありますがアプリが知らないコンテンツフォーマットのデータに関しては無視する、表示しないといった方針にしています。

まとめ

このようにアプリでの表示とAPIのルールを定義することで、以前はスマホサイトで価値検証後にそれぞれAPI開発し、アプリに実装し次回アップデート後に反映、といった進め方から最初からアプリで価値を検証し、改善していく進め方ができるようになりました。

クックパッドでは職種問わずサービス改善に取り組み続けることに興味のある方を募集しています 。もしすぐに採用でなくても、アプリでのサービス改善について興味ある方がいらっしゃいましたら@kaaまでお気軽にどうぞ。

ユーザーの気持ちを考えてデザインをするために大切なこと

こんにちは。クックパッド ダイエットのデザイナーの新妻です。 クックパッド ダイエットでは、「正しく食べてやせる」をコンセプトに銀座と代々木にある店舗でのダイエット指導と、ダイエット情報を毎日配信するメディアサイトの運営を管理栄養士と一緒に行っており、私はデザインやコーディングを担当しています。

今回は新規コンテンツを作る中で、ユーザーの声をどのようにデザインに反映していくかというお話をさせていただきます。

どんな気持ちでダイエットラボを利用している?

クックパッド ダイエットは、ユーザーの約85%が女性で、年齢でいうとメディアの方は20代〜40代と幅広く、店舗の方は40代の方を中心にご利用いただいています。

f:id:lica19:20160728102519p:plain

サイトや店舗ユーザーの目的の多くは“ダイエット”ですが、店舗にいる管理栄養士を通して「歳を重ねるごとに痩せにくくなって困っている」「体調が良くないので改善したい」という、より具体的な悩みがきっかけでお店に訪れる方が一定数おり、これらの悩みは更年期世代に多く「やせたい」という理由だけでなく「体調不良」に悩んで不安な気持ちでダイエットラボを訪れている方がいることがわかりました。

ユーザーの不安を解決できるコンテンツってなんだろう?

「やせたい」という思いから、自己流の食べない・偏ったダイエットを行ってしまう方が多くいらっしゃいます。その結果、一時的に体重が減少しますがリバウンドの可能性も高く、何より体のバランスが崩れ更年期症状が悪化してしまうことも・・・しかし専門家の指導のもと正しい食生活を送ることで心身の不調が改善されることもあります。

そこで、私達の提案する食事改善サービスを知ってもらうきっかけとして【更年期診断】というコンテンツを作る事になりました。更年期症状に悩む方に、いくつかの質問に答えていただき、自分の現状を把握してもらったうえで、改善案の一つとして、ダイエットラボでの食事改善を提案するというコンテンツです。 クックパッド ダイエットにはダイエット診断という100万人以上が実施した大人気コンテンツがありますので、そのシステムを活用し質問内容と診断結果に関しては専門家の指導のもと医学的根拠に基づき作成しました。

各質問に入れるイラストのテイストをユーザーインタビューを元に決めることになり、「最近更年期症状を感じる」という数名のユーザーさんに直接店舗にお越しいただき、3つの質問に答えていただきました。

1.イラストのテイストについて

まず更年期診断の挿絵として良いと思うイラストと、良くないと思うイラストを理由と共に答えてもらいました。最初に仮設を立てた段階では、ターゲットとなる40代50代の女性は、人間味があり感情移入しやすいAやEのようなテイストが有力だと思っていました。逆にBやCは症状に悩んでいる人にとっては少し軽すぎるタッチでふざけたように感じられないかが懸念点でした。

f:id:lica19:20160728102543p:plain

しかし結果はBやCのようなデフォルメされたイラストが人気で「LINEのスタンプのようなイラストで見慣れているので良い」「おしゃれでかわいい」という意見があり、逆にAのようなイラストには否定的な意見が多く、「人間っぽすぎて嫌」ということでした。

仮説の段階では、感情移入のしやすさがポイントだと思っていましたが、実際に話を聞いて見ると更年期症状というつらい経験に対しての質問に答えていく中でイラストのリアルさが逆に気持ちをネガティブな方へ導いてしまうということが分かりました。

2.キャラクターの年齢について

次にイラストを描くにあたり、年齢の表現を探りました。 この4種類のイラストの中で、「自分に近い年齢のイラストはどれですか?」という質問に対し、Bに答えが集中しました。

f:id:lica19:20160728102541p:plain

理由と聞くと「本当はCかもしれないけど、加齢を認めたくない。」「Cがあなたです。と言われたらショック」「現実はDかもしれないけど、気持ち的にはBでいたい!」という実年齢よりも少し若く見えるイラストのほうが良いという意見が多かったです。

これは以前、50代男性向けの健康サービス開発時にも同じようなことがあったことを思い出しました。ストックフォトサイトで「50代、男性」で検索して出てきた画像をユーザーイメージとして提案したら、ちょうどユーザーと同じ年齢層の担当者から「この写真の人は、ちょっと老け過ぎじゃないか?もう少し若い人がいいな。」と言われたことがありました。イラストでも写真でも、実際よりすこし若く見えるほうが感情移入しやすい傾向があるようです。

3.キャラクターの表情について

最後に表情について質問しました。更年期診断は、性質上しかたないのですが体の不調に関してなどマイナスな質問が多くあります。それらの質問の挿絵として、このイラストを見てどう感じるか答えてもらいました。

f:id:lica19:20160728102532p:plain

結果は「この人は本当につらそうな表情で、私も気分が落ち込んでしまいそう」「表情が暗すぎるのでは?」という意見で、私自身は「ちょっと疲れたなぁ」というイメージでこのイラストを選んでいましたので、実際のユーザーが予想以上にマイナスイメージを受けていることに驚きました。 みなさんはどう感じるでしょうか?

ユーザーの声をデザインに反映する

今回ユーザーインタビューをしてみて、私達が思っている以上に更年期症状というのはつらく、不安な状態であるということが伝わってきました。その心理状況はイラストの見え方にも影響しており、表情やリアルさによっては、この診断を利用することでさらに気分が落ち込んでしまう可能性もあることがわかりました。

それらを踏まえ、更年期診断のイラストはなるべくユーザーが暗い気持ちにならないように、以下の様なデフォルメされ年齢がわかりにくく、色味が綺麗なものに決まりました。

f:id:lica19:20160728102534p:plain

診断全体のデザインも、クリーム、ピンク、グリーンなどを使い、フレームの角は丸みを持たせるなど優しい雰囲気に仕上げました。

f:id:lica19:20160728102530p:plain

思い込みをすてて、よりユーザーの気持ちに近づくために

サービスを作る際はユーザーの年齢や利用する環境などから、文字のサイズやボタンの位置など最適なUIを考えるのはもちろんですが、どのような心理状態で使っているのかというのも重要なポイントだと思います。

今回は「ユーザーの気持ちが落ち込まないように」という点に特に注意して制作を進めました。しかし、いくら開発者の中で想定で話し合いをしても、実際のユーザーの声を聞くまで気づけないこともあります。

まずは、小規模に身近な人へのインタビューから始めても良いかもしれません。

今回紹介した更年期診断はこちら

デザイナー募集中です!

webpackを使った Rails上でのReact開発

はじめに

こんにちは、投稿開発部エンジニアの芳賀です。

既存のRailsプロジェクトの中でReact.jsを利用する機会があったので、その時にやったことについてまとめてみます。

私自身は普段RailsのサーバサイドとCoffeeScriptが中心で、最近のJavaScript開発環境についてあまりキャッチアップできていなかったのですが、それらの状況を把握しつつ試行錯誤で開発していった経験から、できるだけ「React採用してみたいけどJavaScript界隈よくわからない目線」で書いてみようと思います。

RailsでReact.jsを使ういくつかの方法

2016年時点で、RailsでReact.jsを使う方法はいくつかあって、どれを採用するかで悩みました。

  1. vendor/assets/javascripts にreact.jsを置いて利用する
  2. react-rails gem を利用する
  3. browserify-rails で npm管理して利用する
  4. railsプロジェクト内に、JavaScript開発用のディレクトリを用意して webpack + babel-loader で利用する

調査したところ、だいたいこんなパターンがあると思っていて、下に行くほどRailsよりもJavaScript開発の知識が必要になってくるイメージでした。

最終的にはwebpackを選択したのですが、それぞれ軽く振れておくと

vendor/assets にライブラリを置く

Railsで外部JSファイルを利用する場合、vendor/assets にダウンロードしたファイルを置いて Sprocketsのマニフェストファイルで読み込んで利用するのが1番手軽だと思います。

手軽だとは思いますが、Reactを使いはじめると他のnpmモジュールもどんどん使いたくなってきて、それらを全部 vendor/assets に入れて sprockets で読み込み順を考えながら開発していくのは、ごく簡単なReactアプリケーションでもすぐ辛くなる印象でした。もっと良い環境を作った方が最終的に楽になると思います。

react-rails

https://github.com/reactjs/react-rails

その名の通り、RailsでReactを利用するためのGemです。 Bundlerで react-rails をインストールするだけで、すぐ利用できるようなお膳立てをしてくれます。

React.jsのファイルが同梱されているのはもちろん、Rubyで設定を書けたり、Reactコンポーネントのレンダリングヘルパーが用意されていたり、coffeescriptでもes2015でもJSXでも書けるなど、JavaScriptよりもRailsやRubyに慣れている場合、かなりとっつきやすいです。

React以外のnpmライブラリは自分でなんとかする必要があります。

browserify-rails

https://github.com/browserify-rails/browserify-rails

React用というわけではありませんが、browserifyというJSビルドツールをRailsのSprocketsで利用できる browserify-rails は、JSモジュールをnpmで管理できて、baberifyを通せば、es2015やJSXの変換もできます。

react-railsのヘルパー関連が必要なければ、browserify-rails のnpmで管理したreactを利用するのも手だと思います。

ただ、開発時のビルドが結構遅くて辛くなってきたのと、既存プロジェクト固有のコードと相性がよくなかったため採用は見合わせました。

browserify-railsに関しては、弊社外村の http://techlife.cookpad.com/entry/2015/12/14/130041 の記事が詳しいです。

webpack

http://webpack.github.io

webpackは依存関係のある分割されたJSやクライアントサイドのアセット群を、いい感じにまとめてくれるビルドツールです。

webpackにはLoaderという仕組みがあり、ソースコードに適用する処理を柔軟に設定できるのですが、babel-loaderを使うことでes2015やJSXで記述したJSファイルを変換することができます。

Reactに関わるモジュールバンドリング(複数ファイルの結合)、ソースコードの変換、ビルドしたコードの配置まではwebpackで行い、ファイルへのフィンガープリント付与などはこれまで通りSprocketsに任せます。

このやり方の場合、Rails開発者がある程度webpack環境について理解する必要があり、若干コストが高いような気もするのですが、今回JavaScriptのコードを触る人間が限られていたのと、JSを触らない開発者はある程度気にしないでもRailsの開発はできるような状態にしておきました。

また、私自身がReact、es2015などをはじめて使ったこともあり、問題があった時に切り分けが簡単であることが重要だったのと、開発中のビルドが速いということが決め手となり採用しました。

webpack利用時の構成

ディレクトリの構成は、以下のような感じで プロジェクトルートの client が webpack環境となっています。

├── Gemfile
├── Gemfile.lock
├── README.md
├── Rakefile
├── app
├── bin
├── client
├── config
├── config.ru
├── db
├── lib
├── log
├── public
├── test
├── tmp
└── vendor

webpack環境のディレクトリは

client
├── src
├── node_modules
├── package.json
└── webpack.config.js

このような構成になります。

client の 構成は一般的なwebpackによるreact開発とほとんど変わらないのですが、 ビルド時にファイルを配置する場所に ../app/assets/javascripts/webpack を指定しています。

client/node_modules../app/assets/javascripts/webpack はバージョン管理対象外としたいので .gitignore に追加しておきます。

# .gitignore
/client/node_modules
/app/assets/javascripts/webpack

webpack + babelの設定

webpack環境の準備をします。 必要な作業は以下の様な感じです。

  1. package.json を作り、npmでライブラリをインストールする
  2. webpack.config.js でビルド設定を書く
  3. foreman で webpack buildプロセスを起動する

1. package.json を作り、npmでライブラリをインストールする

client ディレクトリで

$ npm init -y

を実行して、package.json を生成します。公開することはないので「private」にしておきます。

{
  "private": true,
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  }
}

次に webpack と babel関連のライブラリをインストールします。 npm install -D は 開発時にのみ必要なライブラリをインストールしつつ、packpage.jsonに依存関係を記述してくれるオプションです。

$ npm install -D webpack babel-loader babel-preset-es2015 babel-preset-react

「babel-xxxxxx」が多くて混乱するのですが、 babel-loader はwebpackからbabelを使ってトランスパイルするためのパッケージ。 babel-preset-xxxxx は、es2015やJSXを変換するためのプリセットがbabel本体と分離しているので 個別にインストールする必要があります。

なんとなくBabelをインストールすればいい感じに全部やってくれるんでしょ?と思っていたのですがそうではありませんでした。

そして、いよいよ react をインストールします。 -S オプションは、アプリケーションに必要なライブラリを、packpage.jsonに追加しつつインストールをします。

$ npm install -S react react-dom

2. webpack.config.js でビルド設定を書く

次に webpackのビルド設定を書いていきます。 ここでは最小限やりたいことの

  • ソースコードのエントリファイルを指定する
  • 出力先のルールを設定する
  • 出力する際に、Babelによるトランスパイルを設定する

を、記述していきます

// webpack.config.js
module.exports = {
  entry: {
    app: './src/index.js',
  },

  output: {
    path: '../app/assets/javascripts/webpack',
    filename: '[name].js',
  },

  module: {
    loaders: [
      { test: /\.(js|jsx)$/,
        loader: "babel",
        exclude: /node_modules/,
        query: {
          presets: ["es2015", "react"],
        }
      },
    ]
  },
}

これで client/src/index.js がある状態で

$ ./node_modules/.bin/webpack -w

を実行すれば、ファイルの変更を監視して Railsの app/assets/javascripts/webpack/app.js にビルド結果が配置されるようになります。

さらに packpage.jsonに npm scripts に開発ビルドと本番ビルドのコマンドを用意しておくと、foremanやcapistranoから実行するときに便利です。

{
  "private": true,
  "scripts": {
    "webpack-watch": "webpack -w",
    "webpack-build": "webpack -p"
  },
  "devDependencies": {
    "babel-loader": "^6.2.4",
    "babel-preset-es2015": "^6.9.0",
    "babel-preset-react": "^6.11.1",
    "webpack": "^1.13.1"
  },
  "dependencies": {
    "react": "^15.2.1",
    "react-dom": "^15.2.1"
  }
}

3. foreman で webpack buildプロセスを起動する

このままでは、Rails開発者もわざわざJSビルド用の別プロセスを起動しておかなければならないので foreman start で railsとwebpackのプロセスを起動するようにします。

# Procfile
rails: bundle exec rails server
webpack: npm --prefix client run webpack-watch

その他

今回は最低限の設定のみふれましたが、webpackの設定で アプリケーションコードと react などのベンダーコードを分けて あまり変更のないベンダーライブラリをキャッシュしやすくしたり

複数のアプリケーションコードに分割しておくことができます。

https://webpack.github.io/docs/code-splitting.html#split-app-and-vendor-code https://webpack.github.io/docs/code-splitting.html#multiple-entry-chunks

最後に

今回は RailsでReactを利用する際に、react-railsやbrowserify-railsを利用しないアプローチについて書いてみました。 誤解のないようにお伝えしておくと、弊社のすべてのプロジェクトでこのアプローチを採用しているわけではなく、 react-railsやbrowserify-railsを使っているプロジェクトもあります。

各々のチームにあった方法を検討する参考になれば幸いです。

クックパッドでは エンジニアを積極採用中です。 https://recruit.cookpad.com/

今回のサンプルをこちらにおいておきます https://github.com/func09/react-on-rails-sample