Mirrativ tech blog

株式会社ミラティブの開発者(サーバサイドエンジニア,iOSエンジニア,Androidエンジニア,機械学習エンジニア,インフラエンジニア, etc...)によるブログです

【保存版】スタートアップがユーザビリティテストを3日ですべて終わらす方法

こんにちは、分析チームの坂本です。 テックブログ3回めの登場です。

ミラティブの分析チームは、もちろんBigQueryや機械学習を用いた定量的なデータ分析も行いますが、ユーザーを理解するための定性分析も行う「分析チーム」であることを掲げています。

※最近では、データアナリストとUXリサーチャーの境界が溶けつつあるという議論があると思いますが、弊社もその流れを採用しています。

突然ですが、ユーザビリティテスト = お金と時間がかかる という認識の方もいらっしゃると思います。 ミラティブでは、ユーザビリティテストをやろう!と言ってから3日間&謝礼実費のみでユーザビリティテストが完了しました(被験者3名)。 どんなことをやったのかという内容を書きながら、ハマりどころををシェアしようと思います。

ユーザビリティテストの一般論

まずは、ユーザビリティテストってなんやねんという話を書いて行きます。といいつつ、ここは巨人の肩に立たせていただきます(笑)。

ユーザビリティテストとはなんなのか?だったり、なんの目的で実施するのかなどは、グッドパッチさんの下記のブログが詳しいので、ぜひ読んでみてください。

goodpatch.com

ミラティブでは、ユーザビリティテストを実施する前に、ミラティブで言うとどういうことなの?的な記事をコンフルにしたためました。

f:id:sakamoto10423:20190714183346p:plain
社内に投稿したユーザビリティテストの記事

ミラティブでユーザビリティテストが必要だった背景

ユーザビリティテストってどれくらいの頻度で実施したら良いのか?という質問がよくあります。理想的には週一くらいのスパンで定期的にやるのが良いと思います。

しかし、スタートアップにはそんな時間も余裕もないわけです。オススメとしては、

  • 大きなリニューアル前に改善の方向性を確かめるために実施
  • 大きなリニューアルのプロトができたときに、プロトタイプで実施

です。反対に、小さな変更であれば、ABテストやデータ分析で検証することが望ましいと考えています。大きな変更は、画面の構造や印象が大きく変わると同時に、コードの変更も大きく入ります。なので、小さく失敗するためにユーザビリティテストを行うのがおすすめです。大きくリリースして、「やっぱり仮説が間違っていた」となると、相当のコードが無駄になります。

Mirrativ は、直近1年間で様々な機能追加をしてきました。エモモ・ガチャ・ギフト・コイン・オーブ・ジェスチャーなどなど、は直近1年間で追加された機能です。それらがスモールテストとともに導入されたこともあり、UI/UX上わかりづらいところが散見されるようになってきました。

f:id:sakamoto10423:20190714200502p:plain
UI/UX上わかりづらいメニューの例

たとえば、上記であればヘッダメニューの中に

  • 配信一覧のフィルタを変更する、タブ切り替え
  • 自身のエモモ(アバター)を切り替える

という機能が混在しています。 現在ミラティブでは、このような使いづらい箇所を大きく手直しするプロジェクトが始まっています。そのインプットの一環として、ユーザビリティテストを行ったというのが背景です。

事前準備のTips

ここからがこのブログの本編パートになります。もっといいやり方あるよーってあれば、ぜひTwitterやはてブなどでコメントいただけると嬉しいです。

中継用のカメラはMacのカメラで十分

まず、ユーザビリティテストでほぼ必須なのが中継用のカメラです。被験者の手元を写しながら、その映像を別室に中継するためです。

PCサービスの場合は、テレビ会議システムの画面共有機能で十分だと思います。しかし、Mirrativ はモバイルアプリなので、被験者の手の動きを撮影することが必須です。そのため、何かしらの撮影機材が必要でした。

f:id:sakamoto10423:20190722111801p:plain
Macのカメラでユーザビリティテストを行う

いろいろと試した結果、上記のようにMacを後ろから抱きかかえるようなスタイルで撮影したところ、うまく撮ることができました。その映像をテレビに映したものを写真に撮ったものが下記です。もろもろ経由しているので、下記の写真の解像度はそんなに高くないのですが、テストを行うのに必要十分な画質でした。

f:id:sakamoto10423:20190721130748p:plain
Macで動画撮影した映像をテレビに映す様子

カメラのセッティング時に注意すること

カメラが安価で済んだぞ!と意気揚々としていたのですが、実際のテストを行ったときにちょっとしたトラブルがありました。それは、「部屋の調光によっては、蛍光灯の光が画面に反射してしまう」ということです。

f:id:sakamoto10423:20190717014737p:plain
蛍光灯が反射してしまう

我々は最近、自然光あふれる目黒のオフィスに引っ越しを行いましたが、ユーザビリティテストを行ったのは渋谷の旧オフィスの窓がない会議室でした。そのため、蛍光灯の明かりがばっちりスマートフォンに映ってしまいました。我々は一度、被験者さんに承諾をとった上で、(電気を消して)真っ暗な部屋で実施していただきました。

今後の学びとして、蛍光灯にカバーがついている部屋でテストを実施する・自然光が入ってくる部屋で実施するなどの工夫が必要だと感じました。

配信はGoogleHangoutがよかった

では、次はその映像を中継する方法です。Macのカメラで撮影しているので、ビデオ会議システムに通すと楽ですね。そこで下記の条件を満たすビデオ会議システムを探しました。

  • Macのカメラから受けた映像を共有(配信)することができる
  • できれば高画質
  • 40分以上共有(配信)を行うことができる
  • 録画をすることができる
  • 追加料金なし

zoomなどのオンラインミーティングなどをいろいろと検討しましたが、最終的にはGoogleHangout(Google Meet)を選択しました。ただ、Google Meetで録画をするには、G Suite Enterprise (1ユーザー3,000円/月) のプランの契約が必要だったので、Google Meetで録画することは諦めました。

ちなみに今回は、Google Meetで共有した映像をQuickTimeで画面録画するという手法を行ってみましたが、1ファイルが20GBくらいになり、あとあと管理に困りました。これは要改善ポイントです。

被験者の集め方

では、被験者はどうやって集めるのが早いでしょうか?民間のリサーチ会社さんにお願いすると、やはり(やり取りも含めて)1週間程度かかります。そこで、ミラティブでは社員の友人の方に協力いただくことにしました。

そこで、「募集をするなら黄色に黒!」という定番をリスペクトさせていただき、募集画像をつくり社内のSlackに投下しました。するとその日中に目的にあった被験者の方を3名集めることが出来ました。

f:id:sakamoto10423:20190721132735p:plain
ユーザビリティテストの被験者を社内募集

ミラティブ社では、ユーザビリティテストを行うのがはじめて(少なくとも会社独立後ははじめて)だったので、ユーザビリティテストの意義や成果をメンバーが熟知している状態ではありませんでした。そのため、なるべくみなさまに協力いただけるように、目立つ方法で集客しました。

当日の事前注意 & アイスブレイクの工夫

さて、ここからは当日の話を書いていきます。

ユーザビリティテストは、被験者の方にプロダクトを操作していただくテストです。被験者の方は「自分がテストされている」気持ちになってしまうことがある、と事前に知っていたため、下記のようなスライドを用意し、ご自身のテストではないということをかなり強調しました。

f:id:sakamoto10423:20190721135228p:plain
ユーザビリティテストスライド:はじめに#1

f:id:sakamoto10423:20190721135331p:plain
ユーザビリティテストスライド:はじめに#2

また、アイスブレイクでは「普段どんなゲームをされていますか?」というMirrativ と関係ある内容でアイスブレイク出来たのはよかったです。※例えば、ウイルス対策ソフトなどのユーザビリティテストでは「ウイルス対策って普段されますか?」ってのは本題に近すぎて、アイスブレイクには使いづらい質問だと思います。そういうときは、「オフィスまで迷わずに来れました?」みたいなアイスブレイクが一般的なようです。

当日あたふたしたこと

当日のトラブルというか、あわわわってなったことをいくつか紹介します。Mirrativ ならではのこともありますが、「個々のアプリで考えることがある」という意味で共有しておきます。

配信をして頂く際、やめ時が難しい

f:id:sakamoto10423:20190721140811p:plain
ユーザビリティテストスライド:シナリオ#3

3つ目のタスクとして、上記のようなタスクを行ってもらいました。もう少し具体的に言うと、普段プレイしているゲームを配信してもらうというタスクです。

これはインタビュワーが「では終了してください」と声を掛けるタイミングが難しかったです。というのは、ゲームによっては途中で辞めるとスコアが下がったり、たまたまその時間にオンしているマルチフレンドと協力プレイが始まったり 、そもそもの1試合が長かったり。様々な理由で、ゲームのやめ時が読めません。

パズドラやバンドリ!などは比較的短いほうかなと思いますが、マルチ対戦TPSゲームや麻雀ゲームは1試合が30分程度かかってしまうので切り時が難しいなと思います。

ということで、次回はゲームをプレイされる前に、「今回はテストなので、10分程度で一区切りできるゲームを選択いただけませんか?」とアナウンスするのがよいかなと思いました。

想定外の箇所で詰みが発生する

事前の想定外のところで詰みが発生することがあり、インタビュワーが被験者さんにお声がけすることがありました。その一例を紹介します。

例えばiOSで配信する場合、Mirrativ のコメントや情報(「視聴者が来ました」や「ギフトをもらいました」)はPUSH通知を通じて配信者に知らされます。

f:id:sakamoto10423:20190721143948p:plain
配信者はPUSH通知でMirrativ のコメントなどを知る

ということは、PUSH通知を切っていると、視聴者さんが来たとか、視聴者さんがコメントしたことがゲーム中に全くわからないわけです。そのことにはじめて気づきました。なので、2人めの被験者以降は、配信を始める前にPUSH通知をONにしていただく設定をしていただくことにしました。

当日の様子

f:id:sakamoto10423:20190714182759j:plain
ユーザビリティテスト当日の様子

上記はユーザビリティテスト当日のエンジニアルームです。エンジニアルームにある大きなテレビに大きくテスト中の内容を映し、エンジニア・デザイナー・PM全員で注目して見ていました。やはり、自分たちが作成したプロダクトなので、注目度は高かったです。このように、エンジニアチームを巻き込んでテストを行うのが大切ですね。

得られた成果

3名で実施したユーザビリティテストの結果を資料にまとめました。一部公開しておきます。

f:id:sakamoto10423:20190721150119p:plain
得られた成果スライド

上のような資料にまとめるのも重要ですが、それ以上にエンジニアチーム全員がテストの内容を見ていたことのほうが成果としては大きかったかなと思います。やはり、百聞は一見に如かずですね。

さいごに

ミラティブでは分析チームを募集しています。BigQueryや機械学習を使った分析をすることもあれば、今回のような定性的な分析をしていることもあります!プロダクトに近い分析チームです!

◆アナリストポジション www.wantedly.com

◆分析基盤ポジション www.wantedly.com

業務内容が多岐にわたるので、定性分析やったことないわー、とかだったり、定量分析やったことないわーという方も全然OKです!気軽にポチッとエントリーください。

reviewdog x perlcritic x Jenkins で最高の GitHub レビューライフ

ミラティブのサーバーサイドエンジニア、ハトネコエです!

今日は、GitHub の自動レビューとして reviewdog を導入した話をします。

1. 動機

すでに CTO の夏さんによって、Perl 用の linter である perlcritic が導入されていました。
そして、テストが走る際に perlcritic のチェックもおこなわれ、
指摘箇所があればテストが落ちるようになっていました。

まずは緩めの設定で導入したけれど、perlcritic のチェックをもっと厳しくしたい!
だけど厳しくすると、すでに存在するコード(つまり、プルリクで変更していない部分)が原因で
テストが落ちるようになってしまいます。

残念ながら perlcritic には autofix の機能も無いようで、
設定を変更した後は、人力での修正が終わるまでテストは落ち続けてしまいます。

これでは開発に支障が出るので、
テストでのチェックはやめて、プルリクで変更した部分にだけ指摘がなされる手段が求められました。

2. Danger か reviewdog か

最初に話題に上がったのは Danger でした。

f:id:nekonenene:20190706005348p:plain
CTOの夏さんとの会話(in 私のtimes)

Danger は自動レビューの手段として良いツールです。

Android, iOS, Ruby, JavaScript といった Danger のプラグインが存在するコードベースであれば良い選択でしょう。
しかし今回は Perl。Danger のプラグインは存在しません。
作ってもいいですが、あまり時間をかけたくもありません。

そこで見つけたのが reviewdog です。

reviewdogによるGoのコードレビュー - DeNA Testing Blog

こちらのブログがきっかけになりました。ありがとうございます。

3. reviewdog を選んだ理由

3-1. 比較

両者を比べると以下の違いがありました。

reviewdog Danger
スター数 (2019/07/13) 979 3573
コミット頻度 高い 高い
言語 Go Ruby
コメント 修正すべき行にコメント まとまった1つのコメント
(or 修正すべき行にコメント*1
ドキュメント README.md で充分わかる 情報が散乱していて読みにくい

ドキュメントの読みやすさは主観ですが、
Danger のドキュメントの読みにくさは伝わる……はず……!

reviewdog の方がスター数は少ないですが、
それを補うほど優れた点が複数ありました。

3-2. reviewdog は Golang

まず Go 言語であることに惹かれました。
というのも、最近は bundle install 時に起こるエラーに辟易していて、
できれば Gemfile の管理はしたくないな……と思っていたためです。
bundler のバージョンが v2 になってから、まだ落ち着いていないようにも思えますし。

Go はもう少し単純で、かつ v1.13 でよりモジュール管理が簡潔になる予定です
その上、シングルバイナリでアプリケーションを配布することが可能です。

reviewdog もバイナリを配布していますので、
使用者は Go のインストールをすることなく reviewdog を扱えます。

Danger の場合は ruby(&たいていは rbenv)のインストールが必要になりますが、それらが不要なわけです!
reviewdog のバイナリファイルをダウンロードしてくるだけでいいので、
Docker や Jenkins での実行準備がとても簡単におこなえます。

3-3. reviewdog の errorformat が最高!

もし Danger のプラグインを書くとするなら、GitHub コメントを作成するために、
以下のようにいい感じに lint エラーを整形してあげる必要があります。
https://github.com/loadsmart/danger-android_lint/blob/0.0.7/lib/android_lint/plugin.rb#L134-L157
これはなかなかに面倒です。

一方、reviewdog の場合、
errorformat が内蔵されていることにより、
lint エラーのメッセージ形式を渡してあげれば、あとはよしなに解釈して、修正すべき行にコメントを残してくれます。

reviewdog はとても簡単なのです!

perlcritic のような、Danger のプラグインがない linter を使っているのであれば、
reviewdog はとてもいい選択肢に思えます。

4. reviewdog を使ってみる

reviewdog の使い方については、前述したとおり本家の README.md で十分理解できますが、
ここでもいくらか書いておきます。

4-1. -reporter=github-pr-review

reporter オプションの選択肢は複数ありますが、GitHub を使っているのであれば
github-pr-review reporter を選ぶのが良いでしょう。

まず local reporter は、動作テスト用です。
local reporter の場合のみ、 diff オプションが必要なので注意しましょう。
linter でチェックしたうちの、 diff オプションで渡した部分の結果のみを出力します。

参考 : https://github.com/nekonenene/perlcritic_reviewdog

次に github-pr-check reporter ですが、これは見栄えとしてはいいのですが、
README にある通り、これを動作させるためのサーバーは作者の haya14busa さんのポケットマネーで動かしているので、安定した稼働は保証されていません。

また、アプリ連携によりリポジトリのコード閲覧権限を渡すので、
会社で扱う場合には良くない選択肢でしょう。

reviewdog のアプリ連携画面

というわけで、 github-pr-review reporter を使うことになります。

これの使用にあたっては、 https://github.com/settings/tokens から作成できる
GitHub の Personal access token が必要になります。

公開リポジトリなら public_repo のみにチェック、
非公開リポジトリなら大項目の repo の方にチェックを入れて Token を作成します。

f:id:nekonenene:20190713220213p:plain
公開リポジトリなら public_repo のみにチェック

reviewdog のコメントは、この Personal access token の持ち主からおこなわれる形になるので、
reviewdog 用のアカウントがあると見栄えは良いかもしれません。

reviewdog 用のアカウントを作らないと、自分のプルリクにコメントしまくってる人みたいに…

4-2. 必要な環境変数

-reporter=github-pr-review の使用にあたってはたくさんの環境変数が必要になります。

  • REVIEWDOG_GITHUB_API_TOKEN : 上記 4-1. で説明した Personal access token
  • CI_REPO_OWNER : リポジトリの管理ユーザー名(GitHub ID)
  • CI_REPO_NAME : リポジトリ名
  • CI_PULL_REQUEST : プルリクエスト番号
  • CI_COMMIT : 対象ブランチの最新コミットID( git rev-parse HEAD で取得可能)

サポートされているCI(2019/07/13 現在は Travis CI, Circle CI, GitLabCI)であれば Personal access token だけ渡してあげればいいのですが、
ローカルからの実行や Jenkins からの実行に関しては、これらを全て埋めてあげる必要があることに注意しましょう。

4-3. -efm=%f:%l:%c:%m

efm オプションは大事です。が、
perlcritic の場合は出力形式をいじれるので、どちらかと言えば perlcritic 側の出力形式をいじることが大事になるでしょう。
verbose オプションですね。

%f:%l:%c については、reviewdog がどこにコメントすればいいかを示します。
%m はコメントの内容ですので、ここが工夫のしどころです!

最終的には以下のようになりました。

perlcritic --profile .perlcriticrc --verbose '%f:%l:%c:**%m**, near <code>%r</code>.<br>(Ref: [%p](https://metacpan.org/pod/Perl::Critic::Policy::%p))\n' | reviewdog -efm=%f:%l:%c:%m -name=perlcritic -reporter=github-pr-review

Markdown を使いつつ、バッククォート ` はシェル側で解釈して処理されてしまうので、
HTML タグを使うことで避けています。

指摘内容のリファレンスに簡単に飛べるようにしたのは良い工夫だったと思います。

5. Jenkins で使う際の工夫

上の 4-2. で環境変数をたくさん埋めなければいけないと書きましたが、
Jenkins の場合はどうすればいいのかについて触れておきましょう。

5-1. REVIEWDOG_GITHUB_API_TOKEN

秘匿情報であるトークンをどう扱うか、
ここが頭を悩ませるところだと思います。

Jenkins の Credentials (認証情報)を使います。

<your_jenkins_host>/credentials/store/system/domain/_/newCredentials の URL から、
『Secret text』として API Token を追加します。

f:id:nekonenene:20190713223618p:plain
認証情報の追加

Jenkinsfile からは以下のように扱います。

withCredentials([string(credentialsId: "reviewdog", variable: "githubToken")]) {
  env.REVIEWDOG_GITHUB_API_TOKEN = githubToken
  def reviewdogResult = sh(
    // ※ブログ公開用にコマンドは実際と変えてあります
    script: "perlcritic --profile .perlcriticrc --verbose '%f:%l:%c:**%m**\n' | reviewdog -efm=%f:%l:%c:%m -name=perlcritic -reporter=github-pr-review",
    returnStdout: true
  ).trim()
  env.REVIEWDOG_GITHUB_API_TOKEN = "" // token が環境変数として残るのを避けるため、空文字を再代入(unset は効かない)
  echo "${reviewdogResult}"
}

withCredentials スコープ外では値がマスクされないため、
githubToken を代入した env.REVIEWDOG_GITHUB_API_TOKEN の値を
env.REVIEWDOG_GITHUB_API_TOKEN = "" で初期化しているのがポイントです。

f:id:nekonenene:20190713224534p:plain
Credentials の値がマスクされている様子

これをやらないと、この後ろで sh "env" なんかがあると、トークンの値が平文で表示されてしまいます。

5-2. CI_REPO_OWNER, CI_REPO_NAME

リポジトリオーナー、リポジトリ名が変わることはめったにないので直接書いても良かったのですが、
汎用性を持たせるため Jenkins の環境変数である JOB_NAME を活用しました。

def jobNameArr = env.JOB_NAME.split("/")
env.CI_REPO_OWNER = jobNameArr[0]
env.CI_REPO_NAME = jobNameArr[1]

5-3. CI_PULL_REQUEST

Jenkins の環境変数 CHANGE_ID がプルリクエストの ID ですので、それをそのまま使用しました。

env.CI_PULL_REQUEST = env.CHANGE_ID

なお、プルリクエストに紐付かない Jenkins ビルドでは env.CHANGE_ID の値は null になっています。

5-4. CI_COMMIT

以下のように取得しました。

env.CI_COMMIT = sh(returnStdout: true, script: "git rev-parse origin/${env.BRANCH_NAME}").trim()

単純に git rev-parse HEAD となっていないのには理由があります。

私達は Jenkins のビルド設定に関し、安全のために
『Discover pull requests from origin』の設定で
『Merging the pull request with the current target branch revision』を選んでいます。

f:id:nekonenene:20190713230653p:plain
Merging the pull request with the current target branch revision

これにより CI は、 checkout scm 内での作業として、
指定ブランチのリポジトリをクローンした直後、
プルリクの向き先(たいていは master)ブランチをマージします。

そのため、HEAD のコミットIDが、プルリク上の最新コミットIDと一致しなくなってしまうのです。
これを、 origin/${env.BRANCH_NAME} のコミットIDを見に行くことにより避けています。

プルリクの最新コミットIDと env.CI_COMMIT の値が一致しない場合、
422 Unprocessable Entity エラーが返ってきてしまうので注意しましょう。

ここはハマりポイントだと思います。

6. そして開発はさらなる高みへ

こうして reviewdog の導入を果たした私達は、
「自分の通った道をよりきれいに」のボーイスカウト精神を意識しながら、
より一貫性のあるコードへ既存コードを整えていくのでした。

最終的に perlcritic の severity を夏さんが 1 (一番厳しいやつ)にしたのは驚きました(笑)

整えていくぞ〜〜!!

というわけで、Perl を使いつつも、誰もが読みやすいコードを目指して日々精進している私達に加わりたい方、
大募集中です!! 一緒に輝きの向こう側を目指しましょう!

一部 Go 言語への移行を少しずつ進めている箇所もあるので、
Go 言語やアーキテクチャーについての知見をお持ちの方も大歓迎です!

ご応募はこちらから〜

www.wantedly.com

まだまだサーバーサイドのメンバーは少ないですので、
「設計も改善も任せろ〜〜!」という方、ぜひぜひご応募ください!!

*1:プラグインによりますが、たいていのプラグインは inline mode をオプションとしてサポートしています

日本最大級のプロダクトマネージャーコミュニティのオフ会#16 に潜入レポ

はじめまして。 ミラティブの坂本としふみです。

先日、日本最大級のプロダクトマネージャーコミュニティである pmjp のオフ会に行ってきました。 今回のブログではそのレポをお送りします。

pmjpとは

いきなり 公式サイト からの引用なのですが、pmjpとは下記のようなコミュニティです。

Product Managers Japan (PMJP)は、主にWeb業界のプロダクトマネジメント・オーナーシップに興味を持つ人々が集まるコミュニティです。現職のプロダクトマネジャーはもとより、エンジニア・デザイナー・プランナーなどなど、様々なバックグラウンドを持つ人々が集っています。

プロダクトマネージャーという言葉が定着するはるか前である、2015年ごろから始まっているコミュニティです。いまでこそプロダクトマネージャーのコミュニティはいくつか存在しますが、その先駆けとなったコミュニティです。年に数回オフ会が開かれており、プロダクトマネージャーやプロダクトマネージャーに興味がある人があつまり、それぞれのノウハウや悩みをシェアしています。

今日のブログは、2019/06/18(火)に行われたオフ会#16のレポートです。

オフ会レポ

オフ会の概要

今回のオフ会会場は、株式会社ジーニーさんでした。新宿のきれいなオフィスで、到着したらまず夜景が綺麗でした。まずは主催者である ninjinkun の挨拶から始まります。

f:id:sakamoto10423:20190624234942p:plain
会場のジーニー社

その後、発表が2つ、LTが3つ、そして懇親会と続きます。

発表

※資料が公開され次第、資料を追記していきます。2019/06/25時点で公開されている発表は資料へのリンクを貼っております。

「よいプロダクトをつくるためのよいチームのつくられかた」

ヌーラボ小久保さん(@yusuke_kokubo)の発表です。

タックマンモデルを使用しながら、良いチームへの変遷をナマナマしく語っていただきました。 ヌーラボ社の主力製品の一つであるBacklogに、新しい機能を実装したチームを実例にして、 得られた教訓を共有頂けました。

小久保さんより資料が公開されているので詳しくは資料を御覧ください。

speakerdeck.com

会場からの質問

トピックがチーム作りということもあり、会場からはチーム作りに関する質問がでました。

  • 1on1や振り返りで本音出せますか?個人的には、飲み会とかに頼ってしまいがちだが、1on1において工夫していることはありますか?
    • 現在は本音が出せるようになっている。秘訣は、いきなりオープンに話そうぜ!という雰囲気ではなく、まずは自分自身をオープンにすることが重要。プロダクトの熱意や個人的な事もまずは自分からオープンにしていく。
  • チームがリモートだと思うが、そこにテクニックはあるのか?
    • 本プロジェクトは全員福岡に固まっていたので該当しなかった。リモートはリモートならではチーム作りはあるとおもう。

LeSSのすすめ

Repro株式会社執行役員 林さん

f:id:sakamoto10423:20190625002512p:plain
Repro株式会社執行役員 林さん
次は、Reproの林さんより、LeSSを導入した経緯とその効果についての発表がありました。 LeSSというのは、ファイルの中身を見るコマンド.... ではなく、Large-Scale Scrumの略称です。

Reproの開発にLarge-Scale Scrumを導入したらうまくいったという話をしていただきました。 (※Repro: アプリやWEBに簡単に導入できる分析・マーケティングツール)

資料が公開されていないので、発表の内容を完結にまとめておきます。

Reproはご存知の方も多いプロダクトだと思いますが、非常に多機能で大きなプロダクトとなってきています。2018年にはアプリではなくWEBにも対応したことで、より巨大なプロダクトになってきています。そのような背景もあり、

  • 開発速度の低下
  • PMやQAがプロセス上のボトルネックになった
  • 知識が属人化した

ことが起こっていました。そこで、開発プロセスを見直し、LeSSを導入したら(最初は大変だったが)概ねうまくいったというお話でした。

ということで、林さんの言葉もお借りしながら、LeSSについてまとめておきます。 LeSSは https://less.works/ にそのプロセスがまとめられています。

私が感じたLeSSの特徴をひとつかいておきます。(全部書くとそれだけでブログがおわってしまう...) それは、LeSSは、コンポーネントチームではなく、フィーチャーチームで構成され、バックログは全チームで共通ということです。

f:id:sakamoto10423:20190625003921p:plain
Lessのフィーチャーチームのイメージ

https://less.works/less/structure/feature-teams.html から引用

上記の右のようなチームがフィーチャーチームです。例えば、フリマアプリであれば、出品チーム・落札チームみたいな分け方だったり、サーバーサイド・クライアントみたいな分け方だったりをせず、チーム1,2,3.... のような分け方で、それぞれのチームがそのチームのみで価値の出荷が可能なチームの作り方です。

たしかにこのような仕組みにしておくと、大きなプロダクトでは非常に理になかっていると思いました。コンポーネントチーム制(左)だと、チームの負荷を均一にするには、バックログもコンポーネントA,B,C均等にしておく必要があります。大規模なプロダクトになればなるほど、そんな理想的な状態は実現が難しいだろうなぁと思いつつ聞いていていました。(大規模なプロダクトで左を採用すると、リファクタリングまできれいにできているコンポーネントとそうでないコンポーネントができたりしますね...経験談)

Reproさんと状況が似ている方、是非試してみてはいかがでしょうか?ミラティブ社でも、エンジニアが増えてきたら(末尾で募集してますよ!)、チーム開発の体制やプロセスについて大きく考える時期が来るかもしれません。その日に向けて良いインプットとなりました。

LT

「PM部立ち上げから見る、組織化のメリットと育成論」

f:id:sakamoto10423:20190625010116p:plain
株式会社ジーニー 大橋さん
株式会社ジーニー 大橋弘崇さん

大橋さんからは、先程のReproさんの事例とは逆の状況で、「プロダクトの数が増えてきたのでPM部を作った」というLTをいただきました。

2019年4月にプロダクトマネジメント部を発足させ、現在は10名のプロダクトマネージャーが在籍しているとのことです。部として気をつけて運営していることとしては

  • PMとしての基礎レベルの向上
  • 知見の共有
  • 目線を上げる取り組み

を意識してやれらているとのことでした。

チーム化した結果、メリットは様々あるが目線を上げる取り組みが組織的にできたことが非常に良かったと言われていたのが印象的でした。また、プロダクトマネージャーのスキルはあとから付けれるものが多いが、プロダクトに向き合っていくスタンス自体はあとから身につくものではない。そこのスタンスが高いメンバーをPMチームに入れるというお話をされていました。

「サークルスクエア 〜資金を調達せず、プロダクトを育て続けた18年の記録」

いとうまさし(@itmsc)さん すみません、お話を聞くのに夢中で写真をとり忘れてしまい;;🙇‍♀️

www.slideshare.net

※本稿執筆後に資料が公開されていましたので資料をアップしました。

サークルスクエアは、18年の歴史があるグループウェアです。どんな思いをもって続けてきたか、という話をしていただきました。 www.c-sqr.net

その中で印象的だったお話が、プロダクトを100年続けていきたいという話でした。そのために3つの戦略を採用されているということです。かなり具体的な戦略の話だったので、キーワードだけ記載しておきます。

  • ブートストラップ作戦。資金を調達しない
  • ギャラクシー作戦
  • ラストマン・スタンディング作戦

また、新機能がでるとのことで、その告知もされていました🍦

Happy Ice Cream officeとは

ユーザーストーリーと効果的な開発、そのKPIは対話だよって話

株式会社 Fabric Tokyo 渡辺さん

f:id:sakamoto10423:20190625102819p:plain
Fabric Tokyo 渡辺さん

ユーザーストーリーをどう使うかという実践例の話をされていました。ユーザーストーリーは「つくりましょう!」「うまくいった!」という話が多いのですが、渡辺さんの発表はユーザーストーリーを細かく書いたがうまく行かなかったという実践例で、大変勉強になりました。

もう少し具体的にいうと、ユーザーストーリー(やワイヤーフレームを)PMが書きすぎて、チームのクリエイティビティが損なわれてしまった。という実体験から、より抽象度の高い「課題設定」だけをPMが行い、チームと一緒に作るものを考えるというスタイルに変更されたとの話でした。そのスタイルにするとより課題解決がうまく進んだとのことです。

つまり、開発チームとの会話を増やしたことで、課題解決の質が上がった。つまり、開発のKPIは「対話」というまとめでした。

2019/06/26 15:47追記:渡辺さんから資料が公開されましたので掲載いたしました

speakerdeck.com

懇親会

懇親会では、登壇された方とお話したり、さまざまな会社のプロダクトマネージャーと交流することができます。

f:id:sakamoto10423:20190625103746p:plain
懇親会
pmjpのオフ会は16回めということで、食事の量もドリンクの量もちょうどいいです。一人何本アルコールを開けるかというビール係数、アルコールとノンアルの割合を決めるノンアルレシオというものがあり、コミュニティ内でだいたい値のあたりが付いているという話を昔聞いたことがあります。

まとめ

いろんなフェーズの会社の色んな話を聞くことができ、大変勉強になりました。 プロダクトマネジメントの方法やミッションはそれぞれの会社で違うものの、抽象化して学べるところはたくさんあるなぁと改めて感じました。 私がいまミラティブで経験していることもプロダクトマネージャー界隈の微々たる力になればなぁと思いますので、機会があれば登壇しようかなと思っています。(次の次くらいを狙っています笑)

現役のプロダクトマネージャーの方も、プロダクトマネジメントに興味があるという人も大変勉強になる回なので一度参加されてみてはどうでしょうか。

pmjpのコミュニティには下記から参加できます。オフ会の連絡などもこちらで行われています。

Product Managers Japan (PMJP)

ミラティブはさまざまな職種のメンバーを募集しています

というわけで、オフ会(勉強会)のレポをお送りしましたが、ミラティブでは「勉強会補助制度」と「デクレア制度」というのがあります。

勉強会補助制度というのは、その名の通り勉強会の補助制度です。下記のルールで運用されています。

f:id:sakamoto10423:20190625105439p:plain
勉強会補助制度
また、技術書は基本経費で購入できますので、今回のオフ会ででてきたLeSSに関する本なども購入OKです。

また、デクレア制度というのは、自分の働き方をデクレア(宣言)する!というものです。勉強会に行くから早く帰るといったものから、集中的に新しいスキルをつけたいので今週は残業なしにしたいです。といった使い方です。プロ野球選手が、チームが試合で勝ち続けるために、自分のコンディションにあわせて負荷を調整するのに似ています。 デクレアについて詳しくは👇 note.mu

ミラティブではさまざまな職種のメンバーを募集しています。

全職種の応募はこちら👇 www.mirrativ.co.jp

ちなみに、私がPMをしているプロダクト(今後リリース予定)で、iOSエンジニアを募集しています!👇 www.wantedly.com

「ミラティブを他の人に勧めますか?」というNPS調査をプロダクト改善に活かす方法

はじめまして。 分析チームの坂本としふみです。 今日は、「ミラティブを他の人に勧めますか?」というアンケートをどう分析し、プロダクト開発に活かしていくのかということを記事にしてみたいと思います。

NPS(Net Promoter Score)とは?

f:id:sakamoto10423:20190616154241p:plain
NPS調査の例
アプリやWEBサービスを使っているときに、上記のような質問をどこかで見たことあるのではないでしょうか? これは、Net Promoter Score(NPS)と言われる指標を計測するための質問です。

NPSは、ユーザーの利用継続意向を測るための指標で、多くのアプリやWEBサービスで採用されています。 NPSの計算方法は、点数を下記のように分類し、推奨者の割合から批判者の割合を減算したものをNPSとします。たとえば、推奨者が40%・批判者が8%だった場合、NPSは +32 となります。

点数 評価
10 - 9 推奨者(Promoter) ロイヤルティが高い熱心な顧客。自らが継続購入客であるだけでなく、他者へサービスを勧める『推奨』の役割も担う。
8 - 7 中立者(Passive) 満足はしているが、それ程熱狂的ではなく、競合他社になびきやすい。
6 - 0 批判者(Detractor) 劣悪な関係を強いられた不満客。放置しておくと悪評を広める恐れがある。

ちなみに、NPSの業界平均なども公開されていますが、サービスの特性や国によって異なることも知られています。そのため、NPSを他のサービスと比較するというよりは、自社サービスにおけるNPSの上下に着目することが重要です。

ミラティブもKPIの1つとしてNPSを測定しており、月に1回調査をしています。

自由記入欄を分析し、より深い示唆を得る

一般的なNPS調査では、0-10の点数を質問した後、「その点数にしたのはなぜですか?」という自由記入欄を設けています。この自由記入欄を分析すると、「批判者は何で批判なんだろう?」や「推奨者は何で推奨なんだろう?」という突っ込んだ示唆を得ることができます。

そこで、日本語を解析する一般的な手法の一つである、形態素解析を用います。形態素解析とは、文章を形態素(意味をもつ最小単位) に分解し、その形態素の品詞などを解析していく手法です。例えば、 Pythonで書いてみると下記のようなコードになります。

コード

import MeCab as mc
tagger = mc.Tagger('')
results = tagger.parse('ゲーム配信が簡単にできるので')
print(results)

結果

ゲーム  名詞,一般,*,*,*,*,ゲーム,ゲーム,ゲーム
配信    名詞,サ変接続,*,*,*,*,配信,ハイシン,ハイシン
が      助詞,格助詞,一般,*,*,*,が,ガ,ガ
簡単    名詞,形容動詞語幹,*,*,*,*,簡単,カンタン,カンタン
に      助詞,副詞化,*,*,*,*,に,ニ,ニ
できる   動詞,自立,*,*,一段,基本形,できる,デキル,デキル
ので    助詞,接続助詞,*,*,*,*,ので,ノデ,ノデ

※上記結果は、Colaboratory上のJupyter ノートブック (python3)で動作確認済

「ゲーム配信が簡単にできるので」という文章が「ゲーム / 配信 / が / 簡単 / に / できる / ので」と分解され、それぞれの品詞が推定されている事がわかります。

ということは、形態素解析を使うと 推奨者に多い言葉な何なのか? その逆に、批判者に多い言葉な何なのか? 推奨者だけによく出てくる言葉はなんなのか? というような解析ができるということがイメージできたんじゃなかなと思います。

では実装だ!となるのもよいのですが、世の中にはきっと同じことを考えているひとがいるはずです。自社で開発する必要のあるものだけに集中し、車輪の再発明を避けるのはベンチャー企業の鉄則です。ということで、NPSの自由記入欄分析に有用なデータ分析サービスを紹介します。

ユーザーローカルによる分析

ミラティブでは、ユーザーローカル というサービスを利用しています。ユーザーローカルを使用すると、2つの文章の比較をすることができます。ワードクラウドとよばれる出現回数を表現する図や、単語分類といった図を作成することができます。

f:id:sakamoto10423:20190616155153p:plain
サイクロン掃除機のレビューを比較した例

たとえば上記の例であれば、「吸い込む」と「吸引力」が高評価・低評価ともに頻度高く出現しています。おそらく、吸い込む力についてユーザーが着目しており、期待を上回って満足する場合とそうでない場合の両方があるのかな?ということが推測できます。また、「サイクロン」という言葉は高評価に偏在しているのは、おそらく「サイクロン掃除機がほしい」というニーズを満たしているからではないかと考えることができます。

ミラティブのNPS調査、自由記入欄を解析してみた

ミラティブのNPS調査の自由記入欄を解析してみたのが下記の結果です。

f:id:sakamoto10423:20190616155310p:plain
ミラティブのNPS形態素解析結果1

f:id:sakamoto10423:20190616155352p:plain
ミラティブのNPS形態素解析結果2

このデータを下記のような観点で眺めています。

カテゴリ 眺める視点 具体的には
両方によく出る 良くも悪くもユーザーが注目している機能や感情 「配信」「エモモ」などのの機能だったり、「楽しい」「面白い」というの感情は推奨者・批判者ともに注目されています。 逆に、「ギフト」「エモカラ」などの新機能の言及が少ないので、より浸透させていく余地があるなと感じています。
推奨者にだけ出現・推奨者によく出る 運営がおいているプロダクトの価値とずれていないか確認 「簡単」「交流」「つながり」などの単語が目立ちます。これは、「わかり合う願いをつなごう」という弊社のビジョンや、「スマホ一台で簡単にゲーム配信」というミラティブのコンセプトが受け入れられているんだろうなと感じています。
批判者にだけ出現・批判者によく出る 今後の改善ポイントとして認識 「バグ(る)」「重い」「ラグ」「不具合」など、品質に関する論点が頻度高く出現しています。配信アプリという特性上、「軽くてラグがなくて不具合がない」という品質が強く求められているんだと感じています。

※上記以外にもたくさん示唆はでるのですが、あまり書きすぎると今後のプロダクト戦略が赤裸々になってしまうのでこのへんでご勘弁を。

ちなみに、批判者に頻出している「バレる」「身バレ」などの単語は、「ミラティブ(バーチャル)上の人格やつながりをリアルな知人に知られたくない」という文脈です。これはNPS質問の「ミラティブを友人・知人に勧めますか?」という質問の特性上、「アプリには満足しているけど、リアルな友人に勧めたくない」という人が批判者に入ってしまうためです。今後は、そういった文脈を排除できるよう、質問の内容を改善中です。

また、今回は形態素の出現頻度のみに着目し、示唆だしを行いましたが、文章解析には、より文脈を数値化するような手法など、様々な手法が存在します。NPS調査に関して言うと、「傾向を早くつかみ、プロダクト開発のPDCAをまわす」ということが重要だと判断し、頻度分析にとどめています。(※この分析手法を選択した結果、ミラティブでは、NPSは実施から分析まですべて、非エンジニアであるコミュニティチームが回すことができています。)

解析結果からのネクストアクション

上記の結果から、やはり不具合解消の優先度を上げるべきだということで、まずはNPS調査で挙げられている不具合にはどのようなものが多いのかをリストアップしました。ちなみに、ミラティブのNPS調査では、回答者ごとに暗号化されたuser_idを自動付与しているので、それを復号することでOSや機種も特定することができます。

f:id:sakamoto10423:20190616155845p:plain
事前に値(user_idのハッシュ)が設定されたアンケート画面
※Googleフォームに事前に値をセットする方法はこちらのヘルプページが詳しいです。

そして、NPSに強く影響する不具合を一覧にしてPMと優先度ミーティングを開催し、バックログに積みました。 また、ラグに関しては、「低遅延な配信を可能にする技術」の研究開発を行っています。(低遅延に関する取り組みはテックブログの過去の記事を御覧ください:Mirrativにおける低遅延配信への取り組みについて【開発中】)

ミラティブではエンジニアを募集しています

このようにミラティブでは、ユーザーの声を聞きながら開発をすすめています。 NPSのKPI化だけではなく、毎週金曜日には、ユーザーからの問い合わせのサマリー・AppStoreやGooglePlayレビューのサマリーをグローバル全社員で共有するなど、職種とわず全員がユーザーと向き合う時間をもっています。

そのあたりの雰囲気は、体験入社をしていただけるともっともっと深まるかなと思いますのでお気軽にご応募ください。

www.mirrativ.co.jp

【WWDC2019】ReplayKitラボで聞いてきたこととAppleへのフィードバック

こんにちは、Mirrativ iOSエンジニアの千吉良(ちぎら)です! 先日サンノゼで開催されたWWDC2019に参加してきました。Mirrativ iOSアプリは ReplayKit を利用して配信を行っていて、ReplayKitラボで質問したい項目を事前にまとめてWWDCに臨みました。

今回はReplayKitを軽く紹介し、ReplayKitラボでしてきた質問とその後Appleへ送ったフィードバックについて、公開できると思われる範囲で一部ご紹介します。

続きを読む

【Android】デバッグツールを変更して開発体験を向上する

Mirrativ Androidエンジニアのmorizoooです。

今回は Mirrativ Androidアプリにおいてデバッグ用のツールをStethoからFlipperに変更して開発体験が向上した事例を紹介します。

Stethoとは

Facebookが開発したネットワーク通信デバッグ用のブリッジライブラリで、
Chrome Developer Toolsを使ってネットワーク通信/Preference/SQLiteの確認ができます。
Mirrativ内では主にネットワーク通信確認で使っていました。
f:id:morizo999:20190603210528p:plain facebook.github.io

Stethoの課題

とても便利なツールではあるのですが、ネットワーク通信を確認しながらアプリを起動していると度々クラッシュが起きていました。
Chrome Developer Toolsでアタッチしていないと発生しないのですが、デバッグ時にストレスがたまるので他の代替案を探していました。
github.com

Flipperとは

こちらもFacebook開発したモバイル用のデバッグツールです。
大きな違いはElectronで書かれた専用のアプリが存在し、AndroidだけではなくiOSにも対応しています。
fbflipper.com

Flipperの導入方法

Getting Started · Flipper
ドキュメントに従えばOK
v0.21.0からno-opができたので導入が楽になりました。 以下の設定をしています。

private var client: FlipperClient? = null
// アプリケーション初期化時に呼ぶ
fun setup(context: Context) {
    SoLoader.init(context, false)

    if (BuildConfig.DEBUG && FlipperUtils.shouldEnableFlipper(context)) {
        client = AndroidFlipperClient.getInstance(context).apply {
            addPlugin(DatabasesFlipperPlugin(context))
            addPlugin(FrescoFlipperPlugin())
            addPlugin(InspectorFlipperPlugin(context, DescriptorMapping.withDefaults()))
            addPlugin(LeakCanaryFlipperPlugin())
            addPlugin(NavigationFlipperPlugin.getInstance())
            addPlugin(NetworkFlipperPlugin())
            addPlugin(SharedPreferencesFlipperPlugin(context))
        }
        client?.start()
    }
}

// OkHttpClient作成時に呼ぶ
fun addInterceptor(builder: OkHttpClient.Builder) = builder.also {
    client?.let {
        builder.addInterceptor(FlipperOkhttpInterceptor(it.getPluginByClass(NetworkFlipperPlugin::class.java)))
    }
}

Flipperの所感

とても良いところ

  • Chrome Developer Toolsでアタッチする必要がない
    (Stethoだとインストール時に毎回選択する必要があるしクラッシュすると通信情報が見えなくなる)
  • レスポンスのHeader/Request/Responseが一体となっていてわかりやすい f:id:morizo999:20190604172911p:plain

  • Flipperアプリ単体でadbのログがみれる

良いところ

  • Fresco(Facebookが開発している画像ライブラリ)だと画像が見やすい&画像のキャッシュ状況がわかる f:id:morizo999:20190604173015p:plain

  • Preferenceの内容と変更履歴が見れる&編集可能(Stethoでも内容確認と編集はできる) f:id:morizo999:20190605130720p:plain

  • Flipperアプリ単体でスクショ/動画が取れる

マイナス

* SQLiteの内容が見えない(そのうちできそう
Feature Request Adding Support for SqlLite DB browser and Shared Preference · Issue #33 · facebook/flipper · GitHub

v0.21.0で入った

喜びの声

f:id:morizo999:20190604155300p:plain

オマケ

iOSでも以下の画像のようにライブラリを導入するだけでネットワーク通信, Layout Inspectorが見えます。
UserDefaultsの内容と変更履歴が見れる&編集も可能 (動作するのはシミュレータだけ

  • ネットワーク通信 f:id:morizo999:20190604160544p:plain

  • Layout Inspector f:id:morizo999:20190604155948p:plain

まとめ

Flipperとても便利なので使っていきましょう!!!

We are hiring!
一緒に開発してくれるエンジニアを募集中です! 体験入社というのもあるのでお気軽にどうぞ!

www.mirrativ.co.jp

MirrativのAPI通信に関するiOS実装の改善とCodableの活用

こんにちは Mirrativ iOSエンジニアの千吉良です。

今回は Mirrativ iOSアプリにおいてAPI通信に関する実装の改善を行ない、関連してCodableを活用した話をしたいと思います。

Mirrativ iOSアプリのソースコードには歴史があり、API通信に関するコアの実装は約4年前に実装されたものでした。日々実装を行なっていていくつか課題を感じていた箇所がありましたが、API通信に関する実装はコード量も多く、新しい仕組みを導入して一気に刷新しようというわけにはいきません。既存のファイル構成などを活かしつつ軽量な仕組みを導入して、新規実装のみ新しい方法で実装したり、部分的に修正していけるような実装を考える必要がありました。

続きを読む

Mirrativにおけるプッシュ通知ぼかしへの挑戦

こんにちは Mirrativ CTOの夏です

今回は先日iOSでリリースした通知ぼかし機能について、裏でどういうことをしているのかについて軽く紹介したいと思います。

f:id:hottestseason:20190517204251p:plain

MirrativではOSから提供されるAPI( ReplayKitMediaProjection )を用いて、スマホ画面を直接収録・配信することで、配信用のSDKを各ゲームやアプリに埋め込んでもらう必要がなく、ユーザさんが色々なアプリを気軽に切り替えながら友達と雑談を楽しんだり、ゲームを通じて新しい友達を作ることができます。

その反面、配信者が適切な設定を行っていない場合、意図しないプッシュ通知が視聴者に表示されてしまう場合もあります。

Mirrativでは配信準備画面に注意文言と啓蒙動画を載せていますが、どうしても設定が漏れたりする場合があるため、配信者が注意しなくても、プッシュ通知が視聴者に見えない仕組みを以前から検討していました。

f:id:hottestseason:20190517174205:plain:w300

Android側は NotificationListenerService を利用することで、通知を受信したタイミングで配信を一時的に停止する設定を入れています。

f:id:hottestseason:20190517171341p:plain:w300

iOSに関しては他の配信アプリなども参考に、画面に表示される通知を自動で検知し、通知領域にのみモザイクをかける方針を検討し、 副業の方と整理し、以下のような要件で実装してもらうことになりました。 (本人からの希望で名前はお出ししていませんが、以下の実装詳細の説明などに関しても本人にまとめて頂いたものを流用しています)

  • 配信中に配信者の端末に届いたプッシュ通知 (Remote/Local問わず) にモザイクをかけて配信したい
  • ただしMirrativアプリの通知はぼかさなくて良い
    • 配信へのコメントがぼかされてしまうと、視聴者が「配信者がコメントを読めない」という誤解を招く場合がある
  • 対象は画面上部からスライドインしてくるバナー通知のみ。ひとまず通知センターに表示される通知等はモザイクをかけないで良い
    • 能動的なアクションが必要となる通知は、配信者の注意によって防止できる
  • 同様の理由で、配信者が通知をタップした場合等はモザイクが外れてしまっても良い

つまりこいつです。

f:id:hottestseason:20190510154316p:plain
iOS プッシュ通知

副業の方に実装をお願いする以前、iOS11から利用できるVisionフレームワークの短形検知を利用したプロトタイプを試していたのですが、ゲームなどが動いているバックグラウンドで、OSに一番殺されやすいプロセスの中、さらに配信しながら行う処理であることを考えると、CPU使用率やメモリ使用量などが懸念点となり、汎用的な手法を取るより、プッシュ通知という特定の領域に絞って自前で検知アルゴリズムを実装することになりました。

基本方針の検討

iOSには現状、他アプリからのプッシュ通知イベントをフックする手段が無いため、配信用にサンプルされた画像から通知の存在有無を判定し、その領域を検出する画像処理が必要となります。 通知領域が検出できれば、あとは単純にその領域に対してモザイクをかければよいでしょう。

考えうる方針としては以下があると思われます。

  1. 機械学習的なアプローチ
  2. 非・機械学習的なアプローチ
    1. 既存の汎用的なアルゴリズム
    2. 専用特化したアルゴリズム

1.の機械学習的なアプローチは、背景画像や端末解像度の違い等に対して頑健に作れる、細かな閾値調整等が (2-bと比較して) あまり必要ない、等のメリットはあるものの、一方で学習のために一定量の教師データ (特に正例) が必要となる、デバッグが困難である等のデメリットがあります。

2-a. 既存アルゴリズムは、例えば古典的なCanny法やHough変換などを用いることは可能であり、うまくすれば将来的なUIの変更等に対して非常に頑健に作れる可能性があるものの、基本的に計算量が大きくなるというデメリットがあります。通知ぼかしはゲームアプリ等のプレイ中にも常時動かす処理であるため、計算量は限界まで削減したい所です。

また、これら既存アルゴリズムの対象が主に風景などの自然写真であるのに対して、今回の対象は固定的な通知領域UIであるため、その削減余地は非常に大きいと言えます(エッジの角度を一切気にしないで良い、出現位置を事前に調べることが可能、etc)。

以上から、今回は通知領域検出に特化したルールベースのアプローチを取ります。整理すると、メリットとデメリットは以下となります。

  • メリット
    • 教師データの収集が必要ない (vs 1)
    • 実行時パフォーマンスが高い (vs 2-a)
  • デメリット
    • 閾値等を手動で微調整する必要がある
      • OSアップデートによって通知領域の形状が変更されるなどした場合、閾値を再調整する必要が出てくるかもしれない
    • 端末解像度の違いなどに対して感度が高い
      • 新しい解像度の端末が発売されるために、データを追加する必要がある
      • ただしこの運用コストを多少緩和するアプリを作った。詳細は後述

今回は、メリットに上げた点を優先するためにこれらのデメリットを犠牲にしました。なお、この実装によって正例を自動収集することが可能になるので、それを用いて将来的に機械学習的アプローチに乗り換えていくという方法も考えられますが、収集の仕組みの実装・機能再実装・再QA等のコスト、そして結局UI変更に対しては脆弱であり運用コストをゼロには出来ない点等を考えると、(微妙な所ですが) 現行アプローチの継続に軍配が上がると思われます。

通知領域の検出

通知領域の定義

検出したい通知領域は、例えば以下のような角丸矩形ですが、

f:id:hottestseason:20190510154316p:plain

プッシュ通知は画面上部からスライドインしてくるため、上のような完全な角丸矩形でしか検出できない場合、スライドイン中の通知内容が見えてしまうことになります。よって、以下のような角丸矩形の下部を検出し、その領域を画面最上端まで拡張した領域を検出することにします。

f:id:hottestseason:20190510155649p:plain

ここで言う「領域」(Filled Rectangle) とは、以下2点によって定義できるでしょう。

  1. 外縁がエッジで囲まれている
  2. 内部が塗りつぶされている

これらは機械処理しやすいよう、以下のように換言できます。

  1. 外縁に大きな輝度変化が存在する
  2. 内部に大きな輝度変化が存在しない

f:id:hottestseason:20190510155854p:plain

外縁をまたぐ赤矢印の部分に大きな輝度変化が存在し、内部の青矢印の部分に存在しなければ、領域とみなすことができそうです。矢印の間隔を小さくしていくことで精度は向上しますが、パフォーマンスの関係上、適度に間引くことにします。また、内外どちらも背景色の影響を受ける (特に内部は透かし/ブラーがある) ため、適当な閾値を探す必要があります。

輝度変化の指標

輝度変化を捉える手法はいくつかありますが、ここでは一次微分の分散を用いることにします。具体的には、まず下図中の黄点のように矢印線上のいくつかの点をサンプリングします。

f:id:hottestseason:20190510155954p:plain

その上でRGBそれぞれの一次微分(つまり画素値の差分)を計算し、それらの分散(dv)を下式によって計算します。

image

ここでpiはi番目の画素値、Dは画素間の距離です。dvをRGBそれぞれについて計算し、最大のものを特徴量として使用します。最初にグレースケール化してから計算すると特定ケースにおいて精度が落ちたので、今回はRGBごとに計算するようにしています。

このdv値を、事前に調べておいた閾値と比較し、大きければエッジがあり、小さければエッジが無いと判定することが可能となります。閾値は、外縁・内部ともに2.0が一番精度が高そうでしたが、ここは調整の余地がありますし、将来UIに変更が入った場合も調整する必要が出てくる可能性があります。

検出ロジック

上記のアルゴリズムによって、矢印の両端点が与えられた場合に、それらを繋ぐ直線状にエッジが存在するか否かを判定することが可能となりました。これを用いて、与えられた画像の全領域内に通知領域が存在するか否かを判定していきます。基本的な流れとしては、以下になります。

  1. 矢印の端点群を生成する
  2. 端点群を順に走査し、それぞれエッジ存在判定をする
    • 存在する場合はスコアを加算する
    • bridge(外縁)の場合、スコアは下線部・横線部・角丸部ごとに異なった値を用いる (角丸は通知領域を特徴づける有力な特性であるため強めに評価する。また横線部はそもそもの端点が少ないためこちらも強めに評価する)
    • inner(内部)の場合、スコアは常に1で良い
  3. それぞれのスコアの平均値が基準を満たしているかを、閾値によって判定する
    • 直感的な解釈としては、innerについてはエッジが存在すると判定された矢印の個数の割合。bridgeについてはそれ重み付けを行ったもの
    • つまり、bridgeのスコア平均値が閾値を上回っており、かつinnerのそれが閾値を下回っている場合に、通知領域が存在すると判定する
    • 色々試した結果、bridgeは0.8, innerは0.2で今の所よく検出できている模様

ノックアウト

ある1つの矢印のdv値が既定の閾値を下回った/上回った場合、即座に通知領域が存在しないと判定しbail outします。それぞれ1.0と10.0が効果的でした。これによって、例えば真っ白な画面を判定する際などに、全ての端点ペアを走査することなく即座に検出処理を中止することが可能となり、多少パフォーマンスと検出精度が向上します。

端末ごとの事前情報の調査

上述のアルゴリズムを用いる際、各端末の解像度ごとに通知領域の出現位置を事前に調べておくことが、精度やパフォーマンスの観点から非常に重要となります。例えばiPhone7とiPad miniでは通知領域のx座標が異なりますが、これを事前情報として持っておかないと一定範囲のxに対して検出メソッドの呼び出しをループしなければならなくなり、計算量が飛躍的に増大してしまいます。逆に端末ごとに固定値を調べておくことができれば、x座標を決め打ちすることが可能となります。

この事前情報を調査するため、単にローカル通知を表示するためだけのアプリを実装し、各シミュレータで動かして、通知が表示されたスクショを撮影し、それらに対して非常に単純なロジックによって通知領域を検出して、以下のような端末解像度毎の出現位置を割り出しました。

{
  "1080x1920": {
    "width": 1080,
    "height": 1920,
    "scale": 2.61,
    "notification_region": {
      "x": 21,
      "y": 21,
      "width": 1038,
      "height": 325
    }
  },
  "1125x2436": {
    "width": 1125,
    "height": 2436,
    "scale": 3,
    "notification_region": {
      "x": 24,
      "y": 120,
      "width": 1077,
      "height": 374
    }
  },
  // ...
}

時系列を加味した最適化

上述した手法を用いれば一応通知領域は検出できますが、まだパフォーマンスに改善余地があります。通知領域が存在する可能性のある全領域を30fpsで検索していると流石に重く、手元のiPhone7ではCPU使用率が30-50%程度となりました。よって、どうにかして探索範囲を狭める必要があります。また、対象範囲を狭めることができれば結果的に誤検知が減り精度の向上も期待できます。

ここでは、通知領域の位置の時間的変位が利用できます。噛み砕いて言うと、以下のような想定を置くことが可能です。

  1. 前フレームにおいて、通知領域が検出されなかった場合、探索領域は最上端の一定部分のみでよい (必ず上からスライドインしてくるため)
  2. 前フレームにおいて、ある位置に通知領域が検出された場合、その周辺を優先して探索すればよい

余談ですが、通知領域のスライドアニメーションは一般的なease-in/outなので、これを利用してシグモイド関数等を使って線形モデルよりも精度の高い出現位置予測を出来そうですが、試してみたところそこまで精度が上がらなかったのでやめました。

ただし、前回の検出位置という状態変数を持つことにより、いくつか問題が出てきます。具体的には以下のようなものをケアする必要があります。

  • 通知表示中に配信開始した場合、全領域を探索しないと正しく検出できない
  • 端末回転中は通知検出ができないので、その間に通知が来た場合、全領域を探索しないと正しく検出できない
  • 何かのミスで一瞬通知領域が無いと判定されてしまった場合、次回以降の一定期間も全探索したい (fail-safe的に)

Mirrativからの通知だけモザイクをかけない

通知領域を検出した場合、その通知領域内のアイコン部分を調べ、もしMirrativのアプリアイコンと一致していれば通知領域なしと判定します。 こちらに関しては、SADを用いた単純なテンプレートマッチングを行っています。アルゴリズム詳細はこのへんのサイトを参照して下さい。 Mirrativのアプリアイコンと一致していなければ、対応する領域にCore ImageのCIFilterのうちCIPixellateを適用してモザイクをかけています。 (当初はCIGaussianBlurで実装していたのですが、配信が異常に落ちる事件があった結果、CIPixellateに変更しました)

課題と更なる挑戦

すでにiOSの全ユーザに公開済みの機能とはいえ、まだ特定の端末(新型iPad Proなど)に対応していなかったり、特定のタイミングでMirrativの通知がぼかされたり、 Mirrativ以外の通知がぼかされていなかったりと一部不具合も残っているため、現在CSチームと協力して不具合が起きている箇所の動画を収集しており、さらなる改善に繋げようとしております。

適用領域がニッチとは言え、他にはあまり類をみないソフトウェアだと思うので、さらなる改善後にはOSS化してみようと思っていますので、乞うご期待を!!

ミラティブは多種多様な技術(ライブストリーミング・Unityによる3Dアバター・機械学習などなど)を扱っており、我こそはという方がいらっしゃれば副業などでも構わないので、ぜひご応募ください!!

www.mirrativ.co.jp

追伸

f:id:hottestseason:20190517202752p:plain

追伸の追伸

今年度ミラティブ初めての新卒エンジニアの安西くんがブログを始めました!!

mirrativ-stream.hatenablog.com

機械学習で配信中の映像からゲームを推定する機能をリリースしました

おはようございます、機械学習エンジニアのハヤシです。

本稿は前回紹介した 機械学習で配信中の映像からゲームを推定する機能を開発しています🎮 - Mirrativ tech blog の続きとなります。そのため、背景や機能の紹介については最小限に留めさせていただきます。

背景

前回 の記事に開発の背景や想いを書いています。そちらをご覧ください。

機能の紹介

配信中の映像から「今なんのゲームをやっているのか?」を推定する機能です。 機械学習にて画像認識モデルを作り、どのゲームで遊んでいるかを推定するクラス分類機を作りました。

f:id:namagon:20190311182204p:plain
今遊んでいるゲームを推定しています。

A/B テストとその結果

Mirrativでは、新機能をリリースするときには必ずといっていいほどA/Bテストを行います。A/Bテストを行うことで、機能の目的がどれくらい達成されたかを定量的に確認します。その効果を確認した後、本リリースするかどうかを決定します。本機能ももちろんA/Bテストを行いました。

再度この機能の目的を整理します。

  • 【課題】アプリ設定を行わないことで、視聴数やコメント数が伸びづらい。その結果、配信の継続率がアプリ設定者よりも低くなる。
  • 【解決方法】アプリ設定を自動で行うことで、「マイアプリ」や「おすすめ」タブに乗りやすくなる。視聴数やコメント数が伸び、配信継続率が高くなる。

つまり、本機能の対象になるユーザーさん(A群)とそうでないユーザーさん(B群)で、配信継続率を観測することにしました。

まず、配信者さんのユーザー体験と密接に関わっている視聴者数やコメントユーザー数、コメント数から観測しています。

3月11日 のコメントユーザー数以外、すべての指標で伸びています。

f:id:namagon:20190325154745p:plain
各指標の伸び率をプロット

そして、配信継続率の比較結果がこちらです。

本機能でアプリ設定されたことにより、A群の配信継続率がB群の約1.8倍に向上しました。

f:id:namagon:20190324234814p:plain
A群とB群の配信継続率の比較

また、自動設定の内容を定性的に観察するための機構を開発しました。前回作成したプロトタイプを改良したものになります。

f:id:namagon:20190324221042p:plain
自動設定した際に投稿するチャンネル

すると、自動設定対象の Confidence*1の閾値(以下「推定結果の閾値」と表現します)付近で設定ミスが観察されました。

以上の結果から、推定結果の閾値を引きあげた上で本機能をすべての配信者さんに提供をすることにしました。

配信者さんからのフィードバック

ありがたいことに配信者さんから様々なご意見を頂戴しました、その一部を紹介致します。

  • 「ファンタジーライフ オンライン」 の誤検知が多い。

ファンタジーライフ オンラインの自動設定内容を確認したところ、他のタイトルとは異なり設定ミスが目立っていました。そのため、暫定対応としてそのタイトルは自動設定の対象から外しています。

画像分類でこの問題を解く以上アプリ推定の精度が100%になることはありえません。しかし、精度をあげることで可能な限り設定ミスを減らすことはできます。そのため、画像分類モデルのチューニングや再学習などでモデルのパフォーマンスをあげることで設定ミスを減らしていきます。

  • 仲間内だけに見てもらいたいので自動設定するのはやめてほしい。

あえてアプリ設定をしないことでフォロワー以外の視聴者さんを減らしたがっている配信者さんがいました。ですが、この方の希望は「自動設定をやめてほしい」ではなく「仲間内にのみに配信したい」だと思われます。

しかし、 Mirrativ の iOS 版にはフォロワーだけに配信する「限定配信機能」が実装されていません。*2そのため、アプリ設定の仕様はそのままとして iOS 版の「限定配信機能」の開発を検討することにしました。

  • あるゲームからスピンアウトされたタイトルが、派生元のゲームに誤検知されてしまう。

パズル&ドラゴンズ」からスピンアウトした作品の「パズドラレーダー」が「パズル&ドラゴンズ」と誤検知されてしまいました。

現状は教師データのアノテーションを手動で行っていたため、教師データを作れる量に限度がありました。*3

そのため、Mirrativ で配信されている約70%のタイトルにのみ適用しています。*4

パズル&ドラゴンズ」は自動設定対象でしたが「パズドラレーダー」は自動設定対象でした。

f:id:namagon:20190325171146p:plain
左がパズドラの画面で右がパズドラレーダーの画面です*5

この件については、対象タイトル数を拡大していくことにより解決する可能性があると思われます。 ゆえに、まずは対象のタイトルを拡大し、それでも誤検知が起こるようなら別の対策を打つつもりです。

今後の展開

現状のモデルの精度をあげつつ、今後は自動設定対象のタイトルを増やしていきます。 対象タイトルを増やすにあたり、教師データをどうやって作るかが課題となっています。

今後は以下の手法で教師データを作成して対象タイトルを拡大していく予定です。*6

  • 教師データを自動で生成するモジュールを作成する。
  • 一旦手作業で全タイトル分の教師データを集めてモデルを作る。以降は新規タイトルを転移学習させることで手動でも対応できるようにする。

主要なタイトルから拡大していき、最終的には Mirrativ で配信されているすべてゲームを自動設定の対象とします。

そして、将来的には現在遊んでいるアプリを設定する機能を完全に自動化するつもりです。

We are hiring!

Mirrativ では一緒に開発してくれるエンジニアを募集しています!

体験入社や副業も大歓迎です。お気軽にどうぞ!

www.mirrativ.co.jp

*1:推定結果の確からしさ

*2:Android 版では実装済みです。

*3:アノテーションを効率化するためにツールを自作しました

*4:約70%のタイトルの教師データを作るのに、3人がかりで約60時間かかっています

*5:初めてパズドラレーダーの画面を見たとき、普通にパズドラと見間違えてしまいました。ごめんなさい…

*6:現在は教師データの自動作成を検証中です。

機械学習で配信中の映像からゲームを推定する機能を開発しています🎮

おはようございます、機械学習エンジニアのハヤシです。

本稿では現在テスト中の配信中の映像からゲームを自動で設定する機能についてご紹介します。

背景

Mirrativには「マイアプリ」や「おすすめ」といったタブがあり、そのタブにいろいろな配信が表示されています。視聴者さんはこれらのタブから自分の見たい配信をタップして、視聴を開始します。

また、配信者さん向けの機能として「現在遊んでいるアプリを設定する」という機能があります。配信開始時や配信中にアプリ名を選択し、「いまこのゲームの配信をしているよ」と表明する機能です。(以下「アプリ設定をする」と表現します)

「マイアプリ」や「おすすめ」にどの配信が表示するか判断するロジックに、このアプリ設定の情報を使用しています。つまり、アプリ設定がされている配信は、上記のタブで紹介される確率が高まり、視聴者さんが来やすくなり、コメントも付きやすくなります。

f:id:namagon:20190307080955p:plain
アプリ選択画面。

一方でアプリ設定をしていない配信者さんはアプリ設定をしている配信者さんより配信への入室率や1回以上コメントが送られる割合が下がる傾向にあります。それゆえ配信を続けるモチベーションを保つのが難しく、次回以降の配信の継続率が下がってしまう事象が観測されていました。

コメントがない配信、喋る内容がわからなくなりがちです。私も経験があります……配信してるのに……無言でゲームしてしまいます……つらい……

視聴者さんと配信者さんの適切なアプリのマッチング(見たい・コメントしたい・配信したい)をすることで配信体験の UX を向上させたいと思いました。

Mirrativ は配信プラットフォームであると共にSNSです。配信者さんと視聴者さん共に Mirrativ のプラットフォーム上で配信を通じたコミュニケーションを通じてわかりあってもらうことを願っております。

ゆえに、配信を続けてもらえる配信者さんを少しでも増やすことを目的として当機能を開発することにしました。

しかしながら、iOS/Android ともに OS の仕様上、バックグラウンドで動いている Mirrativ のプロセスから実際にフォアグラウンドで動いているアプリ情報を取得するのは非常に難しいです。

ですが、配信のキャプチャ画像をクラス分類することである程度の精度が出せそうなため、機械学習による配信中のゲームの自動推定機能を開発するに至りました。

f:id:namagon:20190311191922p:plain
イメージ図

対象タイトル

まずは全ゲーム配信中、約70%を占めるゲームにのみに適用して検証して結果が良ければ対象タイトルを拡大していきます。

仕様検討

画像分類で解く以上アプリ推定の精度が100%になることはまずありえません。それゆえはじめは確からしいアプリが推定された際にプレイ中のゲームは hogehoge ですか? [はい] [いいえ] という通知ダイアログを出してユーザーに選ばせる仕様で想定していました。

ところで、ゲームの内容とは無関係の通知ダイアログが出てきたとしてタップしますか?少なくとも僕はしません

配信者さんから見て自動でアプリが設定されることにネガティブな感情を持つことはほぼ無い上、仮にアプリ設定が間違ったとしても重大な問題につながる可能性は非常に低いと判断したため、アプリ未設定の場合はメッセージを出した上で自動で設定することにしました。

プロトタイプ

現在配信者さんが選択しているアプリと画像から推定されたアプリが異なる場合、slack に推定結果を画像つきで投稿するプロトタイプのbotを*1作りました。

f:id:namagon:20190311235832p:plain
ユーザーが設定したアプリと推定したアプリが違うとき投稿されるチャンネル
f:id:namagon:20190307053943p:plain
沸き立つ社内slack

現状のモデルで精度十分でしたが、1枚あたりの推定処理が遅いという課題を抱えていました。

パフォーマンス要件

アプリ未設定の配信者さんに対し可能な限り早く正確な推定をしたいため、現在放送されている全配信の画面キャプチャを1分ごとに画像認識モデルに通すスケジュールバッチを実装することにしました。

この段階でバッチ処理の単位時間と処理件数が算出できたため、あとは実際に運用するインフラの選定に移れます。

今回、モデルの学習処理には Google Compute Engine の GPU インスタンスを利用しています。

しかし、GPU インスタンスを本番運用するとなると CPU インスタンスと比較して利用料金が非常に高価である上リソース監視にGPUも入れる必要があります。ゲーム推定機能は単位時間あたりの処理件数が膨大な量ではなく、モデルの精度もある程度妥協できるため*2 CPU インスタンスの並列処理で対応可能と判断しました。

本番運用するにあたるモデルアルゴリズムの選定

いくつかのモデルを検証したところ、軽量な MobileNet をベースにしたモデルだと精度・処理速度ともにパフォーマンス要件を満たせる可能性が高いと判断しました。

実際にゲーム自動で設定する対象については Confidence *3 の閾値を高めにすることでアプリ設定の正答率を担保するようにしています。

プロトタイプで採用していた VGG16 のモデルと LeNet-5 のモデルと比較してみました。

モデル 設定対象の割合 正答率*4 1枚あたりの処理時間
VGG16 49.7% 98.5% 0.2 sec
LeNet5 55.4% 93% 0.05 sec
MobileNet 63.3% 98% 0.065 sec

精度と処理時間のバランスが最も取れていた MobileNet ベースのモデルを仮採用

試験用の仕組みにデプロイしたところ教師データに Mirrativ の エモモの画像を学習させていなかったため、ゲームとして誤認識してしまう事象が散見されました。

f:id:namagon:20190312000028p:plain
エモモをゲームと認識してしまうミス、かわいいけどこれではだめ、かわいいけど。

それを解決すべく、ゲーム以外の画像を その他 と分類するモデルを作り、自動設定の対象外としました。

f:id:namagon:20190312000054p:plain
その他クラスと認識されるエモモ、これは正しい。そしてかわいい。

モデル 設定対象の割合 正答率 1枚あたりの処理時間
21クラス MobileNet 81.67% 99.2% 0.066 sec

パフォーマンスをほぼ犠牲にすることなく、モデルの精度が更に良くなったのでこれでいきましょう。

配信してみた

アプリ未設定のまま対象タイトルを配信しているとこんな感じでアプリが自動設定されます。

f:id:namagon:20190311182204p:plain
画面は開発中のものです。

今後の展開

現在試験中の機能ですが、ユーザーさんから頂いたフィードバックや自動設定された配信の数値指標から見えてきた今後の展開などを次回の記事で書こうと思います。

追記

書きました!

tech.mirrativ.stream

We are hiring!

Mirrativ では一緒に開発してくれるエンジニアを募集しています!

体験入社や副業も大歓迎です。お気軽にどうぞ!

www.mirrativ.co.jp

*1:私が join する前に副業メンバーに作っていただきました🙇 Mirrativ では副業メンバーも絶賛募集中です

*2:もちろん高ければ高いほどよい

*3:推定結果の確からしさ

*4:Confidence の閾値を超えている画像を対象とした正答率