Data Visualization Japan Meetup 2020(2020年12月28・29日開催)における、小副川 健さん(株式会社ユーザベース/Code for Japan)の講演です。「東京都新型コロナウイルス感染症対策サイト」の初期開発に携わった立場から、技術選定と開発コミュニティの運営を振り返ります。
株式会社ユーザベース、および Code for Japan の小副川が発表させていただきます。よろしくお願いいたします。
タイトルは「東京都新型コロナウイルス感染症対策サイトの開発に携わった話」です。今回のミートアップのテーマでもある「話題になった可視化コンテンツ」ということでキャスティングいただいたのかなと思いますが、私は特に初期にかなり深く携わっていたので、その頃に何を考えながらサイトを作っていたか、というお話ができるといいなと思っております。
**先にネタバラシしてしまうと、可視化のコンテンツとしては全然特別なものではありません。**可視化の研究レベルの話や技術的に高度な話を期待されると「すみません」という感じになってしまうのですが、可視化をして人に情報を伝えるという、可視化のベーシックな機能の部分については果たせていた面もあるのかなと思い、その軸でまとめてみました。
ただ、組み立ててみるとあまり可視化だけの話にはならず、どちらかというとシビックテック——データや ICT を使って地域課題を解決していく活動——の色が強い話になります。
自己紹介
普段はユーザベースという、「経済情報で、世界を変える」というミッションを持った会社にいます。BtoB SaaS の事業で、企業の公開情報を分かりやすく整理してお客様にお届けする——そういうサービスの仕事で、データサイエンティストをしております。普段は自然言語処理で機械学習を使ったようなことをやっています。
それとは全く別に、Code for Japan のエンジニアとして、本業が終わった後や土日にシビックテックと呼ばれる活動をしています。
ユーザベースではフェローエンジニアという立場でもあります。CTO のように経営面へのコミットを強く求められる立場以外で、エンジニアとしてキャリアパスを作るためのものです。日々ひたすらコードを書いていますし、Code for Japan でもひたすらコードを書いています。
シビックテックとは
ざっくり言うと、ICT を使って地域の課題を解決する、世界的なムーブメントのことです。
Code for America が一番の本場のようなところですが、最近は台湾でオードリー・タン デジタル担当大臣が大活躍されていて、g0v(ガブゼロ) という台湾のシビックテックコミュニティもかなり有名になってきました。
台湾の g0v の例のように、マスクの在庫を可視化してオープンデータとして提供することで、在庫量をチェックできるアプリケーションが市民の手によって生まれる——そういった活動がシビックテックなのかなと思っています。
日本でも Code for Japan という団体があり、Code for All という世界的なシビックテックのネットワークに加盟して、他国の団体と交流したり、国内のブリゲードと呼ばれる特定地域に根ざした団体を支援したりしています。
ビジョンとして「共に考え、共につくる」を掲げ、日本の地域課題を解決することを目指すコミュニティです。
なお私自身は一般社団法人の構成員というわけではなく、たまにプロジェクトに業務委託のエンジニアとして入る、といった関係です。ちゃんとした所属として名乗ると誤解を招くかもしれないのですが、事務局長の了解はもらっていて、Code for Japan でエンジニアをやっているということで。
中の人はエンジニアが多いとはいえそれでも20%くらいで、それ以外は公務員や普通の会社員でエンジニアリングではない仕事をされている方、学生の方も参加されています。
Slack でコミュニケーションを取っているのですが、**このコロナサイトの影響で、それまで500人くらいだったコミュニティが一気に4500人くらいまで成長しました。**ただ、一気に増えた後もずっと継続的に活動している人はそんなに多くはないので、実質の活動人数が増えた感じはあまりしていないのですが。
私とシビックテック ― 7年
シビックテックに参加して7年くらいになります。
**一番最初にシビックテックを知ったのは、2011年の sinsai.info でした。**当時、私は都内の某大学で博士研究員をしていて、データとはあまり関係ない研究をしていました。東日本大震災も大学の研究室にいるときに被災したのですが、私自身も困った経験をする中で、「IT を使ってボランタリーな活動で世に貢献していく、そういう道があるんだ」とすごく感動したのを覚えています。
そこからすぐ参加したわけではなく、少し時間を置いて、2012年ごろに富士通に就職してデータサイエンティストとして駆け出しました。そして2013年末、「Where Does My Money Go?」——私の税金は何に使われているのかを可視化するサービス——のイベントに参加したのが最初でした。
これもオープンソースで、データを自治体ごとに差し替えるとその自治体版ができるという仕組みになっていて、その対応自治体を増やすイベントでした。
当時の私は思いっきり駆け出しで、データの加工もろくにできないような状態でした。自治体ごとに費目が表記揺れしていて、そのままソフトウェアにかけられない——そういう体験を通じて、データの標準化や、正しくデータを出すことの重要さを実感できたかなと思っています。
そういう体験もあって「シビックテックは重要だし面白いな」と参加し続けているうちに、本業では得られないフロントエンド系の技術や、政府系のオープンデータ・データ標準化に詳しくなり、それがまた本業にも生きてくる——そういうサイクルを体験できた7年でした。
東京都のコロナ対策サイト
一番最初のリリースは3月3日の深夜——正確には日をまたぐくらいでした。その段階では4枚くらいのパネルしかなかったと思います。本当に基本的な数字だけを表示している、そんなサイトでした。
やっていることは、東京都が公式で発表したデータを可視化したものです。可視化として凝ったものではなく、ただの棒グラフだったり、移動平均線が付いていたり、テーブルの形で検査陽性者の状況が出ていたり——本当にシンプルなものが並んでいるだけです。
特徴① ソースコードが OSS として公開されていた
この活動が面白いと言っていただけた背景の一つに、サイトのソースコード自体が MIT ライセンスの OSS として公開されていたことがあるかなと思います。
裏側は JavaScript でできているのですが、そのソースコードが全部 GitHub で公開されている。誰でもアクセスでき、コピーして自分のパソコンで立ち上げることも、別のところにホスティングすることもできる——そういう配布の仕方をしています。
技術としては Vue.js と、それを助けるフレームワークである Nuxt.js を使っています。このあたりの選定も、自治体のサイトとしてはだいぶ尖っていると言っていただいたところです。
特徴② データもオープンデータで公開していた
棒グラフの下あたりに「オープンデータで入手」というリンクがあり、クリックすると JSON の形でデータがダウンロードできるようになっています。
受賞
いろいろと賞もいただきました。もちろん受賞している主体は東京都です。グッドデザイン賞では大賞の候補まで残り、惜しくも大賞は逃したのですが、金賞をいただいております。
その受賞理由のコメントが非常に象徴的だったのでご紹介すると——
正確な情報を迅速に届けるため、様々な指標の情報やデータをグラフや表で分かりやすく掲載し更新していること。グラフや表などに活用しているデータをオープンデータとして公開していること。ソースコードも公開して、他自治体においても活用が可能な形にしていること。
今まで前例はなかったけれど、やってみると非常に合理的だと思えることを達成できたかなと。そこをグッドデザイン賞でも認めていただいたのは、それなりに良いことが達成できたのかなと思っています。
あと個人的な話ですが、開発者として嬉しかったのが GitHub Trending です。世界で総合1位——1日だけだったと思いますが——を取れたのは、個人的にも嬉しかったです。
62サイトへの横展開
受賞理由にもあった「他自治体への展開」ですが、実績としては 62サイトに展開されました。47都道府県すべてで一度は作られた状態になりましたし、サンフランシスコや台湾など海外でも使われています。
そのうちいくつかは実際に自治体の公式サイトとして採用していただき、運用が続いていると聞いています。
それ以外は個人ベースやボランティア団体がやっているところもあって、データの更新に課題があって廃止されてしまったサイトもあると聞いています。今までのシビックテックではそこまで到達できなかったので、あまり気にならなかった課題なのですが、今回そういう課題も顕在化してきたので、次はそういうことがないように頑張りたいね、という反省が生まれたりしました。
左が神奈川県版、右が北海道版です。ほぼそのまま採用いただいているのですが、自治体ごとに工夫も入っていて、たとえば北海道版には日付のレンジを変えるつまみが入っています。全部オープンソースなので、自治体の都合や表示したいデータに合わせて改造が入るわけです。
なぜ横展開に意味があるのか
このコロナサイトが達成したことは「情報の伝達」です。そして情報の伝達という課題は全国共通です。
それ以外の地域課題も、だいたい全国共通のものが多い。今までのシビックテックでも、「保育園がどこ空いているか分からない」とか、「ゴミナシ」というアプリのように「ゴミはいつ出せるのか」「このゴミは何ゴミなのか」といった課題を、その地域用のアプリを作って解決する、というものがありました。
全国共通の課題が多いので、アプリの横展開は開発するときにだいたい考えることになります。
一番の理想は——
- オープンデータが全国の自治体で完全に標準化されてどこにでもある
- ある地域課題を解くオープンソースのソフトウェアを一つ作る
- あとはオープンデータを自治体ごとに入れ替えるだけで、その自治体用のアプリが完成する
これがシビックテックの一つの理想かなと思っています。
**ただ、実際にやろうとするとデータ側に課題が多い。**今回のコロナサイトでも、県が出しているデータが PDF だったという話も聞きました。データを出してはくれているけれど——
- フィールド名が違う
- 集計しているものが違う
- 形式が JSON だったり CSV だったりバラバラ
- そもそもデータとして公開していない
- 電子的に保存しておらず紙でしかない
そういうデータも結構たくさんあるわけです。
自治体側もそういうオペレーションを組むメリットが今まで取れなかったので、されてこなかったことかなと思います。しかし今回、**東京都は全面的にバックアップして、「サイトを表示するためにどういうデータが必要か」というところから都内でオペレーションを組んでくださった。**そこまでできるという実例ができたので、こういう活動もしやすくなっているかなと思います。
技術選定の話
ここから開発の話に入ります。
非常にざっくりした仕様からのスタートでした。最初は本当に何もなく、どんなサイトになるかも分かりませんでした。決まっていたのは——
- 静的なサイトである
- データごとに拡張する
- 1日1回データが更新される
- 表示したいデータは後で増える
- いくつかページがある
この断片的な情報から逆に設定していきました。
- 静的サイト → スタティックサイトジェネレーターでいいよね
- 1日1回更新 → GitHub Actions を組むか
- データが増える → レイアウトは後でコンポーネントを追加しやすいよう細かいコンポーネントで作る
- ページが複数 → ルーティングができるフレームワークがいい
……ということで、Nuxt.js でいきましょうと決まりました。
Nuxt.js とは
そもそもは Vue.js というフレームワークがあって、Vue 製のアプリケーションをサーバーサイドレンダリングするフレームワーク、というのが定義です。
Vue.js は JavaScript で Web UI を開発するフレームワークの一種で、先ほど大野さんの話に出てきた React とちょうど同じ立ち位置です。React で開発するか、Vue で開発するか、Angular か、と。
Vue も React と同様にコンポーネントごとに作って組み合わせていく。コンポーネントは小さい単位で自己完結的に作られ、再利用可能な形にします。今回で言うと、グラフを表示しているカード1枚1枚、そしてその中の細かい部品も全部 Vue のコンポーネントで作りました。
サーバーサイドレンダリングとは、多くのアプリケーションのように JavaScript を配信してブラウザでレンダリングするのではなく、あらかじめサーバーでレンダリングした HTML だけを配信するものです。ただ今回その機能は使っておらず、スタティックサイトジェネレーターの部分だけを使っています。
Nuxt を選んだ本当の理由
もう一つの大きな特徴として、Vue アプリケーション開発のベストプラクティスを「制限」としてフレームワークに組み込んでいることがあります。
Vue 自体は非常に薄く、規定の少ないフレームワークです。ファイルをどこに置くか、どういう名前にするか、どういう役割を持たせるかは開発チームが決めることになる。ノウハウが共有されることもあまりないので、バラバラのまま作ってしまったり、開発チームが変わるとどこに何があるか分からなくなったりする。
Nuxt.js の場合は、**開発ニーズの8割以上を満たす設計ができるベストプラクティスを、あらかじめルールとして設けてしまっている。**それ以外をやろうとすると大変なのですが、そこを守ってさえいれば簡単に開発ができる。
たとえば HTML のページを1つ作りたければ、pages ディレクトリの下に Vue ファイルを1つ置く。そのファイル名が URL のパスになる。
制限が強いのでできないこともあるのですが、今回はデータを表示するだけのサイトなので、Nuxt.js を使っても後で詰まることはないだろうと考えて選定しました。
さらに、ビルド関係の設定も内包しているという特徴があります。サーバーサイドレンダリング、スタティックサイトジェネレーター、SPA——**人力でやると非常に大変な切り替えが、1つの設定値やコマンドだけでできる。**ディレクトリ構造もはっきりしているので、**新しく来たコントリビューターが迷うことなく開発を始められる。**本質的な開発に集中するためにメリットのあるフレームワークです。
……と、こう話すと合理的な選択に見えると思うのですが、もちろん「React でもいいじゃないか」という話も当然出てきます。
なぜ Nuxt だったのか。実は文脈がありました。
Code for Japan の活動で、避難所などの情報を地図にプロットして、それを紙に印刷して被災地に配る——そういうことを支援するアプリを作っていた時期がありました。Web マップはネット回線や電源がないと使えないので、本当の被災地では役に立たないんですよね。
作ったのは2018年7月、西日本豪雨の水害のときで、そのときは jQuery と Leaflet.js で開発していました。「2018年にそのチョイスはなかなかない」と言われるかもしれません。ただシビックテックのコミュニティは年齢層の高いエンジニアが多く、集まった人たちも「jQuery だったら書ける」という方が多かった。若い方ももちろんいましたが。それで機能したので「jQuery で良かったね」と言いながら作っていました。
ただ、jQuery で作ると一つのファイルに巨大なコンポーネントを書かなければならなくなる。4〜5名で開発していてもコンフリクトが多発したので、「もっと汎用的な作りにするときに何か導入しよう」ということで Nuxt.js をそのときに選びました。そのときになぜ Nuxt だったのかの経緯は、私が選んだわけではないので分からないのですが、そのチョイスがあったのでコミュニティの知識として Nuxt を使える人が結構多く、いけるんじゃないかということで選定した、という背景があります。
ホスティング ― Netlify
サイトは Netlify でホストしています。
一番最初は GitHub Pages を検討していて、GitHub Actions で CI を組んでデプロイしようとしていました。ただ東京都の公式サイトということで証明書に制限があり、「この証明書でないといけない」という指定のものを GitHub Pages では使えなかった——そういう理由で、Netlify ならできるのでやってみようかとなりました。当時から普通にホスト先として有名だったので、チョイス自体は普通だったと思います。
リリースして数週間した3月22日、Netlify がコロナウイルス関係のサイトへのサポートを発表して、有料プランを無償で提供することになりました。今でも東京都のサイトの派生サイトはそちらでホストされているものが多いんじゃないかと思います。
UI コンポーネント ― Vuetify
もう一つ、Vuetify を使っています。Vue で使う、マテリアルデザインのスタイルをあらかじめ適用したコンポーネント群です。
対策サイトの部品は今でも結構これで作られていて、サイト全体は v-app、メインコンテンツは v-container、タブも v-tabs、カード1枚1枚も v-card でできています。
これは後で話しますが、Vuetify は当時アクセシビリティ的にあまり良くなかったらしく、「Vuetify を使いましょう」と言ったのが私だったので、「Vuetify をなんで選んじゃったんですか」と後で怒られたというのが発生して、ちょっと思い出深かったりします。今 Vuetify のサイトを見るとアクセシビリティ対応のチュートリアルがあったりするので、その辺は改善されているのかなと思います。
ようやく可視化の話
**一瞬で終わってしまうのですが、可視化はほとんど棒グラフです。**データの粒度は1日1本。
その1日1本のデータを都庁内で取りまとめるオペレーションが組まれていて、SharePoint に入力されているものを GitHub Actions などの CI で API 経由で取ってきて、data.json に整形して、サイト側で読み込む——そういう構造になっていました。
取りまとめる際に複数部局に分かれているのでデータの反映タイミングがバラバラだったりして、初期はゴタゴタしたのですが、だんだんスムーズになっていった印象があります。
なぜ Chart.js を選んだか
チャートの部分は Chart.js を使いました。
私自身は D3.js が好きなので、一瞬 D3.js でいこうかと思ったのですが——D3.js はご存知の通り学習コストが非常に高い。「生身のチェーンソーをそのまま振り回すようなものだ」と言われるくらい扱いが難しく、間違ったグラフを作ってしまいやすい面もある。
どれくらいのスキルの人たちが今後開発に参加してくれるか分からない状況では、間違ったグラフが作られにくい Chart.js を使いましょうと、そこで理性を取り戻しました。
ただ、データの事情に合わせて特殊な対応が必要になったこともありました。
途中で算出基準が変わったデータがあったんですね。たとえば入院患者数は5月11日から基準が変わったのですが、そのとき「こういうふうに改変してくれ」という依頼が来る。Chart.js だと、この境界を示す枠線を出すだけで大変だったりします。D3.js なら1〜2行でできるような処理なのに。
これは、今は学生インターンとして Code for Japan で大活躍している開発者が「線グラフとしてここに書けばいいんじゃないか」と発想して、実際に線グラフとして矩形を表現して回避しているらしいです。
コンポーネント設計 ― スロット
カード1枚1枚を DataView というコンポーネント(名前は適当だったのですが)にして、中身を後で入れ替えられるようにし、それを並べる、という基本構造を最初に作りました。
Vue には slot というものがあります。HTML は入れ子にできますが、その入れ子の中身を slot の場所にレンダリングするという対応関係になる。それを利用して、中身だけ差し替えて、外側は同じという状況を作りたかったわけです。
**実際に作ってみると、最初に想定していなかった場所に、想定していなかった注意書きなどを出したい、ということが結構ありました。**今だと6か所くらいに slot が刺さっている状態になっているのですが、あらかじめそういう構造にしておいて良かったなと思っています。
slot は1個だけだと困るので複数作ることができて、たとえば description という名前で差し込むとそこに入る。拡張性と、見た目の統一の両方ができるように工夫して実装していました。
実装中の「祈りのような心の動き」
実装している間に祈りのような心の動きが発生したのが印象的だったので、共有させていただきます。
今から考えると呑気すぎる話なのですが、当時はどれくらい続くか、どれくらいの規模になるか全く分かりませんでした。リリースした日も感染者4人だったんですよ。「長期化しないといいな、願わくば数ヶ月で収束してくれるといいな」——それくらいの感覚でいました。
ただ、エンジニアリング的にものを作るときは「大量のデータに対応できるように」と当然考えるので、そういう実装をしなければならない。
- 感染者数の表示に3桁区切りのカンマを入れるという対応をしてくれた方がいて、それをマージするときに「でも、これ要らないといいですよね」と言いながらマージした
- 棒グラフの横幅も、最初は固定幅でリリースしました。今はスクロールバーで3月まで遡れますが、当時はどれくらい続くか分からないし、実装が必要なだけ長くなりそうだということでスクロールなしでリリースした
- そして最近まで残っていたのですが、データの部分に「2020年」という年号が入っていなかったので、サイトが実は年を越せない仕様になっていました。もうあと数日で1月1日を迎えますが、プログラムは「2020年1月1日のデータ」と誤読する状態のまま、しばらく放置されていたという話があったりします
リリース直後 ― リポジトリが特定される
3月3日の深夜にリリースされたのですが、その日のうちに Twitter で GitHub のリポジトリが特定されて拡散されました。
未だになぜ拡散したのか謎なのですが、サイトのソースの変数名あたりからかな、と憶測を立てています。とにかく「東京都のサイトのソースコードがこんなところにある」と拡散された。リポジトリの中で立てていた issue に Figma の URL もあったので、デザインも公開しているということで、それも結構拡散されました。
それ自体は喜ばしいのですが、Figma にアクセスが集中しすぎると人数制限で入れなくなってしまうので、当時コアで開発していたメンバーも入れなくなってしまったということがありました。
そして「こういうことがあるなら自分の技術を活かしたい」と思っていただいて、既に立っていた issue にコミットしてくださる方も大勢いらっしゃいました。
ただ当時は受け入れ体制が全くできておらず、レビューの手順も決まっていない、誰がやるのかも決まっていない。取り込みが全然できず、皆さんの貢献したい気持ちにブレーキをかけてしまった——これが当時、結構ストレスになっていたかなと思います。
さらに、取り込むのに東京都の OK が必要なケースもあるので、善意で立てられた issue でも取り込めるかどうか分からないケースがある。きわどいものに対して、そういう事情を分かっていない方がコミットするような動きも見えたので、結構ヒヤヒヤしていました。
コミュニティの受け入れ体制を作る
そういうときに、開発コミュニティとして今まで蓄積してきた知見も含めていろいろ対策を打ち、1週間後くらいにはレビューして取り込んでいける体制ができました。
具体的には大きく3つです。
① 行動規範とコントリビューションガイドの整備
**これは実はリリースの瞬間には既にやっていました。**こういう行動規範は Code for Japan のイベントで普段から設けているもので、元々あったものを適用した形です。
issue のテンプレートも置きました。.github の下にテンプレートの Markdown を置いておくと、誰かが issue を投稿しようとしたときに「こういう項目を書いてください」という雛形が表示される。箇条書きの部分を埋めるだけで issue が投稿できるし、読む側もフォーマットが統一されているので何をやりたいのかが分かりやすい。こういうものでコミュニケーションコストを下げていました。
② Lint を CI にかける
開発環境を特に指定していなかったので、皆さんいろいろな環境で開発されていました。そうすると、行頭のスペースをいくつにするかといったコード規約を自動で整える処理がかからない開発環境もある。
そこは非常にしつこく、何回も CI にかけて、そういう差分のせいで本来コミットしたかった開発が漏れてしまわないように注意していました。
③ Netlify のデプロイプレビュー
Netlify を使ってデプロイしていると、プルリクエストが来たときに「取り込んだ後のプレビュー環境」を自動で生成してくれる機能があります。独自の URL が発行されて、そこで**取り込んだ後の挙動をチェックできる。**これは生産性を大きく向上させました。
その道のプロが集まってきた
参加者が増えていくと、その道のプロが集まってきてくださいました。2つだけ紹介します。
アクセシビリティ
アクセシビリティのプロの方々が来て、このサイトのアクセシビリティを向上させてくれるということがありました。
3月3日のリリース後、3月6日にオンラインでアクセシビリティのもくもく会が開催され、このサイトのアクセシビリティの問題点を探し出そうという催しが行われました。
「公開処刑されるんじゃないか」と戦々恐々としていたのですが、実際はすごくポジティブなマインドの方々が集まっていて、その後も継続的に改善に取り組んでいただきました。
……ただ「なんで Vuetify を採用したんだ」という怒られはこのときに発生したので、私にとってはちょっとトラウマ、というほどではないですが。
このあたりの話は Code for Japan Summit で詳しくしていただいているので、ご興味ある方はそちらの講演を見ていただくと面白いと思います。
多言語対応
これもその道のプロが集まってくださって、最終的には5か国語に対応することができました。
Nuxt の中で t で始まる文字列を書いておくと、対応を書いた JSON ファイルで自動的に置き換えられ、言語設定を変えるだけで、ソースコードに触れずに多言語化できる——そういう状況を初期の段階で整えることができました。
あとは翻訳の文言を、いろいろな方がやってくださいました。これはオードリー・タンさんにも手を入れていただいたことがあって、結構話題になりました。
これを「普通」にしていきたい
こんな感じで開発が進んでいきました。特に最初の1ヶ月は私もかなりコミットしていたのですが、その時点で既に**各分野の詳しい方が入ってきてくださっていて、「私なんかが出る幕じゃないな」**と。
学生の活躍もかなり素晴らしく、先ほどの国際化(i18n)も音頭を取ってくれたのは学生だったりしました。
私が思ったのは、今回の活動を、今後は「普通」にしていきたいということです。
今回の東京都の対応は結構素晴らしかったと思いますが、実際にやってみると、オープンソースでオープンデータでこういうことをやるのは、すごく合理的なんですよね。こういう合理的な事例があったということ自体をベースにして、次の活動ではそれをどんどん超えていくようなことをやっていきたいと思います。
まとめ
エンジニア視点であのサイトの開発をまとめると、シビックテックのベストプラクティスと呼べるものが浮かび上がってきたかなと思いました。
個人としては、今後の事例の足掛かりとして、次のプロジェクトではもっとより良いものを目指していきたいと思っています。
長くなりましたが、以上で終わります。ありがとうございました。