Interop Tokyo 2017で「IoTいいねボタン」をコントリビューションした話 その3

はじめに

さくらインターネットでは、2017/6/7~6/9に幕張メッセにて開催されたInterop Tokyo 2017のShowNetに「IoTいいねボタン」をコントリビューションしました。

IoTいいねボタンは、弊社のIoTプラットフォームサービス「sakura.io」を活用したデモンストレーションで、来場者の方々に良いと感じたShowNetのテーマラック毎にボタンを押すことで投票できるようにしたシステムです。当日、会場で実物をご覧になった方もいらっしゃるかもしれませんね。

昨年(2016年)に引き続きのコントリビューションとなるIoTいいねボタンですが、今年は新たに地域BWAの無線ネットワークを連携させた実験を行いました。本連載では、3回に分けてこの取り組みについてご紹介します。

第1回 IoTネットワーク構築編
第2回 IoTいいねボタン製作編
第3回 いいね!Viewer開発編

IoTいいねボタン連載最終回の第3回目は、さくらインターネットの山田・河原が担当します。 前半はボタンが押された回数を表示する「いいね!Viewer」がどのように作られているか、中盤は主にデザイン面、そして後半には当日(!)の戦いをお話いたします。

「いいね!Viewer」 概要

実は、筆者である山田と河原が「いいね!Viewer」を作るのは1年ぶり2回目。さくらインターネットは、昨年の Interop でも「いいねボタン」を出展しています。 今年の5月上旬くらいに河原から、「今年もいいねボタンやりますかぁ」というようなことをいわれて、ああもうそんな季節かと思ったりしました。今年も Interop の季節がやってきました。

さて、そもそも件の「いいね!Viewer」とは一体何者でしょうか?!まずは以下の画像をご覧ください。

Interop 会場のあちこちに設置された「いいねボタン」は、ボタンが押されると、内蔵された通信モジュールが、通信モジュールと押されたボタンのカウント数のデータを「sakura.io」 に送信します。 「sakura.io」に送信された情報は、後述する集計サーバを通じて、集計データをグラフ表示するための webアプリケーションに情報が送り届けられます。

この webアプリケーション部分が「いいね!Viewer」です。

もう少し丁寧に説明すると、押下情報は 「いいねボタン」に内蔵された「さくらの通信モジュール」を通じて sakura.io まで送信されます。

次に、sakura.io は Outgoing Webhook という仕組みを使用して、websocket通信で集計サーバにデータが送信されます。集計サーバは、ボタンが押された際、それまでの集計値に変化があることを検知すると、「いいね!Viewer」に対して、通信モジュールとそれに紐づくカウント情報を送信します。

sakura.io 集計サーバ 「いいね!Viewer」はそれぞれ websocket で接続しているので、カウントがほぼリアルタイムで増加していくのをグラフで確認できます。 集計されたデータを確認することで、当日会場のどのエリアが盛り上がっているのか視覚的に把握できるんですね。

※ ちなみに、「いいね!Viewer」が表示されている iPad が設置されるのはわずか1箇所。ですが、インターネットに接続するモバイル端末や他のPC等から「いいね!Viewer」にアクセスすることができるので、会場のどこでもグラフを見ることができます。

集計サーバの技術

さて、「いいね!Viewer」の概要がなんとなくわかったところで、山田からは主に「いいね!Viewer」に使われているソフトウェアの技術面と、当日までの開発の雰囲気をお伝えしたいと思います。

集計サーバ

Node.js の express で動く集計サーバは、「sakura.io」と接続して、送信されてくるカウント数を集計します。集計サーバは、集計した通信モジュール及びそれに紐づくカウント数の合計を「いいね!Viewer」に対して送信する、中間APIサーバのような役割を担っています。

開発を行ったのは、本連載第2回で執筆を行った、さくらインターネットでマルチな活躍を見せる川畑。昨年の Interop も彼が集計サーバの開発を担当しました。

先に少し述べたとおり、「いいねボタン」がある間隔に連打されたボタンの回数とそれに紐づくモジュールのデータは、「いいねボタン」に内蔵された「さくらの通信モジュール」経由で「sakura.io」に送信されて、「sakura.io」の Outgoing Webhook というサービス経由で、集計サーバに json形式のデータで送信されます。

以下は Outgoing Webhook から飛んでくるjsonデータ json形式例。

{
    "module": "XXXXXXXXX",
    "type": "channels",
    "datetime": "2017-06-01T12:21:11.628907163Z",
    "payload": {
        "channels": [{
                "channel": 0,
                "type": "i",
                "value": 5
            },
            {
                "channel": 1,
                "type": "i",
                "value": 1
            }
        ]
    }
}

一方 「sakura.io」から Outgoing Webhook で送信されるデータは、実際にはそのままでは「いいね!Viewer」で使うには不要なデータが多いほか、「いいね!Viewer」では、当日押されたボタンの各カウント数の集計情報も必要であるため、どこかで「いいね!Viewer」に必要な情報に加工してやる必要があります。

集計サーバは、あわせて起動する Redis に通信モジュールごとのカウント数を保存していきます。通信モジュールのカウント数の変化を検知すると「いいね!Viewer」に対して集計したデータを websocket で「いいね!Viewer」へ送信してくれます。

以下は、集計サーバから「いいね!Viewer」に送信される json形式例。

[
  {
    "color": ["sky"],
    "count": 150,
    "module_id": "xxxxxx",
    "name": "ファンクション・プール・ブルー",
    "updated_at": "2017-06-xxT02:37:22.056Z"
  },
  {
    "color": ["sky"],
    "count": 93,
    "module_id": "xxxxxx",
    "name": "対外接続伝送",
    "updated_at": "2017-06-xxT02:37:22.056Z"
  },
  {
    "color": ["blue"],
    "count": 76,
    "module_id": "xxxxxx",
    "name": "ファンクション・プール・グリーン",
    "updated_at": "2017-06-xxT02:37:22.056Z"
  }
]

「いいね!Viewer」の技術

「いいね!Viewer」はしかし、話をもらった時点ではまだイメージの段階ですから、機能的な仕様は徐々に固めていかなくてはいけません。とはいっても、仕様が全て決まるまで何もしないと Interop に間に合わなくなる可能性があるので、初期の打合せでは、とりあえずアプリケーションのベースは作っておくことにしました。

おおまかなイメージは昨年度から持ち越しているし、何にも作れないということはないんじゃないかな。ほんとかな・・?

実装規模とフレームワークの選定

さて、前述の通り、「いいね!Viewer」は通信モジュールごとの集計データを表示するのが役割です。言い換えれば、流れてきたデータを表示させればよいだけなのですが、一口に表示と言っても、デザインに応じてグラフの見た目を更新したり、値によって何かアニメーションをさせたり、あるいは状態によって何かメッセージを表示させたりする必要があるかもしれません。

しかも、データはリアルタイムにどんどん送られてくるので、style や HTML の書き換えも頻繁に行われそうです。

最近はこういった、速度が重要で、ページ遷移を行わないで画面の変化を表現する場合、VirtualDOM を実装したフレームワークによる高速な再描画を選択することが多くなってきました。一方、従来通り DOM API による直接の HTML書き換えのほうがシンプルに実装できることもありますので、このあたりの技術選定は案件の規模感や拡張性の必要性で決めたいところです。

ところで、昨年度の「いいね!Viewer」を思い出してみると、React.js を使っていろいろとページを書き換えていた事を思い出しました。実装自体はさっぱり思い出せないのですが、昨年度と同じくらいの規模感ならば、やはり何らかのフレームワークを選択することになりそうです。

ぼんやり考えて、数日過ぎたあたりで、さすがに今年の「いいね!Viewer」の仕様が固まってきました。肌感覚では昨年度と同じか、昨年度よりもシンプルな構成のように思えました。 (※そして結果的には想像したくらいに収まりました) ただ、この時点では仕様に不明瞭な点が多かったので、使ったことのないライブラリやフレームワークで二の足を踏むのは避けたいという思いはありました。

そこで、昨年と同じように React.js を使ってもよかったのですが、昨年と同じことをしても面白くないし、昨年書いたコードを思い出すよりは、イチから作ったほうが速いかもしれないという邪悪な思いに取り憑かれて、最近社内ツールやプロダクトでも使うことが増えてきた Vue.js を利用することにしました。

近頃個人的に Vue.js でアプリケーションを作っていたこともありますが、このあとデザインの適用及びアニメーションやインタラクションの実装を行う河原も、幾つかのプロジェクトで Vue.js を使って webアプリケーションを作成していたことが選定の決め手となりました。

骨組みづくりと孤独な開発

「いいね!Viewer」の話が来てしばらくの間は、ざっくりとした仕様のもと開発をしなくてはいけません。そのため、ある程度汎用的に作って、細かな部分は後から 丁寧に実装していくことにします。デザイナー兼エンジニアの河原には、デザインとインタラクション部分を大方実装してもらいたいので、こちらである程度の基本部分の実装は終えておきたいところです。

この段階では、接続予定の集計サーバは未だ存在しないので、ローカルで開発において、ある程度本番のサーバに近い挙動をするなんらかの接続先を確保する必要があります。 そこで、しばらくはダミーの情報を返すようなモックサーバを用意して、そこに websocket で接続しに行くようにしておきます。

ただし、本来の集計サーバからどんなJSON形式のデータが送信されてくるのか見当がつかないと、そもそもモックのデータを作ることができません。予め集計サーバ担当の川畑とは、 最低限のJSONデータ形式ついてのみ取り決めを行っておきます。

JSON形式については、このようにSlack上で議論を詰めていきました
これから仕様が確定していけば、さらに必要な情報が増えることが予想されますが、この時点では今後変わることがありそうくらいに意識しておきます。

さて、「いいねボタン」自体ももちろんまだ存在しないので、モックデータを生成するジェネレータが必要です。

今回は、「いいねボタン」を押下したあとの挙動をエミュレートするための webページを作ります。ページ内のテキトウなボタンを押したら、ある程度ランダムに値がカウントアップする (ついでに集計も行われるように)ようにします。生成された値を、Node.js で作られた「モック集計サーバ」に対して websocket でデータを送信できるようにします。

モックデータシミュレータ
「いいね!Viewer」はこの「モック集計サーバ」と接続できるようにして一人もくもくと開発を進めていきます。

機能の取りまとめ

普段の業務の合間合間で実装を進めて、一先ず以下のような機能を中心に実装しておきました。

通信モジュールとそれに紐づくデータの加工及びデータ管理
Store のデータを画面に表示
ルーティング
エラー時のモーダル表示機構
システムメッセージ表示機構
ダミーデータを送信可能なモックサーバとジェネレータ用意
この時点ではまだこんな見た目。機能がシンプルなだけあって、ベースの実装については意外にはやく終えることができました。ただこれから先は、河原のインタラクションを含むデザインの実装が待っています。

デザイン実装前のいいね!viewer
「いいね!Viewer」に限らず、JavaScript の実装で大変なのは非同期通信処理とそれに伴うデザイン・アニメーションの実装部分。 しかし、こういう部分の実装は河原が得意とするところなので完全におまかせします。

作成したコードをリポジトリで共有したら、しばらくは山田側の「いいね!Viewer」実装作業はお休みです。後はよろしくお願いします!

デザインあれこれ

よろしくお願いされたので、ここからは河原がお送りします。 いいねボタン外装と、いいね!Viewerの画面デザインを担当しました。

どんな画面?

基本としては会場内に設置される iPad での表示となりますが、iPad の設置エリア以外でも見られるように、スマホ用のビューもつくります。

表現方法は色々考えていたのですが、じっくり見るものでもないので、

ごくシンプルに押された回数を棒グラフで一覧できるようにする。
細かい数字よりも、どこが多いのかがザックリ見えるようにする。
ボタンが押されたことがリアルタイムに分かるように何らかのインタラクションを用意する
というザックリとした方針でデザインをしました。

Adobe XD の画面

コーディング

デザインもシンプルだったので特筆すべきことは無いのですが、ざっくり新し目の iPhone / Android でちゃんと見えていれば OK という普段無いゆるい縛りだったのでここぞとばかりに新し目の CSS プロパティをふんだんに使ったりして楽しみました。

そして

出来上がったのがこの画面です。細かい調整はあれば現地でしようかな、という軽い気持ちでこのときはいたのですが…

デザイン実装後のいいね!viewer
私の出番は「当日の戦い」に続きます。

直前の戦い

ここからはまた、山田がお送りします。

疎通編

<現地集合編>

Interop の準備が着々と進められる幕張メッセに足を運んだのは、開催を翌週に控えた 6月1日。 この日、「いいねボタンプロジェクト」の開発メンバーと 12:00 に「海浜幕張駅」前に待ち合わせをしていました。ついに、実物の「いいねボタン」を使った、初めての疎通テストを現地会場で行うことになったのです。

もしものことがないように30分前には到着するように早めに家を出たせいか 11:20頃には「幕張駅」には到着。はやくつきすぎたため暇を持て余しそうになります。 時間的にかなり余裕はある。幕張メッセへの経路でも確認しておこうと駅ナカの地図を探します・・・アレ?

うすうす何か変だなと感じたことはありました。昨年も来たはずの「海浜幕張駅」となんだか雰囲気が違うことに。途中「幕張本郷駅」を通過する際、危ない危ないボクが降りたいのは「幕張駅」だからね、だまされないよ、なんて「去年は思いもしなかった」ことに。

有識者の皆さんならもうおわかりと存じますが、降りるべき駅は「海浜幕張駅」だったのです。そして降りたのは「幕張駅」。駅の壁に貼られた案内には丁寧に、ここは幕張メッセの最寄り駅でないことが書かれていました。ここから電車で「海浜幕張駅」を目指すとかなりの時間を消費してしまうことさえも・・・。

しかし、希望を捨ててはいけません。なんと近くのバス停から「海浜幕張駅」をつなぐバスが通っているという案内があったのです。ありがとう幕張駅!

すぐさま駅の階段を駆け下り、100メートルほどはなれたバス停に向かいました。途中何度も諦めそうになったものの、 Interop のために懸命になる仲間の姿が去来したはずです。思えば数年ぶりに全力で走りました。

肩で息をしながらバスに乗り込むと、運転席で時刻まで待機する運転手のかたに、入念に行き先を確認する。こんどこそ問題無さそうだ。助かった。

さほど時間をかけずに「海浜幕張駅」に到着して時計を確認すると、時刻は11:55。ボクは 30分前行動を行った自分に心から感謝をしました。

<疎通確認編>

開発メンバーが無事現地に到着して、入口あたりで入場手続きを済ませます。

高く広がる天井を眺める会場の入り口から、前方3分の1くらいは折りたたみ式長机とパイプ椅子が等間隔に並べられており、既にパソコンを開いて何らかの作業をしている人でいっぱいです。隣には何らかの装置が設置され、作業を行う人達がちらほら見受けられます。会場の奥、残り3分の2は未だ何もない空間で薄暗く、これから何かが設営されるのでしょう。

先に現地で作業をしていたさくらインターネットの大久保(本連載第一回担当)に、会場中央付近の作業場に案内されます。何かのケーブルがいくつか巻いて置かれた机に持参したパソコンを広げて、電源の確保と wi-fi の設定を済ませます。

「いいね!Viewer」については事前にあらかたの実装を終えていたため、すぐに疎通を行うと思われました。ですが、「いいねボタン」製作者の関根・川畑が両者別作業に追われており、すぐには疎通テストとは行きそうもありませんでした。

河原はデザイナーらしく、「いいねボタン」に貼り付けるポップのデザインの調整などをおこなっていましたが、ボクは若干手持ち無沙汰になって、しばらくは一人「いいね!Viewer」と関係のない業務をして待ちました。

夕方ころようやく作業を一段落終えた川畑がやってきました。さっそく関係者で集まり、先程まで作業していた件の長机の周りに関係者が PC を並べます。 「いいね!Viewer」の接続先ホストを川畑の集計サーバに書き換えると、おお・・・予めカウントされていたデータが「いいね!Viewer」上のグラフに表示されています。

上手くデータが取得できているようですね!

ひとまず何もつながらないという状態では無さそう。次に、手元に用意してもらった「いいねボタン」を押してみると、無事にカウントアップしている・・!この物理ボタンへの操作が通信モジュールによって「sakura.io」にデータを送信され、さらに集計サーバを経由してデータを送ってくると思うとなにか感慨深い気持ちになります。

現地作業風景。やり終わった川畑が急に仮眠をとりだします。
疎通テストが終わり、一安心です。と、しばらくは席を外していた川畑ですが、席に戻るなり、複数の「いいねボタン」を一つのグラフにして表現したいんですよと言い始めました。ひどいよー。

もう少し実装よりの説明すると、「いいね!Viewer」上の「ShowNetアクセスコーナー」というグラフは、内部的に 3地点の「いいねボタン」のカウントの合計値を使用するようにしたいということでした。 この3つのボタンは、それぞれ場所は少し離れていますが、全て漏洩同軸によるインターネット体験コーナーであるためだそうです。な、なるほど・・・。

これまで「いいね!Viewer」は 「いいねボタンが設置されたエリア」 と 通信モジュールに紐づくカウント情報を表すグラフ が一対一対応で表現されていました。 これが、「いいねボタンが設置されたエリア」 と 通信モジュールのグループ(あるいは単一の通信モジュール)に紐づくカウント情報を表すグラフ の対応に変更になります。

「いいね!Viewer」が表現したいことに照らして考えると、そもそもバックエンドの集計サーバからは3地点の「いいねボタン」の合計数を送信しても良かったのですが、 今回は取り急ぎ、集計サーバからはグループ化したいモジュールに対して所属するグループ情報を JSON のデータに含めてもらうようにして、「いいね!Viewer」側でその情報を元にグループ化を行うことにしました。

[
  {
    "color": ["blue"],
    "count": 76,
    "module_id": "xxxxxx",
    "name": "ファンクション・プール・グリーン",
    "updated_at": "2017-06-xxT02:37:22.056Z",
    "group": ["some_group"]
  }
]

「集約サーバ」と「いいね!Viewer」の改修はそれぞれ滞りなく進み、無事 3地点の合算値が表示されました。やったね!

「いいね!Viewer」もそろそろ完成が近そうです。 この時はそう思っていました。

当日の戦い

というわけで、河原が当日の戦いをお送りします。 ここまでの頑張りが無事に実を結び、平穏無事に会期を終えること…が出来ればよかったのですが、当然、そんなことはありませんでした。

初日

当日の初日は何かしらの問題に備えて会場入りしておりました。

実は、昨年はちょうど出張中で、実際に会期中の会場に入ってどんな雰囲気でどのように ShowNet が見られているのかを体感することが出来たのが、この時が初めてでした。

特に大きな問題はなく、ボタンを押して貰っているシーンも何度か確認して、よし、と思っていたのですが、しばらくして気がついたのが、なぜかあるボタンだけが突出して押されているのです。iPadの真横に設置されているボタンでした。

なぜだろうと思い、もう少しシッカリと様子を観察してみました。

そうしてわかったのは、そのボタンだけ、すぐそばのiPadに表示されているグラフが反応するので、気になって押してくれていたようです。

ただ、それだけであれば(いいねボタンの趣旨からは外れるものの)楽しんでくれているようで良かった、とホッとできる出来事だったのですが、さらに観察していると解決すべき課題があることに気がつきました。

前回にある通り、通信回数の節約のためボタン押下のデータは5秒に一回だけ飛ぶようになっていました。ボタンの押下自体はその隙間時間でもちゃんと計測されているのですが、データが飛ぶタイミングは5秒に一回です。

つまり、画面を見ながらボタンを押しても、送信待機中に押してしまうと画面反映がすぐにはされないのです。そのため、反応してないのかな?と思って続けてボタンを押してしまう… ということでした。

さすがに、それではまずい、ということで対応をはじめました。

画面としては、反応があったことをよりわかりやすくするためにエフェクトを強くしたりしましたが、それだけでは対策としては不十分で、やはり、どうにか反応をリアルタイムにする必要がありました。

結果として、どうしてもハードウェアを調整する必要があったので、関根に頑張ってもらうことになりました。現場で開発することも検討しましたが、幸い、押下後すぐにデータを送るようにしていた開発版が残っていたので、中身をそれと差し替えることにしてこの課題は解決しました。

ハードウェア交換作業

2日目

しかし次の日もやはり、iPad横のボタンがすごい勢いで押されていました。

なんと今度は(あるいは今度こそは)、リアルタイムに画面が更新されるので、その画面を見て「おっ」と思ってさらに押したり、面白がって連打する人が増えてしまったのです!

このボタン、ただでさえ、とっても連打したくなるボタンなのです。アーケードゲームのものと同じですから。

思わず連打したくなるいいねボタン
このままだと、そのボタンのグラフだけ突出してしまって、他のグラフの多い少ないが分かりにくくなってしまいます。

ここで、対応策はいくつかあったのですが、選択したのは iPad 横のボタンのグラフだけ計算除外する = グラフを突き抜けさせる、という解決(?)でした。

連打を無効にする、という案がいいねボタンとしては妥当かと思ったのですが、このボタンとViewerの面白さを優先したほうが、興味を持ってもらえるだろうという判断でした。

それが良かったのかどうか、残りの会期中も順調にボタンは押されていったのでした。

その後

この他にもQRコードにより気づいてもらいやすくするために、iPadに表示される画面に直接QRを表示するようにしてみたり、会期中に手間なく画面修正ができるようにサーバからメッセージを送るとブラウザリロードが走る仕組みを実装したり、色々とトリッキーな対応を何度か繰り返していました。

そんなわけで、いいね!Viewerは会期中もずっと戦いを続けていたのでした。

制作まとめ

「IoTいいねボタン」と「いいね!Viewer」は、ネットワークから、ハードウェア、ソフトウェア、デザインの様々な領域の組み合わせでつくられています。一見、すごくめんどくさそうなプロダクトですが、 sakura.io を使ったことで、それぞれの領域の開発・制作に集中できました。

IoTいいねボタン・いいね!Viewer はきっと、どこかでまたパワーアップした姿をお見せすることになると思いますので、ぜひ今後の展開をご期待ください!

本連載のまとめ(編集担当:大喜多)

「IoTいいねボタン」のコントリビューションについて全3回でお送りいたしました。本コントリビューションは、無線通信技術・ハードウェアへの実装・サーバサイド開発・フロントエンド開発など、非常に幅の広い技術を結集して構築されました。また、自社プロダクトのアピールだけにとどまらず、OpenBlocks IoT EX1を使用した地域BWA網との接続など、相互接続実証試験としての成果もあり、ShowNetの理念に沿った次世代ネットワークのカタチを示せたのではないかと思います。さくらインターネットは、今後も様々なプロジェクトへのコントリビューションを通じて『「やりたいこと」を「できる」に変える』という理想の実現に邁進してまいります。