イントロクイズWebアプリ Mioをつくった

こんばんは。とある方から「コンテンツ主義じゃない?」と言われて少し落ち込んでいる艮鮟鱇です。コンテンツ主義なので、新しいコンテンツを作りました。仲間内で簡単にイントロクイズで遊ぶ環境を構築できる Webアプリ Mioです。レポジトリはこちらです:

https://github.com/ushitora-anqou/mio

友だちに「イントロクイズ作って欲しいんだけど」と打診を受けて作りました。 Webアプリはこれまでほとんど作ったことが無かったので暗中模索でしたが、 3週間程度でとりあえず形になりました。

サーバにはNodeJS・Express・Sequelize・Dockerを使用し、クライアントにはReactを使いました。サーバ・クライアント間の通信にはSocket.IOを使用しました。レポジトリのREADMEの冒頭に「Deploy to Heroku」ボタンがついていて、これを押すと簡単にHerokuに展開できるようになっています。ぜひ使ってみてください。

動かし方などはREADMEにおおまかに書きましたが、もしMioを動かしたい奇特な方で「どうしても動かしたいけど動かないんだー」という方が居れば Twitterの@ushitora_anqouまでリプライをくださるか、あるいはここのコメント欄に書くか、いっそのことGitHubのIssueを投げて頂ければ、嬉しさのあまり涙を流しながらお答えいたします。

ところで

去年の夏からaqccAQamlなど、どちらかといえば低レイヤーのコードを書いてきましたが、一転して高いレイヤーのコードを書きました。もちろんどちらが良い・悪いではないのですが、強く思ったのは:

Webアプリは需要が大きい分開発も楽だろうと勝手にイメージしていました。実際フレームワークやツールなどが充実しているのは事実で「なんでもかんでも自分で作らないといけない」という状況に陥りにくいのですが、その一方で、そのフレームワークの使い方に振り回されたり、それらを組み合わせたときにどのように動かすべきかなどを理解するのは、そこそこ骨が折れました。それからCSSを用いたページのデザインも、私が今まで扱ってきたプログラミング言語と大きく異なっていて、結局よくわかりませんでした。このあたりはBootstrapを使えばある程度解消するのかもしれませんが、途中から導入するのも面倒だったので、そのままで押し切りました。

JavaScriptのスコープ

JavaScriptと言えば言語仕様が複雑怪奇なことで有名ですが[要出典]、少なくともES6に従って書く分にはそれほど不都合を感じませんでした。ただ、JavaScriptのスコープについてはすこし混乱しました:

CやC++、および類似の言語では、同様のコードを書くと正常に実行され、「ABC(改行)DEF」と表示されます。一方でJavaScriptではそもそも参照エラーとして実行が為されません。これはconstletの変数宣言はブロックの先頭に「引き上げ」られる一方で、ブロックの先頭から実際の変数宣言までの間はこの変数が使用できないというECMAScriptの仕様によるものです。 MDNでは“Temporal dead zone”として参照されています1

音声の取り回し

音楽の再生・通信にはWeb Audio APIとlamejsを利用しました。送信クライアント側で音楽ファイルをデコードし、OfflineAudioContextを使用して始めの15秒を切り出してMP3にエンコードした後(trimMusic)、 Socket.IOを通してサーバ経由で各参加クライアントに送信し、各々のクライアントで再びデコードするという方式を取っています。ただしこれをそのまま行うと音楽によってはクリッピング(音割れ)が生じるため、送信側でDynamicsCompressorNodeを経由させています。これ1つでクリッピングがほとんど無くなるのは、かなり衝撃的でした。

ところで一応クライアント側ではバカでかいファイルを送信できないように制限を掛けているのですが、もちろん野良クライアントからサーバに向けて大きなデータを送信される可能性があります。これを防ぐためにはSocket.IOのServer に渡すオプションでmaxHttpBufferSizeを適当に設定してやると、勝手に通信を切ってくれます。 Mioではserver/config.jsで 500KBに制限しています。手元で実験した範囲では、普通送信される音楽ファイルは300KBを超えることは無いようです。さすがMP3といったところでしょうか。

HerokuとDockerと’Deploy to Heroku’ボタン

以前からHerokuでDockerコンテナを動かすことは可能でしたが、コンテナのビルド自体はローカルで行う必要がありました。ところが2018年の暮れにHeroku上でコンテナのビルドが可能になったため、 Deploy to Herokuボタンを押すだけでDockerを用いたデプロイができるようになりました。Mioではこれを活用しています。

詳細はHeroku公式ドキュメントに譲ることにして、 Mioでの仕組みを簡単に説明します。まずビルド及び実行に必要なDockerfileを作成します。Herokuで使用できるDockerのコマンドには制約があるので注意が必要です。次いでデプロイ時にDockerのビルドを走らせるためにheroku.ymlを作成します。heroku.ymlsetupに、ソフトウェアが必要とするアドオンについて記載しておく必要があります。最後にapp.jsonを作成して、 README.mdDeploy to Herokuボタンをくっつければ出来上がりです。 Mioの場合は特に指定すべきパラメタもないので意外と簡単でした。

押すとすぐにHerokuに遷移してデプロイの確認画面になります。ところで、私にとってこれがはじめての「’Deploy to Heroku’ボタンを押す」経験だったのですが:

名前の長さ

サーバ側ではhapijs/joiを用いてクライアントから送られてくるデータのバリデーションを行いました。その際、ユーザが設定する名前の長さを決めることが必要でした。私が知る限り最も長い日本の名前は「寿限無」なので:

としておきました

いまのおきもち

注:以下ポエムです。

自分が「コンテンツ主義」だと言われて少し動揺しました。確かにaqccとかAQamlとかMioを作って、それを中心に記事を書いたり資料を作成したりしているので、そう見えるのかも知れません。もう少しアウトプットの量を増やせばいいのかもしれませんが、中身の薄いものを執筆したところで意味がなく、面白くないものを書いてもやっぱり意味がありません。そういう意味で、なにかモノを作ってそれについて書くというのは、自分の経験に基づいた文章を作成できるので、中身が薄くなりにくいのかもしれません。この記事が薄くないのかと言われると少し言葉に困りますが。

話は変わりますが、むかし家に『手が脳を鍛える 作って遊べ!』(かざま りんぺい、誠文堂新光社、2004)という本があって、よく眺めていました2。この本の中に印象深い文言があって、正確なところをちゃんと覚えていませんが「明日は何を作ろうか と思いを馳せていると、人生退屈することはない」みたいなことが書いてありました3。当時は「そんな簡単に新しい工作が思いつくものだろうか」と子供心に思ったのですけれど、 Mioを作っている最中に、今まさに自分がそういう状況だと気づきました。対象は工作ではなくてプログラミングですが、「明日は何を作ろうか」「ここをこうすればもっと上手く書けるんじゃないだろうか」「こういう機能を足そう」等々、なにか作品を作っているときにはずっと考えています。

さいごに

Webアプリ初心者が作ったので、Mioにはおそらく脆弱性とか死ぬほどたくさんあると思います。脆弱性でなくても「普通こんな書き方はしない!」とか「ここがおかしい!」など、IssueやPull request大歓迎です。ぜひお願いします。そこまで詳しく見る余裕が無い方も、せっかくここまで読んでいただいたので GitHub右上のStarボタンをポチッと押して頂けると私が喜びます。もう一度レポジトリを貼っておきます。

https://github.com/ushitora-anqou/mio

以上艮鮟鱇でした。ここまで読んでいただきありがとうございました。


  1. @uint256_tさんにヒントを頂きました。この場を借りてお礼申し上げます。


  2. タイトルに「作って遊べ!」とあるのに作ったことはほとんどありませんでした。なぜだろう。
  3. 多分全然違うので、あとでちゃんと調べて書き直します。

コメント

  1. nininga より:

    そのせつはどうも