Webアプリケーション開発において理解しておきたいことまとめ

前にも[似たような記事](https://qiita.com/landwarrior/items/d42f027db7a90f982863)を書いていたんですが、改めて記事にします。
新人教育用に社内のGitのWikiに、より詳細なものを書いたのですが社員全員が見れるわけではないので、もったいないのでこちらにも書いておきたいと思ったのがきっかけです。
社内開発案件の単語を削除して載せているので、ちょっと変なところがあるかもしれませんがご容赦を。
（もし間違いがあればご指摘いただけると助かります）

# 動作の仕組み

Webアプリケーションは、PC（**クライアント**と呼びます）のWebブラウザから、特定のURLにアクセスすることによって利用します。  

例えばWebブラウザのアドレスバーに「 https://www.google.co.jp 」と入力してエンターキーを押すと、Googleのサイトが表示されます。  
これは、クライアントからの要求（**リクエスト**と呼びます）をGoogleのコンピュータ（**サーバー**と呼びます）が受け取り、何らかの処理をしてから応答（**レスポンス**と呼びます）をクライアントに返すことによってWebブラウザに表示される流れになります。

Webブラウザでアクセスするためには、サーバー側が動作していないといけません。  
サーバーはどのように処理されているか、見てみましょう。

# サーバー側の実装

クライアントからのリクエストを受ける際、まずサーバー側では**Webサーバー**という機能がリクエストを受け取ります。  
**Webページ**（ブラウザに表示される1画面のこと。Webページのまとまりを**Webサイト**という）を表示する際にサーバー上にあるHTMLファイル、CSSファイル、JavaScriptファイルをそのままクライアントへレスポンスとして返す場合は、**静的コンテンツ**と呼ばれ、サーバー側はただファイルを送るだけです。  
何らかのプログラミング言語によりデータベースへアクセスしたり、処理した結果をクライアントへ返す場合は**動的コンテンツ**といい、同じURLでもクライアント側からのリクエストによってレスポンスが変わったりします。

動的コンテンツの場合、処理の概要は以下のようになります。

クライアント→（リクエスト）→Webサーバー→アプリケーションサーバー→Webサーバー→（レスポンス）→クライアント

**アプリケーションサーバー**とは、プログラミング言語を処理するためのミドルウェアです。  
動的コンテンツでは**データベース**（DB）に格納されたデータにアクセスすることがほとんどです。  
つまり、アプリケーションサーバーでは以下のようにデータのやり取りが発生しています。

アプリケーションサーバー↔DBサーバー

**DBサーバー**とは、データベースの機能を持つサーバーのことです。  
ここで、サーバーには以下の機能があることが分かりました。

- Webサーバー
- アプリケーションサーバー
- DBサーバー

この構造を、**3層アーキテクチャ**と呼びます。

## アプリケーションサーバー上の実装

アプリケーションのコーディング（プログラムを作成すること）をするのはこの部分になります。  
ここでもアーキテクチャのパターンがあり、よく使われるものとして**MVC**というアーキテクチャ・パターンがあります。  
MVCとは、一般的には

- Model
    - データベースアクセスを担当
- View
    - 画面を担当
- Controller
    - ModelやViewとのやり取りを担当

という風になっています。  
また、MVCではどこに当てはめるのか悩ましい、**ビジネスロジック**というプログラムがあり、簡単に言うと、こういうデータの時はこうしたい、というような、要件にかかわる実装のプログラムもあります。  
MVCは基礎的なパターンであり、実際にはもっと分割して実装します。  
本格的に学ぶためには書籍をいくつか読む必要があるので、要点だけ説明します。

### なぜMVCといったアーキテクチャを採用するのか

例えば、JavaでWebアプリケーションを作成する初期の手段は、サーブレットだったと思います。  
これは、Javaのコード上で文字列としてHTMLを書きまくって、その文字列をレスポンスとして返す、という感じのものでした。  
これではあまりにも可読性（コードの読みやすさ）が悪いため、JSPという仕組みが出来ました。  
これは、通常のHTMLファイルにJavaのコードを埋め込むような形で、少しは見やすくなりました。  
しかし、HTMLとJavaのコードが入り乱れることに変わりはなく、可読性が低いことには変わりませんでした。  
そこで、役割ごとに分担しよう、という発想が、MVCという考え方になります。  
考え方の根本にあるのは、それぞれの役割の結合度を疎結合にする、ということです。  
つまり、お互いに依存しすぎない設計にすることで、変更に強いアプリケーションを作ろう、というものです。  

- データベースの構造が変わったことによる影響は、Modelで吸収してViewやControllerには影響しないようにする
- 画面構成が変わった場合には、Viewで吸収してModelやControllerには影響しないようにする
- 動かしたい機能のURLを変更したい場合は、Controllerのルーティング情報（URLに対して動かす処理の割り当て）などで吸収してViewやModelには影響しないようにする

といったことです。  
これによって、変更が発生した際の影響を最小限にとどめることができます。

## フレームワーク

MVCの概念が分かっても、これを自分で全部実装するのは難しいです。  
そのため、決まりごとに従ってコーディングすることによって本来作りたい機能に集中することができるようにする仕組みとして、フレームワークというものがあります。  
例えばJavaではSpring Bootというフレームワークが有名かと思います。  
様々なフレームワークの集合体みたいなフレームワークになっていて、これを全部理解するのはかなり大変です。  
例えばSpring Bootに含まれるSpring MVCというフレームワークで使用されている、**Thymeleaf**というテンプレートエンジンがあります。  
**テンプレートエンジン**とは、JSPから発展したもの、くらいに思ってもらえればいいかと思います。  
HTMLにJavaの変数を埋め込み、クライアントへレスポンスを返す前に変数に値をセット（**バインド**と呼んだりします）して、静的コンテンツのようにしてからクライアントへレスポンスを返します。  
このように、フレームワークを選択すると、そのフレームワークの使い方を覚える必要が出るのは留意しておく必要があります。  
規模が小さく、発展も望めないようなシステムでは**フルスクラッチ**（全て自前でコーディングする）で作る、という選択もありかもしれません。

# クライアント側の実装

お次はクライアント側のお話です。  
クライアント側といっても、WebブラウザではHTMLファイルとCSSファイルとJavaScriptファイルのダウンロードしかしていない（画像があれば画像も）ので、それらを使うことになります。  
それぞれの役割を簡単に書くと、以下のようになります。

- HTML
    - HyperText Markup Languageの略
    - Webページの**構造**を定義する
- CSS
    - Cascading Style Sheetsの略
    - Webページの**見た目**を定義する
- JavaScript
    - 当時流行したJavaにあやかって命名しただけ、らしい。Javaとは一切関係なし
    - Webページの**動き**を定義する

## HTML

そのWebページにどういったコンテンツがあるか、というようなことをWebブラウザに知らせます。  
Webブラウザを使用しているユーザーにではなく、Webブラウザ自体に知らせている、という点に注意してください。  
これは、例えば盲目の人が音声読み上げ機能を使用してWebページの情報を得る際に関係します（たしか）。  
また、SEO（Search Engine Optimization）にも関係します（たしか）。  
つまり、SEO対策をしたWebサイトはGoogle検索で上位に表示されることになります（BingやYahooでの影響は分かりません）。  
なお、HTMLにはいくつかのバージョンがありますが、特段理由がない限り**HTML5**を選択するのが無難だと思います。

## CSS

ユーザーの視覚に最も影響を与えるものになります。  
最近は見た目のためにHTMLの定義から作りこまないといけなかったりします。  
CSSを書く際は、**クラス**という定義方法を用い、そのクラスをHTMLのタグに適用するのが一般的です。  
なお、CSSにもいくつかのバージョンがありますが、モダンなWebブラウザ（つまり、IE以外）ならCSS3が使えるはずです。  
各WebブラウザにおいてCSS3のどの書き方が使えるかは、調べる必要があります。

## JavaScript

例えば「このボタンを押したらこういう動作をする」という動きを定義します。  
JavaScriptを扱うために必要な知識として**DOM**（Document Object Model）があります。  
DOMとは、HTMLのタグをJavaScriptで操作するために扱うオブジェクト、という理解でいいかと思います。  
JavaScriptのライブラリで有名なものとして、**jQuery**というものがあります。  
**ライブラリ**とは、コーディングしやすくするためにラッピングしてくれるもの（覆い隠してくれるもの）です。  
つまり、簡単な記述だけで後は良しなにやってくれます。  
コード上はすっきり見やすくなりますが、その反面、中で何をやっているのかを理解していないと思わぬバグに遭遇したりします。  
また、ラッピングしているだけなので当然内部ではそれ以上のコードが動いており、結果として動作が遅くなったりします。  
JavaScriptにもバージョンがありますが、これにはJavaScriptの標準を決めるECMAScriptというものも知る必要があります。  
最近の主流は、ECMAScriptのバージョン6（ES6やES2015といった呼び方をする）なんだと思います。  
こちらもブラウザによって実装が異なるため、JavaScriptを書く際にはブラウザの対応状況を調べる必要があります。  
jQueryを使う場合は、ブラウザの差異を吸収してくれるはずです。

# クライアント↔サーバー間通信

サーバー側の実装とクライアント側の実装が分かったところで、お互いの通信のお話です。

## HTTP

Hypertext Transfer Protocolの略です。  
OSI参照モデルで言うと、レイヤー7のアプリケーション層に位置します。  
通信相手との通信確立にはレイヤー4のトランスポート層にある、TCP（Transmission Control Protocol）を使用します。  
HTTPにはヘッダー部とボディ部があります。

### HTTPヘッダー

HTTPボディのデータ形式の指定や、要求するリソース情報や、キャラセット（文字コード）といった情報が格納されています。

### HTTPボディ

実際にクライアント↔サーバー間でやり取りするデータが入っています。

最初のうちは、HTTPにはヘッダー部とボディ部があるんだな、くらいに思っていればOKです。

## 3WAYハンドシェイク

ちょっと余談です。  
クライアント↔サーバー間の通信手段としてTCPを使用しますが、TCPにて通信を確立する手段として3WAYハンドシェイクというものがあります。  
簡単に言うと。

1. クライアント「通信していいですかー？」
2. サーバー「いいですよー。こちらもいいですかー？」
3. クライアント「いいですよー。」

と、3度の通信を経て通信が確立するため、3WAYハンドシェイクと言います。  
リクエストの度に毎回この手順を踏んでいると通信が遅くなる原因になるため、ORマッパーではコネクションプーリングという機構があったりします。  
つまり、一度通信が確立したら一定時間切断せずに取っておく、ということです。

Webアプリケーションの経験が増えるにつれて分かってくる部分だと思いますが、詳しく知りたい方はネットワークの勉強をする必要があります。

# ここまでのまとめ

- クライアント
    - HTML, CSS, JavaScriptを用いて実装
    - サーバーから受け取ったレスポンスをWebブラウザに描画（レンダリングと呼ぶ）
- サーバー
    - Javaといった言語で実装
    - データベースにアクセスし、データを参照したり、更新したり

簡単ですね。  
ここからはより実践的な内容です。

# クラサバとWebアプリケーションの違い

## クラサバ

（Webアプリも広義ではクラサバですが、ここではPCにインストールして使うタイプに限って説明しています）  
クライアント・サーバーシステム（いわゆるクラサバ）とは、クライアントPCにインストールされたアプリケーションがサーバー上のデータベースなどに直接接続し、処理をするシステムのことです。  
クライアントPCに専用のソフトウェアが必要です。  
クライアントPCのスペック、OS、環境などの影響を受けます。  
クライアントPC上で動作しているため、操作中の状態（ステート）はクライアントPCで動作するアプリケーションが掌握しています。

## Webアプリケーション

Webブラウザを用いてアクセスするアプリケーションのことです。  
Webブラウザがあれば操作可能なので、クライアントPCに何かしらのソフトウェアのインストールや、スペックやOSの影響を（基本的には）受けません。  
Webブラウザ上での操作そのものは、サーバー上のアプリケーションでは把握できないのでサーバーにて処理すべきデータがある場合は全てHTTP通信に乗せてサーバーに送信する必要があります。  
このため、HTTP通信は**ステートレス**という概念が重要になります。  

# クライアントサイドとサーバサイドの処理の流れ

クライアント側での処理をクライアントサイド、サーバー側での処理をサーバサイドと呼びます。  

## 前提知識

例えば、以下のようなURLがあったとします。

```
http://localhost:8080/User/hoge?fuga=1234
```

にアクセスする場合、このURLの意味は、以下のようになります。

```
http://{FQDN}:{PORT}{Context Path}?{Query String}
```
- URL
    - Uniform Resource Locator の略
        - リソースの位置を指し示す
- FQDN
    - 完全修飾ドメイン名のこと
    - 上記URLでは`localhost`の部分
    - そのほかの例としては`www.google.co.jp`などが該当
        - この例では、`jp`ドメインのサブドメインとして`co.jp`があり、さらにサブドメインとして`google.co.jp`があり、さらにサブドメインとして`www.google.co.jp`がある
- PORT
    - アクセスするポート番号
    - 上記URLでは`8080`が該当
- Context Path
    - ドキュメントルートからのリソースの位置を指し示す
    - 上記URLでは`/User/hoge`が該当
- Query String
    - クエリパラメタともいう
    - リソースにアクセスする際に渡すパラメータのこと
    - 上記URLでは`fuga=1234`が該当
        - `key`=`value`の組み合わせで記載し、複数ある場合は`&`でつなぐ

コンテキストパスではスラッシュ区切りの階層構造となっていて、上記の例では`User`というリソース配下にある`hoge`のデータにアクセスする、という意味になります。  
その際のパラメータとしてクエリストリングを渡していますが、クエリストリングは必須ではありません。  
そのため、未指定でも動作するように実装することを心がけます。  

サーバサイドではこのコンテキストパスが指し示す処理を実装します。  
上記の例では`User`配下のリソースにアクセスしたいのだと分かります。  
URLに直接リソースの識別子（ここでいう`hoge`）を指定することによって、そのリソースへアクセスすることができます。  
このようにURLの一部に用いることで、URLに単一データ呼び出しという意味を持たせることができます。  
つまり、識別子を除いた`http://localhost:8080/User`という場合は、配下の全てのリソースにアクセス可能、という意味になります。  

## HTTPのメソッド

WebブラウザでアドレスバーにURLを記載して実行した場合はHTTPのメソッドは**GET**になります。  
通常の画面遷移もGETになります。  
つまり、Webブラウザからサーバーに対して要求していることはリソースの取得です。  
サーバサイドではリソースをレスポンスに含めて返してあげるだけでいいので、GETメソッドの場合は**データ更新をしてはいけません。**（例外もありますが）  

次に、更新ボタンを押したときの処理についてです。  
HTMLで`submit`という処理を用意して、HTTPメソッドに`POST`を指定する必要がありますが、その前提のもと記載します。  
**POST**の場合は、サーバーに対してデータを送信します。  
GETとは違いデータを取得するのではなく送りつけているので、サーバー側は何らかの処理結果を保存するのが一般的です。

GETの場合は追加のパラメータはクエリストリングに記載されますが、POSTの場合はHTTPのボディ部に必要なだけ載せることができます。  
言い換えると、GETの場合はクエリストリングとして指定するパラメータの長さに制限があります。  
これはWebサーバーで制限したり、ゲートウェイやルーターなどで制限したりすることも、たしか出来た気がします。  
なので、本来はGETを使いたいところでも指定したいパラメータが多い場合はPOSTを使わなければいけないこともあります。  

## サーバサイドでできること

クライアントからのリクエスト内容に応じて処理しますが、クライアントへのレスポンスは**HTMLを返すのみです。**  
そのHTML上に外部のCSSファイルやJavaScriptのファイルを読み込む記載があるため、クライアントはHTMLを受け取ってから追加でCSSファイルやJavaScriptファイルをダウンロードしています。  

## クライアントサイドでできること

JavaScriptの進化により、今は割となんでも出来るようになってきました。  
ただし、クラサバで出来ていたことがWebアプリケーションでは出来ないことがあります。  
その最たる例がIMEの切り替えと、プリンタ出力です。  
業務用Webアプリケーションで必ずと言っていいほど使われてきたInternet Explorerですが、これには理由があり、Internet Explororはエクスプローラ（Windowsでフォルダやファイルにアクセスする際に使う方です）と内部的に結合しているとかで、IEはOSの機能を一部使えました。  
また、ActiveXやSilverlightといった黒魔術もありました。  
JavaScriptはWebブラウザを動作させているOSのファイルシステムに直接アクセスできないので、勝手にファイルを盗んだり書き換えたり出来ないようになっています。  
こうしてみるとHTMLやCSSの操作くらいしかJavaScriptはできないように見えますが、Googleが始めて一躍有名になったAjaxという技術があります。  

## Ajax

一言でいうと、非同期通信です。  
同期処理や非同期処理という言葉がありますが、例えば同期処理とは、Webブラウザ上の操作をロックして処理し、処理が完了したらロックを解除するような処理のことです。  
処理中はユーザーの操作を受け付けられないため、利便性が損なわれます。  
そのためJavaScriptは非同期で動いています。  
ここにさらにサーバーアクセスしてデータのやり取りをする仕組みがAjaxです。  
Ajaxの利点は、サーバーとの通信において受け取るデータは必要なものだけでいいので、GETやPOSTした後の画面のレンダリングのようにユーザーを待たせてしまうことなく、必要な項目だけサーバーからデータを取得し書き換えることができる点です。

## CORS

便利なAjaxですが、ここにも制約があります。  
CORSとはCross-Origin Resource Sharingの略で、オリジン間リソース共有という意味です。  
オリジンとは、`http://localhost:8080`の部分のことです。  
つまり、異なるWebサイトに対してAjax通信は基本的に出来ないよ、ということです。  
これにも理由があり、セキュリティ対策のためです。  
Web技術にはクロスサイトスクリプティングやクロスサイトリクエストフォージェリといった攻撃手法があり、攻撃者もあの手この手で攻撃してきます。  
なので、モダンブラウザではCORSの制限が厳しくなっています。  

## Ajaxにおける注意点

便利なAjaxですが、当然サーバサイドの実装も必要です。  
通常のGETやPOSTでの同期通信とは違い、Ajaxでの通信時にはデータを**JSON**という形式でやり取りすることが多いです。  
そのため、サーバサイドでJSON形式でデータを返す実装が必要になります。  
仕組み自体は簡単で、JavaScriptでアクセスするためのURLを用意してデータをJSON形式で返すだけです。

---

# 参考文献
今まで私が読んできた中で、お勧めの本を紹介します。

### 基礎

- [スッキリわかるJava入門](https://www.amazon.co.jp/dp/4295007803/)
    - Javaの概要を知るのにちょうどいいです
- [独習Java 新版](https://www.amazon.co.jp/dp/4798151122/)
    - Javaをしっかり理解できます
- [改訂新版JavaScript本格入門](https://www.amazon.co.jp/dp/B01LYO6C1N/)
    - JavaScriptをしっかり理解できます。  
従来の書き方から新しい書き方まで記載されているのでこれ1冊覚えればほぼ大丈夫です
- [リーダブルコード](https://www.amazon.co.jp/dp/4873115655/)
    - 見やすいコードが書けるようになります
- [オブジェクト指向でなぜつくるのか 第2版](https://www.amazon.co.jp/dp/4822284654/)
    - オブジェクト指向を理解できます

### アーキテクチャ

- [Clean Architecture 達人に学ぶソフトウェアの構造と設計](https://www.amazon.co.jp/dp/4048930656/)
    - 難しすぎて最初は理解できません。何度も読み返さないとダメそうです

### 開発手法

シリコンバレーの開発手法を知れる本です。

- [リーン・スタートアップ](https://www.amazon.co.jp/dp/4822248976/)
- [エンジニアのためのデザイン思考入門](https://www.amazon.co.jp/dp/4798153850/)
- [Hacking Growth グロースハック完全読本](https://www.amazon.co.jp/dp/4822255824/)