EVOKEを支える大人数同時参加型クイズシステム開発 後編

後半のこの記事では、システムの具体的な中身について、管理画面、Webフロントエンド、ランキングシステムのセクションに分けて紹介します。

前編では開発したシステムの概要や開発手法などについて紹介をしているので、そちらを先にご覧いただくことをお勧めします。
EVOKEを支える大人数同時参加型クイズシステム開発 前編 – てっくぼっと!

管理画面

役割としては、エンジニアだけしかできない作業を減らすこと、行える操作を限定し、視覚化することでバグの原因を排除することです。主に実装した機能としては、

  1. 問題の追加・編集・削除
  2. 会場の進行管理
  3. 参加者の全回答テーブル
  4. (未使用)問題ごとの回答率グラフ

の4つです。
運営しか使わない1~3の管理画面のデザインは全ての作業においてもっとも優先度が低く、最低限の機能と使い勝手を満たしたバランスで実装しました。

それでは、実際に操作している動画と合わせてご紹介します。

問題の追加・編集(・削除)

このように問題を作成し、解答の差し替えをしていました。
出題順もあるので順序を入れ替えることもでき、当然削除もできます。

image7.gif

会場の進行管理

運営側では、会場の進行状況に合わせて、参加者の画面の遷移や回答の締め切りなどの状態操作を行っていました。

_54443745-7448-485e-e590-e68a13e2a283.gif

参加者の全回答テーブル

問題ごとに正解率を予想し、報酬設計を行っていたので、期待通りに回答が分散しているかを確認しながら進行していました。

image4.png

正答数降順でソートをかけて、得点が高い人ほど上にくるようにしています。

回答率グラフ

本番に時間があれば各問題の集計が終わった後にスクリーンで回答率グラフを表示する予定でしたが、こちらは未使用に終わりました。

image9.gif

スクリーンに表示する想定だったため、画面内に余分な表示を(ブラウザのメニューだったり、マウスポインターでさえ)したくなかったので、全画面にした時に適切なサイズになるようにし、円グラフの表示/非表示はs / h(show / hidden)キーで行えるように実装しました。

円グラフは使いまわせる形で作成したので、最終的な各問題の回答率のビジュアライゼーションも簡単にできました。

image12.gif

Webフロントエンド

当初Unityでネイティブアプリにする予定でしたが、配布や修正が簡単という理由から、Webアプリになりました。

今回、各画面の担当者が好きなライブラリで自由に開発できるようにSPA(シングルページアプリケーション)ではなく画面毎にHTMLを作って開発しました。なので通常のプロダクトではありえないような、ログイン画面はReactで、それ以外はVue.jsという2つのJavaScriptのフレームワークが使われています。

スタイルの記述にはSass(SCSS)を使っています。ネストして書くことでわかりやすく変数やmixin、extendなどが使えるので便利です。また、ブラウザ毎のベンダープレフィックスを書くのが大変なのでautoprefixierを使って自動的に付くようにしました。

Vue.js

Vue.jsは.vue拡張子の単一ファイルコンポーネントにできることと、導入が簡単なので今回使うことにしました。コンポーネント単位でJavaScriptとCSSのスコープが切られるため他のコンポーネントに影響が出ません。

今回のアプリでは使いまわせるコンポーネントがヘッダーくらいだったのと表示自体が単純だったので1つのコンポーネントに全て記述しました。大規模な開発では、コンポーネントをもっと細かい粒度で分けるかファイルを分けるなどの工夫が必要です。

Vue.jsは簡単に始められ、規模が小さい時はイベントバスを使ってコンポーネント間の通信を行い、規模が大きくなったらVuexを使うなど柔軟性があります。

単一ファイルコンポーネント

一つのファイルにHTML、JavaScript、CSSを記述できます。

<template>
        <p>{{ hoge }}</p>
</template>
<script>
export default {
        data() {
                return {
                        hoge: 'Hello, World'
                }
        }
}
</script>
<style lang="scss" scoped>
p {
        font-size: 2rem;
        text-align: center;
}
</style>

ファイルを分けることもできます。

<template src="./hoge-component.html"></template>
<script src="./hoge-component.js"></script>
<style scoped src="./hoge-component.css"></style>

CLI

公式が用意するCLIを使ってWebpackのビルド設定を知らなくても簡単にVue.jsのプロジェクトを作成できます。ターミナルでnpm install -g vue-cliを実行するだけでインストールできます。

$ vue init webpack hoge
$ cd hoge
$ npm install
$ npm run dev

アニメーション

今回のアプリでは主に画面遷移時にフェードイン・フェードアウトアニメーションを実行しています。

Vue.jsでは標準でtransitionコンポーネントを提供しているので簡単にトランジションを追加することができます。transitionコンポーネントでラップされた要素はトランジションの状態毎にクラスが追加されます。

トランジションの例

<template>
        <button @click="show = !show">CLICK</button>
        <transition name="hoge">
                <p>Hello, World</p>
        </transition>
</template>
<script>
export default {
        data() {
                return {
                        show: true
                }
        }
}
</script>
<style lang="scss" scoped>
.hoge-enter-active, .hoge-leave-active {
        transition: opacity .3s;
}
.hoge-enter, .hoge-leave-to {
        opacity: 0;
}
</style>

ランキングシステム

上記のシステムとは別に、会場スクリーンにランキング表示するためのシステムの開発も行いました。これは、各社員のランクを全体で共有することで、会場に一体感を生み出すという狙いのもとで作られました。

このシステムの前提としては以下の通りです。
– 数メートルある会場の大きなスクリーン上に投影される
– 大きな画面故に、ある程度リッチな絵作りが求められる
– 単純なHTTP通信でサーバーにアクセスする

そこで今回は、ゲームエンジンのUniyを用いることにしました。理由としては、アニメーションなどの表現が優れていることとと、スタンドアロンアプリケーションとして安定して動作すること、普段の業務で使い慣れていることなどが決め手となりました。

開発は、エンジニアとデザイナが各1人ずつで進めました。

画面設計

一体感を出すために、できるだけ多くのユーザーのランク情報を画面に表示したいという反面、社員は200人以上いるため、1画面で完結させようとすると明らかに情報過多になってしまうことが明白でした。

そこで今回は一度に表示できるユーザーの人数を極端に減らし、ページャーを用いて大量の情報を表示していくという設計にしました。これで画面全体がかなりすっきりしたのですが、次のような問題が発生しました。

演出

一画面に表示される情報量は減ったものの、人の名前が列挙されただけの画面は少し退屈なものになっていました。改善策として、ある程度全体の視線の導線を作ることができる演出をいれることになりました。

具体的には上から順番に名前が表示されていくといった仕組みです。ダイナミックにランクが書かれた枠がフレームインし、ユーザーの注目が集まったタイミングで名前のマスキングを左右方向から外していくといった演出を作りました。また、上記の演出を時間をずらして平行して再生することで、ユーザーは自然にテンポよく人の名前を視認できるような調整を行いました。

これによって、適切な情報を適切な速度で伝えることができ、かつ会場にいるユーザー全員の感情の変化タイミングを同期することができました。

_7eebb413-f025-29dd-b014-eeb8ba8e9840.gif

本番を想定したオペレーションシステム

今回のシステムでは、歓談中に中間順位を表示する時、最終発表時など、状況に応じて挙動を変える必要がありました。内部実装ではパラメーターを切り替えることで設定可能な設計になっていたのですが、実際にオペレーションをするのは開発者であるとは限りません。そこで、誰でも扱いやすいように予めそれぞれの設定のプリセットを登録しておきました。

_8981be1f-9a92-a041-1843-42955810aa2d.gif

また、司会者の進行に合わせてランキングを表示していきたいという要件もあり、簡単に操作するために全てスペースキーを押下していくことで、順番に状態が遷移していくという仕組みも作りました。

ちょっとした工夫として、状況に合わせて柔軟に対応ができるよう、スキップ機能も実装しました。ランキングの表示演出中であっても、スペースキーを押すことで表示中の項目が自然にフェードアウトし、次のページの再生が始まるようになっています。

image5.png

当日は実際に非開発者が制御を行いましたが、このように様々な状況を考慮したシステムにしてあったため、一切のトラブルなく最後まで切り抜けることができました。

開発の振り返り

開発にはGitHubを用いました。ISSUEベースのタスク管理 + GitHubフローというごく標準的な開発形式で進めました。特別にチームとして意識的に行ったことはありませんが、チーム開発の基本的なところについて自然にコンセンサスを取れていたことが、スムーズな開発に繋がったと思います。

また、他にも下記の要因が挙げられます。

  1. コンセプトを固めてから実装に移ることができた
  2. 短期間でフィードバック期間を設けた
  3. 開発の優先順位を間違えることがなかった
  4. 開発事項をもれなくISSUE化するようにした
  5. 進行の管理者と実装者が分かれていた
  6. コミュニケーションのコストが低かった

1. コンセプトを固めてから実装に移ることができた

『人月の神話』のフレデリック・ブルックス曰く
“Conceptual integrity is the most important consideration in system design.”
とあるようにシステムのコンセプトが定まった上で開発を行うことは、チームにおいて強力な開発手法となります。そして今回は、ベンチマークとするコンテンツがしっかり定まっていたことと、PM(プロジェクトマネージャー)に相当する者が、開発側で迷うことのないレベルまでページ単位で仕様を定めてくれたため、結果としてスムーズに開発を行うことができました。

2. 短期間でフィードバック期間を設けた

開発中に1週間単位程度で開発中のものをそれ以外のメンバーで触ってフィードバックを返すようにしていました。そのため、次に何を優先的に実装するべきか、何が仕様と異なっているかを常に把握しながら実装を進められました。

3. 開発の優先順位を間違えることがなかった

開発順序としては下記の通りになりました。

  1. APIサーバー
  2. UIデザイン
  3. Webフロント
  4. 全体フィードバック
  5. API、フロント修正
  6. アニメーション調整

全体からディテールへというように、理想的な開発ステップを踏めたと思います。
成り行きではありますが、全体フィードバックまではあまり大きなデバッグ作業を行なっていませんでした。しかし全体フィードバックを精度高く行うことができたため、結果としてフィードバック(デバッグ)フェーズで修正項目を一気にリストアップすることが出来、逐次に開発側でデバッグ作業を行うよりも大幅に工数の削減を行うことができました。
開発の粒度としても、大きなプロジェクトですとデータ構造について議論するというステップがあったりしますが、今回のような小規模短期間の開発においては担当に一任できたことは大幅に工数の削減に寄与したように思います。

4. 開発事項をもれなくISSUE化するようにした

これは常にISSUEを見れば実装すべきことが何か、というのをわかるようにメンバーで心がけたことにより、今何を実装すべきかということを見失わないですみました。
ありがちなミスとして、ISSUEをメモ書き代わりに使うのは良いのですが、後から見たときになにをすれば良いかわからないということがあります。それが起こらないよう何をどう実装すれば良いかということがわかるレベルでISSUEを記述することをこころがけることにより、有効にISSUEを活用することができます。

5. 進行の管理者と実装者が分かれていた

今回はチームメンバー数が潤沢だったこともあり、進行管理と実装を別々の者が担当しました。第三者の目線で進捗を管理する方が、適切に問題を指摘でき、スケジュール管理の精度を上げることができました。

6. コミュニケーションのコストが低かった

全員が同期というのもありますが、互いに尊重しあえるメンバーであったため、対話ベースでもチャットベースでもスムーズにコミュニケーションを行うことができました。また開発上必要なことは、最低限READMEに書くことで全員が行う面倒な作業を再現性を保ったまま減らし、開発に集中できる環境が整っていたと思います。
以下は、実際に作成したREADMEの一部です。

image11.png

image3.png

image10.png

各メンバーの開発経験が豊富だったことも、円滑なコミュニケーションに寄与したかと思います。

開発を行なってみて

結論として、今回チーム開発上実践されたことはすべて基本的なことでした。しかし、一つ一つを行うことは簡単でも、全てを揃えるには神経質にならなくてはいけないものです。うまくいかなかったプロジェクトというものは概して上記の要因のどれかが欠けていることが多いのではないでしょうか。

まとめ

今回は、アプリボットの社内文化であるアプリボット総会改めEVOKE、3部で行われたコンテンツとそこで用いた技術の紹介を行いました。いかがだったでしょうか。

アプリボットでは引き続きこういった文化と技術的な挑戦を続けていきたいと思っています。