# システムの構成

## サーバーの物理構成

サーバー自体は固定IPでインターネットから接続できるコンピュータであればなんでもよい。サービスを構成するネットワークは Docker によって仮想化してしまうので、サーバーは1台でもよいし複数台を用いてもよい。自身の経済状況やシステムの堅牢性を考慮して自由に設計してよい。

記事では作業の手軽さとコストパフォーマンスの兼ね合いから最初は

* ConoHa VPS 1GBプラン 1台

を使用するが、金銭的に余裕のある人は AWS, Azure, GCP といったクラウドサービスを利用するといくらか手間を省くことができるかもしれない。

## OSの選定

OSは **CentOS8** を用いる。理由は

1. サーバー用途で実績がある CentOS7 の後継
2. Python3 が標準となっている

の2点である。特に pure な Python3 で書かれた自動化スクリプトであればまったく環境を汚さずに実行できる点が非常にポイントが高い。

## 仮想化

サービスは **Docker** で構築された仮想環境で動作する。各コンポーネントをコンテナとして構成・配置することで、各コンポーネントが物理的にどのサーバー上にあるかは重要ではなくなる。

今回の構成を1台のサーバー上に置く場合は次のような配置になる。

\[画像]

このシステムを商用サービスとして複数台のサーバーに再配置するには、たとえば次のようにすればよい。

\[画像]

## リバースプロキシ

今回はシステム内に複数のWebサービスを配置可能な構成としているから、**nginx** をリバースプロキシとしてユーザにもっとも近い位置に配置してリクエストを各サービスに振り分けるように設定する。

また ConoHa VPS では AWS のような至れり尽くせりのリソース支援を受けられるわけではないので、SSL/TLS通信の設定を自分で行う必要があるが、リバースプロキシでSSLオフローディングの設定を行うことでAPIサーバーの側ではSSL/TLS通信を考慮しなくてよい設計になっている。

## APIサーバー（golang/gin）

APIサーバーはユーザからのリクエストを処理してレスポンスを返すサーバーである。APIサーバーを設置するには WAF（Web Application Framework）を使うと手軽だが、選択肢は無数に存在する。

今回は Go 言語（golang）の WAF である gin を用いる。

{% embed url="https://github.com/gin-gonic/gin" %}

golang は

* 静的型付けのコンパイル型言語（堅牢）
* 仕様がコンパクトで覚えるのが容易（シンプル）
* 並行処理のための機能が揃っている

といった特徴がある。

静的型を持つコンパイル型言語はコンパイル時に明らかなエラーを検出してくれるので、バグや人間が書くべきテストをかなりの度合いで減らすことができ、意図していない動作を起こしにくい。

また golang は汎用ではあるがほとんどサーバーサイド開発に特化した言語で、シンプルな文法でコードの可読性を維持しつつも高い機能性を有する。

実行速度、学習コスト、メンテナンス性などの観点からプロジェクトの最初の開発言語として適していると判断した。

フロントエンドの UI も今回はAPIサーバー上にファイルを設置する。

## フロントエンド（Elm）

フロントエンドはユーザが直接操作する UI の部分である。Webブラウザ、スマートフォンアプリなどが考えうる。Angular, React, Vue.js などが人気であるが、今回はWebブラウザ用の UI を Elm で開発する（HTML, CSS, JavaScript はある程度知っている前提で話を進める）。

Elm は

* 静的型付けのコンパイル型言語（堅牢）
* 仕様がコンパクトで覚えるのが容易（シンプル）
* SPAのようなモダンなUIを作成するための機能が揃っている

といった特徴がある。

Elm は強い静的型付けを行う関数型言語で、実行時にほとんどエラーが発生しないこと、コンパイル時エラーも説明が非常に親切なことが特徴である。言語の仕様とフレームワークが高度に親和しており、フレームワークの存在をほとんど意識せず UI を作成可能である（フレームワークの選択の余地がないので、そこで悩む必要もない）。

マイナーな言語であり、手に入る情報の量や将来性に少々懸念はあるものの、学習コストとメンテナンス性の観点で非常に優れており、よほど変わったことをしなければ Elm で大抵の UI は実装できるので、プロジェクトの最初の開発言語として適していると判断した。

Elm は HTML や JavaScript のファイルにコンパイルされるので、通常のWebサーバーで提供可能である。

## DBサーバー（MySQL）

ユーザのデータを永続的に保管しておくにはデータベースが必要になる。今回はどのようなアプリを作るのかまでは想定していないことから、基本的にはどのような用途でも対応できる MySQL を設置しておくことにした。MySQL に適さないデータを扱うときには別のデータベースのコンテナを増設すればよいだけなので、この点はあまり気にしなくてよい。

## KVS（Redis）

ユーザからリクエストを受信するたびに認証情報などを MySQL からルックアップしていると時間がかかるので、通常は KVS（Key Value Store）と呼ばれる高速な辞書を別途用意しておく。今回はオンメモリで動作する Redis を用いる。

## FirebaseによるAuthentication

ユーザの認証には Google の Firebase を用いる。アプリケーションによってはユーザを識別さえできればほとんど情報を保存する必要がない場合もあり、そういった場合に自前の MySQL に依存させるとメンテナンスの手間が増える。認証部分に関しては Firebase を使っておいたほうが手軽でセキュアで可用性が高い。

