avatar
screenshot
2021年9月〜

qflasher

効率的な反復学習ができるWebで動く単語帳です。

概要

効率的な反復学習が可能なWebで動く単語帳です。 単語帳を作成し、単語帳をめくる感覚で学習を行うことができます。 めくったあとに正解か不正解かを自分で判定し、学習が終わったあとに、不正解の単語だけを繰り返し実行することもできます。

高速に反復を行えるよう、できるだけマウスの移動を少なくするような工夫をしています。

単語帳の学習画面

また、高速に単語帳を作成できるようにキーボードだけで操作できるような工夫もしており、 各入力要素でEnterを入力すると、次の入力要素にフォーカスが当たるようになっています。 CSVから単語帳を読み取る機能も考えてはいましたが、実装はしていませんでした・・・。

単語帳の作成画面

使用した技術

  • TypeScript
  • Next.js Static Exports
  • Chakra UI
  • Playwright
  • Firebase

ログイン → 単語帳の追加 → 単語帳の学習 → 単語帳の削除 → アカウントの削除 という一連の流れを通すテストをPlaywrightで一つだけ書いています。 隔離した環境でテストを行うのではなく、開発環境として使っているローカルのFirebase Emulatorにそのままアクセスしています・・・。

Firestoreを使用する場合には、冗長性をもたせるか、冗長性をなくしてクライアント側でジョインするかを選択しなければいけません。 例えばこのアプリであれば、単語帳のデータと、単語帳に含まれるカードのデータがあります。 単語帳に含まれるカードのデータに単語帳を表すデータをすべて含める冗長な設計と、 カードに単語帳のidをもたせてクライアント側でジョインする設計が考えられます。

前者のメリットは、クライアント側がシンプルになることで、デメリットは、例えば単語帳の情報が更新されたときに、 すべての単語帳のカードに含まれる単語帳のデータを更新するバックエンドが必要になります。 Cloud Functionsなどで実装する必要があるのですが、お金がかかるので冗長性をもたせるのは断念して、クライアント側でジョインする設計にしています。

プロジェクトから学んだこと

このプロジェクトを通じて、Firestoreの難しさを実感しました。 シンプルなデータを保存するだけなら手軽で便利なのですが、複数のデータを紐づける必要がある場合には、 冗長性をもたせるか、クライアントサイドジョインを選ぶ必要があります。 冗長化すると、更新のためのバックエンドの、クライアントサイドジョインではフロントエンドの実装コストが増えます。 フロントエンドはバックエンドと比べてそこまで複雑ではないのですが、 クライアントサイドジョインでは複数のリクエストが飛ぶため、ジョインするデータが膨大になってくるとパフォーマンスが悪くなる懸念があります。 ほかにも、データの検索に制限もあります。

Firestoreの便利な点は、シンプルなデータを高速にやり取りすることや、リアルタイムアップデートをシンプルに実現できることだと考えており、 データがそこそこ複雑になりそうな場合には、デメリットも考えて選択する必要があると感じました。