ナカムラのブログ

福岡在住33歳がWebエンジニアへ転職を目指す

オンラインで○×クイズが遊べる「○×クイズONLINE」をリリースしました

○×クイズONLINE

サービスURL

www.marubatsu-quiz-online.com

リポジトリ github.com

○×クイズオンライン というサービスは、オンラインで○×クイズを行いたいエンジニアイベント参加者向けのパーティーゲームです。 ユーザーは ブラウザ上で自分のアバターを○のエリア、×のエリアに移動することによって二択クイズの回答をすることができ、チャットで ○ or × と発言するのとは違って、誰が、どれくらいの人数の人が、 ○ or × と答えているか、また回答に迷っている様子がリアルタイムで見れる機能 が備わっている事が特徴です。

特徴

アバターの動きをリアルタイムに反映

自分のブラウザで自分のアバターを動かすと、他の参加者全員のブラウザにその動きがリアルタイムに反映されます。同時に、他の参加者のアバターの動きも自分のブラウザにリアルタイムに反映されます。

チャット機能

LINE風のチャットも使えます。もし不要の場合はOFFにできます。

こんな時に使えます

オンラインイベントを盛り上げたい

オンラインでの勉強会やミートアップなど、イベントの余興として最適です。新規参加者もゲームに参加しやすく、和気あいあいと楽しめます。

新入社員歓迎会

新入社員歓迎会などにもご利用いただけます。その会社にまつわるクイズや、一般常識を問うクイズなどを作成すると盛り上がるかもしれません。

オンライン飲み会

仲間と話しながらお酒を飲むだけでも楽しいですが、マルバツクイズで遊ぶと更に楽しくなります。ルールも簡単で誰でもわかるので気軽に遊べます。

使用技術

バックエンド

フロントエンド

  • Nuxt.js 3.5.2
  • TypeScript
  • Tailwind CSS
  • daisyUI

インフラ

環境構築

  • Docker
  • Docker Compose

テスト

Linter/Formatter

  • ESLint
  • Prettier
  • rubocop

CI/CD

外部サービス

簡単な自己紹介

今年で34歳になる福岡生まれ福岡育ちのナカムラといいます。2023年現在、未経験でwebエンジニアになるべく学習&転職活動中です。前職は郵便屋さんでした。
ある日、山道の郵便配達中に急に制御不能になったスーパーカブでフェンスを突き破って崖から落ちて死にかけたことがきっかけでキャリアチェンジを決意しました。
キャリアチェンジの方向性としていくつか候補をあげ、その中の1つがエンジニアでした。プログラミングのプの字も知らない状態からとりあえずProgateをやってみたところこれがとても楽しく(もっと早くに出会っていれば・・・!)、本格的に学習をするためFJORD BOOT CAMPに入隊しました。

このサービスを作った経緯

私が所属するFJORD BOOT CAMPでは月に1度、オンラインでミートアップを行います。日本全国の受講生がオンライン上に集まり、ビデオ通話でアルコール片手に親睦を深める会です。
FJORD BOOT CAMPではこのようなオンラインイベントを定期的に行っているのですが、イベントを盛り上げたり、各参加者同士の親睦を深めるようなパーティーゲーム、特に「リアルタイムで皆の様子がわかるような○×クイズ」が欲しいという要望がありました。とても作りがいがありそうな要件&受託開発に興味があるという理由から開発に手を挙げさせてもらいました。

このサービスの使い方

クイズの出題者として

1. ゲームを作る

ホームの「新しいゲームを作成する」からゲームを作成します。ここでクイズを複数問登録します。

2. 会場URLをコピーする

ゲームの作成が完了したら、そのゲームの会場URLが発行されるのでそれをコピーします。

3. ゲーム会場にアクセス

ゲームの作者が一番最初にゲーム会場にアクセスしてください。アクセス方法は、ゲーム詳細ページの「ゲーム会場へ入る」をクリックしてください。作者が会場に入っていないと、他の参加者が会場に入れないので注意してください。

4. 会場URLを参加者にシェア

ゲーム作成者がゲーム会場URLにアクセスした状態で、ゲームの参加予定者に対して発行されたURLをシェアします。推奨参加人数は10人前後を想定しています。

5. 参加者がゲーム会場にアクセスするのを待つ

参加者全員がシェアしたURLにアクセスするのを待ちます。アクセスした人は「入室済み」となります。

6. 参加者全員が会場に入ったことを確認する

ゲーム作成者には、どの参加者がゲーム会場にアクセスしてきたかわかるようになっています。全参加者が入室したことを確認できたら、「ゲームを開始する」をクリックします。クリックすると接続が始まるので接続が終わるまで待ちます。

7. ゲームを開始する

接続が完了するとクイズが出題できるようになります。画面右上にゲーム作者用のメニューがあるのでそこから出題します。「n問目を出題する」というボタンを一度クリックすると、出題、回答、判定、解説まで自動で行われます。解説まで終わると次のクイズを出題できるようになります。

クイズの回答者として

1. シェアされたURLにアクセスする

出題者からシェアされたURLにアクセスします。

2. 接続が完了するまで待機

アクセスできたら、ゲームが開始されるまで待機します。

3. アバターを動かして回答する

全ての参加者が接続を完了したらゲームが開始できるようになります。出題者からクイズが出題されたらアバターを動かして回答しましょう!

どうやってwebでリアルタイム通信を行っているか

WebRTC

WebRTCというwebプラットフォームでリアルタイム通信を実現するためのプロジェクトがあります。 WebRTCとはwebでリアルタイム通信を行うための様々な技術の集合体で、APIとしてブラウザに実装されており、新しいプラグインなどを追加せず標準で利用できます。WebRTCの一部としてP2P通信が採用されており、今回はこのP2Pという通信技術を利用し、各ゲーム参加者同士のブラウザを相互接続してリアルタイムにデータを送受信することでDOMを同期しています。

P2P

通常webで利用される通信は主にクライアント・サーバー方式となっています。webサイト利用者は各自ブラウザからサーバーに向けてリクエストを送り、返却されたHTMLなどを受け取ります。

クライアント・サーバー方式
P2P通信ではクライアント同士が相互に接続します。完全にクライアント同士が独立して相互接続を行うP2PをピュアP2Pと言い、サーバーを介してクライアント同士が相互通信するP2PをハイブリッドP2Pと言います。今回はサーバーを介して相互接続するハイブリッドP2Pを利用しました。
ピュアP2P
ハイブリッドP2P

SkyWay

ただ、このハイブリッドP2P通信を実現するためにはいくつかのサーバーが必要になってきます。通信相手のIPアドレスなどの情報を知るためのシグナリングサーバーや、NAT越えの要否を判断するSTUNサーバー、実際にNAT越えを行うTURNサーバーなどです。もし完全に自作でwebアプリにP2Pを実装する場合上記のサーバーを自身で建てなければなりません。そこでそのような各種サーバーを用意してくれたり、WebRTCをよりわかりやすく使うためのJavascriptSDKを提供してくれるSkyWayというサービスを利用させてもらいました。

このサービスはweb用のJavascriptSDKだけではなくiOS用やAndroid用のSDKも用意されており、簡単に自身のアプリにビデオ通話機能などを組み込めます。主な想定利用シーンはビデオ通話などのメディアチャネルを通じたリアルタイムコミュニケーション用として提供されていますが、テキストデータなどを送受信するためのデータチャネルも提供されており、今回はこのデータチャネルを利用しアバターの座標データなどをブラウザ間で送受信し、DOMに反映させています。

大変だったこと

1枚のHTMLに多面的な視点で処理を詰め込む

webアプリで複数人が同時接続するリアルタイムなゲームを実装するにはHTML1枚の中にかなり多くの処理を詰め込まないといけません。処理の多さだけでなく、「データを送信する側の処理」と「データを受信する側の処理」といった視点や、「出題者として」、「回答者として」の視点など、多面的な視点を考えながら1枚のHTMLに処理を書いていく必要があります。 また、全参加者同士のブラウザを相互接続する際に、一度に全員が相互接続の処理を開始してしまうとSkyWayのサーバーがパンクしてしまいます。SkyWayではこのような多くのクライアントが同時に接続した場合、SFUサーバを使用してサーバがパンクすることを回避する仕組みが用意されているのですが、それはメディアチャネルのみでデータチャネルはサポート外となっています。なので自力でSkyWayのサーバがパンクしないように各クライアントが相互接続する順番などをハンドリングしていく必要がありました。

このような背景から、コードの保守性や、再利用性、理解しやすさなどは一旦横において「とりあえず動く」という状態のものが出来上がった時、1枚のHTMLに書いたjavascriptの行数が1000行程になり、とんでもない魔境が爆誕してしまいました。どこに何が書いてあるか探すのが大変ですべて投げ出したくなる衝動に何度も襲われました。
ですが諦めず、HTMLをコンポーネントに細分化していき、Javascriptもクラスを分けて何度も整理していく内にかなり見通しが良くなりました。以前は、オブジェクト指向についてフィヨルドで学習していましたが、正直「オブジェクト指向はなぜ重要なのか」ということを実感していませんでした。今回、クラスを利用して整理していく中で、オブジェクト指向の便利さを身にしみて実感しました。

本番環境の動作確認が1人でできない

「複数人で同時に遠隔地からアクセスする」という実際のシチュエーションを再現するのは無理がありました。なのでFJORD BOOT CAMPでは毎週水曜日、自作サービスの進捗を報告するミーティングがあるのですが、そこで他の受講生の方に協力して頂いていました。皆さん積極的に協力いただいてとても助かりました。完全に一人ではこのサービスは開発できなかったと思います。FJORD BOOT CAMPの皆様本当にありがとうございました。

使ってみたい技術を詰め込みすぎて新規学習コストかさんだ

自作サービスの技術構成に関して、「興味がある技術を取り入れたい」、「この際苦手を克服したい」という思いから、フィヨルドのプラクティスには無い技術を多く採用しました(Docker, Typescript, Nuxt, Firebase, Rspec, Vitest, Cypressなど・・・)。特に、認証機能にFirebaseAuthenticationを利用したのですがこれがとても難解で理解するのに時間がかかりました。

実際に開発している時は学習コストが増えすぎて結構しんどかったです。ですがその代わり、自分の技術の引き出しは以前に比べて大幅に増えたと思いますし、未知の技術に対する耐性もできてよかったです。

自作サービスを作る上でやってよかったこと

壊れてもいい練習用リポジトリを用意する

まったく初めて0からサービスを作った経験がなく手探り状態だったので、とりあえずAPIHelloをリクエストし、レスポンスを表示するだけのフロントエンドと、Helloを返すだけのAPIをつくりました。本命のアプリに似た、壊れても大丈夫な練習台を用意しておくと特にインフラ周りを色々試せるので良かったです。

サービスの最重要機能から実装に取り掛かる

まずサービスの最重要機能から取り掛かった点は良かったと思います。今回のアプリのメインの機能は「リアルタイムにブラウザ同士でデータをやり取りする」という部分だったので、その機能が「そもそも実際に実現できるのか」ということを一番最初に確定することで安心感を得られました。もし例えば認証機能やリソースのCRUDなどから実装を始め、アプリの外堀を固めた上でメイン機能の実装にとりかかった場合、それがもし実現できなかった、そもそも不可能だったとき、下手したら今までの作業が全て無駄になってしまいます。なのでまずは最低限のプロトタイプを作成し、本番環境にデプロイまで行いました。このプロトタイプで動作確認を行いリアルタイム通信ができると確信した上で、その他の機能を追加していきました。

早い段階でCI/CDを構築する

早い段階でCI/CDを構築したことも良かったと思います。CI環境は自分が思っているより環境の違いに悩む場面が多いです。ローカルではしっかりテストは動くのに、いざCIでテストを実行すると動かないor何故かテストが落ちたりします。また、ローカルでは動くのに本番環境ではアプリが動かないといったトラブルが起きます。初期段階でこの辺りを構築しておくと、問題が発生した時に原因の特定が比較的容易になると思います。

このサービスのこれから

クイズ会場のUIをもっと洗練させたい

今はPC画面を模したデザインになっていますが、今後はもっと洗練させてよりゲームっぽいUIにしていけたらと思っています。また現在はクイズ会場のUIは1択しかありませんが、この選択肢を増やす、ユーザーがアップロードした画像を背景にするなどできればと思っています。

同時接続人数を増やす

現在は同時接続人数を10人前後で想定していますが、これを20~30人前後で同時接続して遊べるようにできたらなと思っています。

GitHubログイン以外のログイン方法を追加したい

このサービスは基本的にフィヨルドブートキャンプの関係者向けに作ってあるのでGitHubアカウントが必須となっています。これをもっとオープンに、一般の人にも使ってもらえるように間口を広げていきたいと思っています。

わかりやすかった参考資料など

WebRTC

知っている人も多いかと思いますがvoluntasという方が書かれたWebRTCに関する資料になります。日本語書かれていてとてもわかり易く、大変参考になりました。

WebRTC コトハジメ · GitHub

バックエンドとフロントエンドを分ける開発方法について

こちらのwebサイトではバックエンドをRails(API)モード、フロントエンドをNuxtで構成するアプリの作り方をとても丁寧に、わかりやすく解説されてます。またDockerの具体的な使い方やJWT認証についても解説してあり、総合的にモダンなwebサービスの作成方法を学べます。自分はこちらのサイトにとてもお世話になりました。

blog.cloud-acct.com


Nuxt3

Nuxt3について詳しく解説してあります。Nuxt3はリリースされてから日が浅くNextに比べると圧倒的に参考資料が少なかったのでとてもお世話になりました。

developer.mamezou-tech.com


WebAPI設計

WebAPI設計に関して、初学者にとてもわかり易く解説されてます。

www.hypertextcandy.com


OAuth

OAuthについてかなりわかりやすく解説されています。

qiita.com

qiita.com


今回作成したwebサービスでは想定利用者がフィヨルド関係者(エンジニア)なのでFirebase AuthenticationでGitHub認証を使用しました。その背後でどのような処理が行われているのかについてとても参考になりました。

maku.blog


Firebase Authentication

FirebaseAuthenticationでは認証にJWTを使用します。このJWTについてわかりやすく解説してあります。

developer.mamezou-tech.com


Firebase Authenticationを自分のアプリに導入する際に、バックエンドやフロントエンドのやるべきことなどが図解されていてイメージしやすかったです。

qiita.com


フロントエンド(Nuxt)でのFirebase Authの初期化方法などが解説してあります。

www.memory-lovers.blog


バックエンド(Rails)側での JWTの認証方法などが解説してあります。

nishinatoshiharu.com

Firebase認証では、認証が成功したらFirebase側からidTokenというJWT形式(JSONをBase64URLでエンコードしたもの)のトークンが返却されます。これはFirebase上のユーザーを一意に特定するuidやユーザーの情報(今回はGitHub Authを利用したのでGithubのユーザー名、プロフィール画像のURLなど)をJWT形式に変換したものになります。このJWTをフロントからリクエストヘッダ(Authorization)などに含んでHTTPSでバックエンドに送信し、バックエンド(今回はRails)で検証する必要があります。検証が成功するとJWTがデコードされ、ユーザー情報をペイロードから取得できます。

しかし、Firebase公式のFirebase Admin SDK にはRuby用のSDKは提供されておらず、検証において公式SDKを利用することができません。なので自分で検証用メソッドなどを自作するか、外部ライブラリを利用する必要があります。自分は以下のgemを使わせてもらいました。

一つ注意点としてこのgemでは検証のために必要なGoogleのX.509証明書を定期的にダウンロードしそれをRedisに保存し検証時に使用するためRedisが必要になります。なのでRails側からRedisに接続できるように設定する必要があったりと新たに調べることが増えて大変かもしれません。スケジュールに余裕がない人はRailsアプリの認証にFirebaseAuthenticationの採用は見送ったほうがいいかも知れません。

github.com


フロントエンド用各種ツール・フレームワーク

幅広いフロントエンドに関する各種ツール・フレームワークなどの解説をされていて、情報も新しいのでとてもお世話になりました。基本的に入門レベルなのですが、丁寧に解説されていて、記事数も多くて学びたいフロントエンドに関するおおよその概要を掴むときによく参考にさせてもらいました。

reffect.co.jp

コンポーネント設計

フロントエンドをVueやReactなどで作成する場合、コンポーネント設計をすると思います。その際、「どれくらいの粒度でコンポーネントを分割するか」や「コンポーネントにどのような責務をもたせるか」など、設計の指針があった方がいいと思います。自分は当初アトミックデザインというデザインパターンに従ってコンポーネントを設計していたのですが、ルールの粒度が細かすぎて途中からしんどくなってしまいました。なので色々調べた結果、この方のデザインパターンがわかりやすく、自分にはしっくり来たので参考にさせてもらいました。

zenn.dev

ロゴの作成

ロゴの作成にこのサービスを利用しました。とても豊富なテンプレートがあり、操作が簡単でカスタマイズしやすかったです。無料で使えます。

www.designevo.com

さいごに

自作サービスをリリースすることができてとても達成感を感じてます。
完全初心者からここまでこれたのもFJORD BOOT CAMPの方々のおかげです。特に毎週進捗報告会の際に動作確認の協力いただいた方々にとても感謝しています。 まだエンジニアとしてスタート地点にも立っていませんが、はやくエンジニアとしてのキャリアを積んでいけるように頑張っていきたいと思います。ありがとうございました!

初めてのLT会

初めてのLT会

自分は今未経験からwebエンジニアとして転職するためにfjordbootcampというオンラインスクールで勉強中です。このスクールの中で「初めてのLT会」というイベントが定期的に開催されるのですが、今回は初めてこのLT会に参加しました。その中で感じたことやちょっとしたトラブルについて書きたいと思います。

bootcamp.fjord.jp

speakerdeck.com

LT会とは?

Lightning Talksの略で、短いプレゼンのことです。およそ5分の制限の中で自由にプレゼンしていいのが特徴のようですね。内容も基本的に自由でいいみたいです。もちろんテーマが決めてあるLT会ならそのテーマに沿ってそれぞれがテーマを決めてプレゼンします。

メリット

LT会に参加することの最大のメリットは「人前で発表することに慣れる」ということだと思います。人前で話すのが苦手な人には場馴れするいいきっかけになると思います。特に今回のLT会は参加者がfjordbootcampの関係者のみでしたのでかなり心理的なハードルは下がりました。デメリットは特に思い浮かばないんですが、有るとすれば準備に時間がかかることくらいでしょうか。

感想

とても緊張しました。普段人前で話すのはめちゃくちゃ苦手で好きではないのですが、苦手克服のために勇気を出しました。実際に終わってみると、とてもいい経験になったし楽しかったなと思います。内容に関わらず人前で発表した事自体が自信になりますし、他にも、オンライン上でのコミュニケーションも苦手意識がありましたが、少し軽減された気がします。これをきっかけに少しづつコミュニティに入っていきたいと思いました。また、他の人の発表を見ることでいろんな気づきがあってとても刺激になりました。

発表を決めてから本番まで

テーマ決め

今回のテーマは「今自分が取り組んでいること」というテーマでした。自分の場合、ちょうど勉強がてら「自作PCを作ってwebサーバーとして運用する」ということに取り組み始めていたのでちょうどタイムリーなテーマでした。自分みたいに右も左も上も下も分からないような人にとってプラスになるんじゃないか?と思って「自作webサーバーを作る」というテーマで発表することにしました。

資料作り

テーマが決まったらとりあえず何でもいいので書き出してみることにしました。いきなりツールを使わずにとりあえず下書きから始めます。自分はnotionに書きました。

とりあえず文章に書き出す

とにかくまずは頭の中の整理ということで、伝えたいことを書き出しました。

とりあえず整理する

必要なものとそうでないものに分けていく。

とりあえず流してみる

時間配分を掴む。オーバーしたら少し削って・・を繰り返す。

スライドを作る

ある程度内容が固まったらプレゼン資料作成ソフトで作っていきます。自分はmacbookにはじめから入っているキーノートを使いました。

ツールの使い方をしっかり理解しておく

資料自体はすぐ作れたけど、実際に発表する時のことを考えていませんでした。キーノートには(というかこれ以外のツールもそうだと思うけど)プレゼンモードがあって、作成したスライドを再生する機能があります。なので本番は再生モードで発表するのですが、人生で一度もこういった発表をしたこと無いので知らなかった・・・。この機能を知らなかったために、リハーサルでうまく画面共有できなくて(編集画面のまま発表しようとした)めちゃくちゃ焦りました・・・無知すぎる・・・。

リハーサル

fjordbootcampではremoというバーチャルイベントツールを使います。複数人で同時にテレビ電話できるツールですね。ここで発表者が作成したスライドを画面共有して発表します。

通信環境をしっかり確認しておく

初回のリハーサルで最初は調子良かったんですが、いざ画面共有しようとすると何故か通信が不安定になってまともにつながらなくなりました。なので最初のリハーサルでは一度も発表できず、何もできませんでした。数日後にもう一度リハーサルさせていただくことになりましたが、この時はたまたま不安定になったのかな?くらいにしか考えていませんでした。

二回目のリハーサルではなんとか発表をすることができましたが、その後にまた不安定になりまともにつながらず・・・。この時点で発表まであと3日でした。相当焦りました。

最近自分は仕事を辞めたのでしばらく実家にお世話になろうと帰ってきたんですが、現在の実家の通信環境を詳しく把握していませんでした。とりあえず光回線が引き込んであるので問題ないだろうと思っていたんですが、よくよく調べてみるとプランも100MBだし、ルーターも10年以上前のルーター・・・おそらくこれが原因だろうと慌ててプラン変更してWiFi6対応のルーターを買ってきて設置しました。これでなんとか速度も上がり、通信も安定しました。まさか実家の通信環境がここまで昔のままだったとは・・。普段ネットを使うくらいなら問題ないですがremoのような通信に負荷がかかるツールを使う時は通信環境もしっかり確認しておくのが大事だなと思いました。

f:id:keiz1213:20220319130440j:plain
remoのシステムテスト

本番

そんなこんなで本番を迎えたのですが、なんとか発表できました。本番で意識していたことはとにかく落ち着いてゆっくり話すことでした。時間配分は前もって練習していたのであまり気にせず発表できました。緊張すると自分はちょっと早口になるのでこの辺を注意してました。参加している人たちはとにかく温かくて、とても発表しやすかったです。フィヨルドの人たちは本当に優しいな〜と思ったLT会でした。