この記事はNikkei Advent Calendar 2022の 25 日目の記事です。
はじめに
Advent Calendar 2022、最終日を担当する佐野と申します。
私はプラットフォーム推進室・データインテリジェンスグループ(通称 DIG)で管理職をしつつ、計測 SDK の開発や計測実装、ちょっとした分析や開発にも携わっています。 DIG は日経グループの様々なサービスが利用するデータに関わるハード面とソフト面のケイパビリティを持っています。データ基盤の開発・運用を担うデータエンジニア達「Atlas チーム」と、データ基盤を活かしてデータ分析や予測を担うデータアナリスト・データサイエンティストからなる「Insight チーム」に分かれています。
Atlas とは、日経で内製しているリアルタイムデータ基盤で、特にサービスの利用状況や記事の読まれ方を分析するためのデータ収集と、データをレコメンデーションやマーケ施策で活用するためのハブとしての機能を持った基盤です。
ちょうどチームメンバーの萩原さんが Atlas 開発チームに join して半年後に自走するまでの取り組み という記事を投稿していましたね。
この記事では、データアナリストを主な対象として開催したフロントエンド技術を学ぶハンズオン研修について、その意義・内容・成果について紹介します。 デジタルサービスを運営する者として、お客様のサービス利用実態の理解や、分析対象に対するアカウンタビリティの観点で、フロントエンド技術の知識理解が重要ですよ、ということを伝えたいと思っています。
「フロントエンドハンズオン」とは
データ分析におけるフロントエンド技術の重要性
デジタルサービスを運営する私達にとって、お客様、プロダクトであるアプリケーションやコンテンツ、そしてその接触によって生じる顧客体験について、分析と改善を重ねていくことが重要です。 分析するには当然アプリケーションの構造がどうなっているのか、そこでお客様はどんなインタラクションをするのか、それらはどう数値化できるのかを理解していなければなりません。
より正確に、より深く分析しようとすると、自ずとフロントエンド技術の知識理解が必要不可欠となります。
例えば、ウェブサービスの定量評価というと真っ先に想起される指標が「ページビュー数」ではないでしょうか。しかし、一つ一つのページビューは等価ではありません。
1 秒で離脱したページビューと、10 分かけて熟読したページビューとでは、後者の方が「興味をひいた」「価値を提供した」可能性が高いはずで、この違いを定量評価するためにはページビューよりも細かな情報が必要です。
そのため、電子版上でのスクロール深度、滞在時間、読了、動画再生の heartbeat… など多種多様なイベント(インタラクション)を Atlas を用いて計測しています。
また、ボットと人間でも 1 ページビューの価値の捉え方は異なります。読者を知ろうとするとき、ボットからのアクセスは除外しなければ正しい数字ではないように思いますし、広告ビジネスでもボットを適切に除去しなければアドフラウドのような問題に繋がります。一方で SEO 担当者の視点ではボットのアクセスは重要な指標になり得ます。一概に排除すべきではなく、役割に応じて 1 つのページビューの重みが変わる、とも言えるのです。
私達 DIG のデータアナリストには「サービスがどう使われているか」を細かく分解して捉える視点と、それを評価できるよう計測に落とし込むスキルが必要であることは明らかです。 さらに、レポートや分析結果をプロダクトオーナー、開発者、マーケ担当… といった「データの消費者」に正しく伝えるために、データの由来や定義について説明できる必要があります。
「○○のツールから得たデータです」では十分に説明できていないのです。データガバナンスの点でも、計測の時点から理解・介入できることを目指して研修を重ねています。
加えて、Atlas のデータは高速処理され、計測の次の瞬間には数千の変数を持つログデータとして利用可能になっています。
このデータは分析に用いるだけでなく、電子版のレコメンデーションや記事ランキングに供給されたり、CRM やマーケティングのシステムに連携されます。 リアルタイム性の高いデータを、Single Source of Truth のポリシーのもと実現するためにも、信頼できる計測は日経のデジタルサービス全体で重要なテーマとなっています。
ハンズオン研修の狙い
この研修の目的は主にデータアナリストがフロントエンド技術の理解を深め、
- 扱っているデータの性質を把握し、集計の効率を高める
- データを受け手に正しく説明できる
- 必要だが不足しているデータに気付き計測実装に関与できる
といったことを可能にするために実施しました。
特に、DIG はチームを急拡大しているフェーズであるため、ビギナーもいれば、「”何となく知っている” が ”腹落ちとまでは言えない”」メンバーもいます。
そんな中で、データ活用人材に求められる「ビジネス力」「データサイエンス力」「データエンジニアリング力」(※)と、大前提となる IT リテラシーを身につける機会として研修を組み立てました。
※ データ活用人材に求められるスキル:一般社団法人データサイエンティスト協会が提唱している 3 つのスキルを参考
ハンズオン研修の内容
DIG には様々な研修プログラムがありますが、「フロントエンドハンズオン」と銘打って企画した今回は、ウェブの原理原則とウェブサイトの計測にフォーカスしました。
(色々なフレームワークがありますが)データドリブンな意思決定・施策の流れを 6 つのステップで表してみました。
デジタルサービスの分析としては、「準備・収集」のところが計測ツールの実装を含むステップとなり、ここが正しく行われなければ 4 つめの「分析」ステップ以降が上手くいきません。 この図の後ろ半分は SQL や Python、あるいは R の技術、そしてプレゼンテーションのスキルが求められます。しかし後半の全ては前半の 3 つのステップに依存しています。
そこで、このハンズオンではウェブサイトの計測に徹底的に取り組むということで、以下の通り 6 日間のプログラムを組み立てました。
Day | ねらい | やること |
---|---|---|
Day0 | 参加者全員の環境を揃える | brewでnode.jsの環境構築、ターミナル操作の復習する |
Day1 | ブラウザがページを表示するまでの仕組みを理解する | DNSやHTTPのやりとりを詳しく見る、課題提出用リポジトリを準備する |
Day2 | HTMLとCSSを学ぶ | 手元でhttps対応のWebサーバーを立ち上げ、数ページのサイトを開設する |
Day3 | クライアントサイドのJavaScriptを学ぶ | 簡単なスクリプトを動かしてみる、ビーコンを送信してみる |
Day4 | サーバーサイドの処理を学ぶ | HTTP HeaderでのCookie制御、ビーコンをファイルに書き込む、ログを集計する |
Day5 | タグマネージャーを使う | Firebase Hostingでサイトを公開する、Google TagManagerを導入する |
Day6 | Atlasでの計測を実践する | Atlas Tracking JSを導入し、様々なカスタマイズと計測結果の集計を試す |
講師は私自身が務め、教材の準備やセッションの録画、フォローアップ資料の作成など… 受講者の様子を見ながらリアルタイムにカスタマイズしました。
進め方
全体の日数が 6 日であること、予習と復習の課題が課されていること、議論重視であること… どこかのビジネススクールのようだと勘付いた方もいるかも知れませんね。
ハンズオンの各 Day に対して以下の課題を設定しました:
- 予習用の Udemy 動画視聴(日経は Udemy for Business を導入しています)
- 当日は内職せずハンズオンに全集中する
- 復習として、録画やチャットログなど参照しながら、腹落ちしていないことを調べる・質問する
- ハンズオンの週の金曜朝までに指定の課題の回答を指定リポジトリに pull request の形で提出する
ハンズオンは月曜または火曜に 2 時間〜3 時間程度で開催し、その週の金曜朝までに課題提出なので、猶予期間がありません。 記憶がクリアなうちに取り組み反復することを求めました。
研修の参加者
当初は DIG に新たに加わったメンバー向け、とりわけデータアナリストをターゲットにしていましたが、結局はデータエンジニアやデータサイエンティストも含め 10 名ほどが参加しました。 振り返りにも出てきますが、熟練のエンジニアでも学ぶことはあると気付かされる機会になりました。
今後は DIG の外にも広げて行きたいと考えています。
実際の研修内容をかいつまんでご紹介します
ここでは、どんなことを試したか、一部を紹介します。
1. httpsでアクセスできるWebサーバーを用意する(全員の環境を揃える)
ターミナルでコマンドを打って、必要なパッケージをインストールしたり、https 用に証明書と鍵を生成したりしました。
# Expressを使ったWebサーバーを組み立てる準備
npm init
npm install express https
# https化の準備
mkdir keys #鍵を置くディレクトリを作成
openssl genrsa 2048 > keys/server.key #RSA暗号方式の秘密鍵を生成
openssl req -new -key keys/server.key > keys/server.csr # 証明書署名要求(CSR)を生成
openssl x509 -in keys/server.csr -days 1825 -req -signkey keys/server.key > keys/server.crt #先ほど作成した秘密鍵を使い自己署名した証明書を作成
自分で簡易的に作った証明書なので、Chrome でアクセスしたときに警告が表示されます。
そこで thisisunsafe
(これは安全ではないよ)とタイプすることで解除できることが意外と知られていないと気付きました。
2. ブラウザからアクセスできるウェブページをホスティングしてみる
Express を用いた Web サーバーを書き、静的ファイルの公開やビーコンの受け取りを実装しました。 初学者向けに極力シンプルにし、ローカル環境で動かすためだけに組み立てていますので、もちろんこのサーバーを外部公開したりはしません。
index.js
const fs = require("fs");
const path = require("path");
const express = require("express");
const https = require("https");
const app = express();
// Generate HTTPS Server
const server = https.createServer(
{
key: fs.readFileSync("./keys/server.key"),
cert: fs.readFileSync("./keys/server.crt"),
},
app
);
// Public Dir
app.use(express.static(path.join(__dirname, '../client')));
// /stats 宛のリクエストに応答する
app.post('/stats', (req, res) => {
console.log(req.query);
res.sendStatus(204);
});
// Start listening
server.listen(443);
3. ページビュー数やクリック数を計測する仕組みを組み立てる
ここが私達が特に力を入れた部分です。 クライアントサイドで操作に応じてビーコンを送り、サーバーサイドはビーコンの受け取りからファイルへのログ出力、同時にサーバーサイド Cookie の制御を行う処理を実装しました。
クライアントサイド
まずは任意のページ上からビーコンを送る関数を作り、各 HTML ページに組み込みました。
Atlas でも利用している sendBeacon
API を使っています。
analytics.js
function trackPage(pageName){
// エンドポイント
var endpoint = 'https://localhost/ingest';
// 計測変数
var url = document.location;
var referrer = document.referrer;
var userAgent = navigator.userAgent;
// ビーコンのURLを生成
var beaconUrl = endpoint
+ '?url=' + encodeURIComponent(url)
+ '&referrer=' + encodeURIComponent(referrer)
+ '&user_agent=' + encodeURIComponent(userAgent)
+ '&page_name=' + encodeURIComponent(pageName);
// ビーコンを送信
navigator.sendBeacon(beaconUrl);
}
index.html
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8" />
<title>トップ</title>
</head>
<body>
<div>
<h1>トップ</h1>
</div>
<div>
<p>
hoge
</p>
</div>
<!-- 計測 -->
<script src="js/analytics.js"></script>
<script>
trackPage('view', 'page', 'トップページ');
</script>
</body>
</html>
サーバーサイド
サーバーサイド側では、ビーコンを受け取るパスにログのファイル書き込み処理を追加しました。
また、 browserId
Cookie が無ければ UUIDv4 でユニークな ID を生成してセット、既に存在すればその値を採用、といったデバイス識別の原理も再現しました。
index.js
const fs = require("fs");
const path = require("path");
const express = require("express");
const https = require("https");
const app = express();
// Cookie処理とUUIDライブラリ
const cookie = require('cookie-parser');
const uuid = require("uuid");
// HTTPSサーバーを生成
const server = https.createServer(
{
key: fs.readFileSync("./keys/server.key"),
cert: fs.readFileSync("./keys/server.crt"),
},
app
);
// Cookie処理を発動
app.use(cookie());
// 公開ディレクトリを指定
app.use(express.static(path.join(__dirname, '../client')));
/* ログの書き込み周り */
// 出力先を指定
const outpuFile = `${__dirname}/log/access_log.tsv`
// TSVのヘッダーを定義
const tsvHeader = "timestamp" + "\t"
+ "browser_id" + "\t"
+ "url" + "\t"
+ "referrer" + "\t"
+ "user_agent" + "\t"
+ "page_name" + "\r";
// ヘッダー付きの空TSVを作成
fs.writeFile(outpuFile, tsvHeader, (e) => {
if (e) {
throw e;
}
});
// ログを書き込む関数
const logging = (browserId, req) => {
// 書き込む変数を処理
const url = decodeURIComponent(req.query.url);
const referrer = decodeURIComponent(req.query.referrer);
const userAgent = decodeURIComponent(req.query.user_agent);
const pageName = decodeURIComponent(req.query.page_name);
// TSVの1行
tsvRow = String(Date.now()) + "\t"
+ String(browserId || "") + "\t"
+ String(url || "") + "\t"
+ String(referrer || "") + "\t"
+ String(userAgent || "") + "\t"
+ String(pageName || "") + "\r";
// ファイルに追記
fs.appendFile(outpuFile, tsvRow, (e) => {
if (e) {
throw e;
}
});
return;
}
// /stats 宛のリクエストに応答する
app.post('/ingest', (req, res) => {
// ブラウザーID周りの処理
let browserId = '';
if(req.cookies.browserId){
browserId = req.cookies.browserId;
}else{
browserId = String(uuid.v4());
res.cookie(
'browserId',
browserId,
{
maxAge: 60 * 60 * 24 * 365 * 1000,
httpOnly: true,
secure: true,
sameSite: 'Lax'
}
);
}
// コンソール出力
console.log(req.query);
// ログ収集
logging(browserId, req);
res.sendStatus(204);
});
// ポート443をリッスン開始
server.listen(443);
動かしてみる
手元で index.js
を実行しサーバーを立ち上げます。それからブラウザで https://localhost/
を開きます。
index.html
が読み込まれ、そこから analytics.js
が読み込まれ、 trackPage()
が発火しました。
コンソールには受け取った payload が出力されました。
4. 様々なCookieについて理解する
昨今話題になる「サードパーティ Cookie」を正しく説明できますか? ハンズオンでは何をもってサードパーティなのか、を実際にホスト名を変えて試しました。
また、Safari のプライバシー機能「Intelligent Tracking Prevention (ITP)」によって「クライアントサイド Cookie の有効期限が短縮される」ことも手元で再現して学びました。
Cookie の永続性の点で、サーバーサイドのファーストパーティ Cookie がいかに重要か、ビジネスモデル(特にコンバージョン分析ではリードタイム)と Cookie 有効期限が密接に関わる課題であることなど、議論を重ねました。
このテーマはデジタルマーケティングに携わる人達の間ではよく質問される一方で、実装を経験して挙動を明確に説明できる人が少ないとも思います。 私としては、デジタルサービスを多数運営する弊社において誰もが知るべき基礎知識だと考えています。
5. クライアントサイド vs サーバーサイド を試しながら理解する
クライアントサイドで JavaScript を動かす課題の中で、「電卓を作ってみよう」というものがありました。
こんな感じの電卓です。
狙いとしては、ボタンの押下を検知して処理を発動する、所謂 EventListener を知るための課題だったのですが… 電卓はメーカーによって挙動が違う、C と AC、演算子とイコールなど、押された後の処理がとても複雑でした。
さらに JavaScript あるあるで、浮動小数点問題があり、「思った計算結果にならない」と悩まされる人が続出… 予期せずコンピュータの原理にディープダイブする課題となりました。
その延長で、サーバーサイドの処理とクライアントサイドの処理についても議論を重ねました。
例えば足し算を処理するとき、どちらでも同じように計算して結果を示すことはできますよね。 しかし、サーバーサイドでは通信が必要であること、クライアントサイドでは計算ロジックがユーザー側に露出することなど、理解を深めました。
6. ウェブページにおける「エレメント」と「イベント」を理解する
「Catch Me If You Can」という、レオナルド・ディカプリオとトム・ハンクスが出演している映画をご存知ですか?
ほとんど関係ないのでご存知無くても支障ありません。画面に表示されている「●」をマウスカーソルでクリックする、「●」はカーソルが近付くと逃げ回る、というゲームを使って、ページ上の要素(エレメント)とそこで発生するイベントについて学びました。
ここでは、EventListener によって mouseMove
イベントから「自身とカーソルの距離を測り、一定の範囲にカーソルが近付いたら逃げる」処理が動いています。
一応、スロットリング処理をしているため、超高速にマウスカーソルを操作すればクリックできるものの、普通に操作した場合はクリックできないようになっています。
そして、解法として「●」の ID を見つけ、この要素に対してクリックイベントを発火させるスクリプトを書けばよい、逆にいうとマウスカーソルを使わずともクリックできる、という説明をしました。
つまり…
const dicaprio = document.getElementById('dicaprio');
const tomhanks = new Event('click');
dicaprio.dispatchEvent(tomhanks);
のようなコードを実行することで、得点が得られるわけです。 カーソルを追う動体視力もマウス操作の高速さ・正確さのための筋力も必要なく、ウェブ技術の知識で解決できますね。(高速さ・正確さはデータ基盤には求めます)
この経験を通じて、クリック計測やスクロール深度の計測の仕組みを理解してもらえたように思います。
7. 日経で内製しているリアルタイムデータ基盤「Atlas」の実装を実践する
そして最後はもちろん、日経が内製しているリアルタイムデータ基盤 Atlas の計測 SDK である Atlas Tracking JS を Google TagManager から導入するという、実務さながらの実装も経験しました。
研修を終えて
ということで、原理原則を学び、コーディングを通じて手元で再現し、日々分析しているデータがどのように計測されているか理解を深めるハンズオン、6 日間を終えました。
振り返りアンケート
ハンズオンを終えて、アンケートと KPT で振り返りました。 いくつかコメントを紹介します。
「なぜ計測実装が分析業務において重要なのか?」
- garbage in garbage out である、正しいデータでなければ正しい分析結果は得られない
- どのようにサービス利用の行動がデータ化されるか理解することで、数字の意味を丁寧に説明でき、深い洞察も得られる
- データが集められなければ分析もできない、集め方を知り、必要に応じて直せることも重要
「デジタルサービスの分析に『絶対に必要』なスキルは何か?」
- 「問う」スキル
- データの性質を知り、必要に応じて適切に処理できる
- デジタルサービスのドメイン知識
- 新しい技術や関連技術をキャッチアップし続ける姿勢
- 当たり前を過信しない態度、疑うスキル
- 自ら手を動かす
実務への応用
ハンズオンを終えて間もなく、新サービスのローンチや既存サービスの計測実装改良の機会がありました。 そこではハンズオンでの学びを活かし、アナリスト 3 名がそれぞれ計測実装に携わることができました。
おわりに
自社サービスの関連技術はみな理解すると良さそう
ハンズオンを通じて改めて実感できたこととして、自社が採用している技術や、デジタルサービスを展開するのであればその周辺技術について、誰もが「ある程度」は知っているべき、ということでした。 「自分はエンジニアじゃないから」と敬遠せず、まずは触れてみることで実感がわき、実感がわくことで更に調べ学ぶことができるのではないでしょうか。 今回はデータアナリスト向けに開催しましたが、マーケ担当や管理職でも知っていたら業務効率上がるだろうな、と思うことが多々あります。コミュニケーションコストの削減にも寄与すると思います。
学び続けることが大切
データエンジニアも参加したハンズオンとなりましたが、「ITP の挙動を見たのは初めて」「Chrome のセキュリティ警告が thisisunsafe
で通過できると初めて知った」といった声がありました。
端から見ると十分に精通した人であっても、本人としては新たな発見や学びはあるようでした。
広義なマーケティング・マーケティングミックスの考え方と、デジタルサービスを構成する各種技術、そしてデータ収集から分析のスキル… これらを併せ持った人材はあまり多くない印象です。
研修やナレッジシェアを通じてお互いに学び合い、スキルの組み合わせによってユニークな活躍の仕方が発見できる、新たな強みを身につけられるだろうな、と思います。
最終回ということで…
この記事で紹介したチーム内の取り組みに留まらず、日経では部署横断で学びや交流の機会を作り、互いに学び合っています。
その学びの先には、私達自身のレベルアップによってアプリケーション、コンテンツ、UI/UX をアップデートし続けより便利なサービスを作り、 会社のミッションである 「質の高い報道とサービスで 読者・顧客の判断を助け 世界で最も公正で信頼されるメディアになる」 を体現していきたいという思いがあります。 そして、日経を愛用されているお客様一人一人とともに、より自由で豊かな世界のために歩んで参りたいと思います。
2022 年も残すところ僅か、本年も大変お世話になりました。
どうぞよいお年をお迎えください。
2023 年もよろしくお願い致します。