Upgrade to Pro — share decks privately, control downloads, hide ads and more …

AWSマネージドサービスとのテスタブルなアプリケーションコード

 AWSマネージドサービスとのテスタブルなアプリケーションコード

shiro seike

October 08, 2022
Tweet

More Decks by shiro seike

Other Decks in Programming

Transcript

  1. AWSマネージドサービスとの
    テスタブルなアプリケーションコード
    JAWS DAYS 2022 Satellites

    2022/10/08

    清家史郎

    1


    View full-size slide

  2. 自己紹介

    清家 史郎

    @seike460

    - ID

    - GitHub:seike460

    - Twitter:@seike460

    - Work at

    - 株式会社 Fusic (フュージック) 

    技術開発本部/技術開発第一部門 

    - チームリーダー/プリンシパルエンジニア/

    エバンジェリスト

    - Skill

    - PHP/Go/AWS

    - Community

    - PHPカンファレンス2018 - 2022 

    - AWS Dev Day Japan 2021 - 2022 

    2


    View full-size slide

  3. Agenda

    3

    1. テストコード

    2. ユニットテストの導入

    3. マネージドサービスに対するユニットテスト

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

    5. まとめ


    View full-size slide

  4. 01
    テストコード


    View full-size slide

  5. 人はなぜテストをするのか

    5

    不具合は誰も幸せになることがない

    - システム利用者は利用できない為の不利益を

    - システム運用者は障害復旧に時間を取られ、ユーザー離れで不利益を

    - システム開発者は障害対応に心を削られ、

    障害原因に気付いて心を削られ、障害報告に心を削られ、

    障害対応後に残った仕事に心を削られ…

    不具合は人を不幸にする。テストをすることで、不幸な人を救いましょう


    View full-size slide

  6. どうやってテストをすればよいのか

    6

    時間をつぎ込んで、ひたすら手動テストを行うべきなのか

    技術発達により加速する現代の開発速度についていく為には、

    時間を使って解決することは得策とは言えないし、人は必ず間違えます。

    テストをしたから絶対に大丈夫、本当でしょうか?


    View full-size slide

  7. 自動テスト

    7

    ではどうするのか

    私達がプログラムでユーザーの課題を解決するように、

    自動テストを行う事で、プログラムで課題解決を行います。


    View full-size slide

  8. 自動テストは何をすると良いのか

    8

    UI Tests、Service Tests、Unit Testsと分類され、大雑把に言うと

    より疎結合で早い Unit Testsと、より密結合で遅い UI Testsとなる

    The Practical Test Pyramid

    https://martinfowler.com/articles/practical-test-pyramid.html


    View full-size slide

  9. 02
    ユニットテストの導入


    View full-size slide

  10. Bref

    10

    AWS Lambdaを利用したServerless PHPを簡単に実現してくれるオープンソース

    Serverless Frameworkを利用して

    簡単にPHPのCustom RuntimeをAWS Lambdaにデプロイすることが出来ます。

    View full-size slide

  11. Docker / Bref

    11

    DockerHubにてDocker Imageも配布されているため、

    簡単に開発を始める事が出来るのも嬉しいポイント


    View full-size slide

  12. Serverless Framework

    12

    Serverless Applicationを構成管理デプロイするためのツールで、

    Yamlにて設定されたAWS Lambdaを簡単にデプロイすることが出来ます。

    また同じYaml内にCloud Formationを記述する事も出来るため、

    汎用性が高く様々なプラグインも提供されているツール

    View full-size slide

  13. 例題システム

    13

    MVP(Minimum Viable Product)として

    とにかく注文をインターネットから受け取る事が目的で、S3に注文情報を保存し

    人力でその注文情報を見ながら受注生産を行うシステムがあったとします。

    View full-size slide

  14. 注文情報の保存処理を記述

    14

    S3に注文情報(Order)を保存する


    HTTP Requestの情報をS3に

    保存するプログラムを記述することで

    要件を満たすことが出来ました。

    View full-size slide

  15. 事業成長し…

    15

    事業成長し、注文情報を人力で見に行く事が限界を迎えました。

    そのため注文されてからの生産依頼を自動で行うシステムを構築しました。

    システムへの生産依頼はSQSを介して実行されます。

    View full-size slide

  16. 注文情報保存後に、キューイング処理の追加

    16

    S3に注文情報を保存後、

    SQSにメッセージ送信部分を

    追加することで、

    生産依頼システムへ

    連携する事が出来た


    View full-size slide

  17. 更に事業成長し…

    17

    更に事業成長して、注文情報の納期管理や在庫管理を行うため、

    注文情報を検索する必要が出てきました。

    そこでDynamoDBを利用した注文情報検索システムを構築しました。

    View full-size slide

  18. キューイング処理後にDynamoDBに保存する

    18

    SQSにメッセージ送信後に

    DynamoDBへの保存処理を

    追加することで、

    注文情報検索システムへの

    データ追加を行う事が出来た


    View full-size slide

  19. 更に更に事業成長し…

    19

    度重なる機能追加で全ての機能を手動テストすることで、

    品質を担保する事が難しくなってきました。

    そこで自動テストを取り入れる事になります。

    View full-size slide

  20. 再度テストピラミッドをおさらい

    20

    より疎結合で速度の早いUnit Testsを作成したい


    View full-size slide

  21. Unit Testを…書けない!

    21

    今まで追加で全ての情報保存を完全に密結合に

    してしまっているのでUnit テストは出来ない


    このような構造にしてしまっていると、

    Requestを再現して

    他の機能と一緒にテストを行うしかない状態

    View full-size slide

  22. Unit Testの単位を探す

    22

    Unit Testを呼べる単位を考える

    S3への注文情報の保存

    生産依頼システムへのキューイング

    注文情報検索システムへのDB保存

    View full-size slide

  23. 処理の単位で分割をする

    23

    S3でいうとこの部分


    - クライアント生成

    - 保存情報生成

    - 保存処理の実施


    が一つ一つの処理単位となる


    View full-size slide

  24. 注文データ保存を行うModelを作成

    24

    S3へデータの保存を行う、

    Modelを作成することで、

    処理の切り出しを行う



    View full-size slide

  25. 注文データ保存を行うModelを作成

    25

    それぞれの保存先に対する

    処理毎に分割する事が出来ました

    View full-size slide

  26. データ保存先により、Modelを変更する

    26

    主題とは少しズレますが、

    データの保存先がそれぞれ違うので

    S3用、SQS用、DynamoDB用と

    データの保存先毎にModelを作成すると

    更に保存先毎に振る舞いを変更する事が出来ます。


    このModelに対するUnitテストを記述することで

    自動テストを行っていきます。


    View full-size slide

  27. 03
    マネージドサービスに対する

    Unit Test


    View full-size slide

  28. PHPUnit

    28

    PHPでUnit Testを行う場合、PHPUnitを使うのが良い

    様々なWeb Frameworkでも取り入れられているメジャーなTest Framework

    https://phpunit.de/


    View full-size slide

  29. PHPUnitの実行の様子

    29

    Testを記述して実行すると次の様に

    結果を確認することが出来ます。


    ...FE...


    . … 成功したテスト

      想定したテスト結果となった場合

    F … failure(失敗)したテスト

      想定したテスト結果と違う場合

    E … error 

      予期せぬエラー(Fatal Error等)が

      発生した場合


    View full-size slide

  30. setUp()

    30

    各テストケースの直前に実行される関数

    前処理をまとめるのに有効で、

    例の様に予めオブジェクトを生成して

    propertiesに持たせる事が出来ます。


    ※同じ様にtearDownと呼ばれる

     後処理も存在します。


    View full-size slide

  31. マネージドサービス のUnitTest

    31

    早速テストを記述していくに

    あたりModelの見直すべき点を

    確認します


    すると認証情報が

    直接指定されているため、

    テストでも、Productionでも

    同じS3に情報が保存されてしまう


    この部分を見直す必要があります。

    View full-size slide

  32. Mocking

    33

    Aws\MockHandlerを利用すると

    擬似結果を返す事が可能です。


    Client生成時にhandlerに生成したmock
    Objectを渡すと、

    Clientは追加された順番に

    結果を返してくれます。


    View full-size slide

  33. Mocking

    34

    Exceptionの擬似結果を返す事も

    可能なので、意図的にExceptionを

    発生させたい場合等にも利用できます

    View full-size slide

  34. Laravel

    36

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


    View full-size slide

  35. Serveless Laravel (Bref)

    37

    https://bref.sh/docs/frameworks/laravel.html


    Laravelを利用したBrefを

    整備する方法はBref公式ページに

    説明があります。


    手順をなぞるだけで、

    なんの不自由もなくLaravelを

    投入することが出来ます。


    AWS Lambdaの場合はAPIとして

    利用する事がほとんどですので、

    今回はAPIモードで利用します


    View full-size slide

  36. envファイル(.env.testing)

    38

    .env.testingという

    テストの時に利用する

    環境変数を設定する事が出来ます



    View full-size slide

  37. テスト時のIAM情報を設定できる

    39

    envファイルの中には

    AWS_ACCESS_KEY_IDや

    AWS_SECRET_ACCESS_KEY、

    AWS_BUCKETまで

    設定項目が最初から用意されてます


    .env.testingの中に

    テスト用のIAMを記述する事で

    テストの時に利用するIAMを記述し、

    本番と別の、テスト用のS3に

    データ保存を行う事が出来ます。


    言語毎に設定していきます


    View full-size slide

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

    40


    View full-size slide

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

    41

    認証情報を env ファイルから取得し、

    コンストラクタにてs3Clientを生成して、propertiesに s3Clientを持たせる事で

    S3クライアントが何度も生成されることを分ける

    View full-size slide

  40. 現在のアーキテクチャを振り返る

    42

    マネージドサービス環境を振り分ける事で、

    本番環境とテスト環境で利用する領域を分け、

    マネージドサービスに対するテストの問題が

    完全に解決

    もちろんだがそんなことはない


    View full-size slide

  41. Unit Testは大量に行われる

    43

    10テストくらいなら

    気にならないかもしれないが

    120テストならどうなのか


    またS3ではなくDynamoDBのテスト
    で高速に読み書きが

    発生し続けるとどうなるか


    それが更にCI/CDの導入により

    日/100回行われるとどうなるか

    View full-size slide

  42. アーキテクチャを考える

    44

    テスト数 × PR のAWSへのリクエスト発生は

    コスト観点から見ても効率的には思えない


    ではどうするべきなのか


    View full-size slide

  43. 04
    マネージドサービスの

    エミュレート


    View full-size slide

  44. MinIO

    46

    Amazon S3互換のObject Storage、Dockerの利用も可能

    こちらを利用してS3をエミュレートが出来る


    View full-size slide

  45. MinIO UI

    47

    実際ローカルにMinio Dockerを利用して立ち上げた様子です。

    もちろんS3とUIは違いますが、S3と同じくBUCKETが作成出来ます。


    View full-size slide

  46. AWS SDK endpoint

    48

    AWS SDKは「endpoint」オプションが存在して、

    こちらにminioのURLを設定する事で接続先をminioにしながら

    S3のプログラムを書くことが出来、開発時にも役に立ちます。


    View full-size slide

  47. dynamodb-local

    49

    Amazon DynamoDBをエミュレート出来る、DynamoDB local

    AWSが公式に出している安心感もあります。

    同じ様にDockerで、気軽に利用する事が出来ます


    View full-size slide

  48. ElasticMQ

    50

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


    View full-size slide

  49. エミュレート対応(Model側)

    51

    外からConfigを渡せる様に

    ModelClassを作成します


    .envを利用したい場面も

    あるのでコンストラクタ側で

    判定を行う


    View full-size slide

  50. テスト側での対応

    52

    テストケースのsetUpにて

    $configを注入する事で

    テストの際の向き先を

    MINIOに向ける事が可能


    テスト用のBucket生成等も

    合わせて行う


    View full-size slide

  51. ローカル エミュレート

    53

    互換サービスとDockerを利用する事でローカルで

    エミュレートすることが出来ました。


    View full-size slide

  52. LocalStack


    View full-size slide

  53. LocalStack

    55

    LocalstackはAWSのあらゆるサービスを擬似的に使用できる事が可能で、

    MINIOやDynamoDB Localの様にendpointを提供してくれる為、

    テスト時に利用する事が可能


    View full-size slide

  54. LocalStackでAWS サービス再現

    56

    endpointが提供されて、互換性があるので他の互換サービスと同じ様に

    このようなテストアーキテクチャを設定する事が出来ます。


    View full-size slide

  55. GitHub Actions等でも利用可能

    57

    公式サイトに各種CIに対する情報を提供してくれています。

    ローカルテストだけでなく、CIに組み込む事も出来ます。


    View full-size slide

  56. 全てLocalStackで良いのでは?…本当に?

    58

    LocalStack(650MB)

    minio(76MB)


    View full-size slide

  57. エミュレートはあくまでエミュレート

    59

    また、エミュレートはあくまでエミュレートで有ることは認識すべきです。

    最新のサービスについていってない場合や、

    思わぬ結果が返ってくる可能性も0ではありません。


    View full-size slide

  58. ステージング

    環境


    View full-size slide

  59. ステージング環境

    61

    ステージング環境を作りましょう。

    自動テストでも完全に担保出来ないので、

    ステージング環境を動作させる事が

    本当の状態を知る為に重要です。

    テスト観点でもIaCを学ぶ事も重要だと考えます。


    ※自動テストが不要という意味ではないです。

     自動テストで担保出来るものはあります。

     最善を尽くす事が重要だと考えます。


    View full-size slide

  60. ロジックを絞り、エミュレーションしない

    62

    コード設計を綺麗にすることで、マネージドサービスへのアクセスロジックを

    一箇所に集約するのも手です。しっかりしたコード設計が必要になりますが

    完璧にやりきる事ができればインテグレーションテストが一つで済む


    View full-size slide

  61. 処理の単位で分割をする

    63


    - クライアント生成

    - 保存情報生成

    - 保存処理の実施


    が一つ一つの処理単位となる


    保存処理の分離で達成可能


    だが全てのアプリケーションが

    綺麗に分割出来るわけではない

    View full-size slide

  62. 05
    まとめ


    View full-size slide

  63. まとめ

    Point 2

    アプリケーションコードはテストが出来る単位で処理分割すると Unit Test対応が出来ます

    65

    バグをなくすために自動テストを行いましょう

    Point 1


    AWS サービスを各種OSSなどを利用することで、エミュレートして自動テストが出来ます。

    Point 3

    Point 4

    テストは完璧ではないことを知り、様々な手法を学ぶことで、選択肢を知りましょう。


    View full-size slide

  64. ご清聴いただきありがとうございました

    Thank You
    We are Hiring !

    https://recruit.fusic.co.jp/


    View full-size slide