はじめに

私は今までずっとインフラエンジニアとして業務をしていましたが、業務の中でAWSのマネージドな機能と同等の機能をスクラッチ開発する必要性が出てきました。

そのためStep Functionsを改めて勉強して使ってみたのですが、非機能的な観点で色々と考える必要があるなと思いました。
自身の思考の整理のためにも、その時に考えたことをこの記事にまとめておこうと思います。

少しポエム要素が入っていますが、それはご愛嬌ということでご了承ください。

背景

AWS Backupの復元テストという機能を使おうとしたところ、サービス仕様の制約に引っかかり使用することができませんでした。
この復元テストと同等の機能を持つソリューションを生み出すために、今回はStep Functionsを使用しました。

また、Step FunctionsだけではなくLambdaやEventBridgeとも組み合わせることで、一つのソリューションになるように実装しています。

詳しいことは別の記事に記載しているので、ご興味がある方はぜひご覧ください。

以下、実装内容についての詳しい説明は省き、実装する際の方針に限定して書いていきます。

スクラッチ開発を行う上での方針

スクラッチ開発を進める前に、以下のような方向性を決めて実装を進めました。

  • Step Functionsを主軸に実装
  • Step Functionsで実装すると複雑になる処理はLambdaを使用
  • Lambda関数は必要最小限に
    • Lamnda関数の数は最小限に
    • ソースコードは極力シンプルに

私はStep Functionsを今までがっつり触ったことがなかったので自信がありませんが、Step Functionsを使われている方は似た方針を持ってることが多いような気がします。

方針を決める上で気をつけたこと

では、その方針を決めるにあたって何を意識したのかですが、一言でまとめると「メンテナンスコストを減らしたい」です。

サーバレスサービスにおけるメンテナンスとは?

サーバレスを使っているのにメンテナンスコストとはどういうことだ?と思われた方もいるかと思います。
当然のことながら、EC2などのIaaS系のサービスと比較すると圧倒的にメンテナンスの手間は省けます。
これがサーバレスサービスを使う圧倒的なメリットです。

しかし、何もしなくていいわけではありません。


引用:https://docs.aws.amazon.com/ja_jp/prescriptive-guidance/latest/strategy-accelerating-security-maturity/understanding-the-security-scope.html#serverless-services

例えサーバレスサービスであっても、ユーザーの責任範囲(上図の青い部分)は存在します。
つまり、この範囲に限って発生しうるメンテナンスもユーザー側の仕事になります。

具体的なメンテナンス内容については色々考えられると思いますが、今回は主に以下の2つに注目しました。

引き継ぎコスト

今回一番意識した観点でもあるのが、担当者変更などが発生した時に生じる引き継ぎコストです。

システムが安定稼働していたとしても、組織改変などによる担当者変更の可能性は十分にあります。
この時に新任の担当者は実装内容のキャッチアップを行う必要がありますが、実装内容があまりにも複雑だと引き継ぎに時間を要します。

時間がかかるだけならまだしも、もし新しい担当者が理解できなかったら今後の障害発生リスクも上がってしまいます。

ですので、今回の実装においては「複雑すぎない、なるべく誰でも理解できるような実装」を心がけました。

具体的には、Step Functionsのステートマシンの定義をあまり複雑にしすぎないようにしました。
例えば今回の実装では、バックアップボールト内の復旧ポイントから最新の復旧ポイントを抽出する処理を入れています。

この処理はLambdaに任せていますが、ActionsやFlowを工夫して使うことで同等の処理を実装することも可能だと思います。
しかし、そうするとステートマシンの定義が複雑になるので、Lambdaに処理を任せることでステートマシンの定義をシンプルにしました。

ランタイム更新の手間

これはLambdaに限った話ですが、Lambdaで使用できるランタイムは定期的に更新と廃止が行われています。
古いランタイムを使うのはセキュリティ的にも良くないので、定期的に更新を行う必要があります。

このランタイム更新による影響を極力抑えたかったため、Lambda関数は必要最小限の数を用意し、ソースコードは極力シンプルにしました。
実際のソースコードは今回の実装内容詳細を書いた記事に記載していますが、どれもシンプルで短いソースコードであることがわかると思います。

また、Step Functionsではランタイム更新の必要性がないため、ランタイム更新の手間を軽減させる効果があります。

Step FunctionsかLambdaか

今回作ったステートマシンと同等の機能を、Lambda関数だけで実装させるということも可能だと思います。
Lambda関数内で各種AWSサービスのSDKを呼び出すことでStep FunctionsのActionsと同じことができるため、今回作成したステートマシンと同じ実装がLambda関数だけでもできます。

この実装方針も一度考えましたが、関数のソースコードが複雑になり引き継ぎコストが増えるという点、ランタイム更新の際の影響が大きくなるという点、これらを懸念点と考えました。

そのためLambda関数だけで実装するという方針は取らず、Step Functionsを主軸に置いて実装を行いました。

UNIX哲学との共通点

実装を検討していた当時から意識していたわけではないのですが、今回気をつけたことはUNIX哲学にも共通する部分もあると感じました。

https://ja.wikipedia.org/wiki/UNIX%E5%93%B2%E5%AD%A6

特に「一つのことをうまくやる」に似たものが、今回の実装方針に垣間見えると感じています。
Step FunctionsもしくはLambda関数に機能を詰め込みすぎず、必要に応じて両者を使い分けるという実装方針のベースになる考え方だと感じました。

この「一つのことをうまくやる」は、AWSが重視しているBuilding Blockという設計思想にも通じるものです。

AWSは現在200以上のサービスを提供していますが、「これさえあればOK!」ではなく様々なサービスを適材適所組み合わせる使い方をAWSは推奨しています。

AWSの設計思想はUNIX哲学に影響されていると思われる部分が多いので、今よりもさらにAWSを使いこなしたい方はUNIX哲学を学ぶことをお薦めします。
UNIX哲学について書かれている本で一番有名なのが、「UNIXという考え方」です。ご興味があれば是非読んでみてください。

https://www.ohmsha.co.jp/book/9784274064067/

最後に

スクラッチ開発を行うにあたって考えたことを書いてきましたが、これはあくまで一例に過ぎません。
個人の好みや組織の決まりによって、今回書いた内容とは全く違う実装方針をとることもあると思います。

なので、「こんな考え方もあると思う」とか「ここはちょっと違うと思う」といった意見があれば、X(旧Twitter)で記事のURLを引用したりして教えていただけたら嬉しいです。

もちろん共感の声も大歓迎です!
そして、この記事が誰かの役に立ったら嬉しいです。