学生が「数式の書けるチャットアプリ」を作りました【TS/NextJS】

これは [**N予備校プログラミングコース Advent Calender 2021**](https://qiita.com/advent-calendar/2021/nyobi) の 23 日目の記事です。

みなさん、こんにちは！
私は大学で物理学を専攻する学生です。
また、[株式会社ドワンゴ](https://dwango.co.jp)のアルバイトとして **[N 予備校プログラミングコース](https://www.nnn.ed.nico/pages/programming/)** の各種教材開発に携わっています。
この記事では、私が趣味として開発している **数式の書けるチャットアプリ** について、開発の経緯を交えながら紹介します。

![math.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/560678/8f3496c0-6a80-7fe1-abc9-dff52e05d527.gif)
（GIF アニメーションです。動かない場合はクリックしてください。）


# 目次
**=== 紹介編 ===**
[00 ... **数式**が書けるリアルタイムチャット「**ChatZEMI**」](#00--数式が書けるリアルタイムチャットchatzemi)
[01 ... **基本的な機能**の紹介](#01--基本的な機能の紹介)

**=== 技術編 ===**
[02 ... **構成** / Web アプリケーション](#05--構成-web-アプリケーション)
[03 ... **環境構築** / Docker](#06--環境構築--docker)
[04 ... **言語** / TypeScript](#07--言語--typescript)
[05 ... **Web フレームワーク** / React と Next.js](#08--web-フレームワーク--react-と-nextjs)
[06 ... **スタイリング** / TailwindCSS](#09--スタイリング--tailwindcss)
[07 ... **NoSQL データベース** / MongoDB](#10--nosql-データベース--mongodb)
[08 ... **リアルタイム通信** / WebSocket](#11--リアルタイム通信--websocket)
[09 ... **表現** / Markdown](#12--表現--markdown)
[10 ... **数式** / TeX と KaTeX](#13--数式--tex-と-katex)
[11 ... **絵文字リアクション** / アルゴリズム](#14--絵文字リアクション--アルゴリズム)
[12 ... **認証・認可** / Firebase Authentication](#15--認証認可--firebase-authentication)
[13 ... **モバイルアプリ** / Progressive Web Apps](#16--モバイルアプリ--progressive-web-apps)
[14 ... **デプロイ** / Google Cloud Platform](#17--デプロイ--google-cloud-platform)
[15 ... **今後の開発**](#18--今後の開発)

---

# 紹介編

## 00 ... **数式**が書けるリアルタイムチャット「**ChatZEMI**」

今回紹介する、私が個人で開発しているチャットアプリはこちらです。

https://chatzemi.app

**ぜひ自由に利用してみてください（匿名でも投稿できます）！**
**投稿練習ルームはこちらです ↓**
https://chatzemi.app/rooms/public/614a6ee16cfb1899a2e2de96

なお、この Web アプリは現在も開発中のため、正常に動作しないことがあります。仕様にある機能の一部は未実装です。

---

## 01 ... 基本的な機能の紹介

数式やソースコード、太字、見出し、表、画像などの多彩な表現ができる**リアルタイムチャット**です。
ページを再読み込みしなくても、リアルタイムにやりとりが反映されます。
![スクリーンショット 2021-12-23 11.31.04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/560678/05e04fce-2ed7-841f-2fcc-a508409a97b4.png)

誰でも**公開ルーム**に参加して会話したり、ルームを作成したりできます。
![スクリーンショット 2021-12-23 11.27.00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/560678/3b9a67f1-9571-d981-0655-caf734a69355.png)

**プライベートルーム**は、許可されたメンバーしか閲覧・投稿できません。
![スクリーンショット 2021-12-23 11.29.14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/560678/7dd8fea0-01b4-81e5-4ceb-64c1d30dcf06.png)

様々な**数式**が、ボタン操作や TeX 形式で入力できます。
![スクリーンショット 2021-12-23 11.34.26.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/560678/20de2001-adf7-42ec-cf60-ffa9a5e06ef7.png)



---
# 技術編
技術編では、このアプリで使用している技術を簡単に紹介していきます。
N 予備校プログラミングコースで扱っている技術も多く含まれていますので、その関連性も紹介します。

## 05 ... **構成** / Web アプリケーション

今回のチャットアプリ「ChatZEMI」は、いわゆる **Web アプリケーション** です。
Web アプリケーションという言葉は、色んな意味合いで使われることがあります:

(1) Web の**通信の仕組み**を利用したアプリケーション（プログラム）のこと
(2) Web の**表示の仕組み**を利用したアプリケーション（プログラム）のこと

(1) の意味では、HTTP などの Web の通信の仕組みを利用して、サーバーが処理を行う構成を持っていれば、ある種の Web アプリケーションと呼ばれます。 例えば Web API の開発はこれにあたります。
(2) の意味では、たとえサーバー側での動的な処理がなかったとしても、HTML などの Web の表示の仕組みを利用した処理があれば、ある種の Web アプリケーションと呼ばれます。

今回のチャットアプリ「ChatZEMI」は、(1)、(2) どちらの要素も持つ Web アプリケーションです。
クライアント（Web ブラウザ）とサーバーがそれぞれ分担して処理を行う **サーバー・クライアント型** の構成をしています。

クライアント側を **フロントエンド**、サーバー側を **バックエンド** ということもあります。

> **N 予備校との関連**
・Web の表示の仕組みとクライアント側のプログラム ... **入門コース第 1 章**
・サーバー・クライアント型通信、 HTTP 通信 ... **入門コース第 2 章** 
・サーバ側のプログラム ... **入門コース第 3 章、第 4 章** 


## 06 ... **環境構築** / Docker

環境構築は **Docker** を利用しました。

[![スクリーンショット 2022-01-06 16.01.58.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/560678/a889d7ce-b956-dd8c-0fcc-f3a7175c09b4.png)](https://www.docker.com)
[Docker（画像引用: https://www.docker.com）](https://www.docker.com/)

Docker は Linux 上で「コンテナ」を実現するためのソフトウェアです。
**コンテナ** とは、OS 上に論理的な区切りをつける仕組みのことです。コンテナを使えば、1 つのパソコン上に異なる複数の環境を独立に構築することができます。
Docker は元々 Linux 上で動作するソフトウェアですが、MacOS や Windows 上でも利用できるようにする仕組み（**Docker Desktop**）が整っています。

Docker を利用するメリットは、**アプリケーションの開発環境、テスト環境、本番環境を統一的に簡単に構築できる**ことです。
さらに今回の場合は、デプロイに Google Cloud の **Cloud Run** という仕組みを利用しています（後述）。
Cloud Run ではコンテナをデプロイの単位にするので、Docker の利用は不可欠です。

具体的な準備としては、アプリケーションを実行する環境を整えるコマンドの集合体である **Dockerfile** を用意します。
後述するように、このアプリは Next.js を利用しています。 Next.js は Node.js 環境でビルド・実行されるので、Node.js の Docker イメージを利用します。

↓ 本番用 Dockerfile の抜粋（Next.js を利用している場合）

```dockerfile:Dockerfile（抜粋）
FROM node          # ベースとなるDockerイメージ（すでにNode.jsやyarnはインストールされている）
WORKDIR /app       # Dockerコンテナの作業ディレクトリ
COPY . /app        # ホストOSからDockerコンテナへのコピー
RUN yarn install   # package.jsonからnode_modules/を生成
RUN yarn build     # Next.jsアプリのビルド

CMD ["./run.sh"]   # コンテナ起動後に実行するスクリプト
```

```sh:run.sh（抜粋）
yarn start         # Next.jsアプリの実行
```

さらに、開発環境におけるコンテナ起動の簡略化のために **docker-compose.yml** を準備しておくと便利です。

> **N 予備校との関連**
・Linux、コンテナ技術、Docker、Docker Desktop ... **入門コース第 2 章** 
・Docker を利用した環境構築 ... **入門コース第 2 章、第 3 章、第 4 章** 

## 07 ... **言語** / TypeScript

フロントエンドとバックエンドそれぞれで、使用するプログラミング言語を選定します。
まず Web フロントエンドは、ブラウザによってプログラムが実行されるので、原則 JavaScript で書く必要があります（ここでは WebAssembly には触れません）。
他方バックエンドは、サーバによってプログラムが実行されるので、JavaScript（Node.js）でも Python でも Go でも Java でも Scala でも Ruby でもかまいません。

バックエンドで使用できる言語には、それぞれ良さがあって、それぞれに実績があるわけですが、
・ **習得コストが低く、スピード感を持って開発できること**
・ **ライブラリを使いまわせること**
から、バックエンド・フロントエンドともに JavaScript を使うと便利です。

そこで、フロントエンド・バックエンドともに、JavaScript の仲間（AltJS）の **TypeScript** を使用することにしました。
**JavaScript を使用できる状況では、JavaScript の代わりに TypeScript を使うことができます**。
TypeScript で書かれたプログラムは、JavaScript に変換（**コンパイル**・**トランスパイル**）した後に実行するからです。

[![スクリーンショット 2022-01-06 16.07.14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/560678/5d4f118b-55e7-3f04-1641-dce4e052efa0.png)](https://www.typescriptlang.org/)
[TypeScript（画像引用: https://www.typescriptlang.org/）](https://www.typescriptlang.org/)

最終的に JavaScript になるのに、なぜわざわざ TypeScript を使うのでしょうか？
それは、JavaScript にはない機能を使って、効率的・安全に開発を行うことができるからです。

TypeScript は、JavaScript とは異なり **静的型付け** の仕組みを取り入れています。
例えば、C / C++ や Go、C#、Java、Scala、Kotlin、Swift などは静的型付け言語です。
TypeScript では変数に型を指定し、コンパイル時に型チェックを行うことで、型安全性が向上しバグを見つけやすくなります。

また、型の指定は任意なので、安全な場合は型推論を使って省略することができます。そのため、コーディングの生産性を落とすことなく安全な型システムを導入できるのです。

> **N 予備校との関連**
・JavaScript ... **入門コース第 1 章** 
・Node.js（ブラウザ以外の JavaScript 実行環境） ... **入門コース第 3 章、第 4 章**
・Python ... **機械学習コース**
・Go ... **データ構造とアルゴリズムコース**
・Java、Scala ... **大規模 Web アプリコース**、**ニコニコ動画再現コース**


## 08 ... **Web フレームワーク** / React と Next.js

### SPA と SSR

Web フロントエンドとバックエンドの役割分担を考えます。
今回の Web アプリでは、近年標準的になった **シングルページアプリケーション（SPA） + サーバーサイドレンダリング（SSR）**の構成をとることにしました。

まず、**SSR（サーバーサイドレンダリング）**とは、伝統的な Web アプリケーションの実現方法です。
SSR ではサーバー側で完成した HTML を生成し（レンダリング）、それをクライアント側に送ります。

次に、**SPA（シングルページアプリケーション）**は、比較的新しい Web アプリケーションの形です。
ブラウザは、最初に骨組みとしての簡単な HTML をサーバーから受け取り、それと同時に JavaScript プログラムも受け取ります。
SPA では、この JavaScript がブラウザ（クライアント）上で実行され、**JavaScript が DOM を操作することで、ページ遷移せずにページの内容を書き換えます**。
単一のページ（シングルページ）で異なる複数のページ内容を実現するので、シングルページアプリケーションと呼ばれるわけです。

SPA では、データの取得は Web API を通して行います。クライアント（ブラウザ）の JavaScript に **Ajax** と呼ばれる通信をバックエンドの Web API に対して行う処理を記述することで、データを取得するのです。

SPA は、ネイティブアプリのような UI を実現できるので、良い UX を提供するのに有効です。
しかし SPA では、初期のページロードに時間がかかったり、SEO 対策上不利になりやすいなどのデメリットもあります。 

そこで、**SPA と SSR を組み合わせる**手法が広まりました。

### React と Vue、そして Next.js と Nuxt.js
SPA + SSR を実現するための便利な Web アプリケーションフレームワークとして **Next.js** や **Nuxt.js** があります。
生の JavaScript や jQuery を利用しても SPA + SSR を実現することはできますが、フレームワークを使った方が高機能で、しかも有用な知見がたまっています。

Next.js と Nuxt.js の違いは、SPA を実現する JavaScript ライブラリの違いです。
・**Next.js は React というライブラリ**
・**Nuxt.js は Vue というライブラリ**
を使用します。

React/Next と Vue/Nuxt のどちらを選んでも、大体の場合同じようなことは実現できます。ほとんど好みの問題ですが、今回は **Next.js を採用する**ことにしました。

[![スクリーンショット 2022-01-06 16.09.42.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/560678/460264ed-712f-fffe-57ad-c681d6567b36.png)](https://ja.reactjs.org/)
[React（画像引用: https://ja.reactjs.org/）](https://ja.reactjs.org/)

[![スクリーンショット 2022-01-06 16.13.34.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/560678/e8815be7-d639-6c8f-5d6e-5aa7949d3d39.png)](https://nextjs.org/)
[Next.js（画像引用: https://nextjs.org/）](https://nextjs.org/)


### Next.js アプリの構築

Next.js アプリの構築は非常に簡単です。
Node.js と yarn がインストールされた環境（前述の Docker コンテナなど）で、次のコマンドを打つだけで簡単に雛形を作成できます。

試しに雛形の Next.js アプリを作ってみましょう。

```shell:コンソール
yarn create next-app --typescript
```

`--typescript` は、TypeScript でプログラムを書くための準備を自動でしてもらうためのオプションです。このコマンドで、必要なライブラリを全てインストールしてくれます。

雛形ができたら、

```shell:コンソール
yarn dev
```

を打つだけです。ローカルで Next.js による Web アプリケーションが起動します。
ホットリロードが有効になっているので、プログラムを書いてファイルを保存するだけで、すぐに Web アプリが更新されます。

↓ すぐに Next.js アプリの雛形を起動できる
![スクリーンショット 2021-12-24 18.21.08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/560678/5d2f0b32-6030-79a2-4aec-d4a1c0ab8b2a.png)

Next.js は、ページのルーティングがそのままディレクトリ構造になっています。
これは非常に直感的で便利です。

例えば、`/rooms/12345` という URL のページを作成するには、`pages/rooms/[id].tsx` というファイルを編集します。
`pages` 配下のディレクトリ構造が、そのまま該当 URL のページルーティングになっているのです。
ちなみに `[id].tsx` という書き方は、`[id]` の部分が `12345` や `82351` など動的に変化する URL を統一的に扱える仕組みです。Next.js の **動的ルーティング** という機能です。

React と Next.js の詳細な書き方は省略しますが、React では **関数コンポーネント** というカタマリを組み合わせて Web ページを作るのが一般的です。
雛形の Next.js アプリをもとに、関数コンポーネントを作って組み合わせれば、複雑な Web フロントエンドをシンプルに開発できるのです！

### API Routes

Next.js は Web フロントエンドのためのフレームワークです。
そのため、バックエンド API は別のサーバーに別のフレームワークを使って構築してもかまいません。
しかし今回は、Next.js の **API Routes** という機能を使って、バックエンド API も同一の Next.js アプリの中に組み込むことにしました。
API Routes を使えば、ページのルーティングと同様の方法で、バックエンド API のルーティングとロジックの実装をシンプルに行うことができます。
さらに、**フロントエンドとバックエンドで型定義やライブラリを共有することができる**のです。

> **N 予備校との関連**
・SPA、Web API ... **入門コース第 4 章**

## 09 ... **スタイリング** / TailwindCSS

スタイリングは **TailwindCSS** という CSS フレームワークを使いました。

[![スクリーンショット 2022-01-06 16.15.34.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/560678/2085e17e-117e-9f01-c810-4209396703ab.png)](https://tailwindcss.com/)
[TaiwindCSS（画像引用: https://tailwindcss.com/）](https://tailwindcss.com/)


なぜこのフレームワークを選んだのでしょうか？

そもそもの問題として、通常の CSS は、**Web サイトの規模が大きくなると保守（メンテナンス）が難しくなります**。これは主に CSS そのものの言語仕様が原因です。

そこで、クラス名の付け方などを工夫して保守性の高い CSS を書こうとするのが「CSS 設計」という考え方です。有名な CSS 設計手法として、例えば BEM があります。
CSS 設計は機能ではなく、あくまでコーディングの「設計」です。他方で、CSS という言語そのものを拡張して、保守性の高いスタイリングを可能にする Sass という言語を使う方法もあります。 

しかし、これらはいずれもスタイルを自分で定義するので、多くの時間と労力がかかってしまいます。
そこで登場するのが **CSS フレームワーク** です。
CSS フレームワークはよく使う便利なクラスを事前に定義してくれているので、CSS を直接書くことなく、決められたクラスを指定するだけで簡単にスタイリングができます。

有名な CSS フレームワークには Bootstrap や Material UI などがあります。
しかし、Bootstrap や Material UI は便利で非常によく使われている反面、**デザインがありふれた陳腐なものになってしまいやすいというデメリット**があります。

それを解決するのが **TailwindCSS** です！
TailwindCSS は「ユーティリティ・ファースト」の CSS フレームワークと呼ばれます。
TailwindCSS では限られたユーティリティクラスを組み合わせて、希望のスタイリングを実現します。
ユーティリティクラスは、**CSS を直接書くことに似ている**ので、新たなスタイリングの方法を覚える必要はありません。
また、Bootstrap や Material UI と異なり、コンポーネントのクラスはありません。
コンポーネントは React などの JavaScript 側で定義すればよいのです。

TailwindCSS は限られたユーティリティクラスを使うことで、
・**スタイリングにかかる意思決定コストを削減しつつ**、かつ
・**自由で柔軟なスタイリングを可能にする**
という **イイトコ取りの CSS フレームワーク**なのです！

> **N 予備校との関連**
・Bootstrap ... **入門コース第 3 章、第 4 章**

## 10 ... **NoSQL データベース** / MongoDB

データベースは、いわゆる RDBMS（リレーショナルデータベース管理システム）ではなく、NoSQL のデータベースを使いました。 

今回使った **MongoDB** は、JSON 形式のデータを蓄えるデータベース管理システムです。

[![スクリーンショット 2022-01-06 16.18.03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/560678/6bf68fe5-d1cf-f42a-e6a7-7cdca00be41e.png)](https://www.mongodb.com/)

[MongoDB（画像引用: https://www.mongodb.com/）](https://www.mongodb.com/)


JSON は多くのプログラマーに馴染み深い形式だと思うので、非常に直感的に操作できます。
SQL ではありませんが、SQL の基本的な機能については同様の機能を持つクエリが存在します。
従って、SQL に慣れた方であれば、操作に困ることはまずありません。

MongoDB を使うメリットの 1 つは、**開発初期におけるデータモデリングの考慮がほとんど不要**だということです。
リレーショナルデータベースの設計は、最初に考えるべきことがたくさんあって大変ですが、MongoDB を使えば開発と同時にデータ設計を考え、柔軟に変更していくことが可能です。

さらに **MongoDB Atlas** という、クラウド上で MongoDB によるデータベースを構築できるサービスが公式に提供されています。
MongoDB Atlas のインフラは AWS、GCP、Azure から選ぶことができます。今回は、アプリケーションのインフラと共通化を図るため GCP を選択しました。

> **N 予備校との関連**
・データベース、SQL ... **入門コース第 3 章、第 4 章**

## 11 ... **リアルタイム通信** / WebSocket

![websocket.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/560678/fa715809-721c-a3e3-e70e-b42fd1f00cef.png)
[WebSocket の仕組み（画像引用: https://docs.microsoft.com/en-us/azure/application-gateway/application-gateway-websocket）](https://docs.microsoft.com/en-us/azure/application-gateway/application-gateway-websocket)

リアルタイム通信には、**WebSocket** を使用しています。

なぜ、通常の HTTP 通信だけではダメなのでしょうか？
それは、チャットアプリの仕様上、**プッシュ型の通信**が必要だからです。

HTTP 通信は、クライアント（ブラウザ）がサーバーにリクエストを送ってはじめて、サーバーはクライアントにデータを返します。
しかしこれでは、チャットアプリにおいてメッセージを待機していても、リクエストを送らなければデータが得られません。
HTTP 通信はプル型の通信であって、プッシュ型の通信には原則使えないのです。

他方 **WebSocket では、クライアントとサーバーが一度接続を確立すると、その接続を維持します**。接続が維持されているので、クライアントからのリクエストがなくても、サーバーからクライアントへ一方的にデータを送ることができます。
つまり WebSocket はプッシュ型の通信を実現し、それによって**リアルタイムなメッセージのやりとりや絵文字リアクション機能を可能にしているのです**。

具体的な実装としては、**Socket.IO** という WebSocket 通信のためのライブラリを使用しています。
Socket.IO では、何らかの理由で WebSocket 通信が確立できないときにも、定期的に自動リクエストを送ってデータを取得する **ポーリング** という方法で、擬似的なプッシュ通信を可能にします。

> **N 予備校との関連**
・WebSocket ... **入門コース第 4 章**

## 12 ... **表現** / Markdown

このアプリは **Markdown** 形式の入力と表示をサポートしています。

Markdown で入力したテキストは、**Markdown パーサー**によって HTML に変換されるように実装しています。
また今回のアプリでは、メッセージの入力画面で入力内容の状態を管理し、**リアルタイムプレビュー** の機能を実装しています。
そのため、入力した Markdown が瞬時に HTML に変換され、スタイルが付与されて画面に表示されるようになっています。

> **N 予備校との関連**
・Markdown ... **入門コース第 2 章**

## 13 ... **数式** / TeX と KaTeX

![math.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/560678/5da11283-bdad-abd0-cd8d-93d3a8ee0a76.gif)
（GIF　アニメーションです。動かない場合はクリックしてください。）

$\mathrm{\bf\TeX}$（TeX、テフ） は、**数式の描画を得意とした組版システム**です。
また $\mathrm{\TeX}$ に高機能なマクロをパッケージしたものに $\mathrm{\bf\LaTeX}$（LaTeX、ラテフ）があります。
$\mathrm{\TeX}$、$\mathrm{\LaTeX}$ は、数学・物理・情報系など数式を頻繁に使用する分野の人々に、広く浸透している組版システムです。

$\mathrm{\TeX}$ では例えば、

```tex:TeX
ax^2 + bx + c = 0
```

のように書くと、

$$
ax^2 + bx + c = 0
$$

のように数式が描画されます。

$\mathrm{\TeX}$、$\mathrm{\LaTeX}$ は、それ自体が組版システムであり、本来は Web 上で利用できるものではありません。

しかし、$\mathrm{\TeX}$ の数式表現を使って Web 上に数式を描画するライブラリがあります。
有名なものが **MathJax** と **KaTeX** です。
これらのライブラリを使えば、**Web ページ上の** $\{\mathrm{\bf\TeX}}$ **形式の数式を読み込んで、Web ページ上に数式を描画することができます**。

なお、今開いているこの Qiita のページでは MathJax が使われています。
このように数式（$\int f(x)dx $ ）が表示できるのは、Qiita に MathJax を使った処理が実装されているからなのです。

他方、今回紹介しているアプリ「ChatZEMI」では KaTeX を使用しています。
KaTeX は MathJax よりも高速な数式描画が可能です。

**具体的な実装としては、Markdown のパーサーの後の処理に KaTeX による変換を組み込みます**。
こうすることで、Markdown と $\mathrm{\TeX}$ 形式の数式表現を両立しているのです。

## 14 ... **絵文字リアクション** / アルゴリズム

![スクリーンショット 2022-01-06 16.48.55.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/560678/e824e713-6548-cee8-d05d-f77277e16bf0.png)


今回紹介しているアプリには、**Slack ライクな絵文字リアクション機能** を実装しています。
絵文字ピッカーは、オープンソースのライブラリがあるのでそれを利用しています。

他方で、
・**絵文字を押したら、ルームの全員に送信する**
・**誰かが押した絵文字はリアルタイムで受信し、即表示する**
・**絵文字が押された数をカウントして表示する**
・**自分の押した絵文字を取り消すことができる**
・**1 人が 1 つの絵文字のカウントを 2 以上増やすことはできない**
・**自分の押した絵文字は、スムーズな UI のために、通信によらず即反映させる**
といった仕様は、実現する該当するライブラリがないので、オリジナルに実装しています。

Web アプリケーションのプログラミングは、ライブラリを組み合わせて機能を構成することが中心になりがちです。
しかしこの絵文字リアクション機能のように、該当するライブラリが存在しないときは、**機能を実現するためのアルゴリズム（ロジック）をゼロから考える**こともあるわけです。

こういうものは調べてもあまり出てきません。自分でアルゴリズム（ロジック）を考える必要があります。
このときの頭の使い方は **競技プログラミング** の解法を考える時に似ているのではないでしょうか？
競技プログラミングとはいっても難易度が高いわけではなく、例えば AtCoder の初級者向けコンテスト ABC の C 問題くらい、つまり高度なアルゴリズムの知識は必要なく、プログラミング言語の標準機能を素朴に組み合わせて実現できるくらいのレベルです。

なお、こうしたオリジナルの処理には **テスト** が不可欠です。
オリジナルの機能は、**副作用のない純粋関数** として定義しておくとテストがしやすくなります。
副作用のない純粋関数とは、戻り値に処理の結果を集約させ、それ以外の部分で外部に影響を及ぼさない関数のことです。
すなわち、**関数プログラミング** の考え方が役に立ちます。

> **N 予備校との関連**
・アルゴリズム ... **データ構造とアルゴリズムコース**
・純粋関数、副作用、関数プログラミング ... **大規模 Web アプリコース Scala 基礎コース**

## 15 ... **認証・認可** / Firebase Authentication

[![スクリーンショット 2022-01-06 16.22.16.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/560678/ea39d72c-1721-9957-781b-9d9f6f077cdd.png)](https://firebase.google.com/)
[Firebase（画像引用: https://firebase.google.com/）](https://firebase.google.com/)


認証・認可をゼロから実装するのは大変なので、IDaaS （Identity as a service）を利用します。
IDaaS の有名なものには、Auth0、Firebase Authentication、Amazon Cognito などがあります。
今回は、**完全無料**で使える **Firebase Authentication** を利用することにしました。

N 予備校の入門コースでは、OAuth の仕組みを使って GitHub ログインを自前で実装します。
Firebase Authentication を使えば、GitHub ログインや Google ログイン、Twitter ログイン、Facebook ログインなどのほか、通常のメール・パスワード認証や後述する匿名認証を簡単に実装することができます。
認証と認可のためのライブラリはすでに用意されているので、自分でやるのは、その**ライブラリを使うことと UI を実装することだけ**です。

今回はメール・パスワード認証と Google ログインを有効にしています。 ログインフォームなどの UI は自前で実装するので、自由にカスタマイズできます。

さらに今回は、**匿名認証** という仕組みを利用しました。匿名認証を使えば、明示的にユーザーがログインをしなくても、Firebase Authentication が一時的な匿名ユーザーを作成し、ユーザーを管理できます。
匿名認証を使うことで、**最低限のユーザー管理をした上での匿名投稿を可能にしている**のです。

> **N 予備校との関連**
・OAuth、認証・認可 ... **入門コース第 3 章、第 4 章**

## 16 ... **モバイルアプリ** / Progressive Web Apps

[![スクリーンショット 2022-01-06 16.46.46.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/560678/6307c986-81d0-7da2-8e41-c00c2733423b.png)
](https://developer.mozilla.org/ja/docs/Web/Progressive_web_apps)
[PWA（画像引用: https://developer.mozilla.org/ja/docs/Web/Progressive_web_apps）](https://developer.mozilla.org/ja/docs/Web/Progressive_web_apps)

今回は、Web アプリケーションとしてチャットサービスを開発しました。
しかし、**Progressive Web Apps（PWA）** と呼ばれる仕組みを利用することで、Web アプリをモバイルネイティブアプリ（スマホアプリ）のような形態で提供することができるようになります。

開発した Web アプリを PWA 対応化することで、
・**ネイティブアプリと同様にアプリアイコンから起動**
・**ネイティブアプリと同様のスムーズな操作感**
・**オフラインでの動作**
・**Web ブラウザのアドレスバーや戻るボタン・ブックマークなどの不要なパーツを排したシンプルな UI**
を実現できます。

PWA として提供されるアプリケーションは、Android、iOS、Windows、macOS いずれでも動作します。
しかし、2021 年現在 iOS では PWA によるプッシュ通知を実現することはできません。

モバイルアプリとしての本格的な運用を視野に入れた場合、プッシュ通知はとても重要な機能です。したがって、本格的にモバイルアプリを Android、iOS ともに提供するためには PWA 以外の方法（ネイティブアプリ開発等）が結局必要になるのが現状です。

## 17 ... **デプロイ** / Google Cloud Platform

[![スクリーンショット 2022-01-06 16.25.32.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/560678/fe0709c6-c712-9791-9344-27848c35c4b1.png)](https://console.cloud.google.com/)
[Google Cloud Platform（画像引用: https://console.cloud.google.com/）](https://console.cloud.google.com/)


デプロイには **Google Cloud Platform（GCP）** の **Cloud Run** を利用しました。

Cloud Run は、**コンテナ単位でアプリケーションをデプロイできるサービス**です。
今回の Web アプリケーションは node.js がインストールされた Docker コンテナ上で動作するよう開発したので、そのままデプロイすることが可能です。

なお、通常 Next.js アプリで最もデプロイが手軽・安価なのは **Vercel** です。Next.js というフレームワーク自体が Vercel 社によって開発されていることもあり、とても簡単に Next.js アプリをデプロイできます。
また、同じ GCP で **App Engine** というサービスも Vercel と同じ手軽さでデプロイできます。
しかし、**Vercel と App Engine ともに、2021 年現在 WebSocket 通信に対応していません**。そのため、**WebSocket を利用したリアルタイム通信を実現するには、WebSocket に対応した Cloud Run を利用する必要があった**のです。

> **N 予備校との関連**
・デプロイ、Heroku ... **入門コース第 3 章、第 4 章**

## 18 ... **今後の開発**

開発中の機能として
・**ユーザーのフォロー機能**
・**SNS 連携機能**
・**OGP・Twitter Card 生成**
・**プライベートルームの許可メールリスト機能**
・**検索機能**
などがあります。

また、開発コストは上がりますが
・**手書きホワイトボード機能**
・**アンケート機能**
・**モバイルアプリ・プッシュ通知対応**
・**グループ・オーガニゼーション設定機能**
・**機械学習を用いた手書き数式認識機能**
などを実装することも考えられます。

「こんな機能があったらどうか？」、「こうしてほしい」などのご意見があれば、ぜひ気軽にお伝えください！

---
**●この記事を書いた人●**
**小沢泰河** （taigaozawa）
筑波大学の学生（物理学）。株式会社ドワンゴで教材開発保守（アルバイト）。
・[自己紹介サイト](https://taigaozawa.net)
・[Twitter](https://twitter.com/taigaozawa)
・[GitHub](https://github.com/taigaozawa)