3ヶ月で Serverless Framework を導入し、SPA ( Riot.js + RiotControl で Flux 実装 ) をリリースした話


**※ このお話は ( おそらく ) フィクションです。実在の人物や団体とは関係ありません。**

## 前書き

中規模程度のサービスを Serverless 構成の SPA をパイロットリリースしました。具体的なサービス名等は紹介できません ( おそらくフィクションなので ) が、筆者が3ヶ月間でやってきたことを殴り書きして行きます。
基本的にはリリースまでに必要となった材料 ( 参考にしたドキュメントやサイト ) を重点的に紹介していくだけですが、同じような境遇の方々の手助けになれば幸いです。

## 筆者のプロジェクトイン時スペック

* 社歴3年程度
* 主にバックエンド・インフラを担当してきた
* と言いつつもフロントエンドもある程度は（jQuery ゴリゴリ）
* モダンな Web フロントエンド ( いわゆる ES6 や Flux、Webpack 等 ) については「聞いたことある。触ったことある。」程度

## 3ヶ月間のスケジュール ( ざっくりと )

※ 既に要件定義済み

* 1ヶ月目 第1週〜第2週
    * 技術選定
    * 技術習得
* 1ヶ月目 第3週〜第4週
    * 設計
        * 外部設計
        * 内部設計
        * インフラ設計
        * DB 設計
        * API 設計
        * URL 設計
        * コンポーネント設計
    * スタイルガイド作成
    * 開発環境構築
* 2ヶ月目
    * 開発
* 3ヶ月目 第1週〜第2週
    * 開発
* 3ヶ月目 第3週〜第4週
  * テスト
  * リリース

### 構成

![構成図](https://lh3.googleusercontent.com/HZtJ00YskxN7an_-Ft_kHz1A7QvSe_vJ0n1ygWktbPffHnlvkWH9Zianh5Tl8WMWlPy_U6xvE3cSaZJjDBQKS6t1XD7hGOf0UZaxFilkBP4-HERHUW2W90UIgA0GRl6ChWf4xA=w750-h412-no "構成図")

## プロジェクトを構成するパッケージ

※ インストールしたパッケージ全てを掲載していないのでご注意ください。

### SPA

#### global

* [yarn](https://www.npmjs.com/package/yarn "yarn")

> 高速で信頼性が高く、安全なパッケージマネージャ。

> * 高速: ダウンロードしたすべてのパッケージをキャッシュして、同じパッケージを再度ダウンロードする必要はありません。また、操作を並列化してリソース使用率を最大化するので、インストール時間がこれまで以上に短縮されます。
> * 信頼性: 詳細で簡潔な lockfile フォーマットと確定的なインストールアルゴリズムを使用して、Yarn はあるシステムで動作するものは他のどのシステムでも同じように動作するようにインストールすることを保証することができます。
> * 安全: Yarn はチェックサムを使用して、コードが実行される前にインストールされているすべてのパッケージの整合性を検証します。

#### devDependencies

* [babel](https://www.npmjs.com/package/Babel "Babel")

> Babel は、Web アプリケーションと、CoffeeScript、SASS、Jade などの node.js で使用するために開発された多くのクールな新しいファイル形式の間に柔軟なクッションを置きます。 Babel を使用すると、関連する多くのAPIについて心配することなく、さまざまな種類のファイルからシームレスに読み込むことができます。

> * 多くの一般的なフォーマットからスタイルシート、データ、テンプレート、およびスクリプトを簡単にロードします。
> * フォーマットのロックインについて心配することはありません。
> * さまざまなフォーマットを簡単に試します。

* [node-sass](https://www.npmjs.com/package/node-sass "node-sass")

> Node.js の [LibSass](https://github.com/sass/libsass "GitHub - sass/libsass: A C/C++ implementation of a Sass compiler") へのバインディングを提供するライブラリです。これは、一般的なスタイルシートのプリプロセッサである Sass の C バージョンです。
> ミドルウェアを介し信じられないほどのスピードで、自動的に _.scss_ ファイルを css にネイティブにコンパイルすることができます。

* [webpack](https://www.npmjs.com/package/webpack "webpack")

> JavaScript ファイルをブラウザで使用するためのバンドルや、あらゆるリソースやアセットを変換、バンドル、パッケージ化することができるモジュールバンドラです。

* [webpack-dev-server](https://www.npmjs.com/package/webpack-dev-server "webpack-dev-server")

> ライブリロードを提供する開発サーバーでwebpackを使用します。これは開発にのみ使用する必要があります。
> webpack-dev-middleware を使用して、Webpack アセットへの高速なメモリ内アクセスを提供します。

* [gulp](https://www.npmjs.com/package/gulp "gulp")

> 自動化 - gulp は、開発ワークフローで苦労したり時間のかかるタスクを自動化するのに役立つツールキットです。
> 非依存型プラットフォーム - 全てのメジャー IDE に組み込まれており、人々は、PHP、.NET、Node.js、Java などのプラットフォームで gulp を使用しています。
> 強力なエコシステム - npm モジュールを使用して、ファイル変換をストリーミングするための 2000 以上の精選されたプラグインを好きなだけ利用することができます。
> シンプル - 最小の API surface のみを提供することで、gulp は簡単に学習でき、使いやすいです。

#### dependencies

* [riot](https://www.npmjs.com/package/riot "riot")

> シンプルで洗練されたコンポーネントベースのUIライブラリ。

* [riot-route](https://www.npmjs.com/package/riot-route "riot-route")

> > シンプルなクライアント側のルータ

> Riot Router は、以下のようなテクノロジーを備えた最小限のルータ実装です。

> * pushStateと履歴API
> * 複数のルーティンググループ
> * 置換可能なパーサ
> * IE9 以上に対応

Riot.js の一部として始まりましたが、今は独立したライブラリになりました。Riot.js の有無にかかわらず動作します。

* [riotcontrol](https://www.npmjs.com/package/riotcontrol "riotcontrol")

> RiotJS のためのシンプルな Central Event Controller / Dispatcher です。Facebook の Flux アーキテクチャパターンによってインスピレーションを受けました。
> RiotControl は、Riot 自体の精神に基づき非常に軽量です。それは、Flux の要素を忘れて小さくて簡単なアプリケーションを好みます。 RiotControl は、Riot の observable な API に大きく依存して、ビューからストアにイベントを渡して戻します。ストアは多くのビューと対話することができ、ビューは多くのストアと対話することができます。

* [aws-sdk](https://www.npmjs.com/package/aws-sdk "aws-sdk")

> JavaScript 用公式の AWS SDK。

* [amazon-cognito-identity-js](https://www.npmjs.com/package/amazon-cognito-identity-js "amazon-cognito-identity-js")

> JavaScript 用公式の Amazon Cognito Identity SDK。

* [whatwg-fetch](https://www.npmjs.com/package/whatwg-fetch "whatwg-fetch ")

> `fetch()` 関数は、ブラウザ上で Web リクエストをプログラムによって作成するための Promise ベースのメカニズムです。このプロジェクトは、標準 Fetch 仕様のサブセットを実装する polyfill です。

* [validatorjs](https://www.npmjs.com/package/validatorjs "validatorjs")

> validatorjs ライブラリは、ブラウザと Node.js の両方で JavaScript によるバリデーションを非常に簡単にします。このライブラリは、Laravelフレームワークのバリデーターにインスパイアされました。

* [validator](https://www.npmjs.com/package/validator "validator")

> 文字列のバリデートとサニタイズするライブラリ。

### Serverless

#### global

* [serverless](https://www.npmjs.com/package/serverless "serverless")

> Serverless Framework - マイクロサービスで構成されるアプリケーションを構築します。これにより、アプリケーションをメンテナンスするための総コストが削減され、より多くのロジックを迅速に構築できます。
> このフレームワークでは、AWS Lambda、Google CloudFunctions などの新しいイベント駆動型のコンピューティングサービスを使用しています。これはコマンドラインツールであり、足場材、ワークフローの自動化、サーバーレスアーキテクチャの開発と導入のベストプラクティスを提供します。プラグイン経由でも完全に拡張可能です。

#### devDependencies

* [serverless-offline](https://www.npmjs.com/package/serverless-offline "serverless-offline")

> この Serverless プラグインは、開発サイクルをスピードアップするために、ローカルマシン上で AWS Lambda と API Gateway をエミュレートします。そうするには、API Gateway のようなリクエストのライフサイクルを処理し、ハンドラを呼び出す HTTP サーバを起動します。

* [serverless-dynamodb-local](https://www.npmjs.com/package/serverless-dynamodb-local "serverless-dynamodb-local")


> * DynamoDB Local をインストールする
> * サポートされているすべてのパラメータを使用して DynamoDB Local を起動します ( 例: port、inMemory、sharedDb )
> * DynamoDB Local 用のテーブル作成

#### dependencies

* [node-fetch](https://www.npmjs.com/package/node-fetch "node-fetch")

> `window.fetch` を Node.js で利用するための軽量モジュール

* [jsonschema](https://www.npmjs.com/package/jsonschema "jsonschema")

> JSON schema バリデーターは、高速で簡単に使うためにデザインされています。最新の IETF 公開草案は v4 です。このライブラリは主に v4 と互換性があります。

* [validator](https://www.npmjs.com/package/validator "validator")

## 技術選定

#### インフラ

ユーザー認証基盤として Cognito を利用しました ( ユーザー認証基盤を開発してたらリリース間に合わない ) 。詳しくは説明できませんが、SPA + API をベースにすることが必須ということもあり、インフラコストやメンテコストの削減に期待できる Serverless Architecture を選択しました。

#### DB

パイロット運用ということもあり、DB に変更が加わることが予想されました。
そのため、RDBMS ではなく変更に対して柔軟に対応できる NoSQL を選択しました。時期、本リリース時には RDS にするか検討しています。

また、開発当初は DynamoDB を利用していましたが、今まで NoSQL として MongoDB を利用してきた身からするとクエリが貧弱だったりと[使いづらく](http://blog.brains-tech.co.jp/entry/2015/09/30/222148 "ここにハマった！DynamoDB - Technology Topics by Brains")、
途中で MongoDB に変更しました。

※ DynamoDB は悪くありません。そもそも利用用途として間違っていました。

#### API

[GraphQL](http://graphql.org/learn/ "Introduction to GraphQL | GraphQL") が気になってはいたのですが、

[RESTの次のパラダイムはGraphQLか - Qiita](http://qiita.com/sergeant-wizard/items/f10669e33858543dbc0b "RESTの次のパラダイムはGraphQLか - Qiita")

GraphQL の学習コストと採用実績を考慮し、利用例のある REST を選択しました。

#### View ライブラリ

View ライブラリは以下の理由から Riot.js を選択しました。

* 中規模なサービスに React や Angular を導入するのは少し大げさ
* 他のView ライブラリよりシンプルでわかりやすいため学習コストが低い
* デザイナーとの協業がしやすい

## 技術習得

基本的に公式ドキュメントとサンプルは一通り目を通しました ( 通したつもり )。

### バックエンド

#### [AWS](https://aws.amazon.com/jp/ "アマゾン ウェブ サービス【AWS 公式】 - クラウドコンピューティングサービス")

* [公式ドキュメント](https://aws.amazon.com/jp/documentation/ "AWS ドキュメント | AWS")
* [AWS ｜ Developers.IO](http://dev.classmethod.jp/category/cloud/aws/ "AWS ｜ Developers.IO")

#### [Serverless Architecture](https://aws.amazon.com/jp/lambda/serverless-architectures-learn-more/ "サーバーレスアプリケーションの構築 | AWS")

* [サーバーレスアーキテクチャとは何か？　AWSの「Lambda」と「EC2」を比較して解説 CIOのためのAWS最新動向（1）｜ビジネス+IT](http://www.sbbit.jp/article/cont1/32603 "サーバーレスアーキテクチャとは何か？　AWSの「Lambda」と「EC2」を比較して解説 CIOのためのAWS最新動向（1）｜ビジネス+IT")
* [サーバーレスアーキテクチャという技術分野についての簡単な調査 - Qiita](http://qiita.com/zerobase/items/3bc0d15980b472af841d "サーバーレスアーキテクチャという技術分野についての簡単な調査 - Qiita")

#### [Serverless Framework](https://serverless.com/framework/ "Serverless Framework Documentation")

* [公式 Examples](https://github.com/serverless/examples "serverless/examples: Serverless Examples – A collection of boilerplates and examples of serverless architectures built with the Serverless Framework and AWS Lambda")
* [Serverless Frameworkでつくる ｜ シリーズ ｜ Developers.IO](http://dev.classmethod.jp/series/serverless-framework%E3%81%A7%E3%81%A4%E3%81%8F%E3%82%8B/ "Serverless Frameworkでつくる ｜ シリーズ ｜ Developers.IO")
* [Serverless Framework v1.0の使い方まとめ - Qiita](http://qiita.com/horike37/items/b295a91908fcfd4033a2 "Serverless Framework v1.0の使い方まとめ - Qiita")
* [とことんサーバーレス①：Serverless Framework入門編 - Qiita](http://qiita.com/hiroshik1985/items/6d979ff1afb56953b62e "とことんサーバーレス①：Serverless Framework入門編 - Qiita")

### フロントエンド

#### [JavaScript](https://developer.mozilla.org/ja/docs/Web/JavaScript "JavaScript | MDN") ( [ES6](http://es6-features.org "ECMAScript 6: New Features: Overview and Comparison") )

* [JavaScript本格入門](https://www.amazon.co.jp/%E6%94%B9%E8%A8%82%E6%96%B0%E7%89%88JavaScript%E6%9C%AC%E6%A0%BC%E5%85%A5%E9%96%80-%E3%83%A2%E3%83%80%E3%83%B3%E3%82%B9%E3%82%BF%E3%82%A4%E3%83%AB%E3%81%AB%E3%82%88%E3%82%8B%E5%9F%BA%E7%A4%8E%E3%81%8B%E3%82%89%E7%8F%BE%E5%A0%B4%E3%81%A7%E3%81%AE%E5%BF%9C%E7%94%A8%E3%81%BE%E3%81%A7-%E5%B1%B1%E7%94%B0-%E7%A5%A5%E5%AF%9B/dp/477418411X/ref=sr_1_1?s=books&ie=UTF8&qid=1492490156&sr=1-1&keywords=JavaScript%E6%9C%AC%E6%A0%BC%E5%85%A5%E9%96%80)
* [ゼロから始めるJavaScript生活](https://github.com/takahashim/js-stack-from-scratch "takahashim/js-stack-from-scratch: Step-by-step tutorial to build a modern JavaScript stack from scratch")
* [jQueryは必要ない（You Don't Need jQuery）](https://github.com/oneuijs/You-Dont-Need-jQuery/blob/master/README-ja.md "You-Dont-Need-jQuery/README-ja.md at master · oneuijs/You-Dont-Need-jQuery")
* [レトロエンジニアのための近代Webフロントエンド事情 - Qiita](http://qiita.com/uctakeoff/items/ce8da368d020273c6064 "レトロエンジニアのための近代Webフロントエンド事情 - Qiita")
* [連載 | ECMAScript 2015（ECMAScript 6）特集 | HTML5Experts.jp](https://html5experts.jp/series/ecma2015/ "連載 | ECMAScript 2015（ECMAScript 6）特集 | HTML5Experts.jp")

#### [Web Components](https://www.webcomponents.org/ "webcomponents.org")

[連載 | 基礎からわかる Web Components 徹底解説 〜仕様から実装まで理解する〜 | HTML5Experts.jp](https://html5experts.jp/series/web-components-2/ "連載 | 基礎からわかる Web Components 徹底解説 〜仕様から実装まで理解する〜 | HTML5Experts.jp")

#### [Riot.js](http://riotjs.com/ "Riot.js — Simple and elegant component-based UI library")

* [公式 Examples](https://github.com/riot/examples "riot/examples: Demos and examples for Riot and submodules")
* [Riot.jsでフロントエンドの複雑さに反乱するときがやってきた - Qiita](http://qiita.com/aggre/items/928eb2bedbac6a7829c0 "Riot.jsでフロントエンドの複雑さに反乱するときがやってきた - Qiita")
* [フロント界隈で一番イケてるのは AngularJS でも React でもなく Riot.js だという話 | phiary](http://phiary.me/frontend-riot-js-no1/ "フロント界隈で一番イケてるのは AngularJS でも React でもなく Riot.js だという話 | phiary")
* [Riot.js と Atomic Design ではじめるテクニカルクリエイター｜Technical Creator Hub](https://www.cyberagent.co.jp/technicalcreator/article/id=12462 "Riot.js と Atomic Design ではじめるテクニカルクリエイター｜Technical Creator Hub")

#### [Flux](http://facebook.github.io/flux/ "Flux | Application Architecture for Building User Interfaces")

* [公式 Examples](https://github.com/facebook/flux/tree/master/examples "flux/examples at master · facebook/flux")
* [これから始めるReact.js 発展編 - Fluxという設計思想 | CodeGrid](https://app.codegrid.net/entry/react-ex-1 "これから始めるReact.js 発展編 - Fluxという設計思想 | CodeGrid")
* [Fluxアーキテクチャのメモ - yukisovのメモ帳](https://www.pupha.net/archives/3218/ "Fluxアーキテクチャのメモ - yukisovのメモ帳")
* [ReactとFluxのこと // Speaker Deck](https://speakerdeck.com/geta6/reacttofluxfalsekoto "ReactとFluxのこと // Speaker Deck")
* [React.jsとFlux - Qiita](http://qiita.com/koba04/items/b32ba449d753fdb2b597)
* [React+Redux入門 - Qiita](http://qiita.com/erukiti/items/e16aa13ad81d5938374e React+Redux入門 - Qiita)

#### [RiotControl](https://github.com/jimsparkman/RiotControl "jimsparkman/RiotControl: Event Controller / Dispatcher For RiotJS, Inspired By Flux")

* 公式 Demos
    * [demo](https://github.com/jimsparkman/RiotControl/tree/master/demo "RiotControl/demo at master · jimsparkman/RiotControl")
    * [routing_demo](https://github.com/jimsparkman/RiotControl/tree/master/routing_demo "RiotControl/routing_demo at master · jimsparkman/RiotControl")
    * [binary_demo](https://github.com/jimsparkman/RiotControl/tree/master/binary_demo "RiotControl/binary_demo at master · jimsparkman/RiotControl")
* [Fluxとはなんぞや - Panda Noir](http://panda-noir.hatenablog.jp/entry/2016/12/28/143052 "Fluxとはなんぞや - Panda Noir")
* [Riot.jsを快適に動かすgulpタスクの話とRiotControlを用いたFluxデザインを実現してみた話 - Qiita](http://qiita.com/gaogao_9/items/22c7dd16a77fe6195c1c "Riot.jsを快適に動かすgulpタスクの話とRiotControlを用いたFluxデザインを実現してみた話 - Qiita")

#### [Babel](https://babeljs.io/ "Babel · The compiler for writing next generation JavaScript")

* [Babelの手ほどき - Babelとは | CodeGrid](https://app.codegrid.net/entry/babel-1 "Babelの手ほどき - Babelとは | CodeGrid")
* [Babelで始める！モダンJavaScript開発 | HTML5Experts.jp](Babelで始める！モダンJavaScript開発 | HTML5Experts.jp "Babelで始める！モダンJavaScript開発 | HTML5Experts.jp")

#### [webpack](https://webpack.github.io/docs/ "webpack")

* [公式 Examples](https://webpack.github.io/docs/examples.html "examples")
* [webpack で始めるイマドキのフロントエンド開発 - Qiita](http://qiita.com/yosisa/items/61cfd3ede598e194813b "webpack で始めるイマドキのフロントエンド開発 - Qiita")
* [【意訳】Webpackの混乱ポイント - Qiita](http://qiita.com/chuck0523/items/caacbf4137642cb175ec "【意訳】Webpackの混乱ポイント - Qiita")

#### [gulp](http://gulpjs.com/ "gulp.js")

* [現場で使えるgulp入門 | CodeGrid](https://app.codegrid.net/series/2014-gulp "現場で使えるgulp入門 | CodeGrid")"
* [ざっくりGulp.js入門（Mac向け） - Qiita](http://qiita.com/kazukichi/items/884a1379eea5918689ed "ざっくりGulp.js入門（Mac向け） - Qiita")

## 設計

### 外部設計

省略

### 内部設計

省略

### インフラ設計

省略

### DB 設計

省略

### API 設計

以下の記事を参考にしながら設計をしていきました。

* [翻訳: WebAPI 設計のベストプラクティス - Qiita](http://qiita.com/mserizawa/items/b833e407d89abd21ee72 "翻訳: WebAPI 設計のベストプラクティス - Qiita")
* [Web API 設計のベストプラクティス集 "Web API Design - Crafting Interfaces that Developers Love" - フリーフォーム フリークアウト](http://d.hatena.ne.jp/cou929_la/20130121/1358776754)
* [WebAPI でファイルをアップロードする方法アレコレ - Qiita](http://qiita.com/mserizawa/items/7f1b9e5077fd3a9d336b)
* [API Design Guide | Cloud APIs | Google Cloeud Platform](https://cloud.google.com/apis/design "API Design Guide | Cloud APIs | Google Cloud Platform")

手軽さから普段から使い慣れている [Google スプレッドシート](https://www.google.com/intl/ja_jp/sheets/about/ "Google スプレッドシート - オンラインでスプレッドシートを作成、編集できる無料サービス")で設計書を作成しました。
しかし、[Swagger](http://swagger.io/ "Swagger - The World's Most Popular Framework for APIs.") のようなツールを利用すれば、もっとクールな設計書になったかなと思います。

[SwaggerでRESTful APIの管理を楽にする - Qiita](http://qiita.com/disc99/items/37228f5d687ad2969aa2 "SwaggerでRESTful APIの管理を楽にする - Qiita")

### URL 設計

* [Hypertext Style: Cool URIs don't change.](https://www.w3.org/Provider/Style/URI "Hypertext Style: Cool URIs don't change.") ( [日本語訳](http://www.kanzaki.com/docs/Style/URI) )

### コンポーネント設計

コンポーネント設計なんてしたことがなかったため、タグの粒度をどうするかで非常に悩みました。
デザイナーさんが [Atomic Design](https://medium.com/re-write/the-unicorn-workflow-design-to-code-with-atomic-design-principles-and-sketch-8b0fe7d05a37#.6tuwzuio1 "The Unicorn Workflow, Design to Code with Atomic Design Principles and Sketch – RE: Write – Medium") ( [日本語訳](http://postd.cc/the-unicorn-workflow-design-to-code-with-atomic-design-principles-and-sketch/ "珍しいワークフロー：Atomic Designの原則とSketchでデザインからプログラミングまで | デザイン | POSTD") ) を取り入れたいという話をしていたので、[こちら](https://www.cyberagent.co.jp/technicalcreator/article/id=12462 "Riot.js と Atomic Design ではじめるテクニカルクリエイター｜Technical Creator Hub")の記事を参考にして AtomicDesign のコンポーネント単位で設計していきました。

### スタイルガイド作成

スタイルガイドを作る十分な時間を確保することが出来なかったため、以下のスタイルガイドに載っとるようにしました。

* Riot

[voorhoede/riotjs-style-guide](https://github.com/voorhoede/riotjs-style-guide "voorhoede/riotjs-style-guide: Opinionated RiotJS Style Guide for teams.") ( [日本語訳](http://qiita.com/risacan/items/d782fa24ad4d4f8b73f8 "[翻訳] Riotjs Style Guide - Qiita") )

* JavaScript

 [airbnb/javascript](https://github.com/airbnb/javascript "airbnb/javascript: JavaScript Style Guide") ( [日本語訳](https://github.com/mitsuruog/javascript-style-guide "mitsuruog/javascript-style-guide: 常に気をつけたい、JavaScriptへの正しい接し方") )

* CSS / Sass

[airbnb/css](https://github.com/airbnb/css "airbnb/css: A mostly reasonable approach to CSS and Sass.") ( [日本語訳](https://github.com/nao215/css-style-guide "nao215/css-style-guide: A mostly reasonable approach to CSS and Sass.") )

### 開発環境構築

#### Node.js

##### nvm

Node.js のバージョン管理ツールとして `nvm` ( [Node Version Manager](https://github.com/creationix/nvm "creationix/nvm: Node Version Manager - Simple bash script to manage multiple active node.js versions") ) を利用し Node.js をインストールしました。 `nvm` を選択した理由としては、バージョン番号を含む _.nvmrc_ ファイルをプロジェクトごとに作成することで Node.js のバージョンをプロジェクトごとに固定出来るためです。

例えば、プロジェクト ( カレントディレクトリ ) の Node.js のバージョンを v4.3.2 に設定するには以下のようにします。

```sh
$ echo "4.3.2" > .nvmrc
```

次に、 `nvm` を実行すると v4.3.2 の Node.js を利用することができます。

```sh
$ nvm use
Found '/path/to/project/.nvmrc' with version <4.3.2>
Now using node v4.3.2 (npm v2.14.12)
```

_.nvmrc_ ファイルを SPA のプロジェクトと Serverless のプロジェクト ( Lambda で使われている Node のバージョン ( v4.3.2 ) に合わせている ) それぞれに作成しています。

##### Yarn

パッケージマネージャとして NPM よりも高速な [Yarn](https://yarnpkg.com/lang/en/ "Yarn") を利用しています。

Yarn については以下の記事参照してください。

[npm互換のJavaScriptパッケージマネージャーYarn入門 - ICS MEDIA](https://ics.media/entry/13838 "npm互換のJavaScriptパッケージマネージャーYarn入門 - ICS MEDIA")

#### バックエンド

Serverless Architecture の環境を [Serverless Framework](https://serverless.com/ "Serverless - The Serverless Application Framework powered by AWS Lambda and API Gateway") を使って構築しています。
また、 [serverless-offline](https://github.com/dherault/serverless-offline "dherault/serverless-offline: Emulate AWS λ and API Gateway locally when developing your Serverless project") プラグインを使用してローカルで動作するようにしています。また、DynamoDB Local インスタンスは [serverless-dynamodb-local](https://github.com/99xt/serverless-dynamodb-local "99xt/serverless-dynamodb-local: Serverless Dynamodb Local Plugin - Allows to run dynamodb locally for serverless") プラグインによって提供されます。

[公式 Examples](https://github.com/serverless/examples/tree/master/aws-node-rest-api-with-dynamodb-and-offline "examples/aws-node-rest-api-with-dynamodb-and-offline at master · serverless/examples") が用意されているため参考にしながら構築していきました。導入や設定方法は以下の記事を参照してください。

 [Serverless アプリケーションをローカルで開発する - Qiita](http://qiita.com/noralife/items/e36621ddd0e5b8ff4447 "Serverless アプリケーションをローカルで開発する - Qiita")

#### フロントエンド

**※ 開発環境構築に関する記事を投稿しました。 ( 2017/04/27 )**

[Riot.js + RiotControl で Flux を実装してみる - 開発環境構築編 - Qiita](http://qiita.com/kotarella1110/items/e4d0120dd70057ffdfdc "Riot.js + RiotControl で Flux を実装してみる - 開発環境構築編 - Qiita")

今回構築した環境は以下がベースとなっています。

* Riot
* RiotControl
* Babel
* Sass
* Webpack

こちらの環境は [公式 Examples](https://github.com/riot/examples/tree/gh-pages/webpack "examples/webpack at gh-pages · riot/examples") を参考に構築しました。

※ 余談ですが、 [こちらのコミット](https://github.com/riot/examples/commit/596f94f62695c2192bbc56f179991813e09a955d "updated: webpack example using tag-loader · riot/examples@596f94f")以降、 Webpack のローダーは、 [riotjs-loader](https://www.npmjs.com/package/riotjs-loader "riotjs-loader") ではなく公式の Webpack ローダーである [tag-loader](https://www.npmjs.com/package/tag-loader "tag-loader") に変更されたようです。筆者も [公式サンプル](https://github.com/riot/examples/tree/gh-pages/webpack) を見つける前は、 Webpack のローダーとして riotjs-loader を利用していました...。riotjs-loader は Riot.js v3 以降に対応していないようですので、riotjs-loader を利用している方は、tag-loader に切り替えることをお勧めします。

また、以下の理由により Gulp は導入してあります。

[WebpackをGulpに統合する](https://github.com/takahashim/js-stack-from-scratch/tree/ja/tutorial/7-client-webpack#webpackをgulpに統合する "js-stack-from-scratch/tutorial/7-client-webpack at ja · takahashim/js-stack-from-scratch")

> Webpackはさまざまなことを行います。プロジェクトがクライアントサイドのものであれば、Gulpをすっかり置き換えてしまうこともできます。一方で、Gulpはもっと汎用的なツールで、linting、テスト、バックエンドタスクなどに向いています。

とはいえ、今回は linting やテストは行なっていません。今後導入していきたい...。

## 開発

基本的には、[技術習得](http://qiita.com/kotarella1110/items/7802892c84c2afc66e1d#%E6%8A%80%E8%A1%93%E7%BF%92%E5%BE%97)で上げた記事を参考にしながら開発を進めて行きました。
以下では、事前に知っておけばよかった知識や、どんなパッケージを利用して開発をしたかを簡単に記載しています。

### バックエンド

開発着手前に読んでおいた方が良い記事

* [世界に先駆けてAWSサーバレスアーキテクチャでユーザ認証とAPI認可の実装をしてみた - Qiita](http://qiita.com/teradonburi/items/ef535d19c28a009552ec "世界に先駆けてAWSサーバレスアーキテクチャでユーザ認証とAPI認可の実装をしてみた - Qiita")
* [Serverless Frameworkのハマりポイント色々](http://qiita.com/kiida/items/0ce9d3fb1cbe2d8ede22)

#### Serverless Architecture のコードパターン

Serverless Architecture のコードパターンは以下の4パターンです。

[Serverless Code Patterns](https://serverless.com/blog/serverless-architecture-code-patterns/ "Serverless Code Patterns")

> 1. Microservices Pattern
> 2. Services Pattern
> 3. Monolithic Pattern
> 4. Graph Pattern

筆者は、以下のように **各 Lambda 関数 ( `functions` ) につき単一の HTTP エンドポイント ( `handler` ) を持つ Microservices Pattern** で開発して行きました。

```yaml:serverless.yml
service: serverless-social-network
provider: aws
functions:
  usersCreate:
    handler: handlers.usersCreate
    events:
      - http: post users/create
  commentsCreate:
    handler: handlers.commentsCreate
    events:
      - http: post comments/create
```

しかし、開発を進めていくに伴いデプロイの際に [CloudFormation のリソース上限に達して](http://qiita.com/kiida/items/0ce9d3fb1cbe2d8ede22#%E8%89%B2%E3%82%93%E3%81%AA%E3%83%AA%E3%82%BD%E3%83%BC%E3%82%B9%E4%B8%8A%E9%99%90%E3%81%AB%E9%81%94%E3%81%99%E3%82%8B "Serverless Frameworkのハマりポイント色々 - Qiita")しまいました。

> **CloudFormation自体のリソース上限が200なので、デプロイの際に200を超えるリソースがあるとエラーになります。**

そのため、以下のように **全てのCRUD操作をもつ各 Lambda 関数につき複数の HTTP エンドポイントを持つ Services Pattern** に変更しリソース制限を回避しました。

```yaml:serverless.yml
service: serverless-social-network
provider: aws
functions:
  users:
    handler: handler.users
      events:
        - http: post users
        - http: put users
        - http: get users
        - http: delete users
  comments:
    handler: handler.comments
      events:
        - http: post comments
        - http: put comments
        - http: get comments
        - http: delete comments
```

Services Pattern を実現するにはリクエストメソッドまたはエンドポイントに基づいて適切なロジックを呼び出すためにルータを作成する必要があります。
ルータの作成においては以下を参考にしました。

[Routing API Gateway Traffic Through One Lamda Function](http://www.goingserverless.com/blog/routing-api-gateway-traffic-through-one-lambda-function "Routing API Gateway Traffic Through One Lamda Function")

#### [CORS](https://developer.mozilla.org/ja/docs/Web/HTTP/HTTP_access_control "HTTP アクセス制御 (CORS) - HTTP | MDN")

[CORSまとめ - Qiita](http://qiita.com/tomoyukilabs/items/81698edd5812ff6acb34)

Serverless Framework で [CORS を有効にする](https://serverless.com/framework/docs/providers/aws/events/apigateway#enabling-cors "Serverless Framework - AWS Lambda Events - API Gateway")際は、以下のように設定してください。

`cors` を `true` 設定すると、次のようなデフォルト設定が仮定されます。

```yaml:serverless.yml
functions:
  hello:
    handler: handler.hello
    events:
      - http:
          path: hello
          method: get
          cors:
            origins:
              - '*'
            headers:
              - Content-Type
              - X-Amz-Date
              - Authorization
              - X-Api-Key
              - X-Amz-Security-Token
            allowCredentials: false
```

この `cors` プロパティを設定すると、CORS preflight レスポンスに `Access-Control-Allow-Origin` 、 `Access-Control-Allow-Headers` 、 `Access-Control-Allow-Methods` 、 `Access-Control-Allow-Credentials` ヘッダーが設定されます。

XMLHttpRequest を使う場合は `X-Requested-With` ヘッダーと `X-Requested-By` ヘッダーを付与してください。

```diff:serverless.yml
 headers:
   - Content-Type
   - X-Amz-Date
   - Authorization
   - X-Api-Key
   - X-Amz-Security-Token
+  - X-Requested-With
+  - X-Requested-By
```

Lambda プロキシとの統合で CORS を使用する場合 `Access-Control-Allow-*` は、ヘッダーオブジェクトに次のようにヘッダーを含めるようにしてください。

```js:handler.js
'use strict';

module.exports.hello = function(event, context, callback) {

    const response = {
      statusCode: 200,
      headers: {
        "Access-Control-Allow-Origin" : "*", // Required for CORS support to work
        "Access-Control-Allow-Credentials" : true // Required for cookies, authorization headers with HTTPS
      },
      body: JSON.stringify({ "message": "Hello World!" })
    };

    callback(null, response);
};
```

#### [認証と認可](http://dev.classmethod.jp/security/authentication-and-authorization/ "よくわかる認証と認可 ｜ Developers.IO")

* [Amazon Cognito ユーザープールを使用 - Amazon API Gateway](http://docs.aws.amazon.com/ja_jp/apigateway/latest/developerguide/apigateway-integrate-with-cognito.html "Amazon Cognito ユーザープールを使用 - Amazon API Gateway")
* [Amazon API Gateway カスタム認証を使用する - Amazon API Gateway](http://docs.aws.amazon.com/ja_jp/apigateway/latest/developerguide/use-custom-authorizer.html "Amazon API Gateway カスタム認証を使用する - Amazon API Gateway")
* [AWSとシステムの認証認可を考える - プログラマでありたい](http://blog.takuros.net/entry/2016/02/03/081458 "AWSとシステムの認証認可を考える - プログラマでありたい")
* [Cognito UserPoolを使ってAPIを保護しよう  |  HIGHWAY for AWS](http://www.h4a.jp/detail/25148 "Cognito UserPoolを使ってAPIを保護しよう  |  HIGHWAY for AWS")

### フロントエンド

開発着手前に読んでおいた方が良い記事

* [Riot.jsの落とし穴まとめ - Qiita](http://qiita.com/clown0082/items/073c4c2e39ec5ca12962 "Riot.jsの落とし穴まとめ - Qiita")
* [Riot を React の文脈で理解する - Qiita](http://qiita.com/aggre/items/48d2cf9b427affc8b3f9 "Riot を React の文脈で理解する - Qiita")

#### Amazon Cognito User Pools を使ったユーザ認証基盤

[aws-sdk](https://www.npmjs.com/package/aws-sdk "aws-sdk") と [amazon-cognito-identity-js](https://www.npmjs.com/package/amazon-cognito-identity-js "amazon-cognito-identity-js") を利用してユーザー認証を実現しています。

* 公式
  * [JavaScript SDK の使用](http://docs.aws.amazon.com/ja_jp/cognito/latest/developerguide/using-amazon-cognito-user-identity-pools-javascript-examples.html "例: JavaScript SDK の使用 - Amazon Cognito")
  * [API Reference](https://docs.aws.amazon.com/ja_jp/cognito-user-identity-pools/latest/APIReference/Welcome.html "Welcome - Amazon Cognito Identity Provider")
* [Amazon Cognito User Poolsを使って、webサイトにユーザ認証基盤を作る - Qiita](http://qiita.com/horike37/items/1d522f66452d3abe1203 "Amazon Cognito User Poolsを使って、webサイトにユーザ認証基盤を作る - Qiita")
* [cognitoでログイン/セッション管理 - ぱんだのびぼーろく](http://tarepan.hatenablog.com/entry/cognito_UserPools_session_management "cognitoでログイン/セッション管理 - ぱんだのびぼーろく")


[Babel webpack example](https://github.com/aws/amazon-cognito-identity-js/tree/master/examples/babel-webpack "amazon-cognito-identity-js/examples/babel-webpack at master · aws/amazon-cognito-identity-js")

認証基盤を構築する上での Flux のフローは以下の記事を参考にしました。

[Adding authentication to your React Flux app](https://auth0.com/blog/adding-authentication-to-your-react-flux-app/ "Adding authentication to your React Flux app")

#### ルーティング

Riot 公式の [riot-route](https://www.npmjs.com/package/riot-route "riot-route") を利用しています。

* [API · Router](http://riotjs.com/api/route/ "API · Router")
* [Riot.jsのRoutingについて | Tagbangers Blog](https://blog.tagbangers.co.jp/2016/10/23/riotjs-routing "Riot.jsのRoutingについて | Tagbangers Blog")

#### Flux

**※ Flux 実装に関する記事を投稿しました。 ( 2017/04/27 )**

[Riot.js と RiotControl で Flux を実装してみる - Qiita](http://qiita.com/kotarella1110/items/f9958195c929da6508b6 "Riot.js と RiotControl で Flux を実装してみる - Qiita")

コンポーネント間のデータの受け渡しをシンプルにするために、 **Dispatcher として [riotcontrol](https://www.npmjs.com/package/riotcontrol "riotcontrol") を利用して Flux を実現** しました。

![flux-diagram-white-background](https://github.com/facebook/flux/blob/master/docs/img/flux-diagram-white-background.png?raw=true "flux/flux-diagram-white-background.png at master · facebook/flux")

構成としては、 Riot と RiotControl をベースとした以下のスターターキットに習った形となっています。

[riotjs-startkit](https://github.com/wbkd/riotjs-startkit "wbkd/riotjs-startkit: A Riot - PostCSS - Webpack Starterkit")

> This starterkit is based on:

> * Riot
> * RiotControl
> * PostCSS
> * Webpack

[コンポーネント設計](http://qiita.com/kotarella1110/items/7802892c84c2afc66e1d#%E3%82%B3%E3%83%B3%E3%83%9D%E3%83%BC%E3%83%8D%E3%83%B3%E3%83%88%E8%A8%AD%E8%A8%88) の記載にある通り、コンポーネントは AtomicDesign のコンポーネント単位で分割したため、最終的に _src_ のディレクトリ構造は以下のようになりました。

```tree:src
.
├── assets/                       # Image, Font, etc.
├── css/
├── components/                   # Components by AtomicDesign
│   ├── atoms/
│   ├── my-example-1
│   │   ├── README.md
│   │   ├── my-example-1.scss
│   │   └── my-example-1.tag.html
│   ├── my-example-2
│   │   ├── README.md
│   │   ├── my-example-2.scss
│   │   └── my-example-2.tag.html
│   ├── molecules/
│   ├── organisms/
│   ├── templates/
│   └── pages/
├── constants/                   # Action Types
│   └── myExampleActionTypes.js
├── actions/                     # Action Creators
│   └── myExampleActions.js
├── stores/                      # Store
│   └── myExampleStore.js
├── utils/                       # Web API Utils, Mixin, etc.
│   └── MyExampleApi.js
├── config/                      # config
│   ├── development.js
│   └── production.js
├── index.html
├── index.js
└── router.js
```

RiotControl を利用する上での注意点としては、ルーティング等でタグが mount、unmount を繰り返す場合、mount がされる度に dispatcher のイベントもその都度増えていくため、一回だけ実行されればいいイベントが複数回呼ばれページが重くなるケースに遭遇しました。

```html:my-example.tag.html
import dispatcher from 'riotcontrol';

<my-example>
  <script>
  dispatcher.on('EVENT', () => {
    console.log('called event!');
  });
  </script>
</my-example>
```

このような場合は、タイミングは自由ですが dispatcher のイベントを破棄する必要があります。例えば、以下のようにすることで unmount 時にイベントを破棄できます。

```diff:my-example.tag.html
 import dispatcher from 'riotcontrol';

 <my-example>
   <script>
+  var tag = this;

+  tag.on('unmount', () => {
+    dispatcher.off('EVENT');
+  });

   dispatcher.on('EVENT', () => {
     console.log('called event!');
   });
   </script>
 </my-example>
```

#### Riot.js

Atom を作成していく際、例えば四角いボタンを作成する場合はどのように作成するでしょうか？筆者は以下のように開発当初作成していました。

```html:square-button.tag.html
import './button-square.scss';

<square-button>
  <button class={ opts._class }>
    <yield/>
  </button>
<square-button>
```

```html:タグ呼び出し
<square-button _class="green">四角ボタン</square-button>
```

これだと、厳密には Atom ではありません。
以下のように [HTML エレメントをタグとして扱う](http://riotjs.com/guide/#html-elements-as-tags "Custom tags · Riot.js")ことで Atom を作成することができます。

```html:square-button.tag.html
import './button-square.scss';

<button-square>
  <yield/>
</button-square>
```

```html:タグ呼び出し
<button data-is="button-square" class="green">四角ボタン</button>
```

#### REST API リクエスト

Web リクエストを行うためのパッケージとして、[superagent](https://www.npmjs.com/package/superagent "superagent") や [axios](https://www.npmjs.com/package/axios "axios") がありますが、WHATWG によって策定が進んでいる次期標準 の[Fetch API](https://fetch.spec.whatwg.org/ "Fetch Standard") を利用しています。過去バージョンのブラウザへの対応が必要となったため、[whatwg-fetch](https://www.npmjs.com/package/whatwg-fetch "whatwg-fetch") を利用しています。

[お疲れさまXMLHttpRequest、こんにちはfetch - Qiita](http://qiita.com/tomoyukilabs/items/9b464c53450acc0b9574 "お疲れさまXMLHttpRequest、こんにちはfetch - Qiita")

Flux において API リクエストは Action Creator で行い、取得したデータを Store に引き渡すのが正しいそうです。

#### バリデーション

フロント側のバリデーションとして、[validatorjs](https://www.npmjs.com/package/validatorjs "validatorjs") を利用しています。

[フロントサイドのバリデーションにはvalidatorjsが便利 - Qiita](http://qiita.com/hirohero/items/e51ff5a98a0eea425d44 "フロントサイドのバリデーションにはvalidatorjsが便利 - Qiita")

validatorjs の [Available Rules](https://www.npmjs.com/package/validatorjs#available-rules "validatorjs") の日本語訳として、[使用可能なバリデーションルール](https://readouble.com/laravel/5.3/ja/validation.html "バリデーション 5.3 Laravel") を参照するのがオススメです。

Flux においてバリデーションロジックは Store に書くべきだそうです。

[データのValidationについて](http://qiita.com/koba04/items/b32ba449d753fdb2b597#%E3%83%87%E3%83%BC%E3%82%BF%E3%81%AEvalidation%E3%81%AB%E3%81%A4%E3%81%84%E3%81%A6 "React.jsとFlux - Qiita")

> Validationのロジック自体は役割としてはStoreにあるのが正しいのかなと思っています。ViewがActionを投げてStoreが受け取ったときに不正なデータの場合は、エラーのイベントをViewに投げてViewは必要あればエラーの表示をする流れがいいのかなと個人的には思っています。

```
------         ------------        -------------------        ------
|View| --------|Dispatcher|--------|StoreでValidation|--------|View|--- エラー表示
------  action ------------ action ------------------- error  ------
```

筆者はバリデーションロジックを View に書きましたが...。

## テスト

省略

## 終わりに

ざっくりとした内容のため、ここが伝わらない、ここどうしたの？という部分があればコメントください。
また、開発環境の構築や Riot.js + RiotControl を利用した Flux の実現については、詳しく記載した内容として別の機会に公開しようと思っています。