mtx2s’s blog

エンジニアリングをエンジニアリングする。

エンジニアリングによるビジネスパフォーマンスチューニング

ソフトウェアプロダクトの機能リリース頻度は益々高まっている。月に何回リリースしたか、いくつの機能をリリースしたか、開発現場はもちろん、ビジネスサイドでも度々話題になる。しかし、開発チームのこの努力と献身は、ビジネスにいったいどれほど影響を与えられているのだろうか。

皮肉なことに、リリースサイクルを高速にすればすほど、開発チームの意識は、機能をリリースすることのみに集中していく。リリース自体がゴールになってしまう。この状態で、開発チームがビジネス視点を持つのは難しいだろう。

そもそも、リリースした機能と売上との関係性を見出すこと自体、難しい。そうであればなおさら、開発チームの関心はビジネスから離れていく。売上との関係性を見出すことなど諦めてしまう。

コスト(原価)との関係性はわかりやすい。製造原価(材料費、労務費、経費)の共有を定期的に経理部門から受けられるマネージャーも多いだろうし、工数管理も行なっているだろう。だから、開発チームが、定量的なコスト削減目標を持って開発に取り組むことは容易だ。

しかし、コスト削減にばかりフォーカスして、良いプロダクトを作れるのだろうか。コスト削減で得られる効果は、最大でも現状のコストをゼロにすることまでだ。売上とは違い、利益に還元できる額に上限がある。そもそも、サービスを維持し、ユーザー体験や売上を向上させるためには、コストも必要なのだ。

これはマネージャーを悩ませるテーマのひとつだ。「このままで良いのだろうか」と、頭の片隅で違和感を感じつつも、目まぐるしく回転し続ける開発とリリースのサイクルの切り盛りに追われ続ける。そうしているうちに、考えること自体を諦めてしまう。

さて、本記事のタイトルには「チューニング」というワードを用いた。それは本記事が、システムパフォーマンスチューニングのアプローチ方法を抽象として、エンジニアリングによるビジネスパフォーマンスチューニング方法を実装しようという試みだからだ。これによりプロダクト開発チームが、リリースした機能を売上に紐付け、それを指標にプロダクトを練り上げることを可能にしたい。そしてこれを、ユーザー体験の向上を追求することによって実現する。

実際のところ、本記事に書いた内容は、個々の方法論として目新しいものではない。しかし、それらに関する知見の多くは、スタートアップやマーケティング、ウェブ担当者向けに発信されたものが多いように感じる。その点で、エンジニアリング組織向けに整理して共有することに意味があるように考えた。私自身、実践できていないことも多くあるので、これを機に取り組んでいこうと思う。

システムパフォーマンスとビジネスパフォーマンス

Notes on Programming in C ロブ・パイクUNIX哲学 - Wikipedia

ルール1: プログラムがどこで時間を消費することになるか知ることはできない。ボトルネックは驚くべき箇所で起こるものである。したがって、どこがボトルネックなのかをはっきりさせるまでは、推測を行ったり、スピードハックをしてはならない。 ルール2: 計測すべし。計測するまでは速度のための調整をしてはならない。コードの一部が残りを圧倒しないのであれば、なおさらである。

システムエンジニアリングには、システムパフォーマンスへの配慮が常につきまとう。その対象はコードの断片から、ネットワークやシステム構成といったアーキテクチャに及ぶ範囲まで様々だ。

言うまでもなく、システム全体のパフォーマンスを決定づけるのは、その制約条件となっているボトルネック要素の性能だ。パフォーマンスチューニングとは、ボトルネック要素の性能を向上させる行為に他ならない。

パフォーマンス向上の必要性が発生すると、我々エンジニアはつい、直感的に問題だと思う箇所や、以前から気になっていた箇所に手を付けてしてしまう。しかしながら、そのチューニングはシステム全体のパフォーマンスにほとんど影響しない。ボトルネック以外の箇所をチューニングしても、ボトルネックが処理の流れをせき止めるからだ。これでは改善に費やした時間が無駄に終わる。まずやるべきことは、ボトルネックを見つけ出すことだ。

では、ボトルネックを解消したら終わりかというと、大抵の場合でそうはならない。ボトルネックを解消し、せき止められていた処理やパケットが勢いよく流れ出すと、その速さや流量についていけない箇所が現れ、新たなボトルネックとして流れをせき止める。そしてまた、ボトルネックをつぶすことに専念することになる。

こうして、次から次へと現れるボトルネックを順に解消していくことで、パフォーマンスを望むレベルにまで引き上げる。パフォーマンスチューニングは、この地道な努力の積み重ねだ。もし、パフォーマンス向上が限界に達したと判断した時は、アーキテクチャごと作り直すこともあるだろう。

ビジネスパフォーマンスチューニングも、原理は同じではないか。プロダクト上のどこでボトルネックが発生しているのかを見つけ出し、機能開発や機能改善を施してパフォーマンスを引き上げる。次のボトルネックを探す。この繰り返しが、ビジネスパフォーマンスを理想とするレベルにまで引き上げる。もし、ビジネスパフォーマンスがチューニングの限界をむかえたら、ビジネスモデルや戦略自体を変更する、と。

具体的にどうすればよいか。それを次の図にある流れに沿って考えていく。

チューニングの手順
チューニングの手順

フローの明確化

ビジネスに影響するユーザー行動フロー

システムパフォーマンス上のボトルネックは、通信経路も含めた処理フローのどこかで発生する。このフローを把握しておかなければ、正確なボトルネックを見つけ出すことはできない。

では、ビジネスにとっての「フロー」とは何だろうか。それは、ビジネスモデルや戦略によって導き出された KGI や KPI に対して、強い影響を与え得る「ユーザー行動フロー」だとは考えられないだろうか。

シンプルな E コマースビジネスを例に、ビジネスにとってのフローを考えてみる。

ビジネスモデルや戦略とユーザー行動フローの関係性

この架空の E コマースでは、専用のスマホアプリでサービスを提供している。こういった自社独自の E コマースサービスは、オンラインモールへの出店とは異なり、自力での集客が必要となる。つまり、アプリダウンロード数を伸ばすために、広告やキャンペーンといったマーケティング活動に大きなコストを割くことになる。

こうしてコストをかけて集めたユーザーだからこそ、サービスを長く、繰り返し利用して欲しい。短期間で利用をやめられるようでは、ユーザーひとり当たりから得られる全購入金額が小さくなり、集客施策にコストを回せなくなってしまう。こういった背景から、ビジネス上の主要な KPI として「CPA」と「LTV」をモニタしている。

CPA(cost per acquisition, 顧客獲得単価) は、顧客一人を獲得するために費やしたマーケティングや営業のコスト(販管費)を言う。

LTV(lifetime value, 顧客生涯価値)は、一人のユーザーが、サービスを利用開始した日から利用しなくなるまでの間に支払ったサービス利用料などの総合計を言う。この LTV が小さいと、集客施策などに向けて CPA を割くことができなくなる。

なお、ここで言う「顧客」とは、商品を購入したユーザーを指している。

LTV を大きくするためには、ユーザーひとり当たりの購入単価、購入回数、利用期間というメトリクスを向上させることになる。今回の E コマースの戦略は、複数回の購入経験を持つ「リピーター」を増やすことで LTV の向上につなげることだ。開発チームのミッションは、それを、ソフトウェアプロダクトのチューニング、つまりは機能開発や機能改善を通して実現すること、となる。

これらのことから、アプリをダウンロードしたユーザーに期待する行動として導き出されたフローは次の通り。

  1. 欲しい商品を見つけ出す
  2. カートにアイテムを追加する
  3. はじめて購入する
  4. リピーターになる

このフローでは、4 の行動によって、ユーザーがリピーターになることを「最終コンバージョン」と言う。また、そこに至るまでの 1 から 3 までのチェックポイント的なユーザー行動を「マイクロコンバージョン」と呼ぶ。

ユーザー行動フローの例
ユーザー行動フローの例

ビジネスパフォーマンスチューニングでは、いくつかのマイクロコンバージョンを経由して最終コンバージョンにつながるこのような経路をフローとし、ユーザーをより効率的に最終コンバージョンさせるために、機能開発や機能改善を通してチューニングする。

ここで、フローの設計は UI に引っ張られすぎないよう注意する。そうしなければ、UI を変更する度にフローを変更することになる。それでは長期的な改善ができない。マイクロコンバージョンは、この E コマースでの例のように、UI より抽象度の高いユーザーシナリオレベルに粒度をあわせるのが良いだろう。

なお、ここで示した E コマースの例では、集客をマーケティング活動に頼る前提としたが、ユーザーが別のユーザーを呼び込むようなバイラル型の機能をサービスが有しているなら、集客効率をプロダクトで改善することも可能だ。このケースでは、「別のユーザーを呼び込む」というユーザー行動を、最終コンバージョンに位置付けることになるだろう。

ボトルネック探索

ユーザー行動フローのプロセスとメトリクス

ボトルネックを見つけるには二段階の手順を踏む。まず、フロー内のどのプロセスに問題があるかを特定する。次にプロセス内のどのポイントがユーザーの流れをせき止めているかを見つけ出す。

プロセス」とは、フロー内の、あるコンバージョンポイントを通過した直後から、次のコンバージョンポイントを通過するまでの経路を指す。「ステージ」や、「ステップ」とも呼ばれる。

ユーザー行動フローのプロセス
ユーザー行動フローのプロセス

では、どのようにして「問題のあるプロセス」を特定するのだろうか。ここで、各プロセスの状態を可視化する主要なメトリクスとして 、「流量」「滞留数」「移行率」の三つが使える。

流量」とは、そのプロセスに到達したユーザーの総数を表す。このメトリクスには、次プロセス以降に遷移したユーザーの数(=次プロセスの流量)も含まれる。従って、上流のプロセスほど流量が大きい。

滞留数」は、プロセスに留まっているユーザーの人数を表す。対象プロセスの流量から、次プロセス以降に遷移したユーザーの人数(=次プロセスの流量)を引いた値に等しい。「滞留期間」をメトリクスとして利用することもある。

移行率」は、対象プロセスから次プロセス以降に遷移したユーザーの人数(=次プロセスの流量)を、対象プロセスの流量で割った結果を、パーセントで表現した値となる。

(※下図内のメトリクス値は適当に記載したものであり、実在の E コマースサービスを参考にした訳でもなく、特に意味はない)

流量・滞留数・移行率
流量・滞留数・移行率

問題のあるプロセスはどこか

問題のあるプロセスを特定する統一的な方法を明言するのは難しい。以下は参考までに。

移行率が最も低いプロセスこそ、優先的に改善すべきプロセスに見えてしまうが、そうとは限らない。プロセス流量が少なければ、移行率が改善したところで得られる効果は薄く、おすすめできない。

そこで注目すべきなのは、プロセスごとの滞留数だろう。他のプロセスと比較して滞留数が比較的大きいプロセスがあるなら、そのプロセス内にボトルネックがある可能性が高い。滞留数が多いプロセスは、流量が多く、かつ移行率が低い。チューニングによる移行率改善によって、大きな効果を見込める。

極端に滞留数の多いプロセスは、複数のプロセスに分割するという方法もある。例えば、「カートに入れる」というマイクロコンバージョンと、「購入する」というマイクロコンバージョンの間に、「購入フォームにアクセスする」と言うマイクロコンバージョンを入れても良い。そうすることで、問題を切り分けやすくなる。ただし先述したように、あまり細分化しすぎると、フローが UI に依存するようになり、UI を変更する度にフローを再構築することになってしまう。細分化するなら、その点の見極めが必要になる。

どのプロセスの滞留数にも大差がないなら、最終コンバージョンを含むプロセスに目星をつける。どのプロセスをチューニングしても効果に大きな差がないなら、最終コンバージョンに至るプロセスを改善する方が結果に直結するからだ。しかし、流量が不十分ならチューニング効果は薄い。それならば、流量の最も大きい最上流プロセスから順にチューニングし、下流プロセスの流量を増やしていくのが良いだろう。

もし、最上流プロセスの流量(=フロー内の全ユーザー数)が少ないなら、そもそも集客力に問題がある。この状態で、開発チームがフローのチューニングに力を注いでも、結果にはつながらない。むしろ、無駄な機能(「feature debt, 機能負債」)を作り込んでしまうかもしれない。十分な流量が得られるまで待つか、集客にフォーカスした開発を進めるなどした方が良いだろう。

このようにして問題のプロセスを特定できたら、プロセス内を精査してボトルネックとなっている箇所を見つけ出す。

ユーザー行動フローの可視化

ここまででわかるように、フローの状態を常にモニタできるよう、可視化しておくと良い。その方法としては、マーケティングでよく使われる「ファネル(funnel)」が適している。そのために必要となるログを、システムにあらかじめ仕込んでおくことも忘れてはいけない。

ファネル
ファネル

ただし、フローの可視化にはひとつ問題がある。

E コマースの例には、「はじめて購入する」というマイクロコンバージョンがあった。このマイクロコンバージョンを含むプロセス 3 の移行率には、一年前にアプリをダウンロードしたユーザーと、今月ダウンロードしたユーザーが混在している。同一プロセスに滞留しているユーザーであったとしても、一年前から滞留しているユーザーに、アプリを最近使い始めたユーザーと同等のモチベーションを期待することはできない。

このように、全数でのフローの分析はノイズが多くなり、チューニングの効果を読み取りにくくする。ここは、ユーザーをアプリダウンロード時期でグループ分けした上でフローを分析するのが良さそうだ。このように、ユーザーを任意のグループに分けて分析する手法を、「コホート分析」と言う。

可視化に向けては、こういった点も考慮した上でログ設計を行う。

チューニング

イデアバックログ

ボトルネックを特定できたら、チューニング方法を考える。開発チームによるチューニングとは、ボトルネックを解消するための機能追加や機能改善のことだ。

どのようにチューニングすべきか、そのアイデアを得るためには、更なる詳細な定量情報や、ユーザからのフィードバックといった定性情報を収集することになるだろう。それをもとに、より効果的なチューニング方法をユーザ視点で考え抜き、ユーザーストーリーエピックとしてバックログに追加する。

E コマースを例に考えてみよう。「はじめて購入する」をマイクロコンバージョンに持つプロセス 3 を問題のプロセスとし、さらに詳細に調査した結果、次プロセスに移行したユーザーの 80% は、本プロセスを開始してから移行するまでの期間が二週間以内であることがわかった。前プロセスであるプロセス 2 によって、欲しい商品をカートに追加するところまでは終わっている。そこから二週間経過しても購入に至らないユーザーのほとんどは、カートを放置したままアプリの利用が止まり、いつまでもプロセスに滞留したままになっているようだった。

更に調査を進めると、こういったユーザーの多くは、購入判断を後回しにしているうちに毎日が忙しくて時間が過ぎ、商品に対する興味が薄れ、そのうち忘れてしまうというのが実態だった。そこで、このプロセスで二週間が経過しても購入に至らないユーザーに対し、自動でリマインドメッセージを出すというアイデアを採用することにした。カートに商品が入ったままとなっていることをユーザーに思い出してもらい、商品購入を後押しする、というものだ。

バックログのアイテムは仮説

注意したいのは、バックログに追加したこういったアイデアは「仮説であり、それを機能化したからといって、必ずしもチューニングの効果を得られるわけではないということだ。

工数と時間をかけて完全な機能を作り上げても、無駄になるかもしれない。だから、バックログのアイデアを実装する時は、そのスコープを必要最小限に留めておく。小さくリリースして仮説検証を行う。これを何度も繰り返しながら、効率性の高いフローを作り上げていく。

ベンチマークテスト

本番環境が仮説検証の場

ビジネスパフォーマンスチューニングにおいてのベンチマークテストとは、仮説として立てたユーザーストーリーを「検証」することだ。そのためには、ユーザーストーリーに基づいて開発した機能を、本番環境にリリースして試してみるしかないだろう。

つまり、「リリース」とは検証の開始を意味する。この検証を経て、仮説が正解だと判断するに至るか、更なる改良が必要になるか、あるいは失敗だと判断してアプリケーションをロールバックするかなどが決まる。

ここで、「リリース」という行為の位置づけが、開発チームの中で変わることとなる。リリースはゴールではなくなり、マイルストンのひとつになるのだ。

リーン開発なら、カンバンのステータスに「検証中」を加えても良いだろう。スクラム開発なら、検証結果を得ることを Done の定義に含めても良い。

スプリットテストによる仮説検証

本番環境での検証時に困ることがひとつある。それは、検証時の計測結果から、対象機能以外の影響を除くことだ。

計測対象となる指標を、リリース前とリリース後で比較しようとしても、日々実施される様々なマーケティングキャンペーンが実績値に大きく影響を及ぼし、正確な比較ができないことも多い。できればこういった影響を排除するか、影響度合いを揃えたい。

その解決策としては、「スプリットテスト」が適している。この手法なら、複数バージョンのアプリケーションを用いて同じ期間にテストを実施するため、機能以外からの指標への影響を概ね揃えることができる。

スプリットテストでは、ユーザーを複数のグループに分け、グループごとに異なるバージョンのアプリケーションを利用することを通し、どのバージョンが最も良い結果を得られるかを計測する。

E コマースの例で言えば、リマインドを出す機能を装備した新しいアプリを利用するユーザーグループ A と、従来のままのアプリを利用するユーザーグループ B に分けて移行率を計測する。ここで、A が利用するバージョンを「バリエーション」、B が利用するバージョンを「コントロール」と呼ぶ。このテスト手法は、A/B テストとも呼ばれる。

スプリットテスト
スプリットテスト

テスト結果の分析

有意差検定による評価

スプリットテストによってコントロールとバリエーションの実績値に差が出たとしても、それをもって結論を導くことはできない。その差は偶然によるものかもしれない。ではどの程度の実績差が出れば、偶然とは言えなくなるのだろうか。どの程度のテストデータが集まれば十分なのだろうか。

スプリットテストの結果を評価する方法としては、「統計的有意差検定」がよく使われる。その検定手法はいくつかあり、どの手法を使えばよいかは、指標の特性や、得られるテストデータのサイズによって変わってくる(参考:「A/Bテストに用いられれる統計的検定手法(ロジック)のまとめ&比較 | RCO Ad-Tech Lab Blog」)。ウェブ関連のコンテキストでよく使われていそうなものは、カイ二乗検定だろう。

検定では、「帰無仮説」の確率が低いと言えれば、「対立仮説」が立証されたと見なせる。ここでは、「コントロールとバリエーションそれぞれの成果には差がない」が帰無仮説であり、その反証となる「コントロールとバリエーションそれぞれの成果には差がある」が対立仮説だ。一般的には、帰無仮説の確率が 5% 以下になれば「確率が低い」と判断する。これが「有意差」であり、この 5% という数値を「有意水準」と呼ぶ。

これらを踏まえ、スプリットテストを実施するにあたっては、まず有意水準を決める。その上で、検証期間を決める。有意水準の設定を低くすればするほど、有意だと結論づけるために必要となる実績値の差もテストデータの数も大きくなる。その分、検証期間も長く必要となるからだ。

スプリットテストによって、コントロールとバリエーションの間に有意差が出たら、検証を終了する。またもし、いつまで経っても有意な差が出ないまま検証期間が過ぎても、そこで検証を終了する。

ネクストアクションの決定

検証結果として、バリエーション側の成果が大きい状態で有意差が出れば、仮説が正しかったと結論づけられる。そうなれば、バリエーションを全ユーザーに適用して、次のボトルネック探索を開始する。

一方、検証期間内に十分に有意な差が出なかった場合や、コントロール側の実績値が大きい場合は、その原因としていくつかの候補が考えられる。

  1. 仮説としてのユーザーストーリーは正しいが、機能への落とし込み方が良くなかった
  2. ボトルネック箇所は正しいが、仮説として立てたユーザーストーリーが間違っていた
  3. ボトルネック箇所を見誤った
  4. 現在の戦略におけるビジネスパフォーマンスが限界に達した

もし、原因が 4 であると判断したなら、戦略やビジネスモデルを見直すことになる。おそらく、ビジネスパフォーマンスの限界は開発チームより先にビジネスチームで気付く。事業戦略、マーケティング戦略、プロダクト戦略が変わることになるだろう。開発チームは、それに合わせユーザー行動フローを作り直す。リーン・スタートアップ方式ではこれを、「ピボット」と呼ぶ。

最後に

本記事では、架空の E コマースビジネスを例に、コンシューマー向けサービスを想定して話を進めてきた。

コンシューマー向け(toC)ではなく、ビジネス向け(toB)サービスを扱っているケースでは、ビジネスパフォーマンスを大きく左右するのは、機能開発や機能改善より営業活動であるように感じるかもしれない。ビジネス向けサービスでは、業務でプロダクトを利用するユーザー自体の意見が、必ずしも利用契約の締結に繋がるわけではない。多くの場合、決裁者はユーザーではなくその上司であり、意思決定プロセスが、コンシューマー向けサービスに比べて複雑だ。そこに切り込んで、契約を獲得するのが営業チームであり、機能を強化してユーザー体験を上げても、契約には繋がりにくい。だから開発チームにできることは少ないように感じてしまう。

しかし、実際にはそうでもない。営業の武器になるような機能開発もあるだろうし、契約後に継続率を高めて LTV を向上させるような機能開発もある。重要なのは、プロダクト開発が、ビジネスモデルや戦略と連動していることだ。

この記事は「リーン・スタートアップ」の方法論を下地に、それを既存プロダクトの機能開発業務に応用したものだ。リーン・スタートアップと言えば、「MVP」や「BuildMesureLearn」ばかりがフィーチャーされがちだが、「成長のエンジン」や「革新会計」という考え方を押さえておかなければ、期待する結果は得られないだろう。本記事では、ビジネスモデルからユーザー行動フローを定義し、それを拠り所としてチューニングを進めることで、それらの考え方を中心部に取り込んだ。

リーン・スタートアップも、我々エンジニアにも馴染みの深い「リーン開発」や「アジャイル開発」と同様に、「トヨタ生産方式」を一般化した「リーン生産方式」を背景に持つ。その本質は、「無駄をなくし、価値に集中する」ことだろう。