Slide 1

Slide 1 text

AWSマネージドサービスとの テスタブルなアプリケーションコード JAWS DAYS 2022 Satellites
 2022/10/08
 清家史郎
 1


Slide 2

Slide 2 text

自己紹介
 清家 史郎
 @seike460
 - ID
 - GitHub:seike460
 - Twitter:@seike460
 - Work at
 - 株式会社 Fusic (フュージック) 
 技術開発本部/技術開発第一部門 
 - チームリーダー/プリンシパルエンジニア/ 
 エバンジェリスト
 - Skill
 - PHP/Go/AWS
 - Community
 - PHPカンファレンス2018 - 2022 
 - AWS Dev Day Japan 2021 - 2022 
 2


Slide 3

Slide 3 text

Agenda
 3
 1. テストコード
 2. ユニットテストの導入
 3. マネージドサービスに対するユニットテスト
 4. マネージドサービスのエミュレート
 5. まとめ


Slide 4

Slide 4 text

01 テストコード


Slide 5

Slide 5 text

人はなぜテストをするのか
 5
 不具合は誰も幸せになることがない
 - システム利用者は利用できない為の不利益を
 - システム運用者は障害復旧に時間を取られ、ユーザー離れで不利益を
 - システム開発者は障害対応に心を削られ、
 障害原因に気付いて心を削られ、障害報告に心を削られ、
 障害対応後に残った仕事に心を削られ…
 不具合は人を不幸にする。テストをすることで、不幸な人を救いましょう


Slide 6

Slide 6 text

どうやってテストをすればよいのか
 6
 時間をつぎ込んで、ひたすら手動テストを行うべきなのか
 技術発達により加速する現代の開発速度についていく為には、
 時間を使って解決することは得策とは言えないし、人は必ず間違えます。
 テストをしたから絶対に大丈夫、本当でしょうか?


Slide 7

Slide 7 text

自動テスト
 7
 ではどうするのか
 私達がプログラムでユーザーの課題を解決するように、
 自動テストを行う事で、プログラムで課題解決を行います。


Slide 8

Slide 8 text

自動テストは何をすると良いのか
 8
 UI Tests、Service Tests、Unit Testsと分類され、大雑把に言うと
 より疎結合で早い Unit Testsと、より密結合で遅い UI Testsとなる
 The Practical Test Pyramid
 https://martinfowler.com/articles/practical-test-pyramid.html


Slide 9

Slide 9 text

02 ユニットテストの導入


Slide 10

Slide 10 text

Bref
 10
 AWS Lambdaを利用したServerless PHPを簡単に実現してくれるオープンソース 
 Serverless Frameworkを利用して 
 簡単にPHPのCustom RuntimeをAWS Lambdaにデプロイすることが出来ます。 


Slide 11

Slide 11 text

Docker / Bref
 11
 DockerHubにてDocker Imageも配布されているため、
 簡単に開発を始める事が出来るのも嬉しいポイント


Slide 12

Slide 12 text

Serverless Framework
 12
 Serverless Applicationを構成管理デプロイするためのツールで、 
 Yamlにて設定されたAWS Lambdaを簡単にデプロイすることが出来ます。 
 また同じYaml内にCloud Formationを記述する事も出来るため、 
 汎用性が高く様々なプラグインも提供されているツール 


Slide 13

Slide 13 text

例題システム
 13
 MVP(Minimum Viable Product)として 
 とにかく注文をインターネットから受け取る事が目的で、S3に注文情報を保存し 
 人力でその注文情報を見ながら受注生産を行うシステムがあったとします。 


Slide 14

Slide 14 text

注文情報の保存処理を記述
 14
 S3に注文情報(Order)を保存する 
 
 HTTP Requestの情報をS3に
 保存するプログラムを記述することで 
 要件を満たすことが出来ました。 


Slide 15

Slide 15 text

事業成長し…
 15
 事業成長し、注文情報を人力で見に行く事が限界を迎えました。 
 そのため注文されてからの生産依頼を自動で行うシステムを構築しました。 
 システムへの生産依頼はSQSを介して実行されます。 


Slide 16

Slide 16 text

注文情報保存後に、キューイング処理の追加
 16
 S3に注文情報を保存後、
 SQSにメッセージ送信部分を
 追加することで、
 生産依頼システムへ
 連携する事が出来た


Slide 17

Slide 17 text

更に事業成長し…
 17
 更に事業成長して、注文情報の納期管理や在庫管理を行うため、 
 注文情報を検索する必要が出てきました。 
 そこでDynamoDBを利用した注文情報検索システムを構築しました。 


Slide 18

Slide 18 text

キューイング処理後にDynamoDBに保存する
 18
 SQSにメッセージ送信後に
 DynamoDBへの保存処理を
 追加することで、
 注文情報検索システムへの
 データ追加を行う事が出来た


Slide 19

Slide 19 text

更に更に事業成長し…
 19
 度重なる機能追加で全ての機能を手動テストすることで、 
 品質を担保する事が難しくなってきました。 
 そこで自動テストを取り入れる事になります。 


Slide 20

Slide 20 text

再度テストピラミッドをおさらい
 20
 より疎結合で速度の早いUnit Testsを作成したい


Slide 21

Slide 21 text

Unit Testを…書けない!
 21
 今まで追加で全ての情報保存を完全に密結合に 
 してしまっているのでUnit テストは出来ない 
 
 このような構造にしてしまっていると、 
 Requestを再現して
 他の機能と一緒にテストを行うしかない状態 


Slide 22

Slide 22 text

Unit Testの単位を探す
 22
 Unit Testを呼べる単位を考える 
 S3への注文情報の保存
 生産依頼システムへのキューイング 
 注文情報検索システムへのDB保存 


Slide 23

Slide 23 text

処理の単位で分割をする
 23
 S3でいうとこの部分
 
 - クライアント生成
 - 保存情報生成
 - 保存処理の実施
 
 が一つ一つの処理単位となる


Slide 24

Slide 24 text

注文データ保存を行うModelを作成
 24
 S3へデータの保存を行う、
 Modelを作成することで、
 処理の切り出しを行う
 
 


Slide 25

Slide 25 text

注文データ保存を行うModelを作成
 25
 それぞれの保存先に対する
 処理毎に分割する事が出来ました 


Slide 26

Slide 26 text

データ保存先により、Modelを変更する
 26
 主題とは少しズレますが、
 データの保存先がそれぞれ違うので 
 S3用、SQS用、DynamoDB用と
 データの保存先毎にModelを作成すると 
 更に保存先毎に振る舞いを変更する事が出来ます。 
 
 このModelに対するUnitテストを記述することで 
 自動テストを行っていきます。


Slide 27

Slide 27 text

03 マネージドサービスに対する
 Unit Test


Slide 28

Slide 28 text

PHPUnit
 28
 PHPでUnit Testを行う場合、PHPUnitを使うのが良い
 様々なWeb Frameworkでも取り入れられているメジャーなTest Framework
 https://phpunit.de/


Slide 29

Slide 29 text

PHPUnitの実行の様子
 29
 Testを記述して実行すると次の様に
 結果を確認することが出来ます。
 
 ...FE...
 
 . … 成功したテスト
   想定したテスト結果となった場合
 F … failure(失敗)したテスト
   想定したテスト結果と違う場合
 E … error 
   予期せぬエラー(Fatal Error等)が
   発生した場合


Slide 30

Slide 30 text

setUp()
 30
 各テストケースの直前に実行される関数
 前処理をまとめるのに有効で、
 例の様に予めオブジェクトを生成して
 propertiesに持たせる事が出来ます。
 
 ※同じ様にtearDownと呼ばれる
  後処理も存在します。


Slide 31

Slide 31 text

マネージドサービス のUnitTest
 31
 早速テストを記述していくに
 あたりModelの見直すべき点を
 確認します
 
 すると認証情報が
 直接指定されているため、
 テストでも、Productionでも
 同じS3に情報が保存されてしまう 
 
 この部分を見直す必要があります。 


Slide 32

Slide 32 text

Mock


Slide 33

Slide 33 text

Mocking
 33
 Aws\MockHandlerを利用すると
 擬似結果を返す事が可能です。 
 
 Client生成時にhandlerに生成したmock Objectを渡すと、
 Clientは追加された順番に
 結果を返してくれます。


Slide 34

Slide 34 text

Mocking
 34
 Exceptionの擬似結果を返す事も 
 可能なので、意図的にExceptionを 
 発生させたい場合等にも利用できます 


Slide 35

Slide 35 text

env


Slide 36

Slide 36 text

Laravel
 36
 PHPer御用達のWeb Framework、AWSや他のOSSとの相性も良い


Slide 37

Slide 37 text

Serveless Laravel (Bref)
 37
 https://bref.sh/docs/frameworks/laravel.html
 
 Laravelを利用したBrefを
 整備する方法はBref公式ページに
 説明があります。
 
 手順をなぞるだけで、
 なんの不自由もなくLaravelを
 投入することが出来ます。
 
 AWS Lambdaの場合はAPIとして
 利用する事がほとんどですので、
 今回はAPIモードで利用します


Slide 38

Slide 38 text

envファイル(.env.testing)
 38
 .env.testingという
 テストの時に利用する
 環境変数を設定する事が出来ます
 
 


Slide 39

Slide 39 text

テスト時のIAM情報を設定できる
 39
 envファイルの中には
 AWS_ACCESS_KEY_IDや
 AWS_SECRET_ACCESS_KEY、
 AWS_BUCKETまで
 設定項目が最初から用意されてます 
 
 .env.testingの中に
 テスト用のIAMを記述する事で
 テストの時に利用するIAMを記述し、 
 本番と別の、テスト用のS3に
 データ保存を行う事が出来ます。 
 
 言語毎に設定していきます


Slide 40

Slide 40 text

認証情報の設定部分の切り出し
 40


Slide 41

Slide 41 text

認証情報の設定部分の切り出し
 41
 認証情報を env ファイルから取得し、 
 コンストラクタにてs3Clientを生成して、propertiesに s3Clientを持たせる事で 
 S3クライアントが何度も生成されることを分ける 


Slide 42

Slide 42 text

現在のアーキテクチャを振り返る
 42
 マネージドサービス環境を振り分ける事で、
 本番環境とテスト環境で利用する領域を分け、
 マネージドサービスに対するテストの問題が
 完全に解決
 もちろんだがそんなことはない


Slide 43

Slide 43 text

Unit Testは大量に行われる
 43
 10テストくらいなら
 気にならないかもしれないが
 120テストならどうなのか
 
 またS3ではなくDynamoDBのテスト で高速に読み書きが
 発生し続けるとどうなるか
 
 それが更にCI/CDの導入により 
 日/100回行われるとどうなるか 


Slide 44

Slide 44 text

アーキテクチャを考える
 44
 テスト数 × PR のAWSへのリクエスト発生は
 コスト観点から見ても効率的には思えない
 
 ではどうするべきなのか


Slide 45

Slide 45 text

04 マネージドサービスの
 エミュレート


Slide 46

Slide 46 text

MinIO
 46
 Amazon S3互換のObject Storage、Dockerの利用も可能
 こちらを利用してS3をエミュレートが出来る


Slide 47

Slide 47 text

MinIO UI
 47
 実際ローカルにMinio Dockerを利用して立ち上げた様子です。
 もちろんS3とUIは違いますが、S3と同じくBUCKETが作成出来ます。
 


Slide 48

Slide 48 text

AWS SDK endpoint
 48
 AWS SDKは「endpoint」オプションが存在して、
 こちらにminioのURLを設定する事で接続先をminioにしながら
 S3のプログラムを書くことが出来、開発時にも役に立ちます。


Slide 49

Slide 49 text

dynamodb-local
 49
 Amazon DynamoDBをエミュレート出来る、DynamoDB local
 AWSが公式に出している安心感もあります。
 同じ様にDockerで、気軽に利用する事が出来ます


Slide 50

Slide 50 text

ElasticMQ
 50
 Amazon SQS互換のMessage queue、同じくDockerの利用が可能


Slide 51

Slide 51 text

エミュレート対応(Model側)
 51
 外からConfigを渡せる様に
 ModelClassを作成します
 
 .envを利用したい場面も
 あるのでコンストラクタ側で
 判定を行う


Slide 52

Slide 52 text

テスト側での対応
 52
 テストケースのsetUpにて
 $configを注入する事で
 テストの際の向き先を
 MINIOに向ける事が可能
 
 テスト用のBucket生成等も
 合わせて行う


Slide 53

Slide 53 text

ローカル エミュレート
 53
 互換サービスとDockerを利用する事でローカルで
 エミュレートすることが出来ました。


Slide 54

Slide 54 text

LocalStack


Slide 55

Slide 55 text

LocalStack
 55
 LocalstackはAWSのあらゆるサービスを擬似的に使用できる事が可能で、
 MINIOやDynamoDB Localの様にendpointを提供してくれる為、
 テスト時に利用する事が可能


Slide 56

Slide 56 text

LocalStackでAWS サービス再現
 56
 endpointが提供されて、互換性があるので他の互換サービスと同じ様に
 このようなテストアーキテクチャを設定する事が出来ます。


Slide 57

Slide 57 text

GitHub Actions等でも利用可能
 57
 公式サイトに各種CIに対する情報を提供してくれています。
 ローカルテストだけでなく、CIに組み込む事も出来ます。


Slide 58

Slide 58 text

全てLocalStackで良いのでは?…本当に?
 58
 LocalStack(650MB)
 minio(76MB)


Slide 59

Slide 59 text

エミュレートはあくまでエミュレート
 59
 また、エミュレートはあくまでエミュレートで有ることは認識すべきです。
 最新のサービスについていってない場合や、
 思わぬ結果が返ってくる可能性も0ではありません。


Slide 60

Slide 60 text

ステージング
 環境


Slide 61

Slide 61 text

ステージング環境
 61
 ステージング環境を作りましょう。
 自動テストでも完全に担保出来ないので、
 ステージング環境を動作させる事が
 本当の状態を知る為に重要です。
 テスト観点でもIaCを学ぶ事も重要だと考えます。
 
 ※自動テストが不要という意味ではないです。
  自動テストで担保出来るものはあります。
  最善を尽くす事が重要だと考えます。


Slide 62

Slide 62 text

ロジックを絞り、エミュレーションしない
 62
 コード設計を綺麗にすることで、マネージドサービスへのアクセスロジックを
 一箇所に集約するのも手です。しっかりしたコード設計が必要になりますが
 完璧にやりきる事ができればインテグレーションテストが一つで済む


Slide 63

Slide 63 text

処理の単位で分割をする
 63
 
 - クライアント生成
 - 保存情報生成
 - 保存処理の実施
 
 が一つ一つの処理単位となる
 
 保存処理の分離で達成可能
 
 だが全てのアプリケーションが
 綺麗に分割出来るわけではない 


Slide 64

Slide 64 text

05 まとめ


Slide 65

Slide 65 text

まとめ
 Point 2
 アプリケーションコードはテストが出来る単位で処理分割すると Unit Test対応が出来ます 
 65
 バグをなくすために自動テストを行いましょう
 Point 1
 
 AWS サービスを各種OSSなどを利用することで、エミュレートして自動テストが出来ます。
 Point 3
 Point 4
 テストは完璧ではないことを知り、様々な手法を学ぶことで、選択肢を知りましょう。


Slide 66

Slide 66 text

ご清聴いただきありがとうございました
 Thank You We are Hiring !
 https://recruit.fusic.co.jp/