新卒1年目エンジニアがお送りする 〜2019年 Web アプリケーションベストプラクティス〜

この記事は[エイチームブライズ/エイチームコネクト/エイチーム引越し侍 Advent Calendar 2018](https://qiita.com/advent-calendar/2018/hikkoshi) 17日目の記事です。

## はじめに
こんにちは！
2018年が終わろうとしていますね
技術トレンドはどんどん代わり、便利になりつつも、複雑さを増していく一方な気がしてなりません。

そんな中、採用活動などで学生と接すると、「新しい技術追えていてすごいなー」と感じることがあります。

負けてはいられませんね！
そこで、本日お送りするのは、**2019年 Web Application ベストプラクティス** 


**インフラ編**では、「マイクロサービスとマイクロサービスを運用するためのベストプラクティスについて」
**フロント編**では、「人気のNuxt.jsとAtomic Designを用いたベストプラクティスについて」
**バックエンド編**では、「注意しなければいけない2原則」
**番外編**では、「人気の機械学習とブロックチェーンについて」

の4編でお届けいたします。

**新卒1年目のペーペーエンジニアがお送りする1年後の世界**
ぜひご一緒しましょう！

## インフラ編
皆さんは長らく**モノリシックなWebアプリケーション**を作ってきました。
そのアーキテクチャが素晴らしかったからです

![](https://d1.awsstatic.com/icons/jp/cdp/cdp-ec-scaleup.5c0386d2a41db1ea09b491c4d56fcf5ca5d3d86d.png)

このようなモノリシックなWebアプリケーションはアクセスが増えれば同じアプリケーションが動いているインスタンスを増やせれば解決！
デプロイも簡単
まさに理想的なWebアプリケーション開発です。

しかし、組織が大きくなり、人数が増えることで問題が生じます。

:smile: 新しい技術使いたい新卒
:sob: リリースしたいのに他のリリースがもたついていてリリースできない3年目

モノリシックなWebアプリケーションは歴史的背景もあり、なかなか新しい技術を入れづらかったり、
リリースが被ってしまったりということは日常茶飯事ですよね？

他にも、、単一のアプリケーションであるため、セミコロン一つ忘れただけでも、サービス全体が落ちる可能性があり、

:scream: 不具合が発生してるのに、どこが原因なのかなかなか特定できないマネージャー

なんて人たちが現れます。

そこで生まれてきたのが**マイクロサービス**です。

![](https://github.com/GoogleCloudPlatform/microservices-demo/raw/master/img/architecture-diagram.png)

このようにサービスと呼ばれる小さな単位で分割し、APIを用いてそれぞれにアクセスを行うアーキテクチャです。

それぞれのサービスがDockerfileを持ち、独立しているため、**リリースはサービス単位**ででき、
**サービスごとに好きな言語、フレームワークが使えます**。(もちろんリプレイスも容易)

これで全てが解決し、、、ませんでした。

今度はサービスがどんどん増えてしまい、Dockerのコンテナを管理することができなくなっていきました。
そこで生まれてきたのが**kubernetes**です。

k8sを用いたマイクロサービスは難しいです。
でも大丈夫、今からマイクロサービスのベストプラクティスを説明します。

### マイクロサービスベストプラクティス
コンテナを用いた開発の基本的な流れは以下の通りです。

`開発 → ソース管理 → イメージビルド → イメージストレージ → デプロイ → 監視`

#### 開発
主な登場人物はkubernetes、Dockerです

#### ソース管理&イメージビルド&イメージストレージ
ソース管理はgithub
イメージビルドはGoogle Cloud Build
イメージストレージにはGoogle Container Registoryを使います

`cloudbuild.yaml`を用意すれば、Githubと統合して簡単にCloud Buildでイメージの作成ができます。
また、Cloud Buildで生成したイメージは、Container Registoryに自動的に保存されます。

#### デプロイ
デプロイはContainer Registoryに新しいイメージが作成されたことを検知してSpinnakerを発火させます

<img width="681" alt="スクリーンショット 2018-12-15 21.16.58.png" src="https://qiita-image-store.s3.amazonaws.com/0/136353/4f90d415-5f33-32b5-8db7-cba5854d81e2.png">

このような形でk8sを用いたカナリアリリースや本番への継続的デリバリーが可視化することができます。

#### 監視
コンテナの監視にはStackdriverを用います

GKEにデプロイされたコンテナのステータスを表示してくれるだけでなく、デプロイされた**本番のコードに対してブレークポイントを設定**して変数の中身をみたり、**本番のコードに変更を加えることなく、ログを出したり**することができます。
恐ろしい機能ですね :sunglasses:


以上がインフラ編です。
詳しいコード等紹介することができなかったので、僕が勉強に使ったリポジトリを紹介しておきます
https://github.com/GoogleCloudPlatform/microservices-demo

こちらのマイクロサービスはGoogle Cloud Next2018のサミットでGoogleの方たちが使っていたものです
今回紹介しきれなかった、kubernetes、istio、gRPC、skaffoldなどを用いたリポジトリになっているので、眺めると勉強になります。

## フロント編
切り替えてフロント編に入っていきましょう
Vue.js、Nuxt.js、、、とても、人気ですね！
僕も人気にあやかり、[Vue.js Reject Conference](https://vuejs-meetup.connpass.com/event/97557/)に登壇してきましたが、まだまだ伸びそうで安心しました。

一方、別のところで人気を徐々に高めてきているTypeScript。

Vue.jsとTypeScriptの合わせ技は2019年、注目していきたいところです。
ただ、Vue.jsのフレームワークであるNuxt.jsとTypeScriptの組み合わせは、まだまだ不具合が多く、とても本番投与できるようなものではありません。

2019年、新たなサービスを作るのだとしたら、Nuxt.js×JavaScriptで開発を行い、TypeScriptの様子を見て徐々にいれていくのが良さそうです。
ということで、、
Nuxt.jsを使っての開発を行ってみましょう

### Nuxt.js ベストプラクティス
昨今のコンポーネント開発のトレンドは**Atomic Design**です
![](http://atomicdesign.bradfrost.com/images/content/atomic-design-process.png)

言葉では説明しづらいので、画面とコードを合わせて説明します
簡単にログイン画面でも作って見ましょう

#### Atoms
一つのインプットフォームやボタンなど
<img width="1280" alt="スクリーンショット 2018-12-17 0.00.04 2.png" src="https://qiita-image-store.s3.amazonaws.com/0/136353/bd77ae17-f736-c744-b3cf-cfbf2b6abd31.png">

コードで言うとこんな感じ

```vue:components/AppInputTextForm.vue
<template>
  <div class="field">
    <div class="control">
      <input 
        :type="inputType"
        :placeholder="placeholder"
        class="input" 
        @input="$emit('input', $event.target.value)">
    </div>
  </div>
</template>

<script>
export default {
  props: {
    inputType: {
      type: String,
      default: 'text'
    },
    placeholder: {
      type: String,
      default: ''
    }
  }
}
</script>
```

必要なパラメータを親から受け取り、入力された内容をemitで親に通知する機能のみを持ちます

#### Molecules
Atomsを組み合わせた再利用性を考慮したコンポーネント

<img width="1280" alt="スクリーンショット 2018-12-17 0.00.04 3.png" src="https://qiita-image-store.s3.amazonaws.com/0/136353/b968164e-0c47-0b65-b0f9-9cb0edb57a62.png">

コードで言うとこんな感じ

```vue:componentes/AppSearchForm.vue
<template>
  <div class="columns">
    <app-input-text-form
      class="column is-8"
      input-type="text"
      placeholder="何検索する？"
      @input="searchText = $event"/>
    <div
      class="field is-3"
      style="padding-bottom: 14px;">
      <app-button
        text="検索"
        color="is-default"
        @click="$emit('search', searchText)"/>
    </div>
  </div>
</template>
<script>
export default {
  data() {
    return {
      searchText: ''
    }
  }
}
</script>
```

この単位でAPIを叩いたり、Vuexにデータを入れるのは基本的には反則です！
再利用性が失われる危険性があります。
なので、検索ボタンを押した時にイベントを発生させ、親に値を渡しています。
※ 下のログインフォームなどで、他に使う可能性がないのであれば、いいかもしれませんが、、


#### Organisms
ヘッダーなど、それぞれのコンポーネントを組み合わせたもの
ある程度汎用性があり、この単位でVuex(Store)にデータを格納したり、APIを叩いたりします


<img width="1139" alt="スクリーンショット 2018-12-16 23.31.14.png" src="https://qiita-image-store.s3.amazonaws.com/0/136353/ee5aa420-8518-186b-8252-730dcb18c776.png">

コードで言うとこんな感じ

```vue:componentes/TheHeading.vue
<template>
  <div class="hero-head">
    <nav class="navbar">
      <div class="container">
       ...
        <div class="navbar-menu">
          <div class="navbar-end">
            <app-search-form 
              class="navbar-item" 
              @search="search"/>
          </div>
        </div>
      </div>
    </nav>
  </div>
</template>
<script>
export default {
  methods: {
    search(text) {
      // ここでVuexに入れるなりAPI叩くなりする
    }
  }
}
</script>
```

先ほどの`AppSearchForm.vue`から値を受け取りAPIを叩いたり、Vuexにデータをいれたりする機能を持ちます。

#### Pages&Templates
<img width="1139" alt="スクリーンショット 2018-12-16 23.31.14.png" src="https://qiita-image-store.s3.amazonaws.com/0/136353/880c5356-9caf-eadb-1143-31ba6737a40b.png">

その名の通り、このページ全体です
コードで言うとこんな感じ

```vue:pages/index.vue
<template>
  <section class="hero is-primary is-fullheight">
    <the-heading />
    <div class="hero-body">
      <div class="container has-text-centered">
        <div class="columns">
          <div class="column is-6 is-offset-3">
            <login-form />
          </div>
        </div>
      </div>
    </div>
  </section>
</template>

<script>
import TheHeading from '~/components/TheHeading.vue'
import LoginForm from '~/components/LoginForm.vue'

export default {
  components: {
    TheHeading,
    LoginForm
  }
}
</script>
```
ヘッダーとログインフォームコンポーネントを呼び出してます


以上でフロント編を終わります。

## バックエンド編
バックエンドに関しては、そんなに話すことはありません。
注意していただきたいのは2点。

1. あまり大きなフレームワークはかえって邪魔になることもあるということ
2. 他のコンテナとAPIでつなぐ時は、タイムアウトなど例外処理をきちんと徹底すること

です。

1つめについて
k8sを使い、マイクロサービスを作っていると、1機能単位でサービスを分けるため、あまり大きなフレームワークは
かえって邪魔になります。
特に、コンテナの再ビルド時に大きなプロジェクトであればあるほど時間がかかってしまい、遅延が気になってきます。

2つめについて
モノリシックなWebアプリケーションの欠点として、「セミコロン一つ抜けていただけで、サービスが」と説明しましたが、
マイクロサービスでも、この**例外処理をしないと、同じようなことが起きます**
一つのコンテナから別のコンテナのAPIを叩く際、タイムアウトなどの設定をきちんとしなければ、
なかなかレスポンスが帰って来ずに、ユーザーは待ちぼうけになる可能性があります。
叩く側の責任として、例外処理は徹底しなければなりません。
※ k8sやgRPCの設定をきちんと行ったり、Stackdriverでのアラート設定をきちんと行えばほとんどは防げるとは思いますが、、

## 番外編
2018年相変わらずの人気だった機械学習とみなさんそれなりに気になっているブロックチェーンアプリケーション開発について話しますね

### 機械学習について
採用イベントなどに行っていてもよく出てくるデータアナリストという単語ですが、その希少価値はとてつもないものだと思っています。
データアナリストを定義することは難しいですが、僕は、
「サービスの改善点の発見」、「モデルの作成」、「学習」、「分析」、「サービスへの適応」、そして、「継続的改善」が行える人材だと思っています。
よくいるのが、

:smile: モデルの作成ができます！！
とか
:smiley: 分析ができます！

という人

難しい分野なので、モデルの作成一つとっても、色々勉強することがあることはわかりますが、これだとサービスをよくすることができません。
特に「サービスの改善点の発見」、「サービスへの適応」、「継続的改善」を行えるのは、今の所人間が職人技を用いてやるしかないのではないか？と思っています。

今回お話しするのはそれ以外の部分。「モデルの作成」、「学習」、「分析」を楽にしてくれるツールたちについてです。

一番簡単なのはGoogleが提供するAPIを使うことでしょう
会話をテキストにしてくれるAPI　https://cloud.google.com/speech-to-text/
画像解析をしてくれるAPI https://cloud.google.com/vision/
動画解析をしてくれるAPI https://cloud.google.com/video-intelligence/
仕事探しをしてくれるAPI https://cloud.google.com/jobs-api/
翻訳をしてくれるAPI https://cloud.google.com/translate/

などが提供されていて、すでに学習済みのモデルをすぐにでも使うことができます

次に、APIでは物足りない場合、、
[Google Cloud AutoML](https://cloud.google.com/automl/)
を用いれば、学習済みのAPIを自分仕様にカスタマイズすることができます。
例えば、業界特有の言葉がおおいのであれば　、そのテキストを学習させれば良いのです。

最後に、APIのカスタマイズ程度ではどうにもならない学習をさせたいときは
[Cloud ML Engine](https://cloud.google.com/ml-engine/docs/tensorflow/technical-overview?hl=ja)を使うのが良いでしょう
独自の機械学習モデルを作成することができます

また、学習させるデータを用意したい場合は

[Google Cloud Pub/Sub](https://cloud.google.com/pubsub/docs/overview?hl=JA) や　[Google Cloud Datastore](https://cloud.google.com/datastore/?hl=ja)などから得たデータを[Google Cloud Dataflow](https://cloud.google.com/dataflow/)にて整形し、おなじみ[BigQuery](https://cloud.google.com/bigquery/?hl=ja)に流し込む

とよいかもしれません。

### ブロックチェーンについて
[Lineさんが発表したブロックチェーンアプリケーションへの参入](https://www.businessinsider.jp/post-176304)など、密かにその火を強めてきているブロックチェーンアプリケーションですが、エンジニアでも「よくわからない」と言っている人を多く聞きます。

でも、そんなに難しいものではありません。
みなさんの会社の人の中でもブロックチェーンに興味がある人にエンジニアとしてドヤって説明できるようにしておきましょう

以前書いた

「ブロックチェーン」についての記事
https://qiita.com/anneau/items/3be8cd7cd8c34e28f90a

「ブロックチェーンアプリケーションの開発方法」についての記事
https://qiita.com/anneau/items/3a65691c8870761292ee

「ブロックチェーンを使ったサービス」についての記事
https://qiita.com/anneau/items/383200921382d7226666

をお時間のあるときに見ておいてください！

## お知らせ
エイチームグループでは一緒に活躍してくれる優秀な人材を募集中です。
興味のある方はぜひとも[エイチームグループ採用ページ（Webエンジニア詳細ページ）](https://www.a-tm.co.jp/recruit/)よりお問い合わせ下さい！


## 最後に

明日のAdvent Calendar18日目は、エイチーム引越し侍エンジニアの長である、 @hironey さんの記事
**「2年間運用した Rundeck のジョブが全コケした話」**
乞うご期待あれ！！