🐥

AWS初心者が2週間サーバーレス構成アプリのバックエンドを作った感想

2023/10/23に公開

はじめに

9月の初め二週間、とあるハッカソンでタスク可視化アプリケーションを知り合いと5人で開発しました。
その際、初めてAWSを用いて開発をしたためその感想をつらつらと書いています。
ほとんどが開発終了直後に書いたものなので、記事公開日ではもっと上手いやり方を知りはしたのですが、せっかくですから当時の文章をそのまま残しておきます。

技術キャッチアップ編

(2023/10/23追記) アプリケーションの構成をチームで話し合ったのち、APIの仕様を確定させ、AWS上に構築し始めました。AWSを使うのは初めてだったので、全てを調べながら行いました。

AWSのCloud Formationのtemplateファイルについて理解できるまでとにかく時間がかかった

ChatGPTに投げるのがよさそうです
一回勉強してしまえば、ある程度いじるのは簡単にできるようになります。
詳しくはAWS編にて

(2023/10/23追記) Former2が便利!

Former2というサービスがあります。
これはAWSに構築されているサービスを選択することで、Cloud Formation templateやterraform、CDKなどの形式でサービスの構成ファイルを書き下してくれるサービスです。
使い方はサイトにあるので省略しますが、

  1. ポチポチでwebコンソールからプロダクトのガワを構築する
    • 中身まで作り込む必要はないです。
  2. 作成したプロダクトを検索し、全てのサービスを選択する
  3. 生成されたテンプレートをもとに機密情報を削除し、外部から読み込めるように変更する

という使い方をすると、自分で間違ったテンプレートを書くことが減り、とてもスムーズにできると思うので、外部アクセスに問題がなければ、使ってみてください。

Github Actionsの知識0から、CI/CDを構築するのが大変だった。

特に、アクションが発火するタイミングの制御は、今でもよくわからないです。
これに関しては、github actionsのwikiを通読しないことにはわからなさそうですね。
wikiの仕様が結構難しく、使い方を知らないと一生同じところをぐるぐる回ることになります。(マルデカイユウギョミタイ)
日本語に翻訳されてるページは特にやばくて、クリック判定があったりなかったりする項目があるんで、頑張ってクリックするしかなかったです。

Lambdaは簡単!

ただし、外部パッケージを使う時は動かないこともあるので、動作確認とるのは大変です
デバッグもSAM(後述)を使えばある程度はローカルでできるのでますますEASY
開発を始める前にDockerのセットアップだけやりましょう

Lambda on openai

結局よくわからんかったというのが本音。
自分が何をミスって動かなくなっているのかが、エラーが握りつぶされちゃってわかりませんでした。

AWS編

Cloud Formationのtemplate.yamlだるすぎ案件

何が大変って、yamlをひたすら書き続ける作業がとにかく大変です!!!
特に、Cloud Formation用の独自拡張記法があるので、とにかく最初の理解までに時間がかかります。
上にも書きましたが、ChatGPTにガンガン聞いていくのがいいです。
あとは、ある程度書き上がったら、Copilotを導入しましょう。正直、人間が全部書くもんじゃないです。

はまったポイント

  1. 各モジュールの意味するところがわからない。
    これに限っていえば、ほぼほぼドキュメントを読めば解決します。
  2. ベストプラクティスがわからん
    場数踏む & ドキュメント通読 しか解決方法はなさそう。
    特に場数踏むのが大事そうですが、それこそ週一で新しいサービス開発するぐらいじゃないとまともな構成にはできなさそうだね。
  3. Paramertersを指定しとかないと、実行時に外部から埋め込みができない。
    これが今回、Cloud Formation単体で一番はまったところですね。template.yamlでは、
    template.yaml
    Name: !Sub test-${PrNumber}
    
    みたいな感じで、変数埋め込みができて、実行時に--parameter-overrides PrNumber=10みたいに指定してあげることで、ある程度自由にパラメータを制御できます。しかし、これをするためには、template.yaml内に
    template.yaml
    Parameters:
      PrNumber:
          Type: String
          Description: PR NUMBER
    
    上記のようにあらかじめ用意しとかなきゃいかんのです。
    これに気がつくまでに数時間かけたので、ドキュメントは読んだ方がいいです。
  4. openapiの定義ファイルとうまく連結できない
    これが、今回の開発で一番沼ったポイントです。
    結論を言えば、openapiをインポートしようとせずにtemplate.yaml内で完結する書き方にするというのがおすすめです。
    openapiのバージョン違いだったり、何かしらの指定ミスだったりと、起きると面倒なことが起きるので。
    これだけでも数時間とかしたのでもう二度とやらないですね。

とはいえ、Cloud Formationは神です。

いや、これがなかったら開発はローカルで動かすだけのものになってましたね、間違いなく。
バックエンド開発を本番とほぼ同じ環境で動かすことができるのはやはり素晴らしいの一言に尽きます。

同様に、AWS SAMも神です。

Cloud Formationを有効活用するなら、AWS Serverless Application Model は外せません。いやほんとに。特に、SAMのcliがめちゃくちゃ便利です(以下でSAMと言ったらcliのことと思ってください)
sam cliを誤解混じりで伝えるなら、「超簡単なデプロイツール」です。
なぜなら、template.yamlにしたがって全自動で環境を構築してくれるから。
ansibleとか言ってる場合じゃないっすね。github actionsで動かすのも簡単なので、これ使いましょう
もちろん、ansibleが生きる場面もあります。ローカルな複数のサーバーに変更を適用するには、ansibleが使いやすいのは変わりません。ちょっとコツを覚える必要がありますけどね。
とは言え、awsでAPIエンドポイント開発するならSAMを使えば必要十分です。

SAMの良かったポイント

  1. デプロイが簡単。
    githubでCI/CD簡単に組めます。もちろん、ある程度の知識入りますが、コピペで大体は動くでしょう。
  2. ローカルでの動作チェックがある程度できる。
    LambdaとAPI Gatewayをローカルで動かせます。DynamoDBは構築できませんが、どうやらDynamoDBクローンがDockerで公開されているようなので、それを使えばできないことはないですね(私はやりませんが。めんどすぎるし、2週間じゃとても時間が足りない)。
    手元でビルドして動作するので、エラーチェックなんかをデプロイせずにできるのが素晴らしいですね。

DynamoDB難しすぎる

率直な感想です。RDBMSとORマッパーが如何に素晴らしいかを身をもって体験しました。
はっきりと言えます。dynamodbは難しいです。正直、複雑なデータを扱うなら、RDBを使う方が全然楽です。
何が難しいかといえば、検索が難しいです。RDBであれば、第3正規化までできていればクエリの発行に悩むことは稀です。悩む部分といえばどうJOINすれば正しいんだっけぐらいではないでしょうか?どこをどんな条件で検索するかということに悩むことはほとんどあり得ません。
DynamoDBは違います。どんなデータがどんな形で入ってくるかをまず決め、その後にどの値を使って検索をしたいかを明確に定めておく必要があります。しかも検索できる条件は最大で21個です。しかも、一回の検索で使用可能なのは2つの要素までで、かつ片方はHASH値のみでしか検索できません。
つまり、検索条件はめちゃめちゃ考えて設計し、DBに保存する形式まできちんと定めておく必要があるということです。
「NoSQLは簡単」という人を今まで何人も見てきましたが、彼らがただ無知なだけであるということを今回の開発で学びました。いいですか、NoSQLは簡単ではありません。使用するデータやビジネスモデルをきちんと理解している必要があります。かつ、NoSQLのデータストアの特性についてもきちんと理解する必要があります。ここまで色々な要素を考えなければいけないNoSQLは果たして簡単と言えるのでしょうか?
もちろん分かっています。RDBはスケールするコストが半端じゃなく高く、NoSQLはスケールコストが遥かに低いことはわかっています。テーブルをJOINするコストが高く、高速な応答が難しいこともわかっています。それでも言いましょう。実運用の際の検索性を考えたらRDBに勝るものはないでしょう。それぐらいRDBの仕組みは簡潔でわかりやすいのです。
確かに、フロントエンドがただのKey-ValueストアとしてNoSQLを用いる場合はとても楽でしょう。何せ、特定の一意なIDと保存したいデータを一つのjsonにして保存するだけで良いのですから。しかし、DBをガシガシ利用して、検索を効率的に行おうとしている人にはこれほど難しいDBはありません。読み出しに用いたデータの個数だけ料金がかかるシステムで、クエリには一つのHASHと一つのRANGEしか指定できないなど正気の沙汰ではありません。

と、ここまで書きましたが、おそらく自分の使い方が間違っているのでしょう。銀の弾丸はないのですから、大人しくRDBを使うべきだったのです。また、DynamoDBの知識がないこともこの感想に影響しています。おそらく複数のクエリを使って検索する方法があるのではないでしょうか?
今回のプロダクトでは、応答速度は対して重要ではありませんでした。それよりも、後の拡張性を考えると検索の柔軟さが重要でした。NoSQLは検索に用いないカラムを追加することは簡単ですが、検索に用いるカラムを後から追加することはとても面倒で大変です。そう言った点からも、今回のDBに関しては選定を間違えたというのが、今回の結論です。
・・・だってDynamoDB使ってみたかったんだもん。

Github Actions編

これも神ツールです。これのおかげで、開発時間を30時間ぐらいは圧縮できたんじゃないかな?大袈裟かもしれませんが、冗談ではありません。
ただ、色々と言いたいところがないわけではありません。作りが中途半端なてんがまだまだ残っているんですが、改良されそうな兆しはないですね。
自分で色々使ってみると見えてくる部分があるので、研究や個人開発で使ってみることをお勧めします。
ドキュメントだけ見てても何もできませんよ!

詰まったポイント

  1. アクションがフックしない
    これに関しては、なんで解決したのか正直分かってません。
    適当にいじってたらうまくいったので、それを雛形に量産しました。
    きちんと理解できるまでやるべきなんですがね、時間がね、うん。
  2. なぜかラベルを条件に入れてもうまく動作しなかった
    これは原因がわかりました。
    設定をyamlで書くのですが、if節で条件を書く際に文字列はシングルクオート(‘)で囲む必要があるということです。正確には式を書くときにはというべきですが、実質的にハマるのはここぐらいなので、あえてこう書きました。
  3. 再利用可能なアクションがいいのか悪いのかよくわからん
    再利用可能なアクションを作成できるのですが、secretを上位のアクションから何もせず引き継ぐことができません。
    引継ぎたい値を設定した上で、上位のアクションからきちんと渡してあげる必要があります。
    これに関しては、実は知識不足なだけなのではと勘繰っている部分もありますが、理解が難しかったので強引に解決しました。

良かったポイント

  1. PR出してpushするだけというのがあまりにも楽
    いやー、一度だけ別の場所でも触りましたが、CI/CDはいいものですね。一度設定してしまえばあとは自動で動くのはとても魅力的です。
    次からもある程度の期間があるプロダクトではこれを導入します。
  2. デプロイ結果を表示するようにした
    これのおかげで、実装がミスっていることにすぐ気がつくことができたり、フロントエンドへ渡すエンドポイントをさっと渡すことができました。
    これに関しては、自分が工夫した点ではあるのですが、素晴らしい出来だったなと自負しています。

今回の開発では、

  1. PRを出したら自動的にAWS上に環境構築
  2. PRにpushするたびにデプロイ
  3. デプロイ完了時にSlackに通知
  4. PRがマージされたら自動で環境を畳む
  5. PythonのLInterを走らせて構文チェック

を行いました。
これのおかげで、ミスに気がついたり、ソースの綺麗さを保つことができました。
一緒にバックエンドを開発した方も、めちゃくちゃ便利だと言ってくれて嬉しかったです。
今後はChatGPTを組み込んでコメントが少ないソースにはコメントを自動で付与するようなSaggestを出すツールとかを作っても面白そうだなと思いました。

Discussion