PC版トップページリニューアルの狙いと成果

メディア事業部の須藤です。 8/26より、PC版クックパッドのトップページをリニューアルしました。 公開から約3週間が経過しましたが、お試し頂けましたでしょうか?

この記事では、今回のリニューアルを通して解決したかった課題や、新しいチャレンジ、 また、それらを具現化する過程で考えた事を、実際の結果と合わせて書いてみたいと思います。

f:id:sudokohey:20140911170823p:plain

今回のリニューアルで伝えたかったこと

今回のリニューアルで強く意識したのは、「食にまつわる全般を扱うポータルサイト」として、 クックパッドを再認識して頂けるトップページにすることでした。

クックパッドでは2年程前より、従来のレシピサービスとは別の価値を提供する、新規事業・サービスの開発に注力してきました。
例えば、ECサービスである「産地直送便」や、近所のスーパーの特売品が分かる「特売情報」、クックパッド認定の料理教室を展開する「料理教室」などがあり、 それぞれのサービスは幾度かの方向転換をしつつも着実に利用者を増やし日々拡大しています。

もちろんレシピサービスは核となるサービスであり、クックパッドの利用目的の大半は「レシピを探す」という行為であることに変わりはありませんが、 サービスの提供側としては「今日食べるものが決まる」という従来の体験を損なう事無く、新しいサービスの存在や魅力にも気付いて貰いたいという思いがあります。

前バージョンのトップページは、約1年前という過渡的な時期にリニューアルされたため、 まだまだレシピサービスの比重が高い構成となっており、全体としてどうしてもレシピサービス+αといった印象を受けてしまうという課題がありました。 今回のリニューアルでは、その両者のバランスを見直し、最適な構成を検討することで、 食や料理といった特定の領域に特化しつつも、バラエティに富んだサービスを展開している、そういうサイトであることが伝わるトップページを目指しました。

具体的な改善点と結果

上記のようなコンセプトを掲げて取り組んだリニューアルですが、もちろん実際の数字を伴わなければ意味がありません。

まず最初に全体的な結果なのですが、基本的な指標として見ていた、PV、ページ全体のクリック数、離脱率、平均滞在時間については、 横ばいでほぼ変化がありませんでした。ここでまず一安心です。

f:id:sudokohey:20140911171012p:plain

というのも、今回かなり厳し目にコンテンツの整理を行い、ページ内に配置されたリンクの数は前バージョンの約60%程度に、サイトの縦幅も約1000px縮めていた為、 かなりクリック数(サイト内コンテンツへの送客数)が落ち込むことを懸念していたからです。

f:id:sudokohey:20140911171056p:plain

にも関わらず数字をキープできたのは、次に挙げる個別の施策の成果だと考えています。

サービス一覧の新設

前バージョンとの大きな違いの一つとして、提供するサービスの一覧を左上に新設しました。

f:id:sudokohey:20140911171314p:plain

ポータルサイトの構成としては王道といった感じではありますが、サイトの提供する価値を簡潔に説明する上では最も分かり易く、 食や生活に関する様々なサービスを提供していることが、初見の訪問であっても端的に理解出来ると思います。

サービス一覧を設置した影響を数字で見てみると、まず、列記した各サービスのトップページのPVが、約2倍〜5倍程度に上昇しました。(下のグラフはクックパッドニュースの例)

f:id:sudokohey:20140911171350p:plain

公開直後は目新しさでクリックされるものの、日を追う毎に減少するようであれば見直しが必要と考えていましたが、 現在も安定したクリック数が出ているので、自分が良く利用するサービスへの常設の導線として認知して頂けたようです。

プレミアムサービスについても、リンク先のPVが概ね30%〜180%増という結果になりました。 実は、プレミアムサービスというものの存在自体を知らない、あるいは、人気順で検索できること以外はよくわからないといった声が意外にも多く、かねてから課題として挙っていました。
今回、「サービス一覧」という枠内で、広告的にならずにラインナップを自然な形で訴求できるようになったことで、今後その辺りの変化も出てくるのではと考えています。

ちなみに、使い勝手やレシピを探すという基本的な文脈を考慮した上で並び順を決めていますが、 上から順にクリックが多い訳ではなく、基本サービスとしては「ダイエット」が、プレミアムサービスとしては「レシピランキング」がそれぞれ全体の3位、4位に位置しています。(1位、2位は言うまでもなくレシピと献立です。) この辺りは利用実態に合わせて随時見直して行きたいと思います。

目的に応じたコンテンツの整理

前バージョンのトップページでは、ファーストビュー以下、サービス毎に独立した枠を設け積み上げていく構成をとっていました。 枠の掲出順は、利用者数に応じて随時見直しをかけていたものの、「健康レシピ」と「ダイエット」という近しい領域のコンテンツの間に「宅配サービス」の紹介が入ることがあるなど、使い勝手を考えると不自然であったり、 特定のフォーマットを定めずに自由にサムネイルやリンクを設置していた為、運用を重ねるに連れ煩雑になり、統一感が失われるといった課題がありました。

f:id:sudokohey:20140911171425p:plain

新しいトップページでは、これらを「節約・買い物」「健康・ダイエット」といった関心・目的別に大きく分類し、その枠内で該当するサービスを紹介するようにしました。
また、各枠の面積やフォーマットもできるだけコンパクトに統一することで、それぞれがクックパッド全体を構成するいちサービスとしてフラットな印象になるように心がけました。

コンテンツリンクを大量に置き、「ユーザーの選択肢」を増やすことは、基本的には離脱率を下げる効果もありますが、 今後は「なんでも良いからまんべんなくトラフィックを全体に撒く」のではなく、「良い物をより強く」という編成方針と合わせて、訪問あたりのユーザーの満足度の向上に繋げたいという考えがその背景にあります。

ただ、こちらの数字の方はある意味予想通り、プレミアム献立(管理栄養士が選んだ献立)のクリックが2倍になったという例外を除いては、ほぼ全ての枠でクリックが減少する結果となりました。 とは言え、前述の通り、全体のクリック数は下げず、各サービストップへの誘導も上昇しているので、トータルでは上手くバランスできていますし、 各サービス内の具体的なコンテンツページよりも、トップページやカテゴリページといったハブとなるページの方が離脱率が低い為、その分回遊が期待できることもあり、長期的に見た場合には各サービスにとってプラスの結果にできるのではと考えています。

数字が挙った例としては、レシピカテゴリの一覧部分で、僅かですがプラスの成果が出ていました。 前バージョンではリスト状のUIで掲出していたのですが、今回はフラットに大きな面積を割いて並べる形をとりました。

f:id:sudokohey:20140911171443p:plain

数字が上がった要因としては、マウスオーバーするまで隠れていたサブカテゴリを露出させた事が大きく、サブカテゴリ全体のクリック数が20%増となりました。

f:id:sudokohey:20140911171544p:plain

メインカテゴリについても(実は掲出するカテゴリ数自体が2つ減っているのですが)10%ほど増加、また、配下のカテゴリ一覧ページのPVも20%程増加する結果となり、 上手くコンテンツを整理しつつも数字を上昇させられた好例となりました。

動画を利用した新しいチャレンジ

既存の改善のみならず、新しいチャレンジとして、ピックアップレシピを動画化しています。

f:id:sudokohey:20140911171455p:plain

実際にユーザーとして利用してみても、動画の分かり易さは想像を上回るものがあり、文字情報としてのレシピからは伝わりづらい、ちょっとしたコツやテクニックも分かるなど、より多くの方に深くレシピを楽しんでいただけるようになったと考えています。

動画に関してはまだまだ実験段階といった側面もありますが、一旦、動画を最後まで再生する割合を一つの指標として評価しています。 現時点では、クリックして再生開始を基本とし、一部のユーザーを対象に自動再生をテストしており、クリックして再生した場合は30%弱のユーザーが、自動再生した場合は約6%のユーザーが最後まで視聴を完了しているようです。

まとめ

以上搔い摘んでのリニューアル結果報告となりましたが、わずかでも同様の取り組みを行う方への参考になれば幸いです。

ちなみに、クックパッドではここ数年、およそ10ヶ月〜12ヶ月に一度のスパンでトップページのリニューアルをかけています(PCサイトの場合)。 ただ、最近はスタッフの数も増え、展開するサービスも増えている事もあり、もっと短いサイクルで見直しをかけたいと思っているのですが、 開発者やデザイナーのリソースが圧倒的に不足しており、絶賛大募集中です。

もしこの記事を読んで興味をもって頂けた方がいらっしゃいましたら、ご応募お待ちしております!

Android Studioに追加されたGoogle App Engineテンプレートを試そう 導入編

モバイルファースト室の@sys1yagiです。

Android Studio使ってますか?

Google I/O 2014の直前に3つのGoogle App EngineテンプレートがAndroid Studioに追加されました。追加されたテンプレートのうちのApp Engine Java Endpoints Moduleを用いたGoogle Cloud Endpointsの作成と利用について解説します。

MBaaSとCloud Endpoints

Google Cloud EndpointsはGoogleが提供するGoogle Cloud Platformの機能の一つで、Google App Engineを使ってAPIのエンドポイントを定義する仕組みを提供します。

一般的なMBaaSではMBaaSが用意したクライアントライブラリを使ってバックエンドにアクセスします。アプリケーション開発者はスキーマレスなデータストアに対してアプリケーションのモデルを定義したり、クライアントライブラリをラップする構造を構築するといった「MBaaSの提供する機能とアプリケーションを接続する部分の設計」に集中する事になります。

f:id:sys1yagi:20140911152655p:plain

一方Cloud Endpointsはより抽象的なレイヤを設計する仕組みを提供します。一言で表すと「MBaaSを構築する為のPaaS」という言い方になるでしょうか。Javaで宣言的にエンドポイントを記述すると、アプリケーション用のRESTfulなJSON APIのセットが出来上がります。エンドポイントの定義を元に生成されるクライアントライブラリにはエンドポイントへのアクセス用メソッドと、エンドポイントでやりとりするモデルが含まれており、アプリケーションとバックエンドが接続する部分をストレスなく開発できます。

f:id:sys1yagi:20140911152704p:plain

ただし、Cloud Endpointsそのものはデータストアや認証、Push等の機能は備えていません。Google App EngineやGoogle Cloud Messaging等の機能を用いて自ら構築する事になります。Cloud Endpointsを利用してMBaaSの機能を実装している例としてMobile Backend Starterがあり、ソースコードが公開されているので参考にしたり、カスタマイズして利用するといった事もできます。

Android StudioとGoogle App Engineテンプレートでできる事

Android StudioでのGoogle App EngineおよびCloud Endpointsのサポートは初期からありました(Adding a Backend to Your App In Android Studio)。しかしセットアップが煩雑で、元々Google App EngineやCloud Endpointsを使っているケースでなければ利用するモチベーションが上がらないような状況でした。しかし各種テンプレートが追加された事によって、Google App EngineやCloud Endpointsの利用のハードルが下がり、カジュアルに試せる環境が整いました。

Android Studioとテンプレートの利用によって以下の事が出来ます。

  • テンプレートを使ってGoogle App Engine用のモジュールをプロジェクトに追加する
  • Google App Engine, Cloud Endpoints等の機能実装
  • ローカルでAPIサーバを起動し、動作テストする
  • Google App Engineにデプロイする

早速試してみましょう。

セットアップ

※本エントリはAndroid Studio 0.8.9を使用して書いています

Cloud Endpointsのテンプレートは、Androidプロジェクトに対してモジュールを追加する形でセットアップします。ですので予めAndroidアプリケーションのプロジェクトを作成しておく必要があります。本エントリでは「HelloCloudEndpoints/app」というAndroidアプリケーションのモジュールを作成したものとして進めます。

Androidアプリケーションのプロジェクトを開いた状態で[File]-[New Module]を選択します。

f:id:sys1yagi:20140911152727p:plain

"App Engine Java Endpoints Module"を選択し、モジュール名を入力します。

f:id:sys1yagi:20140911152727p:plain

するとプロジェクト内にモジュールが生成されます。生成される内容はGoogle App Engineのプロジェクトで、最低限のモデルとエンドポイントの実装が含まれています。

f:id:sys1yagi:20140911152816p:plain

この時アプリケーション側のbuild.gradleやAndroidManifest.xmlが以下の様に更新されます。

  • settings.gradleに':api'が追加される(入力したモジュール名によって異なります)
include ':app', ':api'
  • build.gradleのdependenciesにCloud Endpointsのクライアントライブラリが追加される
compile project(path: ':api', configuration: 'android-endpoints')
  • AndroidManifest.xmlにINTERNETパーミッションが追加される
<uses-permission android:name="android.permission.INTERNET" />

これにより特にアプリケーション側で設定を追加しなくてもCloud Endpointsのクライアントライブラリを利用出来るようになります。

バックエンドを動かす

まずは生成されたバックエンドを動かしてみましょう。最終的にはGoogle Developers Consoleでバックエンドのアプリケーションを登録してデプロイする形になりますが、開発中はローカルでサーバを立ち上げて動作確認ができます。

ツールバーのRun Configurationに、Cloud Endpointsの構成が追加されているのでワンタッチで起動できます。

f:id:sys1yagi:20140911152827p:plain

実行するとエンドポイントがコンパイルされ、localhost:8080でサーバが立ち上がります。開いてみると以下の様なデモ画面が現れます。この画面ではCloud Endpointsで生成したjavascriptのクライアントを使って、テンプレート生成時に定義されたエンドポイントへのアクセスを試せます。

f:id:sys1yagi:20140911152834p:plain

フォームに値を入力して送信するとエンドポイントから値が返り、画面に表示されます。

f:id:sys1yagi:20140911152844p:plain

実装を読む

では実装がどのようになっているか見てみましょう。予め生成されるクラスはMyEndpointMyBeanの2つです。

MyEndpointはエンドポイントを定義するクラスです。エンドポイントはアノテーションを使って宣言します(アノテーションの詳細は→Endpoint Annotations)。クラス宣言の上部で@ApiアノテーションによってAPI名やバージョン、namespaceを宣言しています。このクラスの中に@ApiMethodアノテーションを使ってエンドポイントの宣言を追加していきます。@ApiMethodのname属性にエンドポイント名を定義し、メソッドの引数、戻り値によってそのエンドポイントのパラメータとレスポンスを定義します。

MyEndpoint.java

package com.sys1yagi.hellocloudendpoints.api;

import com.google.api.server.spi.config.Api;
import com.google.api.server.spi.config.ApiMethod;
import com.google.api.server.spi.config.ApiNamespace;

import javax.inject.Named;

/** An endpoint class we are exposing */
@Api(name = "myApi", version = "v1", namespace = @ApiNamespace(ownerDomain = "api.hellocloudendpoints.sys1yagi.com", ownerName = "api.hellocloudendpoints.sys1yagi.com", packagePath=""))
public class MyEndpoint {

    /** A simple endpoint method that takes a name and says Hi back */
    @ApiMethod(name = "sayHi")
    public MyBean sayHi(@Named("name") String name) {
        MyBean response = new MyBean();
        response.setData("Hi, " + name);

        return response;
    }

}

MyBeanクラスはひとつのStringを持つシンプルなモデルです。MyEndpointのsayHiメソッドの戻り値に使われています。

MyBean.java

package com.sys1yagi.hellocloudendpoints.api;

/** The object model for the data we are sending through endpoints */
public class MyBean {

    private String myData;

    public String getData() {
        return myData;
    }

    public void setData(String data) {
        myData = data;
    }
}

ここでエンドポイントsayHiの実際のレスポンスを見てみましょう。以下のリクエストを行うと、

http://localhost:8080/_ah/api/myApi/v1/sayHi/Cookpad

以下の様なレスポンスが返ります。MyBeanクラスが自動的にJSONに展開されている事がわかります。

{
  "data" : "Hi, Cookpad"
}

詳細は省きますが、Cloud Endpoints用のコードをコンパイルする際、エンドポイントに関わるクラスを解析しGoogle APIs Discovery Serviceに従ったdiscoveryファイルを生成します。discoveryファイルにはエンドポイントの仕様やレスポンスの定義がされており、この定義に従ってサーバを構成します。またこのdiscoveryファイルを使ってクライアントライブラリの生成なども行っています。エンドポイントが返すJSONもこのdiscoveryファイルによって生成します。

アプリケーションでAPIを利用する

次にCloud Endpointsが生成したクライアントライブラリを使ってAPIにアクセスしてみましょう。アプリケーション側で用意するものは特にありません。最初にテンプレートを追加した時点でdependenciesにクライアントライブラリの定義が追加されているからです。

クライアントライブラリのパッケージ名はエンドポイントの@Apiアノテーションに指定したnameとnamespaceに従います。ですので今回は「com.sys1yagi.hellocloudendpoints.api.myApi.MyApi」がエンドポイント用のクライアントとなります。

初期化

クライアントはBuilderを使って作成します。BuilderのコンストラクタにはHttp通信をハンドリングするHttpTransport、JSONをパースするJsonFactory, Httpリクエストを初期化するHttpRequestInitializerを渡します。特殊な事をするのでなければクライアントライブラリに含まれているデフォルトのクラス群を利用すれば問題ありません。

private MyApi getApiClient() {
  return new MyApi.Builder(AndroidHttp.newCompatibleTransport(),
      new AndroidJsonFactory(), null)
      //for genymotion.
      //if you use android emulator, you should replace to "10.0.2.2".
      .setRootUrl("http://10.0.3.2:8080/_ah/api/")
      .build();
}

Builderクラスでは各種クライアントの設定ができます。上記の例では、ローカルサーバに対してエミュレータ(Genymotion)で接続するためにsetRootUrl(String)でURLを指定しています。

実行

MyApiクラスには各種エンドポイントへアクセスする為のメソッドが実装されています。以下の様にエンドポイント名と一致するメソッドに引数を渡し、execute()を実行するとエンドポイント側で定義した戻り値と同じモデルを受け取れます(実際は異なるクラスです)。

MyBean response = myApi.sayHi("Cookpad").execute();

execute()はブロッキングされるので、実際に利用する際はAsyncTaskなどを使う事になります。

class SayHiAsyncTask extends AsyncTask<String, Void, String> {

  @Override
  protected String doInBackground(String... params) {
    try {
      MyBean response = getApiClient().sayHi(params[0]).execute();
      return response.getData();
    } catch (IOException e) {
      return e.getMessage();
    }
  }
}

実行するスレッドを意識しなければなりませんが、通信にまつわる部分を意識しなくてもAPIを簡単に利用できます。

new SayHiAsyncTask() {
  @Override
  protected void onPostExecute(String s) {
    textView.setText(s);
  }
}.execute("Cookpad");

f:id:sys1yagi:20140911152904p:plain

次回

如何でしょうか。Cloud Endpointsのテンプレートを使う事で簡単にAndroidプロジェクトにバックエンドの実装を追加できる事がわかりました。バックエンドでモデルを定義すると、通信処理やJSONのフォーマット等について意識する事なくクライアント側でデータを受け取れるようになります。バックエンドが決まっていなかったり、インタフェースが決まっていない状態でのプロトタイピングに使えそうです。もちろんバックエンドはGoogle App Engineですので、しっかり作りこんで本番で運用する事もできます。

今回作成したプロジェクトのソースはコチラで公開しています->HelloCloudEndpoints

次回はTodoアプリの作成を通して、Objectifyを使ったモデルの定義とデータストア操作、APIの作成、デプロイまでを解説したいと思います。

参考