発表者は、その日何をしていたのか - 発表の舞台裏 JAWS DAYS 2019 編


新しい朝が来た希望の朝だ、発表の朝だ!

JAWS DAYS での発表の朝を迎えて、発表者 lulzneko は絶望していた。
なんと発表資料が完成していないのです 😱


2019年2月23日に開催された JAWS DAYS 2019 で『AWS x JAMStack で構築・運用するサーバーレスな Web Front』と題して JAMStack にまつわる発表をしました。その発表の舞台裏ということで、発表者が当日何をしていたのかを綴ります。

シリーズの記事

JAWS DAYS 概要

発表したイベント JAWS DAYS 2019 ですが、AWS のユーザーコミュニティ JAWS-UG 主催、後援 アマゾン ウェブ サービス ジャパン株式会社さん で 行われる JAWS-UG 最大のイベントです。

場所は TOC五反田メッセで、さまざまなイベントや展示会などが開催される場所です。

会場入り

ストーリーとスライドの配置は完成していて、そこに載せる図 AWS における JAMStack の配置 の章で使うものが間に合ってなかったレベルなのですが、慌てて PowerPoint を操作する朝から始まりました。
なんか、前回の デブサミ舞台裏 でも同じことを書いた気がします。

なお、前日の 22日には発表用資料をうっかり消し飛ばす事故を起こしました。
慌てるとよくないことがあるので、急ぎつつも作業ミスをしないのが大事です。

急いでスライドを完成させ、所用を済ませと、あわただしく過ごして午後一の会場入りをしました。
資料の都合というより所用があって午前入りできなかったのですが、午前中のセッションも聴きたかった。

会場である TOC五反田メッセは、本館とは別の建物になります。
“TOC” だけで考えていると、うっかり本館へ行ってしまい、結構な回り道を歩くことになります。
そうです、うっかり本館へ行ってしまいました。微妙な場所からの移動だったのでタクシーさんに乗せてもらったのですが “メッセ” が伝わってなかったようで、がっつり本館へ。あまり東京の道に慣れてないとのことでしたので、結構な周り道を徒歩で堪能させていただきました。

受付

無事会場入りできたので次は受付です。

イベント開催用の建物なので、入ってすぐに受付になります。
手前に参加者の受付があり、少し進んだところに発表者の受付があります。
クロークもあるので、モコモコのジャケットを預けられたのが嬉しいです。

受付で Doorkeeper のチェックインをします。QR コードを表示して読み取ってもらいます。
続いて自分の名前が書かれてるスピーカーパスをもらい、印刷したアイコンの切り紙を差し込みます。(写真では名前部分が隠れてますが、当日はアイコン画像を端において名前は見えるようにしています)

受付が終わると、発表時間までフリーなのでセッションを楽しんだり、控室で作業したりできます。

発表 10分前

前の発表が終わり、落ち着いたところで演台へ近づき発表準備に入ります。

進行の方から名前等の最終確認を受けます。

そして、電源の確認。
今回はちゃんと持っていきました!(持って帰るのを忘れました💦)

発表者サポートは、進行の方が残り時間をボードで教えてくれます。
10分、5分、3分。しっかり出してくれるので助かります。

マイクはワイヤードで、演台にセットされています。持っているほうが安定するので、外して持つようにしました。
会場は各セッションごとの個室ではなく、会場の後ろ側が空いている&壁が天井までつながっていない仕様のため、マイクの音が小さめでレシーバーで聞くようになっています。会場の後ろのほうで聞いていると音があまりしないので、話すときにどんな感じか心配しましたが話している分には側のスピーカーから聞こえるので違和感はなかったです。

プロジェクターが大きく、普段は投影画像を直接指さすタイプなのですが、さすがに届かない感じです。そろそろマイ・レーザーポインターを用意したほうが良いと思いつつ、準備完了。

発表用スライドの URL をツイート。

発表

いざ、発表!
ご清聴ありがとうございました!!

たくさんのツイートありがとうございます!!
2019/02/23(土) JAWS DAYS 2019 <7> 15:10~ #jawsug #jawsdays - Togetter

@kondoyuko さんに、グラレコを作っていただきました。ありがとうございます!

※ QA は後ほどまとめます。

懇親会まで、徘徊

Ask the Speaker はないので終了。
発表用スライドの URL を再度ツイート。

エゴサして、Like、RT、Follow-…

回れてなかった出展ブースを巡り、スタンプラリー
すべて回ったはずなのに、スタンプが1つ足りず。。。どこが足りないのかはわからない仕様なので諦める&配布終了に間に合わず。残念。
(次の日になったらアプリで表示できなくなったのでキャプチャできず)

懇親会

すごい人数でした。🍻 楽しかったです!


以上、発表者の一日でした。
なんとか無事発表を終えることができました。

次回は、2019年3月9日(土)『【CTOって本当にかけるの!?】ベンチャー6社のCTOチームと競う新規サービス立ち上げハッカソン』でハックしに行きます。
2/25日現在、まだまだ枠がある(8/30人)ようなので、よかったら一緒にハッカソンしましょう。

また、ちょっと来て話をしてよ、といったようなことなどありましたら、Twitter DM/メンションを @lulzneko へ気軽にいただければ幸いです。
これまでの発表歴は、こちら [Slides | Riotz.works] https://riotz.works/slides になります。


聴きに来てくださり、ありがとうございました。
スタッフの皆さま、支援ありがとうございました。

そして、ポエム的なものをここまで読んでくださり、ありがとうございます。

デブサミ 2019 Ask the Speaker にて頂いた QA まとめ

Developers Summit 2019 で『サーバーレスで最高に楽しめるアプリ開発』のお話をした後の Ask the Speaker で頂きました QA をまとめます。

頂いた質問は要点のみを一般化して書いています。背景などが入っていないので若干わかりにくい部分がありますが、ご了承ください。

シリーズの記事

発表資料と Togetter

デブサミ2019【15-B-6】サーバーレスで最高に楽しめるアプリ開発 #devsumiB - Togetter
たくさんのツイートありがとうございます!!

1. ピタゴラ装置式で障害が発生したら、どのように追跡するか?


たとえば IoT プラットフォームの例では、AWS Lambda を細かく分けていますし、いくつかのサブシステムや AWS アカウントをまたがって処理を行っていたりします。

また入力ソースがバッチとウェブがあり、途中から同じ処理フローになっていきます。

障害が発生すると、結局のところログを洗っていくしかないのは変わらずで。分散されているので地道に追いかけています。

開発メンバーのひとりが、トレースID をヘッダーにつけてリレーする方式を導入を進めてくれているため、導入されている範囲は比較的探しやすいです。

その方法は以下となります。

  • リクエストを最初に受けた場所は、次のリクエストを投げるときに TRACE_ID というヘッダーに UUID をつけて送る (※ TRACE_ID は本記事用の仮名)
  • 中間の処理でも TRACE_ID がなかったら、そこから TRACE_ID をつけ始める
  • TRACE_ID を受け取った場合は、その値をリレーして使っていく(新たに発行しない)

マイクロサービスのトレーシング用ライブラリや基盤もあります。いまちょっと名前が思い出せないです。すみません。まだ、しっかり調査できてないので導入できてないです。

※ 本記事投稿時追記
マイクロサービスのトレーシングは Zipkin という分散トレーシングシステムを思い出して話していました。名前がすぐに出てこないとは💦
同様のプロダクトやサービスがあり、今後調べていきたいと考えています。

2. ラップ・アプリのモバイル通知が Amazon SNS でないのは?


ラップ・アプリは Web API を AWS に構築しています。
AWS を使っているので Amazon SNS(Simple Notification Service) を使ってモバイル通知をすれば、ワンストップになるので良いのではないかとも考えられます。

これについては、ざっくり行ってしまうと「普段から使っていたから」が一番大きい理由になります。

これは、ハッカソンという時間が限られた場で開発をするので、使い慣れているものを使うのが一番ということになります。

では、なぜ普段使いだったのか(普段 AWS なのだから、SNS が普段使いでもよいはずで)

モバイル通知を必要としたころの調べで、FCM(Firebase Cloud Messaging) のほうが手軽に扱えて、サポートするモバイルデバイスが広かったので FCM を使い、その後も使い続けているといった理由になります。

今なら Amazon SNS でも変わらないのかな。いずれ調べてみたいと思います。

3. IoT プラットフォームでファイル分割処理場をしてる理由は?


開発当時 AWS Lambda が 5分しか稼働できなかったため、ファイルを分割しながら DynamoDB へ投入しているとタイムアウトしてしまったためになります。

そのためいかに高速に処理を行えるようにするかを考え「ファイル分割だけ」をすることが高速化につながったので、ファイル分割を入れています。

高速化のために AWS Lambda のローカルストレージを使ったりとさまざまな工夫が入っています。

2019年2月現在は 15分まで稼働できるので、このシステムではファイル分割をしなくても処理しきれるかもしれません。

4. IoT プラットフォームの DymemoDB はコスト高ではないか?


たしかに DynamoDB を 3つ使っていて、データの内容物としてはおぼ同じものになり、ムダになっているように見えます。

まず DynamoDB のストレージ料金は、高額ではありません。
データの複製を大量に持ったとしても、ストレージについては気にしなくてもよいかもしれません。

ストレージ料金に対して Read/Write のキャパシティが高額です。
このシステムはバッチ処理で一時的に大量データを読み書きする必要があるため、とくに1つめの DynamoDB のキャパシティは高く設定しています。

それでも何百ドルとまでは行っていないはずなので、1つの DynamoDB にして処理ロジックを複雑にさせるより、複数配置するほうを選んでいます。

※ 本記事投稿時追記
2019年2月東京リージョンのストレージ単価は 0.285 USD/GB
10GB のデータベースで約3ドル、超大規模デモない限りロジックの簡易さを求めてもよいのではないでしょうか。

Read/Write キャパシティについては、オンデマンドキャパシティモードも出たので、状況に応じて変わってくるかと思います。

Amazon DynamoDB 料金
https://aws.amazon.com/jp/dynamodb/pricing/

AWS Simple Monthly Calculator (簡易見積ツール)
https://calculator.s3.amazonaws.com/index.html?lng=ja_JP

5. Amazon SNS で処理を分岐するメリットと活用方法について


IoT プラットフォームの例では、Amazon SNS で本処理と Redshift へデータを渡すのを分けています。

スライドの図では処理の流れを示したかったので矢印が Amazon SNS → DynamoDB の用になっていますが、実際の流れとしては Amazon SNS へ Subscribe しているので矢印が逆になります。

処理を分岐しているというより、データの公開場所を用意したので、欲しい人は見に来てくださいという形になります。

この形のメリットはデータを欲しくなった人が増えた時に、Amazon SNS の Subscribe を追加するだけで追加でき、ロジックを変更しなくてよいものになります。

6. Amazon SNS でウェブの処理を分岐できますか?


Amazon SNS の Subscribe で動作するのは非同期処理になります。

ウェブのリクエストが Amazon SNS の先の処理結果を必要とせず、何かしらのデータを Amazon SNS に公開して、ウェブのレスポンスを返せる場合は、処理分岐として利用可能です。

プログラミングの if文のような条件分岐としては利用できません。
Amazon SNS はデータの公開場所を作っておき、そこにデータを置く人、データをもらう人、それぞれがそれぞれのタイミングで動作するイメージになります。


Ask the Speaker へ来てくださり、ありがとうございました。

QA や議論ができ、とても楽しかったです。そしてお話しいただくことで気付きを得たり、考えの整理にもつながり、とても勉強になりました。

できる限り思い出して書きましたが、もし入ってなかったり、別途気になることなどがありましたら Twitter @lulzneko へ DM やメンションいただけたら幸いです。

発表者は、その日何をしていたのか - 発表の舞台裏 DevSumi 2019 編


新しい朝が来た希望の朝だ、発表の朝だ!

デブサミでの発表の朝を迎えて、発表者 lulzneko は絶望していた。
なんと発表資料が完成していないのです 😱


2019年2月14日~15日に開催された Developers Summit 2019(通称:「デブサミ」)で、『サーバーレスで最高に楽しめるアプリ開発』と題してサーバーレスにまつわる発表をしました。その発表の舞台裏ということで、発表者が当日何をしていたのかを綴ります。

シリーズの記事

デブサミ概要

発表したイベント デブサミ ですが、技術書籍で定評のある翔泳社さんが開催している “技術者コミュニティとの連携から生まれた総合ITコンファレンス” です。

今回は Developers Summit 2019 冬 のイベントで、ホテル雅叙園東京で開催されました。よく結婚式などで使われ、建物内に滝と庭園があるすごい場所です。

会場入り

ストーリーとスライドの配置は完成していて、そこに載せる図 ピタゴラ装置を組み立てる 楽しみ の章で使うものが間に合ってなかったというレベルなのですが、慌てて PowerPoint を操作する朝から始まりました。

lulzneko は遅筆で資料の一部が、間に合ってないことが結構あったりします。
今回はデブサミの次週に JAWS DAYS での発表もあるため、早めに着手したのですがギリってしまった。
あまり本質的でないところとかでも、気になってしまったり、こだわったりしてしまうのが原因なのですが。。。
スライドや文章、図が早く作れる方はうらやましいです。

急いでスライドを完成させ、所用を済ませと、あわただしく過ごして午後一の会場入りをしました。
なおデブサミの運営さんからは、”講演開始50分前までにご到着ください。” とのことですが、やはりセッションを見たいので早く到着するに越したことはないですね。
(資料の都合というより所用があって午前入りできなかったのですが、午前中のセッションも聴きたかった)

会場である雅叙園は実はエントランスとは別の裏道があります。
目黒駅を出て雅叙園に向かう、あのヤバい坂に差し掛かる手前で左に曲がります。住宅地のような感じもある道ですが、気にせず進むと右にアマゾンジャパンさんのオフィスへ行く道が出てきます。
実はこれが裏道で、アマゾンジャパンさんのオフィスへ入り、すぐに右へ行くとなが~いエスカレーターが出てきます。これを降りると、エントランスから入って左手に見えてる庭園へ出ることができます。
あのヤバい坂は急で長距離なだけでなく、車もバシバシ通るので裏道(こっちも車は結構通るのですが)を使いたいところ、もちろん使わせてもらいました。(目黒駅に帰る場合はエスカレーターで登れるので、裏道のが断然いいですね)

受付

無事会場入りできたので次は受付です。

雅叙園は結婚式などでも使われる素敵な場所で、エントランスを入ってすぐに素晴らしい庭園とお洒落なレストラン街があります。

はじめて来ると、IT イベントはやってなさそうな雰囲気に焦りますが、気にせず奥まで進むと、デブサミの看板のあるエスカレーターが出てくるのでビビらずに進むのが大事です。

エスカレーターを上がり2階へ着くと受付がありますが、発表者は3階まであがり、発表者受付に進みます。
こちらも “3F控室前の受付へお越しください。” とメールの案内にあります。

受付で、自分の名前を発表時間、lulzneko の場合ですと「15-B-6 サーバーレスで最高に楽しめるアプリ開発」といった感じで伝え、名刺1枚を渡します。

スピーカーパスをもらって、自分の名前を書きます。
せっかくなのですが名前を書いても、ぱっと見でわからないので印刷したアイコンの切り紙を持っていて、それも差し込んでいます。

受付が終わると、”講演開始30分前” までには控室にいるようにとの説明を受けます。

あとは時間までフリーなのでセッションを楽しんだり、控室で作業したりできます。
セッションは事前登録なしでもスピーカーパスで入ることができます。

ただし lulzneko は、リハーサルに参加してなかったので、流れの確認と接続チェックがあるので、まずは控室入りとなりました。

※ 発表者受付では入場者バッグは配布されていませんでしたが、2階の受付でスピーカーパスを見せたらもらえました♪

控室 & 流れの確認

セッション用に使っているのと同じ規模の部屋になります。

長机に椅子、電源、コーヒー、お茶、スナック、お弁当が用意されています。
電源が豊富に用意されているのがありがたいです(ACアダプター忘れましたが)。発表前に少し手直ししたり、作業したりすることがあり、電源がないとバッテリーの心配が出たりするので重要です。

スタッフの方より名前を呼ばれ、流れの確認に入ります。
スピーカー事前確認フォームで入力した内容を元に、会社名や名前、タイトルを確認します。進行の方が始まりに名前を呼んでくださるためですね。

続いて機材の確認で PC だけ、音声や映像の再生は不要、スマホを使うが接続の必要なしなどを確認し、ディスプレイへの接続チェックをします。
VAIO は HDMI、VGA どちらもいけるほか、接続問題もほぼなく助かってます。一度だけ HDMI はつながらなかったことがあったのですが、ケーブルが長すぎたと思われます。

続いて、バックアップの確認になります。
こちらも事前フォームで PDF を提出したものの確認になります。”必ず2/12(火)までにバックアップデーターを提供する。” こと案内があったのですが、当日の午前中に提出でした 🙇

PDF を提出はしているのですが、実は発表資料はウェブアプリでできています。(ラップのアプリを埋め込みで動かしたのは、この仕掛けだったりします)

発表用のバックアップとしては、ウェブアプリが必要なので Google Chrome でプレゼン URL へアクセスしてもらいました。
その際に URL をうまくお伝えできずに、テキストファイルを作って USB メモリーへコピーしたのですが、スタッフさんより「USB メモリー を PC へ接続して大丈夫ですか?」との確認があり、きちんとされてるなぁと。

そして電源の確認。
忘れてしまったことを素直に白状し、使わないようにしてバッテリーが大丈夫なこと説明しました。
スタッフさんを、とても悲しい表情にさせてしまいました。すみません 🙏

発表者の移動動線

最後に、発表時の流れの説明を受けます。
受付時に以下のようなカードをもらっており、こちらの説明です。

雅叙園は結婚式などでも使われており、そのための裏動線が用意されているとのことです。すごい!

控室は図の「C会場 Ask the Speaker」の上の部屋になります。
その部屋のエスカレーター側入り口とは別の裏口から出て、エレベーターへ回ります。
そして2階に行き、各会場へ入るという流れになります。

確かにデブサミ級のイベントになると、参加人数も多いですし、入り口で事前登録のチェックなどをしているので、発表者が入り口から入ってくると都合が悪そうです。

このような観点からも会場選びとかされているのでしょうね。ザ・プリンス パークタワー東京 が IT系イベントで使われているのも、もしかしたら?

なお Ask the Speaker の受ける場合は、発表終了後に退出される参加者さんへ突して所定位置へ移動するとの説明を受けます。スタッフさんから「私がお客様を掻き分けて進むので、しっかり付いてきてください」とのことです。

まぁ、確かにメイン動線へ戻るためのルートはなさそうですし、早く Ask 席へ移動すること、またスタッフさんを次の発表者につけるためにも突るしかないのでしょう。

以上、説明を受けてフリーです。
コーヒーを堪能して心を落ち着け、セッションとブースへ!

発表 30分前

控室に待機し、発表準備に入ります。
スタッフさんから名前を呼ばれ、先ほど説明を受けた裏動線で移動開始です。

「B会場なので厨房を通ります。気を付けてください。」
「みなさま、ここを通る時は楽しそうにしてます。やっぱり珍しいんですかね。」
「昨日は厨房でケーキを見ていたら食べたくなって買いました。1階で売って、とてもおいしいですよ。」
「こちらで少々お待ちください。」

と、適切なナビを受けて会場裏に到着です。

倉庫のような場所の丸椅子で少々待機。30分前に移動してるとはいえ、20分の休憩があるので直前の発表の、ほぼ終了時点で待機場所到着です。

自分の資料を見直す時間もなく莫大な拍手が聞こえ「入ります。どうぞ!」の案内。

正面のすぐ横から入ってセッティング。
進行の方から名前等の最終確認を受け、発表用の「雅叙園ウォーター(秩父源流水)」をもらいます。

そして、電源の確認。
また進行のスタッフさんを、とても悲しい表情にさせてしまいました。すみません 🙏

発表者ツールとしては、まず演台の下に正面投影用と同じ内容を表示するディスプレイがあります。
こちらへ事前に映しておき、切り替えたらすぐに表示されるようになっています。すごい。
(デモのときに QRコードをスマホで撮るためにしゃがんだのが、このディスプレイです)

客席正面の真ん中に大きなカウントダウン時計があります。演台の手元にもカウントダウン時計があります。
正面のは、とても大きく見やすくて助かりました。(手元のはなぜか動いてなかった)

マイクはワイヤレスで、ハンドマイクとピンマイクがあります。
持っているほうが安定するので、ハンドを選びました。

レーザーポインターもあります。
普段は投影画像を直接指さすのですが、さすがに届かないのでお借りしました。

発表用スライドの URL をツイート。

発表

いざ、発表!
ご清聴ありがとうございました!!

たくさんのツイートありがとうございます!!
デブサミ2019【15-B-6】サーバーレスで最高に楽しめるアプリ開発 #devsumiB - Togetter

Ask the Speaker

お片づけをして、Ask 席へ向かって突ります。
スマホの片づけとかあったので、お待たせしてしまいました。すみません。

10名ぐらいの方に来ていただきました。ありがとうございます!!
いただきました質問はできる限り思い出してメモりましたので、別途まとめを書きたいと思います。

[2019.2.23 追記] こちら『デブサミ 2019 Ask the Speaker で 頂いた QA まとめ』にかきました。

何か気になることなどQAや、またフィードバックなどありましたら、Twitter @lulzneko へ DM をいただければと思います。オープンになっているので、とくにデブサミに限らず気軽にいただければと。

おわり

発表用スライドの URL を再度ツイート。

これまでは発表前だけだったのですが、ある Twitter の 投票 で、発表後にスライドを共有してほしいというのが1番だったので再度ツイートするようにしました。遅くなってしまったので、お片づけ時にツイートすべきでした。反省。
(発表前は2番だけど、発表時に手元へあるといいこともあるので)

エゴサして、Like、RT、Follow-、バッテリー切れ…


以上、発表者の一日でした。

色々しでかし気味なヤバい一日でしたが、無事発表を終えることができました。

いろいろなイベントで話をする機会をいただいておりますが、スタッフさんとの濃密なやり取りや、裏動線を使った移動などははじめてで、これはぜひ伝えたいなと思い書いた次第です。

文才があったら発表者目線な読み物にしたかったのですが、ムリかったので淡々と描く形になりました。
発表者サイドではありますが、舞台裏がどうなっていたのか少しでも伝わりましたら幸いです。

次回は、2019年2月23日(土) 15:10~ JAWS DAYS 2019 で『AWS x JAMStack で構築・運用するサーバーレスなWeb Front』のお話をします。 もしよろしければ、お越しください。

また、ちょっと来て話をしてよ、といったようなことなどありましたら、Twitter DM を @lulzneko へ気軽にいただければ幸いです。
これまでの発表歴はこちら [Slides | Riotz.works] https://riotz.works/slides になります。


聴きに来てくださり、ありがとうございました。
スタッフの皆さま、支援ありがとうございました。

そして、ここまで読んでくださり、ありがとうございます。

Riots.works での JAMStack の利用

最近注目を集め始めている “JAMStack”、より良いパフォーマンス、より高いセキュリティ、より安価で簡単なスケーリング、より良質な開発者エクスペリエンスを提供するアーキテクチャ。

Riotz.works でも注目しており、実際に活用しています。今回は、この JAMStack を Riotz.works でどのように使っているかをご紹介します。

Riotz.works 公式ウェブサイト

公式ウェブサイトのトップページ https://riotz.works、Works ページ、Engineers ページが Gridsome で JAMStack なサイト作りをしています。

Gridsome は 2019年1月現在バージョン 0.4.5 で速いペースで開発が行われておりますが、必要な機能が未実装だったり、実行環境によってはさまざまな準備や設定が必要だったりします。
StaticGen では 30位あたりになります。

数あるサイト・ジェネレーターから Gridsome を選んだのは、まずは Node.js で作られていること念頭に置きました。
これは Riotz.works では Node.js、主に TypeScript で開発を行っているため、スキルセットや開発環境を合わせたかったのがあります。

続いて Vue.js ベースであることを選びました。
こちらも開発が Vue.js ベースで行っているので合わせたかったものになります。

そうすると、比較的メジャーと思われる GatsbyJSHexo などが落ちてしまいます。
GatsbyJS は非常に興味深いのですが、いつかは使ってみたいと思っていますが、今回は Vue.js ベースとしました。

選択肢としては Nuxt.jsVuePressGridsome、VueWebsite になります。

Nuxt.js はアプリ作成で使っていますが、ウェブサイトやブログ構築よりアプリ向けに感じます。
そうなると Vue.js 公式である VuePress が最有力になりそうです。

もうひとつの Gridsom も調べたところ、 “highly inspired by Gatsby.js” とあり、また Vue.js ベースであることが、まさに私たちの考えと一致するものでした。

そしてデータソースを GraphQL で扱えるところが魅力的です。
入力ソースは基本的に Markdown を使いたいと考えていますが、エンジニアによっては CMS を使いたいケースもあるでしょう。このような複数のソースを GraphQL で扱えるのが助かります。

このような経緯から Riotz.works 公式ウェブサイトは Gridsom で構築することにしました。

ただし、これまでの開発経緯から Articles と Slides は Gridsom とは異なる技術を使っています。
リンクを踏むとヘッダーが異なるのはこのためです。Gridsom へ意向を考えてはいますが、なかなか着手できてない状況です。。

Riotz.works Articles ページ

Articles ページは、Hexo で作られた JAMStack なサイトです。

この Articles こそ Gridsom が活用できる場所ではあるのですが、Gridsom が登場する以前に Hexo で作ったものになり、いずれは Gridsom へ移行したいと考えてはいますが、Gridsom はまだ初期開発中で Category や Tags などのページを自前で作る必要があり、作りこみができてないです。(いずれ公式でサポートされるとは思うので待ちたいのもあり。。)

HexoStaticGen でもトップ5に入る人気のサイト・ジェネレーターです。

記事は Markdown で書けるので、エンジニア・フレンドリーといえるのではないでしょうか。
一方で表現力は落ちてしまう点がありますが、最後は HTML を直接書いて埋め込めるので、どうしても Markdown で表現しきれない部分は HTML でカバーできます。(あまりやりたくないので奥の手という感じですが)

ブログサイトをとても手軽に作ることができ、テーマも多数用意されているので好みのデザインにすることも簡単ですし、各種 Plugin もあるので簡単に拡張することもできます。

日本語の情報も多いので、比較的簡単にやりたいことや、困りごとを解決できます。

JAMStack なブログサイトをつくり始めるには、よい入口と言えるでしょう。

Riotz.works Slides ページ

Slides ページは、静的サイトではありますが完全に手組の HTML で、”構築済みの HTML” とはなっておらず、アクセスを受けてから JavaScript で HTML を構築しているので JAMStack なサイトではありません。

こちらは、Markdown ファイルをソースとしたプレゼンスライドを作れる remark.js を使っています。

仕組みとしては事前に用意された Markdown ファイルを、スライド形式の HTML に変換して表示なので、JAMStack とは相性が良く、JAMStack なスライドシステムがあったら使いたいと考えています。

Markdown からスライドを作るライブラリとしては reveal.jsremark.js ぐらいで、どちらも事前構築の HTML には対応しておらず、現時点では現状のままか、時間を作って自前開発をしたいところです。

JAMStack なスライドシステムがあったら使いたいと考えていますが、現時点ではなさそうなので、しばらくは現状のままでしょう。

スライドシステムについては時間を作って自前開発にチャレンジしたいとも思っています。
ソースは Markdown で書きたいのがありますし、カジュアルな勉強会ではリアルタイムなフィードバック機能を動かしてみたいなど、いろいろとやってみたいことがあります。

ラップ、タップ、アップ 🎶

最後にハッカソンで作った ラップ、タップ、アップ 🎶 ですが、こちらも JAMStack なアプリです。

技術としては Nuxt.js を使っていて SPA で静的サイトとして生成、ホスティングしています。(SSR、サーバサイドレンダリングにすると JAMStack ではなくなります)
これにより基本的な画面は “構築済みの HTML” となり、CDN に配置した際のメリットを出せます。

ラップ対戦のルーム作成はクライアントサイドのJavaScript から Web API を呼出しています。
また動画の中継と配信も JavaScript のライブラリからサービスを呼び出しています。

ハッカソンの 24時間という限られた時間の中で、フロントエンドとサーバサイドを分離し HTML をツールを使って生成する JAMStack のアーキテクチャがまさに活かせた瞬間といえるのではないでしょうか。

サーバサイドの機能が Web API 形式で提供されているため、ロジックの変更や UI の変更といったものが相互に依存せず最小限の修正で組み込みできました。


JAMStack は公式ウェブサイトのような完全な静的サイトのほか、ブログやアナウンスなどのニュースといった緩やかな更新が発生するサイト、そしてアプリといったさまざまなサイトが実現でき、Riotz.works の中でも多様な使い方をしています。

とくに ラップ、タップ、アップ 🎶 のような、サイト・ジェネレーターで静的ホスティングなサイトを作っていて、Web API を呼び出しているようなケースは意外とあったりするのではないでしょうか。

実は JAMStack なサイトを作っていたけど、JAMStack のキーワードが知られてなく、そんな名前がついていたんだというケースがいろいろありそうです。(実は ラップ、タップ、アップ 🎶 作成時点では JAMStack の言葉は知らなかったです)

ただ、これだけ JAMStack な サイトと書いてきましたが 実はホスティングが GitHub Pages で、JAMStack ベスト プラクティスの CDN に 乗ってなかったりも。。

これまでの経緯から GitHub Pages を使ってて、またカスタムドメインを使っているほか、4サイト(リポジトリ)がのっかっているので一斉に引っ越しする必要があり、作業時間を作るのに苦慮しているためです。

JAMStack、それはハイパフォーマンスなウェブフロントを実現するアーキテクチャ

“JAMStack” と呼ばれる新しいウェブの開発手法で「より良いパフォーマンス」「より高いセキュリティ」「より安価で簡単なスケーリング」「より良質な開発者エクスペリエンス」を提供するアーキテクチャが注目を集め始めています。

JAMStack とは何か、どのように使い、どのようなメリットがあるのか、公式サイトの情報をもとに読み解きます。

JAMStack の定義


オフィシャル・サイト https://jamstack.org によると、以下の要素に基づく最新のウェブ開発アーキテクチャとされています。

  • クライアントサイドのJavaScript
  • 再利用可能なWeb API
  • 構築済みの Markup (HTML)

HTML に JavaScript そして Web API なので、ウェブフロントの開発をする場合によく使うであろう技術と言えるでしょう。

ここでは動的な要素をサーバーサイドで組み込んだ HTML などをレスポンスするのではなく、クライアントサイドのJavaScript から Web API を通じて取得/更新し、クライアントサイドでダイナミックに描画する方式、いわゆる REST API などを使ったウェブフロントの作り方を指しています。

そして Markup (HTML) の部分がポイントなのですが “prebuilt at deploy time” 、デプロイ時に事前ビルドされているとしています。そして多くの場合、サイト・ジェネレーターなどを使って作ります。(ツールの紹介は後述


The JAM Stack44ページ目 のスライドにある、この図が JAMStack のアーキテクチャをシンプルに表現しています。
Git に Push されたコードから、ビルドツール(サイト・ジェネレーターなど)が動作し、Web API などのデータと組み合わせて、構築済みの HTML を生成、CDN へ配置して配信します。

なぜ JAMStack なのか

なぜ JAMStack、とくに構築済みの HTML をデプロイするのか。

公式サイトでは、大きく4つ「より良いパフォーマンス」「より高いセキュリティ」「より安価で簡単なスケーリング」「より良質な開発者エクスペリエンス」のメリットを上げています。

より良いパフォーマンス

最初のページを高速に表示するためには、HTML を事前に構築しておき CDN で配信することが最適です。
構築済みでない場合、高速に配信できる CDN を介することができず、また HTML を生成するための処理を待つことにもなります。

より高いセキュリティ

サーバーサイドの処理をマイクロサービスとして API に抽象化されているため攻撃の対象となる部分を小さくできます。
また、事前に構築済みの HTML をデプロイしているため、HTML を処理するためのプロセスはオフラインにできることもメリットといえるでしょう。

より安価で簡単なスケーリング

デプロイするものは構築済みの HTML となるため CDN に配置することができ、スケーリングすることが容易になります。
CDN が安価かは悩ましい部分はありますが「Web サーバ」と「AP サーバ」をスケールさせるために用意することを考えると、CDN だけでよいので簡単とはいえるでしょう。

より良質な開発者エクスペリエンス

疎結合にすることで、よりターゲットを絞った開発とデバッグを可能とします。
構成を簡素化できることは開発者の精神衛生上よいといえるでしょう。

このようにロジックを Web API として分離し、フロントエンドを構築済みの HTML としておくことで、多くのメリットを享受できます。

ベストプラクティス

JAMStack なプロジェクトを構築する際に、いくつかのベストプラクティスを活用することでスタックのメリットを最大限に発揮できます。

CDN に全部配置されている

JAMStack なプロジェクトは、サーバサイドのコードに依存しないため、単一のサーバではなく分散して配置できます。
CDN から直接サービス提供することでスピードとパフォーマンスを発揮できます。アプリがネットワークにエッジまで配置されることで、より良いユーザー体験になります。

すべてが Git に存在する

JAMStack なプロジェクトは、誰もが git clone でき、必要な依存関係を npm install などのような標準的な手順でインストールし、プロジェクトをローカルで実行する準備ができているはずです。複製するデータベースも、複雑なインストールもありません。
これによってコントリビューターの負担を減らし、ステージングとテストのワークフローも簡略化されます。

モダンなビルドツール

モダンなビルドツールの世界によるアドバンテージを受けましょう。
それは動きの速い世界でジャングル(無法地帯)を志向するかのようですが、未来のブラウザを待たずに最新のウェブ標準を使うことができるようになります。
それは現時点では Babel、PostCSS、webpack、そしてその仲間です。

自動ビルド

JAMStack のマークアップ(HTML) は、事前ビルドされているため、コンテンツの変更はビルドを実行するまで反映されません。このプロセスを自動化するとフラストレーションを軽減できます。
これを webhook で行うことも、自動的にパブリッシュするプラットフォームなどを使うこともできます。

アトミックなデプロイ

JAMstack なプロジェクトが非常に大きくなるにつれて、新しい変更のために数百ものファイルを再デプロイする必要があるかもしれません。 これらのファイルを一度にアップロードすると、プロセスの完了までの間に不整合を生じる可能性があります。 これを避けるに、すべてのファイルがアップロードされるまで変更が行われない「アトミックデプロイ」を実行できるシステムを使用します。

キャッシュの即時無効化

ビルドからデプロイへのサイクルが定期的に行われるようになったら、デプロイの実行が反映されるようにします。CDN は側にキャッシュを消去できます。

サイト・ジェネレーター

JAMStack のメリットはわかったとして、それでサイトを作るには「構築済みの HTML」が必要となってきます。
この構築済みの HTML は手組みの HTML を用意することではなくて、サイト・ジェネレーターを使うとされています。

主なサイト・ジェネレーターは、こちら StaticGen に列挙されています。

有名どころとしては GitHub Pages でも使われている Jekyll などがあり、HugoHexo といったブログ構築用の静的ジェネレーターや Next, Nuxt といった ReactVue.js のアプリ・フレームワークなどもあります。

JAMStack のコンテキストでは GatsbyVuePressGridsome などを目にすることが多いようにも感じます。

ヘッドレス CMS

これはとくに JAMStack の要件ではないのですが、JAMStack なブログや情報発信サイトを作る際に使われるものです。

WordPress などの CMS はコンテンツを配信するための部分が含まれ、そのままホスティングすると JAMStack なサイトにはならないので、別の仕組みが必要となりますが、WordPress などのように優れたコンテンツを管理するための仕組みが欲しくなります。
そうしたニーズに応えるのが、このヘッドレス CMS です。最低限の UI でコンテンツを管理することができ、作成したコンテンツを API 経由などで提供し、上記サイト・ジェネレーターなどと組み合わせてサイトを作ります。

主なヘッドレス CMS は、こちら headlesCMS に列挙されています。

前半に Open source なヘッドレス CMS が並び、後半に Closed source があります。
またサービスとして提供されているものは、こちらの Closed source に含まれます。たとえば最近よく目にする Contentful は Closed source になります。

サイト・ジェネレーターによっては、WordPress の REST API からコンテンツをとってきたり、ローカルの Markdown ファイルを使うこともできるので、サイト・ジェネレーターの機能と管理方法に合わせて選択します。

参考情報


実際のところ、Web API ベースなアプリ開発をしていると、意識はしてなくとも JAMStack なウェブフロントを作っているなぁというケースもあったりします。

さっくり言ってしまうと、そんな Web API ベースなアプリでウェブフロントを構築済みの HTML として CDN へ配置するものに、JAMStack の名前がついた感じになります。

名前がついたことで認識され、認識されることで広まる流れになっていくのではないでしょうか。

2018年の振り返り

2018年最後のポスト、1年間の活動を振り返ります。

サマリー

  • 発表: 6回
  • 記事: 3本
  • アプリ開発: 3本
  • ハッカソン: 1回

発表 6回

2018.02 Agile & DevOps 勉強会 - @lulzneko & @lopburny

クローズドな Agile & DevOps 勉強会で スマートデバイス と クラウドサービス を 自動パーソナライズする IoT バックエンド開発チームにおける Agile と DevOps プラクティス の発表をしました。

タイトルが長くでピンとこないのは、オリジナルのタイトルは製品名が入っていたからで、公開に当たって製品名を外す必要があったからになります。

ベースとなる話は昨年の Serverlessconf Tokyo 2017 で発表した ava チームが選択した TypeScript による AWS Lambda 開発 になり、Java で開発していたプラットフォームを TypeScript で開発しなおす大手術をしたプロジェクトではどのような Agile & DevOps でやっていたのかを話しました。

私たちとしては必要に駆られてのことでしたが、途中でプログラミング言語を切り替えるのは衝撃を受けたほか、そのようなことをできる人たちがいることに驚いたと言われ開発者として誇らしく感じ、そして必要なことであればどのような困難でも真正面から取り組んでいくスタイルはずっとキープしていきたいと改めて感じるイベントでした。

2018.05 JJUG CCC 2018 Spring - @lulzneko

日本最大のJavaコミュニティイベント JJUG CCC で Java から TypeScript へ 切り替えて加速するサーバーレス開発 の発表をしました。

Java のコミュニティで「Java をやめて TypeScript を選びました」という主旨の発表になり、かなり緊張しながら入室したことを覚えています。
仕事では Java をずっとやってきて、よく勉強でお世話になっていた会に、このような立場で発表するとは思っていませんでした。

会場は満員御礼で立ち見でも聞いてくださる方も多く、そして熱心に耳を傾けてくださり発表者冥利に尽きる会でした。

内容については賛否両論、手厳しい指摘も上がっていましたが、新たなる可能性についての話につなげられたと思っています。

批判や厳しい指摘を恐れず、発信したいことはしっかり話す。そして議論へつなげ盛り上げることの大切さを実感できた会だと感じました。

発表について1つ反省点が、タイトルは「Java から TypeScript へ切り替えて加速する」としているのに、「Java と TypeScript の親和性」についての話になっていたなと。資料を書いているうちに、どんどんアイデアが膨らんでしまうのに気をつけねば。。

2018.06 SPAJAM 2018 東京D予選 - @lulzneko & @lopburny & @javaponny

日本最高峰のアプリクリエイター競技会 の スマートフォン アプリ ハッカソン SPAJAM。ハッカソンの内容については後述、ここでは発表パートについて。

リアルタイム の 競演 と 参加型観戦 で 音楽を最高に楽しむ🎶 「ラップ、タップ、アップ」 で発表しました。

徹夜でアプリ開発をしたあとの発表会。体力的にも集中力的もかなり厳しかった。スライドに何を書くのかとても苦戦しました。

一方で話し始めるとランナーズハイならぬスピーカーズハイとでもいうような高揚感で、今までの発表の中で一番ノッテいたと思います。

発表の神様が降りてきてくださった、そんな発表でした。
このような発表を毎回できるように精進しようと心から思いました。

進行より東京D予選は最難関と言われていましたが、どのチームも素晴らしい発表をされており、最高の発表をライバルの立場として体験させてもらえたことに感謝です。

2018.09 Serverlessconf Tokyo 2018 - @lulzneko & @lopburny & @javaponny

サーバーレスアーキテクチャを用いたアプリケーション構築における知見の共有を目的とした、コミュニティ主導の技術カンファレンスで、リアルタイム動画ラップ バトル アプリを 短時間で作り上げた完全サーバーレスな秘技 の発表をしました。

Serverlessconf Tokyo は Riotz.works の原点ともいえるイベントで、2017年のイベントで発表させていただいたのが Riotz.works の始まりになります。

SPAJAM で作ったアプリはフル・サーバーレスでできており、サーバーレスで戦ったからこそ、優秀賞を受賞することができたと思っています。
そのサーバーレスの素晴らしさをハッカソンの観点からお伝えできたのではないでしょうか。

今回の会場は東京タワーのスタジオで 25m プール 1面分の超巨大スクリーンでの発表でした。

このような会場ははじめてで緊張したものの、発表する楽しさを強烈に実感できる場所でした。また、このような場所で発表に臨めるよう技術と活動をしっかり行っていこうと思いました。

Vue Fes Japan 2018 Reject Conference - @lulzneko & @lopburny

日本開催初の大規模 Vue.js カンファレンスで Vue.js/Nuxt.js で 実現できた PWA の リアルタイム動画ラップ バトル アプリ のリジェクトコンで発表しました。

プレイドさんのオフィスで開催され、芝生スペースの素敵な場所でした。
フロント系のイベントははじめての参加で、今まで参加してきたイベントとは雰囲気が違う感じを受けましたが、楽しさはかわらず、技術イベントはいいなぁと再認しました。

懇親会では多くの方々と話をする機会がありとても楽しかったです。

東京 Node 学園祭 2018 - @lulzneko & @lopburny

年に一度、真剣に学んで楽しもう! 日本最大のNode.jsカンファレンス! で Vue.js/Nuxt.js で 実現できた PWA の リアルタイム動画ラップ バトル アプリ の発表をしました。

TypeScript でサーバーレスを推している身として Node.js の総本山ともいえるイベントでお話しできるのは最高の体験でした。

記事 3本

こちらは全然かけなかったので反省です。
とくに TypeScript のスターター記事を書き始めたのに2回で止まってしまった。

引き続き TypeScript でサーバーレスは推していきたいので、しっかり記事を書いて発信していくとともに、Nuxt.js や Gridsome などを使い始めているので、こちらも情報発信をやっていけるようにしたいです。

活動の仕方を見直して、記事を書く時間をしっかりとるようにしたいです。

アプリ開発 3本

まだ公開できないプロトタイプが1本ありますが、3本作れたのはよかったです。

ラップはハッカソン制作作品ですが、少しずつ機能追加などもやっていて、引き続きいろいろな機能を追加したり、おもしいことを試せたらと思っています。

ウェブサイトは Gridsome を使ってリニューアルしました。 Slides と Articles の引っ越しはできていませんが、リニューアルで念願だった Works と Engineers が追加できました。
Gridsome は JAMStack としておもしいので、ちゃんと使いこなせるようにしつつ情報発信をしていきたいと感がています。

ハッカソン 1回 - @lulzneko & @lopburny & @javaponny

SPAJAM の スマートフォン アプリ ハッカソン に 参加しました。
自分自身も、Riotz の メンバー 全員 で はじめてハッカソンに参加した記念すべきイベントでした。

5人でチーム編成のところ、Riotz は 3人とチャレンジングな参加でしたが、サーバーサイドはサーバーレスの武器を活かすことでチャレンジできる、そしてアプリ側もネイティブではなく敢えて PWA を使うことで持てる技術を最大限に生かせることで戦えると考えていました。

とはいえ日本最高峰のアプリクリエイター競技会を謳っているイベントであり、参加した東京D予選ドワンゴ会場は最難関の予選会場(進行談) とのことで、すごい人、すごいチームばかりでした。

午前のチームを超えて全体でのアイデアソンではポンポンすごいアイデアを出す方、発表の時間では今すぐ公開可能レベルのアプリ、TED 会場かと錯覚するプレゼン、参加者のとてつもないレベルに面食らいました。

当日発表のテーマ「音楽」に対して、メジャーからストリート、Google Home、Spotify に Tシャツ制作サービス連携、スマホのあらゆる機能活用と、想定しきれないありとあらゆるものがそろっていたと思っています。

Riotz.works は幸いにして「優秀賞」をいただけましたが、どのチームがとってもおかしくない、最難関の予選会場(進行談) だったのではないでしょうか。

そのような方々相手にアイデアと技術を競えたことに感謝です。
ハッカソンははじめての参加でしたが、このような最高に高揚し意地を張れる場所に、多く参加できるよう技術の研鑽と戦うマインドをキープしていきたいと思う場でした。


この1年は Riotz.works が発足して、ほぼ1年と半分。

多くの場所でお話しさせていただきました。サーバーレスはアプリ開発にとって最強の武器」を標語に活動してきた自分たちの思いをたくさんをお伝えできたのかなと思っています。

一方で残していけるはずの記事がたくさん作れなかったことは反省です。
話をすること、文章を書くこと、どちらも凄く好きなのは、今文章を書いていて感じていますが、時間を作ることが下手だったのかなと。
この辺は来年に向けて改善をしっかり考えていこうと思います。

よかったところを伸ばし、反省点を見直して次の年へ繋げられるよう頑張ります。

よいお年を。

共有:

2018年の Riotz Works の活動を振り返る

どうも、Riotz Works のうさぎ(@lopburny)です!

昨日、年内予定していた全ての用事が終わり、年末の連休に突入しました。僕は例年クリスマスが終わった時点でそわそわして集中力が持たなくなりますが、今年は色々あって今日からやっと休暇に入ります。

そして Riotz Works も結成から1年が経過し、個人的にはここ数年で最も忙しく過ごした1年で、充実できた1年だったと思います。

一方、反省点も多々あり、ちゃんと振り返って来年の活動に活かしたいという気持ちもあります。この記事は、そんな Riotz Works での活動を振り返り、発表では言えなかったこと、私が感じたことをつらつらと書いていきます。

2018年のうちにやってきた発表

※ 2018/12/29 時点

これ、ちょうど1年前は、たったの1行でした😂

まさかこのページが埋まるとは、想像していませんでしたが、何事もチャレンジしてみるもんですね。Riotz Works の活動は、今のところ仕事というわけではないので、メンバーの 100% ピュアなモチベーションでやってこれたのも効果的だったと思います。

スマートデバイスとクラウドサービスを自動パーソナライズする IoT バックエンド開発チームにおける Agile と DevOps プラクティス

@Agile & DevOps 勉強会、 発表資料はこちら

2月、@lulzneko@lopburny が発表しました。Riotz Works が結成して 1回目の発表が Serverlessconf Tokyo 2017 という大きくてパブリックな発表だったのに対して、今回(2回目)は Closed な勉強会だったので比較的緊張はしなかったです。

しかし、タイトルにもあるように、勉強会のテーマは Agile や DevOps といった開発プロセスなので、参加者のみなさんが必ずしも Web やクラウドに明るいわけではなく、様々なバックグラウンドを持つ人にどう伝わるか悩ましいところでした。

中盤の自分のパートが AWS に触れたことがない人には分かりにくい内容だったと自覚し、補足説明をたくさん入れるようにしましたが、本番では早口で突っ走るような話し方になっていたかもしれません。

発表後、「刺さる人には刺さった」というコメントをもらったときは嬉しかったです。

Java から TypeScript へ切り替えて加速するサーバーレス開発

@JJUG CCC 2018 Spring、 発表資料はこちら

5月26日。@lulzneko の単独発表です。

AWS Lambda は、リリース当初から現在に至るまで、Java ランタイムを選択すると必然的に Cold Start に悩まされることになります(Cold Start を無視してもいいケースなら問題になりません)。この問題に対するアプローチはいくつかあると思いますが、私たちのチームが身をもって実践してみたことで、「Java 開発者において、TypeScript は良い選択になり得る」というのがポイントになります。

発表会場が開始後すぐ埋まり、立ち見の方もいらっしゃるほど盛況でした。このアプローチに対するフィードバックは賛否両論ありましたが、みなさんにとって興味深い内容だったのではないかと思います。

リアルタイムの共演と参加型観戦で音楽を最高に楽しむ🎶「ラップ、タップ、アップ」

@SPAJAM 2018 東京D予選、 発表資料はこちら

6月16日~17日。今回はカンファレンスではなくハッカソンです。@lulzneko@javaponny@lopburny 3人で出場しました。メンバー全員初めてのハッカソンで、Riotz Works としても初です。もともとこの SPAJAM というハッカソンには注目していて、Riotz Works 結成前から「出てみたい」と何度か話したことがありました。そして、思い切って、エントリーしたのです。

1日目の朝、そわそわしながら会場へ向かい、午前のアイディアソンを終えて、ハッカソンのテーマ(音楽)が発表されました。会場近くの築地市場で海鮮丼を食べながら、どうする?何作る?と議論をはじめ、私が思いついたのが、このラップバトルです。言ってみたものの、これどうやってつくるの、やばくね、みたいな感じでした💦

ラップバトルのサービスは世の中にいくつも存在しますが、僕はよりインタラクティブな演出がいいなと思ったのと、ラップバトルの「対戦」と「観戦」を 同時にかつリアルタイムにできる仕組みを作ることで差別化を図りました。いわば Twitch のゲーム実況ストリーマー同士が即座で対戦を始め、その様子をそれぞれのチャンネルで数百〜数千の人たちが観戦しながらコメントやヤジを飛ばす様子。そういうのが作りたかったです。

果たして作りきれるだろうか。。。午後から真面目に調査します。数時間ほどでなんとか SkyWay のサンプルを動かすことができました。夜になって会場を出た時点で、ようやく翌日の発表に向けた最も基本的な機能(リアルタイム動画ストリーミング)ができました。そして、夜も気を抜くことはできません。オールナイトで作業して30分ほど仮眠を取り、発表直前まで開発を進めた結果、なんとかデモができるところまで作れました。

結果は・・・なんと、優秀賞をいただきました!!

今でもあの感動を忘れられません。恐らく今年起きた出来事の中で最強のインパクトでした。。

そして帰りに飲んだビールは間違いなく今年飲んできたビールの中で最高の味でした。😂

残念ながら SPAJAM の本選に出ることはできませんでしたが、次はもっと進みたいと思います!!

リアルタイム動画ラップバトルアプリを短時間で作り上げた完全サーバーレスな被疑

@Serverlessconf Tokyo 2018、 発表資料はこちら

9月29日。@lulzneko@javaponny@lopburny 3人で発表しました。Serverlessconf Tokyo での発表は、去年に続き2回目となります。夏のハッカソンの余韻がまだ残っていて、この発表の準備にも気合が入りました。特に、会場スクリーンのアスペクト比が 48:9 という、ものすごく大きくて迫力のある会場だったため、わくわくしつつもかなり緊張していました😂

気合を入れて会場に着き、生でみる会場の広さとスクリーンの迫力にびっくりしながら、デモの準備をしました。ちゃんと動くのを確認してこれはいける!と思ったんですが、本番では開始とともにデモが固まって動かないことに。そういうことにならないよう、開始10分前からアプリを立ち上げた状態で待機したのですが、なぜか開始のタイミングで 僕のスマホが固まってしまったんです。えーーー、なんで。。。ショック。。。とパニックになってしまった僕は、落ち着いて話すことができず、発表中に焦りを出してしまった気がして反省しています。

当時 @lulzneko が言っていたように、「デモが動かないことは、よくあることですね」と、一旦落ち着いて進めていき、メンバーが対応してくれることを待つべきだったことを学びました。

幸い、メンバーが対応してくれたおかげて、発表中にデモが復旧し、ハッカソンで作ったアプリを披露することができました。また、サーバーレス関連の色んな方々とお話ができて、他の発表についても、どれもすごく勉強になったので、貴重なイベントでした。

Vue.js/Nuxt.js で実現できた PWA なリアルタイム動画ラップバトルアプリ

@Vue Fes Japan 2018 Reject Conference、 発表資料はこちら

11月10日。@lulzneko@lopburny が発表しました。前回の Serverlessconf ではバックエンドの内容がメインでしたが、今回はフロントエンドにフォーカスした話です。元々、Vue Fes Japan そのものにエントリーしましたが、枠が非常に限られていたらしく、採用にはならずとも魅力的な内容だということで、 Reject Conference に参加させていただくことになりました。

Riotz Works のメンバーは、全員フロントエンド以外の領域を得意としています。ですが、フロントエンド/バックエンドの領域にこだわらず、思いついたことは自ら形にしていくことが大事だと思っていますし、ハッカソンでものを作っていく中で、人の目にダイレクトに届くUIの重要性と楽しさに気づいてしまったので、もっと極めたいなと思っています。

今回の発表は、今まで数を重ねてきたこともあり自信持ってできた気がして、懇親会でも色んな方々とお話させていただき、個人的に最も楽しくできた発表でした。

Vue.js/Nuxt.js と TypeScript で実現する PWA なリアルタイム動画ラップバトルアプリ〜フル Node.js エコシステムで戦ったモバイルアプリのハッカソン〜

@東京Node学園祭2018、 発表資料はこちら

11月23日。@lulzneko@lopburny が発表しました。今回も話のネタそのものは変わらないですが、Riotz Works が Node.js を使い始めて、2018年をどう過ごしたかという集合体のような内容です。またサーバーサイド(Node.js)→フロントエンド(Vue.js)→Node.js環境全般 という流れができたのと、Node.js コミュニティでの発表ということで胸が熱くなりました。

発表も比較的慣れてきたところで順調に進みましたが、React 界隈の方々が多く、前回よりは重い空気になることもありました。ですが発表の順番が最後で、たくさんの方々に聞いていただき、たくさんフィードバックをもらえたので、かなり手応えのあったイベントでした。

2018年を振り返って、よかったこと

あえて2点にしぼると、こんな感じです。

  • ハッカソンに出て、アイディアを形にできたこと
  • 次々と発表が決まり、絶え間なくイベントに参加できたこと

2018年を振り返って、反省したいこと

たくさんありますが、これも2点にしぼります。Riotz Works というより個人的な話ですね。

  • タスクの優先順位を考慮した、自分のリソース管理
  • 発表以外のアウトプットができていない点

当たり前な話ですが、何らかの活動を継続して進めていくためには、自分の体力・時間などのリソース管理を上手にできることが重要なポイントかなと思います。

僕は思いつきとその時のモチベーションに左右されやすいタイプで、できないことも意地を張って挑戦し続けたりするので、無駄にした時間が結構ありました。目標やコミットしたことに対して確実に結果を出すためには、もっと冷静に自分を見直して、シビアにならないといけないですね。

あと、もっとブログ書きたかったのですが、上記のリソース管理ができなかったせいか、できていません。書きたい話は結構あります。2019年からばんばん出して行きたいと思います。

終わりに

ちょっと長くなってしまいましたが、いかがだったでしょうか。
Riotz Works は 2019年も楽しく活動していきたいと思います。みなさん良いお年を〜

API Gateway の WebSocket でチャットを実装 w/Serverless Framework

この記事は Serverless Advent Calendar 2018 の 22日目になります。

AWS re:Invent で発表された API Gateway の WebSocket 対応、ついに利用できるようになりました!
WebSocket がサーバーレスで簡単に利用できるようになるとアプリの幅も広がり、いろいろなことができるようになります。
さっそく API Gateway の WebSocket を試してみたいと思います。

※ 今回 Serverless Framework の serverless-websockets-plugin を使いますが 2018年12月現在、暫定の実装になるとのことです。API Gateway の WebSocket 対応が AWS CloudFormation で未サポートのため Serverless Framework 本体には含まれず Plugin になっているとのこと。正式版では構文など変わる可能性があることに注意が必要です。

しかしながら “With all that out of the way, play with our new presents!” ということで、楽しんでみましょう!

環境
開発者の環境は以下となります。

  • Windows 10 64bit + WSL Ubuntu 18.04.1 LTS
  • Visual Studio Code
  • Node.js 8.10.0
  • Yarn 1.12.3
  • TypeScript 3.2.2
  • Serverless Framework 1.35.1
  • Serverless Websockets Plugin 1.0.0

参考情報

WebSocket について

HTTP ベースの Web API ではサーバーに対して接続、リクエストを送り、処理結果のレスポンスを受け取り、切断終了の流れになります。
必要に応じて、このリクエスト/レスポンスのやり取りを繰り返す形になります。

それに対して WebSocket はサーバーに接続後、コネクションを維持したまま双方向でメッセージを送ることができます。
これは通常のリクエスト/レスポンスに当たるやり取りのほかに、サーバー側から任意のタイミングでメッセージを送れます。

たとえば私たちがハッカソンで作った「ラップ、タップ、アップ 🎶」では、演奏者へのフィードバックとして「👍」を送ることができ、その数をリアルタイムでカウントする機能があります。

この「👍」をリアルタイムでカウントする部分を HTTP ベースの Web API で作るとすると、アプリから「👍」の数を取得する API を繰り返し「リクエスト/レスポンス」して受け取る必要が出てきます。
仮に数に変化がなかったとしてもアプリ側は知るすべがないので、繰り返し「👍」の数を取得しに行かなければなりません。

WebSocket が使える場合、コネクションは維持したまま必要な時に「👍」の数をサーバー側がアプリへメッセージを送ることができるようになります。
「👍」の数に変化がなかった場合は維持されているコネクションの中にメッセージが流れないだけでアプリはとくに何もする必要はありません。変化があった時だけサーバーが教えてくれるので、それに応じてアプリの表示を変えるだけになります。

これにより不要なリクエスト/レスポンスを減らせるほか、よりリアルタイムに近い状態で変化を受け取ることができるようになります。
HTTP ベースでは「リクエスト/レスポンス」で受け取り、次のリクエストを出すまでの間にあった変化は結果しか受け取れません。5だった「👍」を次のリクエスト/レスポンスでは 10になっているかもしれません。

WebSocket では状態の変化を断続的に返すことも可能になるので、5、6、7… とメッセージを返せます。

これにより、よりスムーズに描画を変えていくことができるようになります。
これはチャットのようなコミュニケーションや金融などの取引の価格情報などに使うことができます。

今回 API Gateway がこの WebSocket に対応したので、その使い方をチャットを実装することで確認します。
(WebSocket でチャットは定番すぎますが、「👍」のカウントだとさみしいですからね)

※「ラップ、タップ、アップ 🎶」では、API Gateway がまだ WebSocket が扱えなかったので、 Firebase Realtime Database を使って実現しています。

Node.js プロジェクトの準備

Serverless Framework のボイラープレートを使って、TypeScript の Node.js プロジェクトを作成します。

プロジェクトのディレクトリを作成しプロジェクトのひな型を作ります。

1
2
3
4
5
6
7
8
9
username@pc:~$ mkdir samples-apigateway-websocket-chat
username@pc:~$ cd samples-apigateway-websocket-chat
username@pc:~/samples-apigateway-websocket-chat$

username@pc:~/samples-apigateway-websocket-chat$ npx serverless create --template aws-nodejs-typescript
Serverless: Generating boilerplate...
(省略)
Serverless: Successfully generated boilerplate for template: "aws-nodejs-typescript"
Serverless: NOTE: Please update the "service" property in serverless.yml with your service name

続いて Serverless Framework をローカルで追加し、AWS SDK と WebSocket クライアント wscat、必要なパッケージを最新化してインストールします。
Serverless Framework はグローバルに追加して使うようですが、複数人開発でグローバルのを使っているとバージョンの違いなどでトラブルがあったので package.json で明示して、それを使うようにしているためです。サクッと試すにはグローバルでもよいでしょう。

1
2
3
username@pc:~/samples-apigateway-websocket-chat$ yarn add -D serverless serverless-websockets-plugin wscat
username@pc:~/samples-apigateway-websocket-chat$ yarn upgrade --latest
username@pc:~/samples-apigateway-websocket-chat$ yarn add aws-sdk

package.json をプロジェクトに合わせて修正します。
主に name description author あたりを合わせるとよいでしょう。
また、作成しているのはアプリケーションなのでモジュール公開の防止のために "private": true を設定しておくとよいでしょう。private の詳細は、こちらの package.json | npm Documentation をご確認ください。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
{
"name": "samples-apigateway-websocket-chat",
"version": "1.0.0",
"private": true,
"dependencies": {
"aws-sdk": "^2.382.0"
},
"devDependencies": {
"@types/aws-lambda": "8.10.17",
"@types/node": "^10.12.18",
"serverless": "^1.35.1",
"serverless-webpack": "^5.1.1",
"serverless-websockets-plugin": "^1.0.0",
"source-map-support": "^0.5.6",
"ts-loader": "^5.3.2",
"typescript": "^3.2.2",
"webpack": "^4.5.0",
"wscat": "^2.2.1"
},
"author": "Riotz.works (https://riotz.works)",
"license": "MIT"
}

Serverless Framework の設定

serverless.yml を編集し Serverless Framework の設定を行います。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
service:
name: samples-apigateway-websocket-chat

plugins:
- serverless-webpack
- serverless-websockets-plugin

provider:
name: aws
stage: ${ opt:stage, 'dev' }
region: ${ opt:region, 'us-west-2' }
runtime: nodejs8.10
iamRoleStatements:
- Effect: Allow
Action:
- execute-api:ManageConnections
Resource:
- arn:aws:execute-api:*:*:**/@connections/*
- Effect: Allow
Action:
- dynamodb:Scan
- dynamodb:PutItem
- dynamodb:UpdateItem
- dynamodb:DeleteItem
Resource:
- Fn::GetAtt: [ ChatConnectionsTable, Arn ]
environment:
DYNAMODB_CONNECTIONS:
Ref: ChatConnectionsTable
websocketApiName: ${self:service.name}-${self:provider.stage}
websocketApiRouteSelectionExpression: $request.body.action

functions:
connect:
handler: handler.connect
events:
- websocket:
routeKey: $connect
disconnect:
handler: handler.disconnect
events:
- websocket:
routeKey: $disconnect
defaultMessage:
handler: handler.defaultMessage
events:
- websocket:
routeKey: $default
sendMessage:
handler: handler.sendMessage
events:
- websocket:
routeKey: sendMessage

resources:
Resources:
ChatConnectionsTable:
Type: AWS::DynamoDB::Table
Properties:
TableName: ${self:service.name}-connections-${self:provider.stage}
AttributeDefinitions:
- AttributeName: ConnectionId
AttributeType: S
KeySchema:
- AttributeName: ConnectionId
KeyType: HASH
ProvisionedThroughput:
ReadCapacityUnits: 1
WriteCapacityUnits: 1
SSESpecification:
SSEEnabled: True
StreamSpecification:
StreamViewType: NEW_AND_OLD_IMAGES

plugins に API Gateway WebSocket を使うための serverless-websockets-plugin を追加します。

iamRoleStatements では、API Gateway の WebSocket API を呼び出すための execute-api:ManageConnections に許可を与えます。
また WebSocket に接続しているクライアントのコネクションを管理するための DynamoDB が必要なので、DynamoDB に関する許可も与えます。

30行目、31行目の websocketApiNamewebsocketApiRouteSelectionExpression は、serverless-websockets-plugin の設定になります。websocketApiName は管理用にわかりやすい名前を設定しておくとよいでしょう。

functions は WebSocket のイベントとアクションに合わせて定義を行います。
eventswebsocket が追加でき、 websocketApiRouteSelectionExpression に設定された Key の値と routeKey の文字列のマッチングによって起動する Lambda を振り分けています。
$connect $disconnect は WebSocket の接続と切断に対応します。また $default はマッチするアクションがない場合に呼び出されます。
最後の sendMessage が WebSocket で受け取るメッセージのキーになります。具体的には { "action":"sendMessage", "data":"hello world" } のような JSON の action に入る文字列のマッチングになります。

resources は WebSocket のコネクション管理用 DynamoDB を定義しています。
今回は最低限の ConnectionId だけを管理します。名前など無しの完全に匿名のメッセージだけのチャットになります。(WebSocket の動きと実装を試すってことで💦)

AWS Lambda の実装

handler.ts に処理を実装します。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
import { APIGatewayEventRequestContext, APIGatewayProxyEvent, APIGatewayProxyHandler, APIGatewayProxyResult } from 'aws-lambda';
import { ApiGatewayManagementApi, DynamoDB } from 'aws-sdk';

interface APIGatewayProxyEventWithWebSocket extends APIGatewayProxyEvent {
requestContext: APIGatewayEventRequestContextWithWebSocket
}
interface APIGatewayEventRequestContextWithWebSocket extends APIGatewayEventRequestContext {
domainName: string,
connectionId: string
}


const apigateway = ({ domainName, stage }): ApiGatewayManagementApi => new ApiGatewayManagementApi({ endpoint: `${domainName}/${stage}` });
const dynamodb = new DynamoDB.DocumentClient();

export const connect: APIGatewayProxyHandler = async (event: APIGatewayProxyEventWithWebSocket): Promise<Result> => {
console.debug('Starting Lambda handler: event=%s', JSON.stringify(event));
await dynamodb.put({ TableName: process.env.DYNAMODB_CONNECTIONS, Item: { ConnectionId: event.requestContext.connectionId }}).promise();
return new Result('Connected');
};

export const disconnect: APIGatewayProxyHandler = async (event: APIGatewayProxyEventWithWebSocket): Promise<Result> => {
console.debug('Starting Lambda handler: event=%s', JSON.stringify(event));
await dynamodb.delete({ TableName: process.env.DYNAMODB_CONNECTIONS, Key: { ConnectionId: event.requestContext.connectionId }}).promise();
return new Result('Disconnected');
};

export const defaultMessage: APIGatewayProxyHandler = async (event: APIGatewayProxyEventWithWebSocket): Promise<Result> => {
console.debug('Starting Lambda handler: event=%s', JSON.stringify(event));
const params: ApiGatewayManagementApi.Types.PostToConnectionRequest = {
ConnectionId: event.requestContext.connectionId,
Data: 'Error: Invalid action type'
};
await apigateway(event.requestContext).postToConnection(params).promise();
return new Result('Error: Invalid action type', 500);
}

export const sendMessage: APIGatewayProxyHandler = async (event: APIGatewayProxyEventWithWebSocket, context, callback): Promise<Result> => {
console.debug('Starting Lambda handler: event=%s', JSON.stringify(event));
const connections = await dynamodb.scan({ TableName: process.env.DYNAMODB_CONNECTIONS, ProjectionExpression: 'ConnectionId' }).promise();
await Promise.all(connections.Items.map(async ({ ConnectionId }) => {
try {
const params: ApiGatewayManagementApi.Types.PostToConnectionRequest = {
ConnectionId: ConnectionId,
Data: JSON.parse(event.body).data
};
await apigateway(event.requestContext).postToConnection(params).promise();
} catch (e) {
if (e.statusCode === 410) {
await dynamodb.delete({ TableName: process.env.DYNAMODB_CONNECTIONS, Key: { ConnectionId: ConnectionId }}).promise();
} else {
throw e;
}
}
}));
return new Result('OK');
}


class Result implements APIGatewayProxyResult {
public constructor(public body: string, public statusCode: number = 200) {}
}

4行目~10行目の interface 宣言ですが、こちらは API Gateway の WebSocket 対応の TypeScript 型定義がまだ入っていないので補完するために宣言しています。 requestContext に入ってくる domainNameconnectionId が必要なため追加しています。型定義が更新されたら不要となります。

13行目 ApiGatewayManagementApi のインスタンスを取得する関数ですが、API Gateway から WebSocket のメッセージを返す際に endpoint が必要となり、これが domainNamestage から決まってきます。固定値の場合はよいのですが、今回のように動的に決まってくる場合は requestContext から受け取った domainNamestage が必要なため毎回インスタンスを生成しています。

16行目~58行目で serverless.yml に定義した Lambda のエントリーポイントと実装があります。

connectdisconnect は WebSocket の「接続/切断」の際に呼び出されます。
接続時に connectionId を DynamoDB へ保存し、切断時に削除しています。切断は呼び出されないこともあるので、注意が必要です。

defaultMessage は WebSocket で受け取ったメッセージに対応するアクションがなかった場合に呼び出されます。ここでは “Error: Invalid action type” をクライアントに返しています。
WebSocket でメッセージを返すには ApiGatewayManagementApipostToConnection() を呼び出します。その際にクライアントの connectionId が必要となります。
この関数のようにメッセージを送ってきたクライアントだけにメッセージを送る場合は requestContextconnectionId が使えるので、それを使ってエラーメッセージを返します。

最後の sendMessage は、チャットのコメントを送る処理になります。リアルタイムに複数クライアントへメッセージを送る WebSocket を使う処理の肝となる部分です。
複数クライアントにメッセージを返すには、メッセージを送るべきクライアントすべての connectionId が必要となり、それぞれに ApiGatewayManagementApi#postToConnection() を行う必要があります。
つまり API Gateway が接続中のクライアントを知ってくれてるわけではないので、自前で管理する必要があり、そのために DynamoDB を用意しているものになります。

今回は全員参加の簡単な実装なので、DynamoDB のコネクション管理テーブルをスキャンし、全件に対して ApiGatewayManagementApi#postToConnection() を呼び出しています。(なんか、もっとスマートな実装できないかなぁ)

ApiGatewayManagementApi#postToConnection() を呼び出す際に、コネクションが切断されているクライアントがありえます。先ほど「切断は呼び出されないこともあるので、注意が必要です。」と書きました通り、クライアントが切断されてもイベントが呼び出されないケースもあります。そのため DynamoDB への削除されず connectionId が残るケースもありえます。その場合 statusCode410 のエラーが投げられるので、そのエラーが投げられた場合は DynamoDB から該当する connectionId を削除しておき再発防止しておきます。

デプロイ & 実行!

デプロイは Serverless Framework がしっかりやってくれるので、以下のコマンドで行えます。
あらかじめ AWS の Access Key の用意とプロファイルを設定しておきます。(デフォルト・プロファイルでない場合は --aws-profile [your profile name] と利用するプロファイル名を --aws-profile で指定します)

1
2
3
4
5
6
username@pc:~/samples-apigateway-websocket-chat$ yarn serverless deploy
(省略)
Serverless: Deploying Websockets API named "samples-apigateway-websocket-chat-dev"...
Serverless: Websockets API named "samples-apigateway-websocket-chat-dev" with ID "6ovkt8XX" has been deployed.
Serverless: Websocket URL: wss://6ovkt8XX.execute-api.us-west-2.amazonaws.com/dev/
Done in 137.90s.

デプロイが完了すると、コマンドの実行結果に WebSocket の URL が出力されます。
その URL に対して wscat で接続し API Gateway WebSocket の動きを確認します。

1
2
3
username@pc:~/samples-apigateway-websocket-chat$ yarn wscat -c wss://6ovkt8XX.execute-api.us-west-2.amazonaws.com/dev/
connected (press CTRL+C to quit)
>

接続できると > で入力待ちになります。 { "action":"sendMessage", "data":"hello world" } とメッセージを送ると、チャットのコメントが帰ってきます。

1
2
3
4
5
username@pc:~/samples-apigateway-websocket-chat$ yarn wscat -c wss://6ovkt8XX.execute-api.us-west-2.amazonaws.com/dev/
connected (press CTRL+C to quit)
> { "action":"sendMessage", "data":"hello world" }
< hello world
>

複数のコンソールから接続すると、送ったコメントがすべてのコンソールに流れてきます。
WebSocket でリアルタイムに複数クライアントへメッセージが遅れていることが確認できます。

チャットとは名ばかりのコメントだけを送りあうだけの実装(しかも wscat によるコマンドライン)でしたが、API Gateway WebSocket の実装がつかめたかと思います。

Serverless Framework は今後の AWS CloudFormation 対応によって変わってくる部分がありますが、こんなに簡単に設定できるのでとても助かります。

WebSocket が簡単に利用できるようになったので、いろいろなアプリづくりに生かせそうで楽しみです。


では、ハッピー・サーバーレス・ライフ! ハッピー・ホリデー!!

Serverless Framework と TypeScript で Hello & Version の Web API を実装

前回サーバーレスなアプリケーションのひな形を作りました。
今回は、ひな形で作られた AWS Lambda のソースを Hello World にし、また新しくアプリケーションのバージョンを返す Version Web API を追加します。

シリーズの記事

環境
開発者の環境は以下となります。

  • Windows 10 64bit
  • Visual Studio Code
  • Node.js 9
  • TypeScript 2.7
  • Serverless Framework 1.26.0

主な実行環境について、また全部稼働まではいきませんが以下を想定しています。
※ Amazon API Gateway などは、Serverless Framework が自動設定するので省略、明示的に使うものとしてリストになります。

  • Amazon S3
  • AWS Lambda

ベースとなるソースコード

前回の続きとなりますので、こちら https://github.com/riotz-works/samples-hello-serverless/tree/0.0.1 をもとに追加開発します。

本記事と一緒に作成する場合は前回のソースもしくはタグを指定してチェックアウトしたソースをお使いください。

1
2
3
c:\Temp\nlog>git clone --depth 1 -b 0.0.1 https://github.com/riotz-works/samples-hello-serverless.git
Cloning into 'samples-hello-serverless'...
(省略)

Hello Web API の改修

Serverless Framework のボイラープレートで生成した Lambda のプログラムは handler.js で以下のようになっています。
これを Hello World の Web API へ改修するにあたり、このままで responsebody を変えるだけでよさそうです。今回は message'Hello Serverless !!' にし、input は削除することにします。

1
2
3
4
5
6
7
8
9
10
11
12
13
import { APIGatewayEvent, Callback, Context, Handler } from 'aws-lambda';

export const hello: Handler = (event: APIGatewayEvent, context: Context, cb: Callback) => {
const response = {
statusCode: 200,
body: JSON.stringify({
message: 'Go Serverless Webpack (Typescript) v1.0! Your function executed successfully!',
input: event,
}),
};

cb(null, response);
}

そしてプロジェクトのディレクトリ直下で汎用的な名前の handler.js だと、このあと追加する Version Web API の配置などで困ります。
まずはディレクトリ配置を見直し、Lambda のハンドラー・ファンクションのソースが入っていることがわかるように src/handler 配下に置おきます。
続いて Hello Web API のハンドラーに対応したファンクションのファイル名として greetings.ts とすることにします。

ファイル名と配置を変えたので Lambda の定義をしている serverless.yml を修正します。
hello ファンクションのハンドラーは handler.hello と定義されていましたが、greetings ファクション src/handler/greetings.hello ハンドラーに変更します。

Hello Web API ができました。
この時点で serverless deploy コマンドを使いデプロイできます。(–aws-profile [profilename] を忘れずに)

Version Web API の作成

Hello Web API が作れましたがボイラープレートのままだったので、新しく Web API を追加したいと思います。
とりあえず、アプリケーションのバージョンを返す Version Web API を作ることにします。
仕様は「HTTP GET /versionpackage.jsonversion を返す」にします。

まずは、Lambda のハンドラーのソースを配置する src/handlersystems.ts を作ります。
他にシステム関連の Web API の想定はありませんが、システム関連 Web API のハンドラーを配置する systems.tsversion のハンドラーを追加するイメージにしました。

コードは以下のようにします。(このコードを使う場合は、1行目の Copyright は書き換えてください)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
/* Copyright 2018 Riotz.works. */
import { APIGatewayEvent, Callback, Context, Handler } from 'aws-lambda';
import { version } from '../../package.json';

/**
* System Web API's AWS Lambda handler function.
*
* @param event – event data.
* @param context – runtime information of the Lambda function that is executing.
* @param callback – optional callback to return information to the caller, otherwise return value is null.
* @see http://docs.aws.amazon.com/lambda/latest/dg/nodejs-prog-model-handler.html
*/
export const handle: Handler = (event: APIGatewayEvent, context: Context, cb?: Callback): void => {

const response = {
'body': JSON.stringify({
'version': version
}),
'statusCode': 200
};

if (cb !== undefined) {
cb(null, response); // tslint:disable-line
} else {
context.succeed(response);
}
};

主なキー・ポイントは以下になります。 先の Hello Web API と若干異なる部分 (context.succeed() とか) がありますが詳細は後日の記事として、基本的には変わりありません。

  • 3行目で、バージョンのもとになる package.jsonsystems.ts の相対パスで指定し version 要素をインポートします
  • 17行目で、インポートした version 属性の値をレスポンス・ボディとしてセットします

Visual Studio Code の環境によってはエラーが出ないかもしれませんが、3行目のインポート文でエラーにあります。

何も表示されていなくても serverless package を実行するとエラーが出力されます。

1
2
3
4
5
C:\Temp\samples-hello-serverless> serverless package
Serverless: Bundling with Webpack...
(省略)
ERROR in C:\Develop\repos\riotz\samples-hello-serverless\src\handler\systems.ts
(3,25): error TS2307: Cannot find module '../../package.json'.

これは package.json のモジュール定義が存在しないためになります。
このように型定義などを確認してくれるのが TypeScript のありがたいところです。
一方で今回のは若干無茶な実装でした。標準モジュールには存在しませんし、適切なモジュール定義をとってくることも難しいでしょう。さりとて package.json と何か別ファイルで version のダブルメンテはしたくないです。。。 ということで、モジュール定義を追加することにします。
ソースディレクトリの srctypes.d.ts を追加します。.d.ts ファイルでしたらとくに命名規則はなく typing.d.ts もよく見かけます。

コードは以下のようにします。(1行目の Copyright は書き換えてください)

1
2
3
4
5
6
7
8
9
10
/* Copyright 2018 Riotz.works. */

/**
* Module declaration for JSON file.
*/
declare module '*.json' {

/** version element of package.json using Version API. */
const version: string | undefined;
}

*.json なので、モジュール定義が見つからなかった JSON ファイルの型定義になります。
その中に version が文字列として存在することを定義しますが、これはすべてての JSON ファイルに当てはまることではないので、型定義は string | undefined としドキュメントで注釈しました。
頑張ると package.json 固有のモジュール定義もできたのですが version を取得するだけにしては複雑になりすぎたので、このあたりを落としどころとしました。

最後に serverless.yml へ Version Web API の Lambda 定義を追加します。
functions: greetings: の下に追加します。

1
2
3
4
5
6
systems:
handler: src/handler/systems.handle
events:
- http:
method: get
path: version

Version Web API ができました。

デプロイ

AWS 環境へデプロイします。前回の デプロイ と 稼働テスト 同様に、AWS のプロファイを参照して serverless deploy --aws-profile [profilename] を実行します。

endpointshelloversion の URL が出力されるので、それぞれブラウザでアクセスすると、プログラムした JSON が返ってきます。

ソースコード

今回作成した部分までのソースを GitHub へアップしました。
https://github.com/riotz-works/samples-hello-serverless/tree/0.0.2


Hello Web API はボイラープレートのレスポンスを改修しただけだったのでとくに大きな変化はありませんでした。一方で Version Web API は新しく追加となりましたし、両方のプログラムを配置するためにプロジェクトの構造も変化させました。

Hello と Version で実装レベルが異なっている部分はありますが、これについては次の記事で確認しながら合わせこみをしていきたいと思います。できれば TypeScript のコンパイラ設定や Lint にまでふれられたらと思います。

Serverless Framework と TypeScript でサーバレス開発事始め

前回の記事から時間が空いてしまいましたが、ちょうど新しいプロダクトの開発を始めるところなので Serverless FrameworkTypeScript で開発する際の事始めについてまとめます。
例によって Hello World になりますが、こんな感じで作り始めをお伝えできればと思います。

シリーズの記事

環境
開発者の環境は以下となります。

  • Windows 10 64bit
  • Visual Studio Code
  • Node.js 9
  • TypeScript 2.7
  • Serverless Framework 1.26.0

主な実行環境について、今回は準備なので全部稼働まではいきませんが以下を想定しています。
※ Amazon API Gateway などは、Serverless Framework が自動設定するので省略、明示的に使うものとしてリストになります。

  • Amazon S3
  • AWS Lambda

想定アプリケーション

ウェブサイトで、アクセス時に JavaScript で Web API を呼び出し “Hello World” の挨拶を取得します。 まずは動作させるところを目標にシンプルな形で進めます。

ウェブサイトは Amazon S3 に HTML を配置し静的ウェブサイトのホスティングを使います。
本格稼働するには Amazon CloudFrontAmazon Route 53 などが必要となりますが、まずは稼働を目指し S3 だけで進めます。

Web API はサーバーレスで作りたいので AWS Lambda を使います。
インスタンスやコンテナーの管理が不要で、純粋にアプリケーションの開発やメンテに集中できるのサーバーレスにこだわりたいです。
こちらも本格稼働にあたっては Amazon API Gateway にカスタム・ドメインを割り当てたりしますが、まずは稼働を目指し自動割り当てで進めます。

開発環境の構築

コーディングにためのエディターを用意します。こちらは手慣れたもので大丈夫です。今回は Visual Studio Code を使いました。
こちら https://code.visualstudio.com から取得できます。

続いて Node.js をインストールします。こちら https://nodejs.org からダウンロードしてインストールします。今回は 9.5.0 Current をインストールしました。

プロジェクトの作成

Node.js がインストールできたら、プロジェクトのディレクトリを作成します。
今回は C:\Temp\hello-serverless をプロジェクトのディレクトリとしました。

続いて Serverless Framework を 導入します。今回は Visual Studio Code の ターミナルを使っていますが、コマンド プロンプト からも同様のコマンドになります。
今回はプロジェクトごとに Serverless Framework を 導入したいので、-g なしで npm install serverless としました。

1
2
3
4
C:\Temp\hello-serverless> npm install serverless
(省略)
+ serverless@1.26.0
added 302 packages in 44.148s

Serverless のモジュールが導入され、node_modulespackage-lock.json が作られています。

Serverless の AWS/TypeScript ボイラープレートからプロジェクトのひな形を作ります。
※ 今回はプロジェクト・ローカルにServerless Framework を導入しているため node_modules\.bin\serverless コマンドになります。node_modules\.bin にパスを通しておくか、めんどくさい場合は npm install -g serverless-g をつけてグローバルに入れてしまうのも手です。

1
2
3
4
C:\Temp\hello-serverless> node_modules\.bin\serverless create --template aws-nodejs-typescript
(省略)
Serverless: Successfully generated boilerplate for template: "aws-nodejs-typescript"
Serverless: NOTE: Please update the "service" property in serverless.yml with your service name

Node.js/npm プロジェクト関連のファイルが追加されます。

package.jsondevDependencies に Serverless Framework が入っていないので、もう一度 --save-dev を付けて npm install --save-dev serverless を実行します。
※ 最初から --save-dev しないのは package.json が作られているとボイラープレートが展開できないためです。

他のモジュールもインストールするため、npm install を実行します。

プロジェクトの設定

自動生成された設定が入っているので、プロジェクトに合わせた設定を行います。

package.json は、最小限 name description author あたりを変更しておきます。
また、作成しているのはアプリケーションなのでモジュール公開の防止のために "private": true を設定しておくとよいでしょう。private の詳細はこちら package.json | npm Documentation をご確認ください。

serverless.yml は、service: name: の値を変更しておきます。

tsconfig.jsonlibesnext を追加します。
2018年2月現在、これを追加しておかないとビルド時に参照しているモジュールで以下のようなエラーが発生するためです。

1
2
3
4
5
6
7
C:\Temp\hello-serverless> node_modules\.bin\serverless package

ERROR in C:\Temp\hello-serverless\node_modules\@types\graphql\subscription\subscribe.d.ts
(17,4): error TS2304: Cannot find name 'AsyncIterator'.

ERROR in C:\Temp\hello-serverless\node_modules\@types\graphql\subscription\subscribe.d.ts
(29,4): error TS2304: Cannot find name 'AsyncIterable'.

プロジェクトのビルド

serverless package コマンドでビルドします。

1
2
3
4
5
6
7
8
9
C:\Temp\hello-serverless> node_modules\.bin\serverless package
Serverless: Bundling with Webpack...
ts-loader: Using typescript@2.6.2 and C:\Temp\hello-serverless\tsconfig.json
Time: 2085ms
Asset Size Chunks Chunk Names
handler.js 2.94 kB 0 [emitted] handler
handler.js.map 3.18 kB 0 [emitted] handler
[0] ./handler.ts 350 bytes {0} [built]
Serverless: Packaging service...

TypeScript がコンパイルされ、JavaScript とソースマップが作られ、.serverless ディレクトリに AWS CloudFormation のテンプレートと Lambda のデプロイ Zip が作られます。

デプロイと稼働テスト

ビルドに成功したら serverless deploy コマンドで AWS 環境へデプロイします。
デプロイにあたっては AWS IAM ユーザー のアクセス・キーが必要となります。あらかじめ作成アクセス・キーを取得し、%USERPROFILE%\.aws\credentials (e.g. C:\Users\username\.aws\credentials) に記述しておきます。
IAM のアクセス権は PowerUserAccess では足りず IAM 周りの権限追加が必要です。まだ絞り込みきれておらず結局 AdministratorAccess を使ってしまっています。頑張らないと。。。

1
2
3
4
[hello]
region = us-west-2
aws_access_key_id = ZDEJREC4D1GM3DXXXX
aws_secret_access_key = ce4FH4Dcyh5DGh2dDGG4hDk6DYfhDAjrFhXXXX

デプロイを実行します。
serverless deploy --aws-profile hello--aws-profilecredentials[] で指定したプロファイル名を指定します。

1
2
3
4
5
6
C:\Temp\hello-serverless> node_modules\.bin\serverless deploy --aws-profile hello
(省略)
endpoints:
GET - https://ca3kg0hrXX.execute-api.us-east-1.amazonaws.com/dev/hello
functions:
hello: hello-serverless-dev-hello

無事にデプロイできると自動生成された API Gateway のエンドポイントが出力されます。

ブラウザでアクセスすると、handler.ts の実装の通り「Go Serverless webpack (TypeScript) v1.0! Your function executed successfully!」のメッセージと HTTP リクエストの内容が表示されます。

お掃除

serverless remove で AWS 環境をクリーンアップできます。

1
2
3
4
5
6
7
C:\Temp\hello-serverless> node_modules\.bin\serverless remove --aws-profile hello
Serverless: Getting all objects in S3 bucket...
Serverless: Removing objects in S3 bucket...
Serverless: Removing Stack...
Serverless: Checking Stack removal progress...
..........
Serverless: Stack removal finished...

ソースコード

今回作成した部分までのソースをGitHub へアップしました。
https://github.com/riotz-works/samples-hello-serverless/tree/0.0.1


初期設定に多少の作業がありましたが、Serverless Framework を使うことで簡単にデプロイとクリーンアップができました。

アプリケーションとしては Lambda でメッセージを返すレベルではありますが、インフラ面を考えると、これをしべて AWS マネジメントコンソールではかなりの手間がかかります。それを Serverless Framework が補ってくれるので、サーバレス開発のインフラ運用が削減できるメリットに加えて、インフラ構築も格段と楽になるのではないでしょうか。

また Try & Error を繰り返すうちに AWS 環境がついつい散かってしまい、よくわからないリソースを放置されるケースが出てきたりします。開発環境とはいえ Serverless Framework で環境を作るようにすると片付けも簡単ですね。

引き続き、このプロジェクトに設定やコードを加えてもう少し発展させていきたいと思います。