日本経済新聞社のAdvent Calendarの11日目の記事です。
こんにちは。日本経済新聞社 データビジュアルセンター 戦略コンテンツグループの中川です。
戦略コンテンツグループは、日経ビジュアルデータと呼ばれる、ニュースをよりわかりやすく解説するためによりビジュアルな表現で記事を作成しています。その中で、エンジニアとして、コンテンツ作成だけではなく、業務改善の仕組みづくりを行ったり、記事データからSNS戦略を考えたり、様々な表現を記事で使えるようにアプリケーションを作ったりしています。
課題
日本経済新聞社では、日々報道機関としてニュースを配信しています。その中でも定期的にデータを更新するページがあります。今年は特に、ワクチン接種がどの程度進んでいるのか、感染者数はどれくらいかなど毎日の状況を知りたいニーズに応えるデータがありました。

チャートで見る日本の接種状況 コロナワクチン では、厚生労働省と首相官邸、内閣官房 情報通信技術(IT)総合戦略室の発表を元にデータを集計し記事として出しています。 特に人の健康や生命に関わる大事な情報であるため、データの間違いや表示の間違いは許されません。
ページの開発方法
この定期的に更新されるコンテンツの作り方は、下記のように役割分担が明確に決まっています。
-
記者チーム
- 表示されるデータの収集や集計をスプレッドシート上で行う
- データの内容の確認・本番反映
- 最終的なリリース判断と責任
-
エンジニア、デザイナーチーム
- 定期更新コンテンツページの開発、改修

たとえば、記者側で正しいデータに整形して、スプレッドシート上で確認していたとしても、実際にWebページ上で正しく更新されているかは、いちいちページにアクセスして見ないとわからないという状態でした。
アクセスしてページを見ても、どこが前回と異なる値なのか、何がどう異なるのか差分がわからない状態です。

スプレッドシートと記事ページを見比べたり、変更前と変更後のキャプチャをそれぞれ撮ってクイックルックでカチカチ切り替えて人力差分チェックをしたりで時間がかかってしまいます。
解決策
この状態を聞き、ビジュアルリグレッションテストのように、何が画面に変更があればその差分をわかりやすく並べ表示することで、それが意図された変更なのかが誰でも判別することができる状態を目指せるのではないかと考えました。
考えた要件
以上の状態から、考えた要件は下記となりました。
- 記者チーム側がデータを更新するときに、前の状態と今の状態とその差分が表示されると良い
- 記者チームやディレクターやエンジニアやデザイナー職種問わず、誰もがその差分を確認することができる
- 連絡手段にSlackを利用しているので、その結果がSlackにまとめられるとよい
ビジュアルリグレッションテストとは
改修前後のスクリーンショットを撮影し、その差分を比較検証するためのテストです。
検討したツール
以前、プロモーションチームに所属していたときは、reg-suitを使ってLPのビジュアルリグレッションテストを導入したことがありました。
reg-suitの紹介
reg-suitを簡単に説明すると、GitHubとCircleCIを用いて、PRごとに差分を比較して表示する便利ツールです。

流れとしては、GitHubにpushすると、CircleCI上でPuppeteerを動かし、スクリーンショットを撮影し指定したフォルダに収めます。そのフォルダをreg-suitで指定すると、reg-suit側で指定したS3に、静的サイトとしてアップロードされます。 それが完了すると、GitHubのコメントに通知が飛びます。
Puppeteerで、スクリーンショットを撮影するコードは自分で書く必要はありますが、まさしく、これが欲しかった!がまとまったツールです。

通知に関しても、どれくらいのページが変更されたのかを見やすくしてくれます。diffがなければ、diffはないとコメントが自動で変更されます。この変更を受け入れるかどうかは、人間の目で確認しないとマージできないというような制御も可能です。

this reportを押すと、このように指定したS3にレポートが生成されます。

差分の見せ方に関しても5パターン用意されています。

このコンテンツでreg-suitを使えない事情
しかし、こんなに便利なreg-suitですが、このプロジェクトでは利用できませんでした。
このページは、前項でも記述したとおり、2つのチームの成果物から成り立ちます。 一つはGitHubで管理しているリソース、もう一つは記者チームがチェックしているスプレッドシートのデータです。

このデータ自体は記者チームが責任を持って管理しています。GitHubやCIを通さず、記者チームの判断で反映できるような仕組みを採用しています。

reg-suitでは、GitHubで管理しているリソースの範囲内であれば、スクリーンショットを取得して差分を比較することはできますが、本番環境に反映されるデータ自体は反映されません。 本当に差分を比較したいのは、本番環境で表示されているものと、過去表示されたものです。

また、レポートの通知自体もGitHubのアカウントを持っていないと確認できず記者チームにとっては負担になる。差分をさっと見たいのにクリック数が多いなどの要件に対する不備もありました。よって、reg-suitでは実現できないという判断をしました。 こうなると残された手段は、自作するしかありません。
差分を検出して、Slackに投下するしくみ
利用したツールやライブラリ類など
- CircleCI
- Python3
- スクリーンショット撮影:selenium :webdriver-manager
- S3にアップロード :Boto3 :python-dotenv
- 画像加工: opencv-python: NumPy
- Slack通知: Python Slack SDK
1.実行方法を決める
記者チームが、データの更新を行った後にすぐに差分を撮影して、自動で投稿するのがベストではありますが、時間がかかりそうでした。今回は、早めにプロトタイプを作って便利か検証したかったので、データの整形が終わり本番反映される時間帯の後である毎日17時頃に、CirlceCIで定期実行するように設定しました。
2.比較画像を用意する
CircleCI上でブラウザをheadlessモード(バックグラウンドで動くモード)で立ち上げてページを表示し、スクリーンショットを取ります。
次に、S3にアップロードしてある、前回変更時に撮影した画像をダウンロードしておきます。
3.画像の高さを揃えて、比較や加工しやすくする
改修作業がはいると大幅にページの高さが変わる可能性があります。そのページの高さの変更に備えて、現在のページのスクショと過去のページのスクショの高さを揃えるようにOpenCVで足りない高さ分白画像を追加します。

4.画像の差分を検出するための準備をする
OpenCVで画像の差分を比較し、差分マスクを作成します。

差分マスクだけだと、何もわからないので、画像を暗くしてマスクと重ね差分が明確になるように合成します。

5.画像の差分を検出し、差分があれば作成したスクリーンショットをS3にアップロードする
作成したマスク画像から、白色ピクセル数を算出し、白色の部分が全体のどれくらいの割合を占めているのかを計算します。計算式は 白色ピクセル数/画面ピクセル数 です。今回はなにか少しでも変化があれば変更だとみなしたため、 白色ピクセル数/画面ピクセル数>0 であれば変更として検知しました。

変更を検知しなかった場合は、ここで処理を終了します。 変更を検知した場合は、S3に今回撮影した画像をアップロードし、次回の検出で用いるようにします。
6.Slack投稿用に画像を合成する
変更を検知した場合、Slack投稿用に変化後、変化前、差分の3種類の画像を並べて合成します。ここでまとめた理由はSlackで画像をクリックしたときに、一画面でまとめて見ることができるようにするためです。

7.Slackに投稿する
最後に、files.uploadAPIでSlackに画像とともに通知します。 Slackには下記のように、投稿する事ができました。

この画像をクリックすると、左側から「変更後」「変更前」「差分」を一覧で見ることができるようになりました。 Slackからワンクリックで、差分の変更を見られるようになり、reg-suitよりも少ない手数で目的を達成することができます。

導入後の声
- 記者の方からのコメントとしては、「便利な仕組みをありがとうございます」という声をいただきました。
- ディレクターやデザイナーからのコメントとしては「明らかにおかしい箇所がないか簡単に判別できるのはありがたいです。
特にデザイナーの視点からだと、データの桁数によってレイアウトが変わる要素があるので、意図していないレイアウトになっていないかが一目で分かるのが良いです」でした。
終わりに
今回作成したのはプロトタイプでした。今後良くするためにさらなる改善として、下記を認識しています。
- 現状CircleCIで17時頃、差分検知を実行している。本当は記者チームが、データの更新を行った後にすぐに差分を撮影しSlackに投稿したほうがよい。このとき、ボタンを押した時にリクエストを送り、Lambdaなどで差分の検知、画像の合成、Slackの投稿が行えると更によい改善ができる。
- 現状ChromeのPC画面サイズしかスクリーンショットを取得して差分検知をしていない。別のブラウザやモバイルサイズなどいろいろな画面パターンで検証できたほうがさらに安心感が高まる。
- コンテンツ内の上部の文章が変更されて、行数が変わってしまうと玉突き的にレイアウトがすべて下にずれたと検出されるという場合がある。現状は一番上の位置をあわせて比較しているためそういう現象が起きてしまう。グラフの画像の検出に特化して、グラフが描画されているクラスに絞ってスクリーンショットを撮影して比較するという手法を使うと、検出の精度が上がりさらに便利になる。
戦略コンテンツグループは記者、デザイナー、エンジニアと3つの職種が協力しながらコンテンツを作成している社内では珍しいチームです。こんなに職種が異なることも珍しいために、実は困っている、こんな業務をしているのだが時間がかかっているというのを伝達しにくい場合があると感じました。
今何に困っているのか、どうなったら便利なのかを聞いても、それぞれの想像の範囲内しか返答ができないことを感じます。記者チームにまさかそんなに便利なことができるなんてと言われることがあります。話してみるともっと良い方法や、仕組みづくりができるのではないかという提案ができることがわかりました。
想像力を働かせながらこうなったら喜んでくれるかな?と考えながら、プロトタイプを作り、様子をみて会話をして更に改善していく喜びがありました。
今後もチーム全体の力を向上させるために、エンジニアとして業務改善の仕組みづくりに貢献していきたいと考えています。
明日は12日目、山崎一樹さんによる「Anthos Service Mesh でサービスメッシュ運用を楽にする」です。お楽しみに!