育てる開発環境

これは Kyash Advent Calendar 2023 の13日目の記事です。

近頃、寒いのか暑いのかわからない気候で大変ですね。 体調管理が難しくて、鼻がぐずったりお腹こわしたり大変です。 もうちょっと厚めの毛布にしたほうがいいかなぁ〜なんて悩みながら日々を過ごしています。

Kyash で働き始めて1年ぐらい経過して、はじめの頃は Software Engineer in Test(SET)として自動化を推し進めていたのですが、最近はBackend Engineerとしてプロダクトの開発のお仕事のほうが多くなっています。 SETとして社内のプロダクトのリソース全てに関与していたとき、自動化を推し進めるにあたって考慮しなければならないことが多いなぁと感じていたのですが、Backend開発のお仕事においても同様の感想を持ちました。 その中でも特に課題に感じたのは開発環境です。

Kyashでは、各々の開発者、主にWeb開発に関わるメンバーにおいては、それぞれの開発環境が提供されています。 提供 という言葉を使ったわけは、各々にEC2インスタンスが1つ割り当てられ、開発用途として自由に使っても良いサーバーが提供されているという意味合いを表現したかったからです。 EC2インスタンス上で開発を進めていたのですが、少し使いにくいなと思う場面がでてきて、改善に努めています。


まず、メモリやストレージを食い尽くしたりCPU使用率が上がったとき、EC2インスタンス自体が立ち上がらなくなってしまった場合、自分で解決する手立てがないことです。 EC2インスタンスはTerraformで管理していて、マネジメントコンソールから色々操作する権限は少ないです。 これでは壊れたときに、自力で解決する機会が少なくなり、結局、直すにも他のチームに頼らざるを得ない状況です。

2つめは、コンテナのログを見るために、わざわざEC2インスタンスにログインし、docker compose コマンドを実行する必要があることです。 Kyashでは、マイクロサービスに寄せたプロジェクト構成を採用しており、全ての機能を成立させるには30個ほどのコンテナを起動させる必要があります。 コンテナ自体はEC2インスタンスで起動しているため、どうしてもEC2インスタンスにターミナルからログインして、$ docker compose log xxx を実行する必要があります。 複数のプロジェクトにまたがる改修をしていたり、機能調査するために複数のインスタンスの状態を確認したい場合、何個もターミナルを開かざるを得ない場合があります。

3つめは、デバッグポートを開けていないので、ブレイクポイントを置いたリモートデバッグができないことです。 KyashではIntelljのGolandやVScode統合開発環境として利用できますが、printfデバッグしかできなくなってしまいました。 Kyashはリリースされてから一定期間が経過し、ソースコードの量は膨大でして、どこでどんな値を変数に入れているのか分かりにくかったり、ある時点の状態でセッションにどういう値を持っているのかを追うのがしんどい場面があります。 そういうときに、ブレイクポイントを置いて、デバッグができないのはとても辛い状況でした。

他にもあるのですが、代表的なものは上記3つでした。 一方で、Docker Desktopのライセンスは会社で支払っており、ライセンスも付与してもらっていたので、これをうまく使いたいなと考えていました。 ということで、EC2インスタンスを利用した開発環境を導入する以前は上述の現象はなかったことだったので、昔のKyashの偉人が作ってきた開発環境を生き返らせることにしました。


VirtioFS

私が初めてKyashの開発環境を構築した1年前は、まだDocker DesktopでのファイルシステムのデフォルトはgRPC FUSEでした。 VirtioFSはまだ正式採用されていませんでしたが、現在は正式採用されました。

www.publickey1.jp

かつてのKyashでは、Intel Macを開発者に支給しており、開発環境もmacOS上のDockerに構築していました。 しかし、起動するコンテナが30個を超えてきたあたりから、macOSの動作が緩慢になり、 profiles タグを指定して、特定のコンテナのみ起動するなど、工夫して利用していました。 その後、profiles タグを指定して起動するコンテナを選びながら利用することも手間となり、EC2インスタンス上の開発環境を構築することになりました。

VirtioFSは、2022年末にDocker Desktopで正式採用されたファイルシステムで、ファイルアクセスの高速化が期待できるアップデートでした。 Docker Desktopが重くなる現象は私も体験済みで、色々工夫しなければならないことは知っていたのですが、今回扱う端末はM1 MacIntel Macより性能が良いともっぱらの噂だったし、VirtioFSが正式採用されたと聞いたので、かつてのmacOS上に構築する開発環境も工夫次第で良くなるんじゃないかと考えました。

Docker image

  • arm64

支給されたmacOSはM1チップ搭載のMacbook Proでしたので、コンテナのベースイメージを arm64 に対応したimageでビルドし直すことにしました。 docker composeで起動する30個のコンテナは、3種類ぐらいのDockerfileからビルドされたイメージを利用していたので、それぞれのイメージをビルドし直しました。 OSバージョンが古く、サポート期限が切れていたので、最新のLTSイメージを採用しました。

  • image size

ビルドイメージのサイズが大きいと、ローカルストレージが圧迫し、ビルドにも時間がかかってしまうので、 arm64 に対応したイメージで軽量なイメージを選びました。 Production環境と同等のイメージを採用したかったのですが、既存のビルドイメージの最新版のほうがサイズが小さいことがわかったので、結果的に既存のビルドイメージの最新版の arm64 に対応したものを選択しました。 なお、KyashはGo言語を主に使っているので、distrolessも検討したのですが、Dockerfileの内容を少し変更しなければならなかったため、今回は見送りました。 次の機会に軽量なコンテナイメージを利用できるようにしたいものです。

github.com

docker compose v2

これはパフォーマンスチューニングにあまり影響はないと思いますが、docker-compose.ymlをcompose.ymlに変更し、記述方法もDocker Compose V2に準拠した記述に変更しました。 最新のDocker Desktopを利用している場合、docker-compose コマンドは docker composeエイリアスされるようなので、せっかくなので、V2に合わせました。 ymlファイルの version の指定をなくしました。

matsuand.github.io

- version: '3'
services:

compose.ymlの分割

既に利用していたdocker-compose.ymlには、1つのファイルに全ての services を記述していたので、1,500行ほどの巨大なファイルになっていました。 profile タグをつけてある程度整理されていたとはいえ、どのようなコンテナが設定されているのか見通すのが困難な状態でした。 せっかく profile タグをつけていたので、 profile の種類ごとにcompose.ymlを作成し、 docker compose -f でファイル指定して起動するようにしました。 EC2ローカル環境で利用している docker compose コマンドは -f を指定しないので、デフォルトの docker-compose.yml を参照します。 今回作成するymlファイルはEC2ローカル環境に影響しないように、 compose-arm64.yml とし、それを profile ごとに分割しました。

volumes

Docker Desktopが重くなる原因の中でとても有名なものは、LinuxMacファイルシステムが異なるので、volumeマウントすると遅くなるというのは見聞きしていたので、volumeマウントのチューニングを行いました。 ローカル開発環境だけで使うのなら、そこまで即時ホスト上に反映する必要もないと思ったので、ほとんど cacheddelegated をvolumeに指定しました。

volumes:
  - ./tmp/postgresql/data:/var/lib/postgresql/data:delegated
  - ./tmp/mysqldata:/var/lib/mysql:deletated

docs.docker.jp

Makefile

compose.yml を分割すると、docker compose 実行時にいちいちymlを指定するのが面倒なため、Makefileを作成することで、コマンドの簡略化を行いました。 主に作成したmakeコマンドは以下です。

  • up : -f を指定して、docker compose upするコマンド
  • down : -f を指定して、docker compose downするコマンド
  • rm : 起動中のコンテナ一覧を peco に渡し、pecoから操作するコンテナを選んで stop してから rm するコマンド
  • bootstrap : コンテナ起動時、初期設定を行うためのコマンド
  • migrations : 各コンテナで必要になるDBの初期データを投入するためのコマンド

上記を組み合わせて、以下のコマンドを定義しました。

  • setup : 初めて開発環境を構築するときに実行するコマンド
  • reset : 全てのコンテナを削除し、DBデータやCacheを削除するコマンド
  • restart : 起動中のコンテナを1つ選んで削除し、再起動するコマンド

その他

環境構築時、手動で行っていたファイル変更や、足りないgo moduleをインストールする手順をスクリプトにまとめ、bootstrap時に実行するようにしました。 そうすることで、ほぼmakeコマンドのみで開発環境をコントロールできるようにしています。


おわりに

私が開発するときに、考慮しなければならないことや不便に感じることはできるだけ解消したいと考えています。 自分が開発するにあたって、気持ちよく作業するためにツールを開発したりチューニングしたりするのは開発者の嗜みだと思っています。 堅苦しいことばで表現すると開発生産性や作業効率の向上を行うために、組織理論や開発手法などにフォーカスが当たりがちですが、自分の手元の端末の開発しやすさにも目を向けて、開発環境もHackingしていきたいなと思っています。 組織の生産性を上げるためには小難しい施策が必要かもしれませんが、自分の生産性を上げるためには自分自身が工夫したり試行錯誤することが必要です。 キーボードやマウス、PC、モニターに持つこだわりを開発環境にも持って、開発しやすい開発環境を育てていきたいですね。

Kyashでは在宅勤務メンバーが多いため、ローカル環境の立ち上げに手間取ってしまうと回復させるためのフォローが大変です。 なので、できれば make コマンド一発で全ての環境が立ち上がることを理想としています。 幸いDocker Desktopを使った環境構築のノウハウは、検索でとても多くの情報を得ることができます。 解決できるヒントが数多くあるということは、自力解決能力を養う機会も多くなるため、レベルアップのためにDocker Desktopを使っていきたいと思います。

ちなみに

Quality Assuranceをリードするエンジニア(SET)として在籍しているのに、実装したり、ローカル環境再構築など、開発業務にコミットし過ぎでは?と思うときが時たまあります。 ただ、品質を上げたり不具合を少なくしたりするためには、システムテストの数を増やしたり、精度や頻度を上げることも有効であると考えていますが、そもそも不具合を作り込まない組織にすることも大切だとも考えています。 そのために、個々の開発者がストレスなく開発できるような環境を提供することや、リリース前に不具合に気づくことができる下地作りが必要だと思っています。 それが自動テストを動作させる上で必要なことだし、今やっていることが、Quality Assuranceをリードするエンジニアとして達成したい状態に近づくことに、大きく乖離しているとは思っていません。 歌って踊れてなんでもできるエンジニアになろうかなって思っています。

来年は、卒業されていったKyashの数々の偉人の積年の願いであるStaging環境をもっといい感じに運用するぞ〜!!!
明日の投稿もぜひお楽しみに。バイバーイ。

JaSST'23 Tokyoに参加しました

3月9日〜10日の2日間にかけて、 JaSST'23 Tokyo が開催されたので、参加してきました。 JaSSTは5年ぐらい前に当時のチームメンバー参加したことがあり、日本大学の学食でカレーを食べた記憶があります。

tech.pepabo.com

当時、参加してみてみんなでその気になり、その後、みんなで頑張って勉強してJSTQB Foundation試験を有明まで受けに行った良い思い出がありました。 それを契機に、私は脆弱性検査やペネトレーションテスト、自動化を行うセキュリティ関連の業務に従事することになるのですが、当時所属していた組織から離れることになってしまったため、JaSSTへの関与も希薄になってしまっていました。 風のうわさでみんなの活躍を見聞きすることはありますが、元気にやっているだろうか。 ちなみに、今回の JaSST'23 Tokyo 参加後、JaSST運営メンバーの方とお話できる機会があり、「次はALですね!」と言われて、お、おぅ。。と尻込んでしまいましたw

今回は残念ながら1人での参加になってしまいましたが、テスト活動に関連する職務についたので、当時の熱感を取り戻したくて参加しました。 会場は御茶ノ水にある日本大学ではなく、Discordによるオンライン参加でした。 2日間とも参加したのですが、会場移動がないので聞きたい講演を次々に回るのにはオンラインは便利だなと思いましたが、情報交換会をあまり活用できなかったなぁと反省しています。


現在も、当時と同じように効率的にテストが行えるようにツールを作ったり、UIテスト検証やAPIテストについての基盤作りに勤しんでいます。 Go言語で本格的に開発を行ったことはなかったので、ポインタや型アサーションなどの言語特徴を勉強しながら楽しく取り組んでいます。 当時と同じように、ソフトウェアの品質を高めるための「多層防御」を行うためにはQAだけでなくプロダクト開発に関わる組織全体で取り組む必要があるため、啓蒙活動も担当しているのですが、やっぱり一筋縄ではいかず、他社の事例や同じような職務についている方のお話を聞きたいという思いもありました。 全部は書ききれないので、参加した講演をかいつまんで紹介したいと思います。


基調講演 Chaos Engineering to Continuous Verification

  • 講師:Casey Rosenthal(Verica)

継続的なCI/CDサイクルの信頼性や安全性を高めるために、カオスエンジニアリングを提唱していました。 意図的に障害を起こすことにより、その後に起きるシステム的な問題や復旧プロセスの問題をあぶり出そうとしています。 例えば、ある組織でStaging環境のKafkaを意図的に止めたら、Production環境のKafkaがStaging環境のKafkaに依存していて本番障害が発生してしまったことを紹介されていました。 このようなシステム間の依存性はなかなか顕在化することが難しく、ソフトウェアの複雑性が高い場合に起き得る問題であるとしています。 システムの複雑性はシンプルに保つべきですが、アベイラビリティ(可用性)の高いソフトウェアは複雑性が高くなり、実現可能ではないので、検証して問題把握に務めることが大事だとおっしゃっていました。

また、システムの複雑性の他に、人的なエラーについても言及していました。 医療過誤件数を減らすために、医療過誤を多く起こしていたスタッフの上位5人を解雇したが、結果的に裁判件数が増えてしまったそうです。 解雇したスタッフはハイスキルを持った人材であったため、ローレベルのスタッフがより多くの医療過誤を起こしてしまったことが原因だったそうです。 しかし、人がエラーを起こす確率はほとんど同じで、根本原因を解消しても、アベイラビリティ(可用性)を上げることは難しいそうです。 なぜなら、人は必ずエラーを起こすので、最終的に「気をつけましょう」的な対策しかできないからです。 エラーの原因を起こしてしまった1人のせいにするのではなく、組織のコミュニケーションレベルや予算配分を含めた原因に対処するほうが、アベイラビリティ(可用性)は上がるそうです。

私のチームで読んでいる チームトポロジー 価値あるソフトウェアをすばやく届ける適応型組織設計 にも似た概念が書かれていましたが、ソフトウェアのアベイラビリティ(可用性)や品質を上げるためには、QAやエンジニアなどの特定のロールに責任を依存させるのではなく、組織全体で原因に対処する必要があることを再認識しました。

ただ、本番で障害を意図的に発生させるなど、危険度の高い試みについてはビジネス層や経営層を巻き込んだ意思決定が大前提にあり、少しハードルが高いなぁと感じました。


カオスエンジニアリングの裏話

  • 講師:堀 明子(オーティファイ)、松浦 隼人(オーティファイ)

オライリーから出版されている「カオスエンジニアリング」の訳者である Autify の松浦さんによる、カオスエンジニアリングをテーマにした講演を聞きました。 基調講演と同じく、私達が扱っているソフトウェアシステムの複雑性は高く、互いのコンポーネントがどのように干渉しあっているのかを把握することは、現状ますます難しくなってきています。 複雑性の高いソフトウェアに対して、ソフトウェアテストとカオスエンジニアリングがどのような関係性にあるのかを、以下のように説明されていました。

  • Known knowns : 知っているし、理解している(テスト)
  • Unknown kowns : 知らないが、理解している(直感)
  • Known unknowns : 知っているが、理解していない(監視)
  • Unknown unknowns : 知らないし、理解していない(カオスエンジニアリング、オブザーバビリティ)

ソフトウェアテストは妥当性確認を行うが、カオスエンジニアリングは未知のものを見つける作業であり、検証のアプローチが多いです。 Validation(妥当性確認)に重きを置くソフトウェアテスト、Verification(立証や検証)に重きを置くカオスエンジニアリングの対比を説明し、Unkown unknowns(知らないし、理解していない)部分を受け持つのがカオスエンジニアリングとのことでした。

  • Testing vs Experiments
    システムが期待通り動くことを確認する作業と、仮説検証し実験を試みる作業
  • Validation vs Verification
    妥当性確認を行う作業と、検証を行う作業
  • Steady states
    システムの定常状態に関する仮設を立てる (Steadyは決まった恋人みたいな和訳もあるが、安定して不変な状態と説明)
  • Blast radius
    実世界の事象を多様化(Vary)させること 多様化(Vary)させることが大事で、具体的には本番環境で実験すること、継続的に実行できるように自動化すること、影響範囲を局所化することなどを述べていました

Blast radiusは和訳すると「爆発半径」となるが、英語原文を直訳してわかりやすく「影響範囲」としたことなど、翻訳のときに使ったTipsを紹介してくれました。

principlesofchaos.org

セキュリティ監査を行うときにも通ずることだなぁと感じ、とても参考になる概念だなと思いました。 ソフトウェアテストにおいても、探索的テストがうまい人ってシステムの定常状態を把握し、仮説検証を自然と行える人がよく不具合を見つけられる印象を持っていたので、対立関係ではなく互いに参考になると思いました。


ローカル環境を用いたアジャイルテスティングの実践事例~より高速なフィードバックを目指して~

  • 講師:村岡 里紗(freee)

私が所属している組織でも、開発が終わった後にQAを行っており、品質保証活動がボトルネックになっているという課題があり、同じような課題にfreeeさんはどのように取り組んだのか興味があったので講演を聞きました。 freeeではマイクロサービスアーキテクチャを採用しており、開発環境の構築が厄介なので、検証環境を準備して開発エンジニアにデプロイしてもらっているそうです。 しかし、そうするとどうしてもテストが後回しになり、不具合検知タイミングが遅れてしまっていたことを課題にしていたそうです。 そこで、軽量なローカル環境をQAエンジニアの作業PCに構築し、スプリント毎にテストを行い、スプリントが終わった後に通しのテストを行うことによって、1週間かけて行っていたQA活動が3日で終わるようになったとのことです。 ただ、軽量なローカル環境を使えている人はまだ少ないようで、操作知識や環境の拡張時において、課題となるみたい。 やっぱりDockerを使って環境構築しているようでしたが、ターミナル操作ができるQAエンジニアは少ないようです。 私も同じことを考えていたので、「QAメンバーにDockerなどの開発環境をレクチャーするコツなどはないですか?」と質問してみましたが、地道にコマンドから教えている、と回答いただき、熱心に取り組んでいるんだなぁと感じました。

他にも、QA活動の一環として、開発の状況を把握するため、ミーティングに参加しまくっているそうです。 これについて、私はできていないなと反省しました。

軽量なローカル環境を持てるようにすることについての意義について、とても参考になりました。 定量的な成果(1週間〜3日)が出たことは素晴らしいのはもちろんですが、副次的な効果として、テスト担当者のドメインに対する習熟が促進され解像度が上がることも、品質活動に関して良い効果を生んでいるのではないかと思いました。 その結果として、より早い段階で不具合を検出でき、より具体的なフィードバックを行えるようになり、リリースサイクルの短縮にも寄与していると思います。 しかし、そのようなサイクルを回すには、QAエンジニア側も多くの負担を強いられるので、完全な形で実現するために色々考えて実施していかないとダメなんだろうなぁと感心しました。


結合テストの自動化にQAはどうかかわっていったか

speakerdeck.com

続けて、サイボウズさんのテストの自動化に関する取り組みに関する講演を聞きました。 UIテストよりE2Eテストの優先度を上げ、自動化の普及に取り組んでいるそうです。 APIテストのオーナーが開発チームにある場合、テストをどのように設計したら良いのかわからないそうです。 逆にオーナーがテストチームにある場合、修正に膨大な時間が取られます。 その場合、開発チームはテストが壊れることにあまり意識が向かなくなるようで、DevOpsチーム全体でAPIテストのオーナーシップを持たなければならないと言っていました。 DevOpsチーム全体でオーナーシップを持つことにより、問題が発覚するまでの時間が短くなり、開発者がテストを壊すことに意識が向くようになるそうです。 結果的にフィードバックループが速く回転することにより、全体としての負荷が下がったそうです。

テスト計画にも問題があったそうです。 テストの観点や背景が、暗黙知が働いていて曖昧になっていたようです。 このテストで何を評価したいのか?、このテストでやるべきなのか?、などの議論がなかなか進まなかったそうです。 QAメンバーもテスト項目の言語化スキルが必要と分かり、結果的にQAもより深く目的や観点を考えるきっかけとなり、テストの責務について認識するようになったそうです。 それによって、自動化の設計がしやすくなり、工数も減っていったそうです。 このように、QAと開発者が互いに信頼やリスペクト意識を持つことにより、より質の高いテストコードの設計ができるようになったそうです。

素晴らしい取り組みだと思いましたが、QAと開発の相互理解が肝となり、長い時間をかけて今の状況を作り上げたのではないかと感じました。 私は開発者なので、どうしても開発者目線でQAチームを見てしまうことがあるのですが、暗黙知が働いたテスト計画書を見た覚えはあります。 目的が明確でないと自動化の設計がとても複雑になり、冗長な設計になり、結果的に自動化することによって逆に負荷が高くなってしまいます。 QAと開発者が互いに尊重しあい、前向きに議論できる関係性が構築できれば質の高い自動テストが実現できる事例を紹介いただき、大変参考になりました。


終わりに、 JaSST'23 Tokyo に参加してみて、開発チームとテストチームは互いに尊重しあう文化作りが大切だなと改めて実感しました。 テスターからの不具合報告に「バグ」というキーワードを織り込んではいけないとかはよく耳にしますが、テストチームからの過度なへりくだった対応もあまり良い効果を生まないような気がします。 逆に開発チームがテストを破壊することに無関心でいることも、良い結果を生みません。 現在、テストの自動化に取り組んでいますが、ツールの検証や実装だけでなく、組織の文化的な側面にもアプローチしていかなければならないと感じました。

自動化は界王拳の夢をみるか

この記事は、 Kyash Advent Calendar 2022 の8日目の記事です。

adventar.org

 久々のブログ投稿となります。肌寒い日が続きますね。
今年、2022年11月、Kyashの仲間に加えてもらいました。Software Engineer in Test(SET)という役割で声をかけていただき、ソフトウェアテストに関する自動化を推進するポジションとして、1ヶ月程度、過ごしております。

 私は40歳の大台に差し掛かる今まで、ソフトウェアエンジニアとして主にバックエンドの開発に勤しんできました。もうかれこれ15年程度はこの業界で働いていて、荒波にのまれながらあれやこれや担当していたので、サーバー開発だけでなく、データ基盤やモバイル開、技術責任者なんかも経験してきましたが、私の主戦場はバックエンド(サーバー)開発だと自認しています。
 そんな中、今回、Software Engineer in Test(SET)という、少し毛色の変わったロールに挑戦しております。過去に脆弱性診断士としてセキュリティ診断を行っていたことや、品質向上のためにテストの自動化に取り組んでいたこと、JSTQB資格の取得などを評価いただいて、現在に至ります。
 入社してからまだ1ヶ月で、まだまだ成果と言えるような結果を出せているわけではないですが、今回は、今まで取り組んできたこと、これからKyashで、どのようにソフトウェアテストに取り組んでいきたいのかを書きたいと思います。


 Kyashは、資金移動業ライセンスを取得しており、お客様の大切なお金に関わるシステムを提供しているFintech企業なので、品質にかけるコストについて重要視しています。入社前に id:konifar さんや id:ymzkmct さんから、現状のQAについて、予めお話を伺っていたのですが、入社後、QAチームメンバーとコミュニケーションを取らせてもらって、改めて、想像以上にしっかりとテスト活動に取り組んでいるんだなと感じました。
 Kyashの開発サイクルでは、エンジニアチームが要件定義や実装を進めていく段階で、QAメンバーもテスト計画を立て、開発が終わったらマニュアル(手動)によるテストを実施し、品質の担保を維持しています。Kyashはモバイルアプリ中心のサービスであるため、どうしてもマニュアルテストでなければテスト実施できなかったこともあって、かなりの時間をかけてテストしています。
 しかし、サービスを開始してから5年程度経過し、多くの機能が実装され、中でもリグレッション(回帰)テストにかかる時間が増えてきたため、リリーススケジュールに影響するようになってきてしまいました。そこで、モバイルアプリのリグレッションテストの自動化を実現するため、様々な可能性を模索している段階です。

 現在、Webサービスのテストについて、多くのソリューションが提供されており、また、品質を重視する組織が増えてきたこともあり、E2Eやリグレッションテストの自動化率が上がってきているのではないかと思います。また、クラウドベースのインフラ環境を構築している組織も増え、テスト実施の素地を整えやすい環境になってきたことも、ソフトウェアテストの自動化を後押しする要因の1つかなと考えています。
 しかし、広く普及している便利なソフトウェアサービスは、モバイル端末で操作するものが多く、ブラウザ操作によるテストではなく、アプリ操作によるテストを行わなければならない場面も多いと思います。Kyashはまさに、アプリ操作がメインのサービスであり、自動化がしづらく、テスト工数の肥大化に悩まされています。

 Kyashでは、新しく追加した機能が正しく利用できるかの観点でテストシナリオを設計し、テスト計画に落とし込んでから機能テストを実施しています。その後、プログラムの変更に伴ったシステムへの予想外の影響が起きていないかを確認するために、リグレッションテストを実施しています。Kyashのシステムテストを長く担当してくれているメンバーによる探索的テストも実施しているため、広範囲に渡って不具合への対策が行われています。

 一方で、ソフトウェアテストチームが正しく機能していると感じましたが、開発チームは今どきなスクラムを実践できているのに、テストはウォーターフォールのまま置き去りにされていないかと感じました。ソフトウェアテスト下流工程のようになっていやしないかと。。
 とはいえ、それはKyashだけではなく、ソフトウェアテストにおいては往々として起こることであり、また、開発とテストのトレードオフ的な関係性を解消できている方が稀だと思います。重厚なテスト活動を行えば、開発期間が短くなるし、テスト活動を軽視すれば品質に問題が出るし・・・とか言うありがちな問題です。

 id:konifar さんや id:ymzkmct さんとお話したとき、決済事業者としての高い品質を保ったまま、効率的にソフトウェアテストを行うことにより、生産力の爆上げを両立したいと聞いたとき、正直、難しい課題だなと感じました。

blog.kyash.co

 決済事業者として、1円の間違いやミスも許されないドメインを扱っているので、テスト活動を軽視してよいわけがありません。ただ、Kyashは決済システムを0から自社で作ってきたという自負のある会社です。極めて作ることにこだわりがある組織なので、もしかしたら、培ってきた技術力を活かして、生産性の爆上げと高品質を両立できるのではないかと思い、入社を決めました。


 テスト活動の自動化において、KyashではAutify for Mobileを利用させていただいています。

autify.com

 Autify for Mobile の良いところは、テストコードを書かなくても、モバイルアプリ操作の自動化を実現できる点です。初めてテストプランを作成したとき、ブラウザ操作だけで、エミュレーターが起動し、テストシナリオが作成できたときは、「モバイルアプリのテスト自動化もここまで来たか!」と感動しました。
 Kyashでは、Pull Requestがマージされたとき、GitHub Actionsでアプリをアップロードし、テストプランを起動するように設定していましたが、度々、テストが失敗するケースがありました。テストが失敗する理由は様々ですが、Pull Requestをベースにテストシナリオを起動していては、シナリオを修正する契機が開発者に依存してしまい、テスターがテストを修正する機会が少なくなり、テストの精度がなかなか上がらないと考えたため、定期的にテストシナリオを起動するようにしました。
 Autify for Mobile では、定期実行する機能は提供されていませんが、テストプランを起動するAPIが提供されているので、これを利用して、平日2時間ごとにテストプランを起動するようにしました。

 Autify for Mobileのアカウント設定から、パーソナルアクセストークンを取得します。

 今回は、お手軽に定期実行したかったので、Google App Scriptを利用しましたが、以下のPOSTリクエストが実行できればどのような環境でも動きます。

curl -X 'POST' \
  'https://mobile-app.autify.com/api/v1/test_plans/xxxxx/test_plan_results' \
  -H "Authorization: Bearer 1234567890abc" \
  -H 'accept: application/json' \
  -H 'Content-Type: application/json' \
  -d '{
  "build_id": "xxyyzz"
}'

 そして、POSTリクエストに成功したら、以下のようなjsonが戻ってきます。起動したことを通知してほしかったので、SlackのIncomming Webhookにjsonの内容を投稿しています。

{
  "id": "abcdef",
  "test_plan": {
    "id": "xxxxx",
    "name": "Autify Test Plans",
    "created_at": "2022-11-01T01:32:42.999Z",
    "updated_at": "2022-11-05T01:54:18.999Z",
    "build": {
      "id": "xxyyzz",
      "name": "app.build",
      "version": "0.0.1",
      "created_at": "2022-11-29T09:04:56.999Z",
      "updated_at": "2022-11-29T09:04:57.999Z"
    },
    "execute_environments": [
      {
        "os": "iOS",
        "os_version": "14.4",
        "device": "iPhone 12"
      }
    ]
  }
}

 起動後、Autify for Mobileのテスト結果ページに実行中のテストプランが表示されます。今まで作ってきたテストプランの実行が終わるのに、だいたい1時間から2時間弱かかっています。
 Autifyには、テスト実行が終わったらSlackに通知する仕組みもあり、テスト実行が終わったら通知してくれます。

 このように、テスト実行回数を増やし、テストシナリオの精度を上げる取り組みを実施しています。


 Kyashでは、テスト自動化の取り組みを始めたばかりなので、Autifyのような自動化を始めやすいサービスから導入を進めています。自動テストは壊れやすいため、オートヒーリング機能についても期待しています。
 しかし、全てをAutifyで自動化できるとは考えておらず、AppiumやSeleniumなどのテスティングフレームワークを使ったテストコードの整備を行い、網羅率とテスト精度を上げていく取り組みを行っていきたいと考えています。

 また、アジャイル開発にテスト活動を組み入れたいと考えており、スプリントの最後にテストをするのではなく、スプリントサイクルにどのようにテストサイクルを組み込んでいくのがチームとしてベストなのか模索していきたいと考えています。

 Kyashは様々なサービスと連携しているため、テスト環境の整備や運用についても、テストエンジニアが率先して取り組んでいく予定です。それは、いついかなるタイミングでテストを実行しても、正しいテスト結果(正誤問わず)を返せる冪等性を担保した環境を整備することにより、開発サイクルを高速化できると考えているからです。いつでもどこでも正しくテストできる事により、Kyash Tech Teamが掲げる3倍界王拳の実現をテストエンジニアから後押ししていきたいと考えています。

 Webやアプリ開発の様々な技術を駆使して、ソフトウェアテストに取り組み、QuarityをEngineeringしていきたいと考えています。それはもしかしたら、QAエンジニアとか開発エンジニアという枠組みを取っ払い、すべてのKyashのエンジニアがソフトウェアテストの自動化や精度向上に関わる活動を行うマインドセットを持った組織になる未来が訪れることを意味するのかもしれません。

 Kyashでは、ソフトウェアテストの自動化を始め、様々な職種で仲間を募集しています。少しでも興味がございましたら、カジュアル面談でのご連絡もお待ちしております!

herp.careers

Debianの言語設定を変更した

unionsep.hatenablog.com

前にDebianのLocal timeをJSTに変えたんですが、そういえば、言語設定が英語のままだな〜と思ってました。 Amazon Linuxで言語設定変えたけど、これ、言語設定と共にやっといてもええかな〜と思ったんで、メモします。

unionsep.hatenablog.com

OSは Debian 10

$ cat /etc/os-release
PRETTY_NAME="Debian GNU/Linux 10 (buster)"
NAME="Debian GNU/Linux"
VERSION_ID="10"
VERSION="10 (buster)"
VERSION_CODENAME=buster
ID=debian
HOME_URL="https://www.debian.org/"
SUPPORT_URL="https://www.debian.org/support"
BUG_REPORT_URL="https://bugs.debian.org/"

こういう感じで英語な感じのレスポンス

$ ll
-bash: ll: command not found

日本語のパッケージがインストールされてなかったんで追加

$ sudo apt install task-japanese locales-all

ロケールを変更するには localectl コマンド これで /etc/default/localeja_JP.UTF-8 に変わった

$ sudo localectl set-locale LANG=ja_JP.UTF-8 LANGUAGE="ja_JP:ja"

変えた設定を適用する

$ source /etc/default/locale

日本語が返ってきたっす

$ ll
-bash: ll: コマンドが見つかりません

Ubuntu立てるときに、はじめにやることの大体のアレ

AWSでもGCPでもどんなクラウドでも、もしくはクライアントPCでUbuntuをインストールしてなんかするときに、ワイが大体やることをまとめたかったのでメモ書き。 いつも大体やってるんだけど、ほとんどあのコマンドなんやっけ?とかなって調べて「あぁそうやったわ」ってなるのがいい加減面倒くさくなったので。。

  • OSは以下
    今回は訳合って Ubuntu 20.04 。 書いた時点で最新のLTSである 22.04 が良かったんだけど、MongoDBがうまく対応してなかったかなんかで一個前のLTSを採用した。
$ cat /etc/os-release
NAME="Ubuntu"
VERSION="20.04.4 LTS (Focal Fossa)"
ID=ubuntu
ID_LIKE=debian
PRETTY_NAME="Ubuntu 20.04.4 LTS"
VERSION_ID="20.04"
HOME_URL="https://www.ubuntu.com/"
SUPPORT_URL="https://help.ubuntu.com/"
BUG_REPORT_URL="https://bugs.launchpad.net/ubuntu/"
PRIVACY_POLICY_URL="https://www.ubuntu.com/legal/terms-and-policies/privacy-policy"
VERSION_CODENAME=focal
UBUNTU_CODENAME=focal
  • rootになる
    初期設定はroot作業が多いので、面倒くさいからrootで作業してる。 sudoでやったほうがいいけど、まぁ、これだけだしそんなにセキュリティがちがちじゃなくてもいいかな。
$ sudo -s
  • aptのアップグレードとアップデート
    AWSUbuntu作ったら source.listリポジトリap-northeast-1 のミラーを見てるみたいなで、それをそのまま利用させてもらう。 クライアントPCとかでデスクトップとして使うとかの用途なら、どこかの大学とかが公開してるミラーサイトに変更する。
# apt upgrade
Reading package lists... Done
Building dependency tree
Reading state information... Done
Calculating upgrade... Done
The following NEW packages will be installed:
  linux-aws-5.15-headers-5.15.0-1017 linux-headers-5.15.0-1017-aws linux-image-5.15.0-1017-aws linux-modules-5.15.0-1017-aws
...
# apt update
Hit:1 http://ap-northeast-1.ec2.archive.ubuntu.com/ubuntu focal InRelease
...
  • 時間合わせる
    過去に記事にしたけど、とっちらかっるのが嫌なのでリンクと内容書いとく unionsep.hatenablog.com
# timedatectl
               Local time: Wed 2022-08-17 02:39:47 UTC
           Universal time: Wed 2022-08-17 02:39:47 UTC
                 RTC time: Wed 2022-08-17 02:39:46
                Time zone: Etc/UTC (UTC, +0000)
System clock synchronized: yes
              NTP service: active
          RTC in local TZ: no
# timedatectl list-timezones|grep Tokyo
Asia/Tokyo
# timedatectl set-timezone Asia/Tokyo
# date
Wed Aug 17 11:40:38 JST 2022
  • 日本語にしたいな
    英語( us )のままでも別にいいんだけど、マニュアル( man )は日本語のほうが緊急時に助かったりするので、日本語にする。
# localectl status
   System Locale: LANG=C.UTF-8
       VC Keymap: n/a
      X11 Layout: us
       X11 Model: pc105
# localectl list-locales
C.UTF-8
en_US.UTF-8
# apt install language-pack-ja -y
Reading package lists... Done
Building dependency tree
Reading state information... Done
...
# localectl list-locales
C.UTF-8
en_US.UTF-8
ja_JP.UTF-8
# localectl set-locale LANG=ja_JP.UTF-8
  • ホスト名変えたいな
    AWSだとプライベートIPを含む名前になるみたいなんだけど、管理サーバが多くなってきて脳みその切り替えのコストがしんどくなってきたんでわかり易い名前に変更してます。
# hostnamectl
   Static hostname: ip-xxx-xxx-xxx-xxx
         Icon name: computer-vm
           Chassis: vm
        Machine ID: aaaaa
           Boot ID: bbbbb
    Virtualization: kvm
  Operating System: Ubuntu 20.04.4 LTS
            Kernel: Linux 5.13.0-1029-aws
      Architecture: x86-64
# hostnamectl set-hostname XXXXX
  • ここで一旦再起動
    ロケール変えたりホスト名変えたけど、リブートしないと反映されないっぽいので、一旦このタイミングで再起動してる。
# reboot
  • マニュアルを日本語にする
    ゆっくり英語のマニュアルを読むのはいいんだけど、急いでるときはちょっとしんどいんで man は日本語にしておく
# apt install manpages-ja
パッケージリストを読み込んでいます... 完了
依存関係ツリーを作成しています
状態情報を読み取っています... 完了
以下のパッケージが新たにインストールされます:
  manpages-ja
アップグレード: 0 個、新規インストール: 1 個、削除: 0 個、保留: 0 個。
...
# apt install manpages-ja-dev
パッケージリストを読み込んでいます... 完了
依存関係ツリーを作成しています
状態情報を読み取っています... 完了
以下のパッケージが新たにインストールされます:
  manpages-ja-dev
アップグレード: 0 個、新規インストール: 1 個、削除: 0 個、保留: 0 個。
...
  • visudoのエディタを変える
    visudoのエディタが nano であんまり慣れてないから vim.tiny に変える。 選択肢の4番を指定する。
# update-alternatives --config editor
There are 4 choices for the alternative editor (providing /usr/bin/editor).

  Selection    Path                Priority   Status
------------------------------------------------------------
* 0            /bin/nano            40        auto mode
  1            /bin/ed             -100       manual mode
  2            /bin/nano            40        manual mode
  3            /usr/bin/vim.basic   30        manual mode
  4            /usr/bin/vim.tiny    15        manual mode
  • ユーザを追加
    ユーザ作ってから、 visudo を使ってパスワードなしで sudo できる権限をつける。
# adduser unionsep --disabled-password
Adding user `unionsep' ...
Adding new group `unionsep' (1001) ...
Adding new user `unionsep' (1001) with group `unionsep' ...
Creating home directory `/home/unionsep' ...
Copying files from `/etc/skel' ...
Changing the user information for unionsep
Enter the new value, or press ENTER for the default
   Full Name []:
   Room Number []:
   Work Phone []:
   Home Phone []:
   Other []:
Is the information correct? [Y/n] Y
  • 追加したユーザに sudo できるようにする
    visudo で開いた /etc/sudoers.tmp に以下追加
# visudo
unionsep ALL=NOPASSWD: ALL
  • 作ったユーザがkeypairでログインできるようにしてる
    AWSでは、ubuntu というデフォルトのユーザが作成され、インスタンス生成時にこのユーザに独自の keypair を設定してる。 各々のユーザに keypair を作って各々のインスタンスに配布したいのだけど、Bastionに入れるユーザがワイしかいないので、コピーしてる・・・
# cp -r /home/ubuntu/.ssh /home/unionsep/
# chown -R unionsep:unionsep /home/unionsep/.ssh

その他、 ll コマンドなんかの alias や、 LSCOLORSls コマンドの色つけたりするけど、Ubuntuはすでにできてるのでやらない。 作ったインスタンスはAMIとかにしておくんだけど、AMIって課金対象だったりするので、あんまり作ってないなぁ。 Ansibleで構成管理したりしたらコマンド一発だしね。。

こんな感じで作ったインスタンスnode やら java やら elasticsearch やらなんやかんや入れて構築したりしてる感じ。

では〜

あれ?iTerm2でコピーできんくなった

いつの日か、iTerm上で文字列を選択しても、コピーできんくなった。。
いや、あれ?このインスタンスだとできるけど、これだとできんなぁ。。みたいな感じだったので、まぁ、ついてないだけやろって思ってたけど、いやもうムリコレーってなったんで、雑にググったらこちらのページに行き着きました。

gozuk16.hatenablog.com

ありがとうございます、助かりました!
なんかvi起動したときの、 visual mode でよく起きるわぁ〜とか思ってたらその通りでございました。
重複になりますが、僕もウェブに残しておきます 🙇‍♂️

  • Preferences > Profile > Terminal > Terminal Emulation
    • Enable mouse reporting のチェック外す

Amazon LinuxのタイムゾーンをUTCからJSTに変える

Amazon Linux(2ではない)を選択してインスタンスを立てたらタイムゾーンUTCだったのでJSTに変更しました。

  • OSを確認
    CentOSってイメージだったけど、 rhel fedora ってなってるってことは、必ずしもCentOSと一緒ってことではなさそうなんすね。
$ cat /etc/os-release
NAME="Amazon Linux AMI"
VERSION="2018.03"
ID="amzn"
ID_LIKE="rhel fedora"
VERSION_ID="2018.03"
PRETTY_NAME="Amazon Linux AMI 2018.03"
ANSI_COLOR="0;33"
CPE_NAME="cpe:/o:amazon:linux:2018.03:ga"
HOME_URL="http://aws.amazon.com/amazon-linux-ami/"
  • 時間を確認
    うん、9時間ずれてる。
$ date
202078日 水曜日 02:23:56 UTC
  • /etc/sysconfig/clock を修正
$ sudo vi /etc/sysconfig/clock
#ZONE="UTC"
ZONE="Asia/Tokyo"
UTC=true
sudo ln -sf /usr/share/zoneinfo/Asia/Tokyo /etc/localtime
  • 時間を確認
    9時間戻った。
$ date
202078日 水曜日 11:41:30 JST
  • crondを再起動
    Amazon Linux(2ではない)は、 systemctl が入ってなかったので、 service コマンドで再起動すれば良さそう。
$ sudo service crond restart
Stopping crond:                                            [  OK  ]
Starting crond:                                            [  OK  ]