AWS をフル活用して「サーバレス」な SPA を実装できる「サーバーレスシングルページアプリケーション」を読んだ

6月末に O'Reilly から出版された「サーバーレスシングルページアプリケーション」を読んだ.ただ読むだけじゃ理解度が浅くなってしまうかもしれないなと感じて,今回は全ての実装を写経してみた.そのため少し時間はかかってしまったけど,フロントエンドには苦手意識があったし,今まで SPA の実装もしたことがなかったので,前半部分は特にワクワクしながら楽しめた.今回,監訳者の id:yoshidashingo にご献本を頂き,本当に感謝しかありません.ありがとうございます!と同時に,ガッツリ読もうと意気込んだタイミングで仕事に忙殺されてしまったりして,書評のタイミングが遅れてしまったのはすみません!

サーバーレスシングルページアプリケーション ―S3、AWS Lambda、API Gateway、DynamoDB、Cognitoで構築するスケーラブルなWebサービス

サーバーレスシングルページアプリケーション ―S3、AWS Lambda、API Gateway、DynamoDB、Cognitoで構築するスケーラブルなWebサービス

どんなものを実装したのか?

まず最初に,本書でどんなものを実装したのか?を紹介したいと思う.本書の表紙に描かれてるようなダッシュボードサイトではなく(最初はちょっと期待してしまった笑),LearnJS という名前の「JavaScript プログラミングパズル」を実装する.僕が実際に実装したアプリケーションのキャプチャを以下に載せておく.

f:id:kakku22:20170716152327p:plain f:id:kakku22:20170716152335p:plain

ちゃんと SPA になっていて,ハッシュイベントの変更をトリガーして次のページが表示される.app.js で以下のようなルーティングを定義するため,実際に遷移する URL は /#problem-1/#profile になる.今までは Rails など一般的なウェブアプリケーションの経験が多かったので,実際に自分で実装した SPA が動くと「おおおー!」という感動があった.

var routes = {
  '#problem': learnjs.problemView,
  '#profile': learnjs.profileView,
  '#': learnjs.landingView,
  '': learnjs.landingView
};

実際に以下の公式アプリケーションをすぐに試せる.

技術スタック

本書のサブタイトルにもある通り,AWS を活用して「サーバレス」を実現している.具体的には S3 からアプリケーションを配信し,Google のソーシャルログインには Cognito を使う.さらに自分の解答を DynamoDB に保存し,既に正解している問題ページを表示したときには,その解答を初期表示できるようになっている.また API Gateway + Lambda から DynamoDB に接続してエンドポイントを提供するところも解説されている.

SPA の部分は,React や Vue.js などではなく jQuery 2.1 を使う.非同期処理が必要な部分は jQuery.Deferred を使う. JavaScript のテストには Jasmine + Spy を使って,テストがしにくい部分もモックでテストできるようになっている.

素晴らしかったこと

デプロイファースト

LearnJS の雛形を GitHub から取得して,ローカル起動が確認できたら,すぐに S3 に本番デプロイしよう!という流れから始まる.これは本当に素晴らしいと思う.僕が好きな「ThoughtWorks アンソロジー」に書かれている「ラストマイル」の話と同じで,デプロイなど運用系のタスクを最後まで残しておくと,潜在的な問題が最後に露見するというものだ.本書では最初にいきなりデプロイをして,その後も章ごとに必ずデプロイをする.ローカルで動いているものが,全く同じように S3 でも動くのは,当たり前だけど非常に重要だと思う.同時にそれを支えるのは,便利スクリプト sspa なので,ここも参考になった.

github.com

テストファースト

最初からテストファーストで進んでいくため,例えば learnjs.showView 関数を実行したときの期待値を先にテストコードとして実装し,エラーを確認し,次に関数を実装し,テストが通ることを確認する.まさに TDD を体験できるのも本書の良さだと思う.今回特に写経をしながら進めたため,ミスによって動かなくなったケースが多くあった.そういうときにも,テストを実行して,期待値と合わない部分を特定することによってミスの発見を効率化できたので,実体験としてもテストファーストの恩恵を受けることができた.

f:id:kakku22:20170716152459p:plain

ハッシュイベント

今回実装した SPA のキモはハッシュイベントだったと思う.window.location.hash に変更があったときに window.onhashchange でトリガーして,ルーティングに飛ばした.また2章ではブラウザバックしても何も動かなかった部分が,3章でエイリアスルートを追加することによって動くようになった.このあたりを知れたのも個人的には大きかった.

リファクタリング

本書ではとにかく「小さく作る」ことが重要視されているため,例えば,最初は /#problem-1 ためだけの実装をして,動作確認が終わったら問題番号の部分をパラメータ化して /#problem-* に対応するルーティングを実装していく.他にも Correct! と Incorrect! の表示を作って動作確認をしてからフェードインの効果を追加するなど,リファクタリングを繰り返し行なっていく.この流れも参考になる.よく仕事でも「過剰に汎用化しすぎて使えない」ものがあったりして,改めて「小さく作る」ことを意識したいとも思った.

Cognito

実は今まで Cognito を使ったことがなく,今回初体験だった.今回は Google+ API を使った IdP 接続を実装した.とにかく簡単に実現できたし,この部分をフルマネージドにできるのも効果的だなと思った.本書では使うことはなかったが,Cognito User Pools も検証してみたい.今まで機会がなく使ったことがなかった Cognito に少しでも触れられたのも良かった.

API Gateway + Lambda + DynamoDB

個人的には使ったことがあり,解説の部分はある程度流し読みをしたが,「サーバレスの概念は理解しているが,実際に実装したことがない」という人にとっては最高のテーマだと思う.無料枠もあるし,まず試してみるのが良いのではないかと思う.1点 sspa スクリプトが API Gateway に対応していなく,手動で /popularAnswers の POST リソースを作るところはちょっと笑った.

セキュリティとスケールアップ

最後にはセキュリティで気を付けるべき点と,スケールアップの方法,そして CloudWatch を使ってモニタリングをする話も紹介されていて非常に手厚かった.今回実装したアプリケーションが完璧ではなく,現実問題では様々な考慮が必要であることが伝わる.S3 のアクセスログを分析する部分は,今なら Athena でクエリを投げればもっとリッチな体験ができるし,サーバレスだと思うけど,原著の発売日が2016年6月なので,まだ発表されていなかった.

aws.amazon.com

ハマったこと

CSS の記述が一部書かれてなく,思った通りのデザインにならなかった.そこは実際に公式ページを Chrome DevTools で解析して調べた.具体的には以下なので,ここは気を付けてもらえればと.

3章

ツールバーを実装するときに,以下の CSS を追加しないと,LearnJS のフォントサイズが大きくならなかった.また,そのために margin-top を 30px から 60px に修正する必要もあり,ここは本書に書いてあるものの,コードとしては書かれてなく,見落としてしまった.

.text-lg {
  font-size: 32px;
}

4章

Cognito 連携をしたときにナビバーにログイン済のメールアドレスを表示するが,そこで使う以下の CSS を追加しないと,デザインが微妙に崩れてしまった.

.navbar-padding-lg {
  padding-top: 12px;
  display: inline-block;
}

正誤表

O'Reilly から正誤表が公開されていて,現時点だと1点だけある.今後増える可能性もあるので,見ておくと良さそう.この「マイナスが抜けてる」件は,写経していると「変だな?」とすぐ感じたので,特に困ることはなかった.

www.oreilly.co.jp

ソースコード一覧

今回は答えを見ずに頑張って写経することを目標にしていたので,1度もダウンロードすることはなかったけど,公式のソースコード一覧が公開されている.どうしても困った!という場合は見てみるのが良いのではないかと思う.

pragprog.com

エディタ

2章までは vim で写経をしていたけど,ミスが連発したり,app.js がもっと大きくなる気配を感じたので,途中からは使い慣れた RubyMine で写経をした.フォーマットもできるし,コードジャンプもできるし,シンタックスチェックもできるし,圧倒的に効率が良くなった.もし写経をするなら,エディタを用意してから取り組むのが良いと思う.

まとめ

  • 本書を写経しながら SPA を実装することができた
  • S3 / Cognito / DynamoDB / API Gateway / Lambda などを組み合わせることで,本当に「サーバレス」で実現できた
  • 写経 + 動かなくてデバッグした時間も含めると,約6.5時間(13 ポモドーロ)で終わった

関連記事

監訳お疲れさまでした!素晴らしかったです!

yoshidashingo.hatenablog.com

API Gateway + Lambda をもっと深く学ぶなら同じく6月に出版された「実践 AWS Lambda」がオススメ!

kakakakakku.hatenablog.com