00:00
国分さん、前回、単体テストについてお聞きしたかなと思うんですけど、
単体テストって、単体テストが書きづらかったら、
設計の良し悪しが分かるみたいな、設計が悪いんじゃないか、みたいなスメールが分かるんじゃないかっていうところだったんですけど、
テストって、ただ単体テストだけじゃないじゃないですか。
結合テストとか、エンドツーエンドテストとか、あとは手動も含めると、急エンドテストとかもあるかなと思うんですけど、
これって、どこまでをテストで担保すれば、我々エンジニアは安心できるんですかね。
テストしようと思えば、どこまででもできてしまって、終わりが見えないかなと思ってまして。
はい。それでは結構コツが一個あってですね、いろいろなバグがありますよね。
例えば画面の表示崩れとか、計算ロジックのミスとか、いろんなバグがあると思うんですけど、
いろんなバグを考えて、それ一つ一つのバグを一番早く見つける動作確認フローを意識しようっていうところが大事だと思います。
バグを見つけることが一番の目的であるってことですかね。テスト全般に関して。
そう、ただ一番早くっていうのが一番大事なんですね。これはどういうことかっていうと、
例えばバグって、さっき言った画面の表示崩れっていうのは、画面まで実装しないとわからないことですよね。
そうじゃなくて、例えばロジックのミスとかってのはサーバー側とかで返ってくるレスポンスがおかしいってことで見つかったりとか、
あるいはもっとクラスとかの単体テストで見つかったりするっていうことは、
その単体テストで見つかってたロジックのバグっていうのを、画面とかのエンドツーエンドテストで見つけるっていうのは損なわけですよ。
なぜかというと、もっと早く見つけられたと。バグってもっと早く見つければ見つけられるほど、
修正コストとゲイン究明コストが安いってことが経験的に知られてますから、あるべく早く見つけるってことがすごく大事なわけですね。
それは開発フローというか、開発サイクル的に早く見つけて、手戻り少なくしようというようなお話ってことですかね。
そうです。特に開発者が意識すべきなのは、いろんな層、多層防御が大事なんですね。
セキュリティと同じなんです。セキュリティもよく一つのセキュリティアプライアンスで防御しようとするなと。
いろんな層で防御するんだってことをよく言いますけど、それと同じでバグもいろんな層で防御しようっていうことなんですね。
例えば、リントってありますよね。リントにかけると、例えばファンクションをファンティオンって書いちゃったとか、そうもないバグっていうのは見つかるわけですよ。
リントすると構文解析失敗しますって出てくる。それは単体テストとか結合テスト、エンドツールテストしなくてもわかることなので、それはリントで見つけたいんですね。
あとは、リントじゃ見つからないものってあるわけですよ。例えば、足し算するんだけど、足し算で多数変数間違えちゃったっていうのはリントじゃわかんないですよね。
これは単体テストじゃないとわかんない。単体テストでわかるんだけど結合テストでわかんないもの。
あ、じゃあ逆か。単体テストでわからないんだけど結合テストでわかることっていうのもあって、それぞれの単体テストは成功してる。
だけど組み合わせるとバグるみたいなのもあって、そういうのは結合テストじゃないですか。こんな風にいろいろなバグっていうのがあって、いろいろな一番早く見つけられるポイントっていうのがあるっていう感じですね。
03:02
それでいろんなバグを想定して、いろんなバグを一番早く見つけるように、どれだけ防御の層を組み立てられるかっていうことが動作確認フローを意識しようってことの本質ですね。
なるほど。じゃあそれぞれテストの項目ごとに、項目というか層なんですかね。今言った話だと。
層ごとに目的意識を持って、ここではこういったものを見つけたい。例えばUIのところだったら、UI周りのバグをできる限り早く見つけるみたいなことが意識できていることの方が一番重要っていうことですかね。
そうです。で、すごく大事なのが、あるテストで、例えば本当は結合テストじゃないと見つからないとか、エンドツーのテストじゃないと見つからないっていうものを単体テストで見つけようと頑張りすぎちゃうことってあるんですよ、時々。
それは損なんですよね。それはすごく損で、大抵は無茶をするので単体テストの良いところが失われちゃうことが多いんですよ。例えば結合テストって遅くて不安定ってよく言われますよね。
それはいろんなものをガッチャンコするからいろんなところに変更が入って、そうすると結果的に壊れやすくなっちゃう。でも単体テストは一つしか扱ってないから壊れるより良いって一つですよねっていうのがあって、
そうすると単体テストの良いところって早くて壊れにくいってところだったのに、それを結合テストみたいにいろいろモリモリ紙単体テストみたいにしちゃうと遅くなっていくし、何より複数のリードで壊れちゃう。脆弱なテストになっちゃうんですよね。
なので単体テストの良さを殺しちゃうっていうのがあって、なのでテストをするんだけど、テストはここで十分自然にカバーできる範囲だけを意識しようみたいなところがやっぱ大事で、
それを自然にカバーできる範囲のこの層ではこの層自然にカバーできる、この層ではこれを自然にカバーできるってこういうふうに組み立てていって、突き抜けるものがあんまないねっていう風になったらOKです。
なるほど、その層ごとにまあやっぱり適切な範囲を設定してテストをして、テストの項目を決めていきましょうという話かなと思うんですけど、その領域でどうやって決めていくんですかね。
多分間があると思うんですよね。ここからここはこの層みたいな感じで決めるかなと思うんですけど。
えっとそれはですね、どうしようかな。いい方法があるんですが、またちょっと話しちゃおう。
私が今から説明する方法はODC分析って呼ばれるもの、直行欠陥分類法みたいな感じの日本語訳が当たるんですけど、っていうのをちょっとこれから話しますね。
これは皆さんがそれぞれどんな層があるのかってことを意識しなくてもできる方法、結構ボトムアップにできる方法なんで、これをちょっと先に紹介しようと思います。
皆さんが開発をしているとバグ必ず見つけますよね。そしたらバグをデータベースに入れましょう。データベースってマイスキルとかに入れるとかって意味じゃなくて、
XMシートとか何でもいいんで、バグチケット、バグトラッキングシステム何でもいいんで、一旦入れましょう。
メモを取るということですね。
メモを取るということです。記録を取るということですね。記録を取った後に、それぞれについていくつか属性を割り当てるんですね。
06:00
ODC分析だと4つ属性があって、このうち一番大事なのがトリガーって呼ばれてるもので、これって本来どこで見つかるべきものだったのってことを考えるわけです。
例えばさっきのファンクションをファンティオンって書いちゃってバグチケットになっちゃいました、エンドツアーのテストで見つかりましたってなったら、
いやいやいやってなるわけですよ。それリントで見つかったじゃんってなるんですね。
っていう風に何かバグを見つけた時にさ、これリントで見つけらんない?ちょっとリント探してみるよとか、これ3体テストで見つかったんじゃない?3体テストで見つけようよっていう風に一個一個バグについて一番早く見つけられる段階はどこかってことを特定するってことを繰り返すわけですね。
そうしていくと自然に多層的な防御になってくるわけです。
なるほど、じゃあ何かが起きた時、バグを発見した時にそれを一回メモして振り返ってみて、それが一番最適に見つかる場所はどこなのかというところを後からちょっと学習しましょうねというところなんですね。
そうですね、それが一番積み上げができて知識が少なくできるいい方法かなと思っています。
確かにわかりやすくありますね。
ODC分析以外にはやっぱりいろいろあって、他の人のワークフローを勉強するっていうのも一つの手ですね。
例えばオープンソースソフトウェアとかでCIとかが組まれてたりするのよく見ると思うんですよ。
CIが組まれてる時に、CIだとちょっと手元のところはちょっと見えないんだけど、プッシュするまでは見えないんだけど、プッシュした後にどういうワークフローが組まれてるかっていうのはオープンソースのやつすべてわかるわけですね。
インターバクションズのワークフローヤムール見ればわかるわけですよ。
そうするとコミットごとにはどういうものが動いて、プルリクエストのマージするかしないかのタイミングで何が動いて、
マスターにマージされたとか、あるいはリリースブランチにマージされたら何が動いて、最終的にマスターブランチとかメインのブランチにマージされた時に何が起こるか、
全部それぞれタイミングごとに動くものが違うはずなんですね。
そうすると、なるほどここにこんなもの入れてた、ここでこんなもの見つけてたのかっていうことが勉強できます。
そうすると引き出しが広がっていいっていう方法もありますね。
なるほど、じゃあ既存のプロジェクトのテストを見た時にどういった層が組まれているのかっていうところの分析をすることで、
より勉強になるというか、自分のプロジェクトの方に生かすことができるっていう話なんですね。
そうですね。
なんか単純にOSSのプロジェクトとか見て、こういうテストがあるんだぐらいまでは誰でも見ればわかるかなと思うんですけど、
そういう層を意識するみたいな話は結構できてる人少ないんじゃないかなと、なんとなく個人的に思ってて。
はい、おっしゃる通りだと思います。ただこれは層が不足しているっていうことを別の声で聞くことが多いですね。
例えば、単体テストに30分かかりますとかっていう現場。
これは圧倒的に層が不足してるわけですよ。
CIを回していて、プッシュの度にCIが回るような環境でそのテストが30分かかりますよという環境。
09:01
これはもう圧倒的にいろいろなことが間違えていて、いくつか工夫していかなきゃいけない点があります。
まずはビルド時間が長いことがありますね、大抵は。
ビルド時間長い問題。例えば言語にもよるんですけど、ラストは長いですね、ゴーは短いですね。
いろいろビルド時間が長いってなるんだけど、ただビルド時間って実はビルドする単位によって決まりますよね。
例えば、一つのパッケージの中にめちゃくちゃいろんなファイルが入っていればめちゃくちゃ遅くなるし、
そうじゃなくて、ちっちゃいパッケージごとに分かれていれば早くなるっていうふうにすることができるわけですよね。
基本的にパッケージを小さくすれば小さくするほど、さっき言った階級ポイントが増えるわけです。
そのパブリッシュのポイントとか、プッシュするポイントとかが増えていくっていうのがあって、
そして単体テストの流度っていうのが小さくなるので早くなるってくるわけですね。
なので小さなテストに切り分けてそこでだけ動かすってことを分割してやっていくとできるようになるわけですよ。
そういうふうにすると単体テストの30分かかるって一つの巨大なものにするな単体テストから、
それぞれ小さな高速に完了する小さなテスト、しかも変更した部分だけが動くってことが大抵できますから、
ってことができるようになって高速化するっていうのがあります。
これはコンパイルの層を早くするっていうのと同時にその単体テストの層も早くしていて、
っていうふうなことを工夫をしています。
これ自体は分割の工夫だったりはするんですけど、層の工夫っていうと、
あとは単体テストってリントで見つかるべき問題が見つかってないかみたいのを意識するってのは結構大事ですね。
もうちょっと静的に解析したときに発見できるものがあるんじゃないかというところを、
既存の単体テストのところから振り返ってみてみるっていうところですかね。
そうですね。例えばRubyとかPerlとかPythonとか書いてるときに、
未宣言の変数参照しなくて落ちるってことがよくあると思うんですよ。
Rubyだとニルになるのかな。でもそういうふうに落とすちょっとモードとかある気がするんですけど、
そういうときに単体テストでそれが発見されました、発見されたことは喜ばしいがってなるわけですよ。
それはリントでわかるよねっていう話なので、そういうのとかはリントで見つけようっていうことを言っていくことが大事なわけですね。
今聞いてる限りだとテスト、広い意味でのテスト、単体テストだけではなくて全体のテストにおいても、
やはり設計というかテストの設計というか戦略かもしれないですけど、
テストをしていくということに関して全体感を持った戦略設計が必要になってくるのかなと思ったんですけど、そうなんですかね。
おっしゃる通りで、大雑把に言うとテストの設計では数量に関するものっていうのがよく知られていますね。
例えば単体テストはこれくらい、結合テストはこれくらいっていう数量の大きさの関係についての経験則というかベストプラクティスが知られていて、
よくテストピラミッドっていうふうな言い方をします。
テストピラミッドどういう、それもそうなんですかね。
12:01
これもそうです。ピラミッドはそうなっていて、一番下はよく典型的には単体テストっていうのが書かれていて、
単体テストはここでは要するに前に言った通り関節入出力をモックするようなテストだと思ってください。
これがピラミッドの一番下にあります。
真ん中には結合テストがあって、一番上のピラミッドのキーストーンのところにはエンドツールのテストがあって、
これは何を表しているかというと、この面積の大きさがそれぞれのテストの量がどうあるべきかってことを伝えているんですね。
なるほど、どのぐらいの、まああれか、だから仮想の方がテストの量としては多いべきであるということなんですね。
じゃあ単体テストが一番多くあるべきだし、もしかしたらその下にリントのルールみたいなものがもしかしたらあるかもしれない。
そうです、リントとか口文ハイライトの層がありますね。
なるほど、じゃあそういったものを意識して、最終的にはあれなんですかね、ちょっと違うかもしれないんですけど、
QAテストのテスト項目っていうのは一番ちっちゃくなるべきなんですかね、それという。
そうですね、おっしゃる通りです。本当は一番ちっちゃくなるべきです。
例えばもうちょっとここには少し難しいものがあって、今言ったそのテストピラミッドのテストって何を検証してるかっていうと全部機能要件なんですよね。
機能がこうあるべきだってことだけを測っている。
確かに。
だけど本来そのQAのテストっていうのは機能要件だけじゃなくて、ユーザーアビリティとかの見つけたりとかもしますね。
例えば、なんか今一瞬チラッて変なの映ったんだけどっていうのはテストだとなかなか見つけられないんですけど、
人間だとやっぱりちょっと分かるとか、あとはなんかこのボタン押し心地よくないですね。
押したのか押せたのか押せてないのかよくわかんないで、22回押しておりましたみたいなとかっていうのも本当は見つけてほしいので、
これはやっぱ単体テストとかエンドチェーンのテストで見つからない。
そういう意味だと、そういうテストはそれはそれとしてあるべきなので、このピラミッドの数量関係とは別にあるべきなんですけど、
ただその機能に絞ったQAっていうふうな意味で言うと、エンドチェーンテストよりも少ないべきでしょう。
いうふうに私は考えています。
さっきの話だとちょっと自分の中で腑に落ちたところが1個あって、QAテストですね。
QAテストでテストケースいろんなものを用意するかなと思うんですけど、
それが機能要件のテストケースと機能要件、UXだったり、ボタンの押し心地がいいかとか、速度がちゃんと出ているかどうかとか、
そういったところのテストケースっていうのは別々で管理して別々で実施していく方がいいんじゃないかなと思ったんですけど、そういうもんなんですかね。
そういうもんだと思いますね。UXのテストを除いて、その非機能の中には性能とかも入っていて、
性能のテストってのは機能要件のテスト終わってからじゃないと無駄が多いんですよね。
あんまり同じタイミングでは実施できないし、同じテストケースも利用できないしっていうのがあるので、
それを暴けた方がおそらく得だろうと思います。
なるほど、じゃあフェーズが違うってことなのかもしれないですね。
さっき言ったテストピラミッドの一番頂点としてテストケース、機能要件のテストケースのQAがあって、
15:06
それとはまた別フェーズなのか、ワークフローによると思うんですけど、
そこで並列化なんかで機能要件のQAも行われてるみたいなのが理想ではありそうって感じですかね。
そうですね。ただ一つだけ言えることはUI UXのテストはもっと早く見つけられるんですよ。
なるほど。
これはどうしてかっていうとUI UXのテストってFigmaのプロトタイプモードとかあるじゃないですか。
じゃあペーパープロトタイプみたいな。
そうですそうです。あそこで多くのことはユーザビティの問題はわかるわけです。
実際触らせてみると今ユーザー迷ったなとかっていうのはペーパープロットでわかるわけですよ。
なのでペーパープロットの時点でわかることはペーパープロット時点で見つけたいっていうのはありますね。
つまり実装よりもはるか前の時点で見つけたいっていうのはありますね。
それもバグじゃないとは思いますけど、一番早く見つけるっていうところが目的だからこそ、
一番最初に見つけた方が手戻りないよねっていうような目的と合致してるよねっていう話ですね。
そこに関しても。
いや、かなり腑に落ちるなと思うんですけど。
逆にですね、テストを書くっていう時に自分が結構やりがちなのが何か案件があるわけじゃないですか、タスクが。
何か一個あるわけじゃないですか、Aっていうタスクが。
ただその時にAっていうタスクを終わらせる際にですね、全体のテストのこととかって考えてないんですよ。
プロジェクトごとにこういうテストの方針があるよねみたいなのは何となくありつつも、
そのタスクをこなして、それに対するテストがちゃんと書けているかどうかだけなんですよね。
なんかその時に全体を見て、じゃあこの層でこの部分のテストはここに書いてみたいなのをしっかり意識していくことっていうのがやっぱし重要なんですかね。
なんか結構難しいなと思って。
そうですね重要だし難しいなっていうのもすごく同意します。
やり方は大雑把に分けて2つ私は知っているって感じですね。
まず一つ目のやり方は先ほど言った通り、バグっていうのを見つけちゃった後、結構事後的なものですね、レトロスペクティブ的に。
後でこれいつ見つかったんだろうっていうのを見つけて、そこから学習していくっていう経路が一つ。
もう一つあるのが、外側からテストを書いていくっていう方法があります。
外側からって言い方ちょっとわかりづらかったな。ピラミッドの上から書いていくっていう方法があります。
この方式っていうのはエンドツーエンドテストファーストです。
なんかあんまり聞き慣れないワーティング。
聞き慣れないですね。ただこれテスト界隈だとよく議論されるもので、テストケース、これよくTDDの界隈で言われるんですね。
TDDテスト駆動開発っていうのがあって、テストを最初に書こうみたいなプラクティスよく聞きますよね。
これはテスト駆動開発の代表的なプラクティスで、その中には幅違って、なるべく小さな部品、
18:02
例えば計算機ってプログラムを作るときに、1たす1とかって解釈する部分とか計算する部分からテストを書いていってTDDしていって、
いつか育っていくと最終的なテストの塊っていうのが計算機に最適なテストになってるみたいに考えるボトムアップアプローチっていうのと、
最初に計算機ってこうあるよねって、1たす1イコール2ってやったら2って表示されるはずだみたいな、
一番最初のそういう風なテストケースから考えるっていう、一番上から考えるアプローチも結構あるんですよ。
こっち側のアプローチっていうのは私は結構テスト設計には結構有利だなと思っていて、皆さんにちょっとやってみてほしいっていうのがあります。
なんとなく今までやってたTDDって、TDDをちゃんと学んできたわけでもないので、多分我流で自分はやってきちゃってるかなと思うんですけど、
なんとなく今言ってくれた2つの方式、ボトムアップなのかトップダウンなのかなと思うんですけど、ピラミッドの上からいくか下からいくかみたいな話かなと思うんですけど、
下からいってたなと思ってて、いっつも。単体テストのところを書いて、なんとなくそれで動いてるからちょっと満足して、
ちょっとだけ結合テストの部分1個とか2個書いて、よし満足みたいな感じのことを大体やってたなというのを今ふと気づきました。
それを逆からやってみるといいんじゃないっていうような提言ですかね、今。
その通りです。これはすごくメリットがあって、メリットと難しさもあるんですけど、ちょっとそれをお話しします。
メリットはエンドツーエンドテストしやすい設計に必ずなるんですよ。それはそうですよね。最初にテスト書くわけですから、そのテストを通すように設計をしなきゃいけないわけで、
変なローディング画面が挟まった結果エンドツーエンドテストが失敗しましたみたいなことは最初から少なくなるわけです。
それがすごくいいこと。エンドツーエンドテストファーストな設計とか仕様になるってことですね。それはすごくいいことで、
あともう一つはやっぱりボトムアップで組み立てていくと最終的にユーザーにとって嬉しくないみたいな仕様になっているときって周りにあるんですよ。
つまりできるっていうのを積み重ねていったら、最終的になんかできたんだけど、別に嬉しいのライン届いてないみたいな。
エンドツーエンドテストは逆に言うと嬉しいのラインを上から攻めるんですよ。嬉しいっていうのは実現方法は全然わかんない。
実現方法はわかんないんだけど嬉しい、こうあれば嬉しい、こうあれば嬉しいって言って、この下から積み上げているものとこの上から嬉しいっていうのを掘り下げていたものが繋がると
いいプログラクトができたってことになるわけですよね。実現できてかつ嬉しい。これはどっちから攻めてもいいんだけど、私はなんか本当は両方攻めた方がいいんだろうなと思っていて、
エンドツーエンドテストを最初に書くっていうのも大事だし、かといってそれだと実現できないものになっちゃうこともあるから、
実現した下から攻めていって、エンドツーエンドテストを変えていくってこともやっぱり途中で必要になるっていうのもあるかなと思っていて、こういうふうに両方を攻めていって
21:01
できると嬉しいっていうのがくっつくところをうまく探すっていうのがこのTDDの極意なんだろうと思います。
なるほど。どっちかだけじゃなくて、いいバランスでどっちからも攻めていこうっていう話かなと思うんですが、
そうやっていくとなんとなくふと思うのが、ゴミじゃないんだと思うんですけど、不要なテストっていうのもどんどんできていくんじゃないのかなってなんとなく思うんですよ。
例えば過剰なエンドツーエンドテストが一番最初、このタスクはこうあるべきっていうかこういう完了条件だからこういうエンドツーエンドテストを書こう、
こういうパターンもあったからこういうパターンも書こうみたいなので、どんどん過剰になっていった結果、そのタスクがいっぱい終わったときには
いっぱいエンドツーエンドテストもあってすごく重いみたいないうの全然あるなと思ってて、そこらへんの間引きというか、削除することも厭わないほうがいいんですかね、一度書いたテスト。
はい、ここは少し難しい問題で、私はおすすめの方法が一つあります。一つは実行時間順に並べてリスト化して、上の方ほど削除対象になりやすいっていう風にすることです。
長いテストを削除対象とするということですね。
ただ長ければ悪いってわけでもなくて、長いけど高価値なシナリオを保護しているってケースもあるわけですよ。例えばお客様の課金シナリオが長い、テストも10分かかってる。
でもこれは消すわけにはいかないになると思うんですよ。こういうのはあるので、だからリストの上の方に載ってる、つまり実行時間がめちゃくちゃ長いっていうのは
消す対象にはしたいんだけど、直ちに消すわけじゃないっていうのが難しくって、だから上から順に並べてって、これそんな重要じゃないなってなったら、結構上の方にある遅いテストっていうのを消していくと結構ハッピーになるかな。つい最近私もそういうことやってました。
なるほど、じゃあそのタスク内で終わらすわけではなくて、そのタスクをDDDでやっていって、
エンドとエンドテストからとか、あとは単体テストから、上からも下からもどんどん攻めていって、テスト書き換えて、プロダクトというかそのタスクが完了しましたと。
そのタイミングにおいてはそのままでいいけども、その後ですね、コードのリファクタリングみたいな形と一緒でテストの整理っていうのをすべきってことですかね。
そうですね、特にエンドツアーのテストはなかなか消せないんですけど、単体テストのテストケースは私はじゃんじゃん消していいと思っています。
なんでかっていうと、単体テストが保護しているその振る舞いっていうのは簡単に置き換え可能なことが多いんですよね。
前、前回2回の時に、いい設計っていうのは差し替えてすぐに実現できる設計だってことを私は述べたと思うんですけど、
その差し替えられた前の差し替え前のコンポーネントのテストは一体どうなっちゃうんだって話があって、私はこれ全然消しちゃっていいと思ってるんですよ。
24:02
だって使わなくなったわけですから。そういうものはそのコンポーネントと一緒に寿命を終えたって言って消しちゃうっていうのはすごくいいと思います。
だけどそういうふうに中身変えるんだけど、エンドツアーのテストにはなかなか影響を及ばないっていうことは結構よくあるわけで、そういうのは残しておきたいっていうのはありますね。
なるほど。やはり一旦、忙しい時ってタスクがいっぱいある時って、なかなか全体を俯瞰して見る機械って時間取れないかなと思うんですよね。
リファクタリングの時間が取れないみたいな話と大体一緒かなと思うんですけど、ただそういう時こそ一旦立ち止まってテストの設計というか、
今のプロジェクトのテストの在り方としてどうなってるのが一番品質が良いのかだったりとか、そのプロダクトの品質が良くできるのかっていうところを今一度考え直す機械を複数持っていた方がいいよねっていうところですね。
結局のところ。そういうことですね。これももうちょっと一般化すると、AS-ISと2Bの両方を確認しようってことなんですね。
今言ってた現状がどうなってるかの分析ってのは、AS-IS、今私たちはどこに立ってるのかってことを知るわけですよ。テストが遅いな、困ってるなとかってこれが出発点なわけですよね。
そこから2B、例えば何分以内に終わるべきだみたいなことを考えて、その差分を考えるわけですよ。
例えばここら辺の遅いテストが全部一層したら3分になるだろうなってことを考えたりするわけですね。そういう風な差分とかを考えると具体的なちゃんとプランに変わるわけですよ。
なのでやっぱり大事なのはAS-ISを常に確かめて、これは定期的にでいいんですよ。毎日やらなくてもよくて、1週間に1回とか月1回とかでいいんで、定期的にAS-ISを確かめて、2Bもちゃんと見失わない。
これさあ本当は単体で30分とかありえないよねっていう風な2Bを見失わないってことですね。つまりこれ本当は5分ぐらいで終わるべきでしょっていうのが、
5分でも長いですね本当は。ある人は100msだって言ってました。単体で100msで終わるべきだと。
っていう風なぐらい2Bを見失わないのもやっぱり大事なことだと個人的に思ってます。
なるほど。ちょっと具体的な失敗例ではないんですけど、ちょっと最近あったことで、今やってるプロジェクトのテストが遅いと。
2つのCIに分かれてて、片方のCIに寄せたんですけど、最近1つのCIに寄せて。
そしたらちょっと不安定だったりとか、単純に実行時間が遅くなってしまったから、これをどうにか最適化していきたいっていうような話が上がりました。
それ自分がやってたんですけど、やった方法として、単純にメトリクス取って、どこがボトルネックなのか把握して、
で、キャッシュできるところはキャッシュしたりだったりとか、そういう実行の時の整理をしていったみたいな感じなんですよね。
あとはマシンスペックがちょっと足りないところは金で殴るみたいな感じのことをやったんですけど、
27:03
その時にちゃんとテストの中身まで見て、どこが削減できそうかみたいなところまで踏み込んだ方が、
やっぱり今後というか未来においてはより良くなっていくっていうところですね。
そうですね。ただこれは人間がやるのは結構大変だと思っているので、こういうのは私はLintに近いものに任せるといいと思っていて、
Lintの中にはネットコードを見つけるものがあるんですよ。ネットコードっていうのはどこからも使われていないコードっていうことです。
誰からも呼ばれていないような関数だったり、誰からも参照されていないようなグローバル変数だったり、こういうものをネットコードっていうわけですよね。
これは参照関係とか呼び出し関係、コールグラフと呼ばれるものを分析するとすぐに出せるわけですね。これは使われていないと。
ちょっとRubyとかだとインスタンスイーバルとかを使われちゃうと、魔法を使われちゃうと文字列とかで参照されちゃうみたいな、そういうふうな抜け道はあるとはいえ、
結構角度高く使われていないものとかっていうのを出せるので、そういうものを削除する。ついでにテストも消すっていうことをやると、比較的楽にいらないテストを消すってことができるんじゃないかなと思います。
なるほど。テストから参照されてるからそのLintで怒られないみたいなのありがちかなと思うんですけど、それもちゃんと設定すれば把握できるって感じですかね。
これは結構簡単で、語言語とかだとanscotest.goみたいな感じで、そのテストとかテストじゃないかって見分けられるじゃないですか。
Rubyとかの場合はスペックフォルダの中に入ってたりとかするっていうのですぐ見つけられると思うんですけど、それ消してLintをかければいいです。
なるほど。単純にファイルごと消して、一旦消しちゃってってことですね。すごい思いも寄らなかったです。頭いいですね。
なかなか筋力で解決するみたいな感じですけど、確かに合理的。それやったら一番早いですね、確かに。
ありがとうございます。ちなみに時間もいい感じなんですけど、最後に言いたいのがAIですね。
最近AI使ってコードを書かせたりするんですけど、そのプロダクションコードはAIで書かせると。
じゃあテストは人間が書くのか、はたまたそれが逆なのかとか、そういったところ、AIとテストの兼ね合いとかってどう思います?
どっちがどっちになるべきかとかあったりしますか。
まずすごく言えることは、AIはHowを知ってるんだけどWhatは知らないんですよ。だから人間がWhatを伝えなきゃいけないわけですね。
例えばこういう仕様であるべきだとか、お客様がこういうことを喜ぶとかってことはWhatがどうして人間が伝えなきゃいけない。
AIは多分そのWhatを満たしてくれるっぽいものを出してくれるんですけど、それをいちいち確認しなきゃいけないわけですよ。
それをどうやって確認しますかっていう話だと思っていて。なのでAIはHow、つまりそのWhatをプロンプトにして書くと、
ここの仕様を生み出す技術がこうです。ドーンと出してくる。じゃあ確認するかっていちいちポチポチやってたら日が暮れちゃうわけですね。
30:02
なのでテストとかってのを書いてもらって、そのテストっていうのを人間がレビューして、本体実装とか別にどうでもいいですよ。
そのスペースに至る。だからテストのケースを見て、そうそう、こういう入力ってのは大抵見なきゃダメで、この入力ちゃんと見られてるんで、
このケースについては自分のやりたいこと達成してるねとかっていうふうに見るっていうふうに、テストケースをレビューするっていうふうなことにすると結構自立性高く
AIが動き、かつ人間もWhatを見失わないで、ちゃんとそれっぽいものができてるっていうふうなことを追いかけられるのだろうと思っています。
じゃあどちらも人間が書かずにテストケースをちゃんとレビューして、どういう振る舞いが良しとされるかっていうのは人間がちゃんと決断して決めていって、
これが通ればいいよねっていうようなツールとして使うっていうところなんですかね、テストケースを。
まさにそうで、最近私が経験したケースだと、TUIアプリケーションっていって、これはクロードコードとか、あとはもしかしたら使ってる人は使ってるかもしれない、
TIGっていうGitのTUIツールがあって、ああいうふうにターミナルで矢印とか押したりすると結構インタラクティブに動いてくれるようなツールとかっていうのが結構あると思うんですけど、
これ私開発してる時にゴールデンテストっていうのをしました。ゴールデンテストっていうのはスクリーンショットテストとかもよく言われていて、
TUIアプリケーションなんでスクリーンショットは全部文字列なんですよ。画面のターミナルに映ってるもののテキストのコピーなんですけど、
これをゴールデンテスト、保存しておいて、テストするっていうことをしてたんですね。
この時にすごく便利なのが、何かクロードコードっぽいような、例えばこのカーソルの前の文字列にしたいとかっていう時に、
なんかそうあれあれ、プロンプトでここの部分さあこういうふうにしてほしいんだよって言うと、大抵うまくいかないんですよ。
なぜかというと、クロードがあれって言ってるけどどこのことだねっていうふうに分からなくなっちゃうからだけですね。
人間ってその指示するのとすごく苦手なんですけど、これゴールデンテストにするとすごく簡単になるんですよ。
なぜかっていうと、文字列をエディター開いて、こここれ文字に変えて、保存ってやると、
はい今テスト落ちてるね、これテストグリーンにしてっていうふうにすると、どこ直してるかAIは正確に理解をして分かるわけです。
というふうに、なるべく人間がこうあってほしいっていうのをいかに精度良くそのテストに落とし込めるかってことは結構今の時代重要なスキルだなと思っていて、
そのためにやっぱりいろんなテストを学んでいきましょうっていうのは私が最近よく思ってるのです。
なるほど、AIに渡すコンテキストの一部としてテストケースっていうのはかなり有用だし、
実際に実行できるっていうところが普通のプロンプトとは違うところ、その検証可能なところ、機械的にっていうところがやっぱりテストとしてはかなり良い、
AIにとっても良いツールなんじゃないかっていうところですね。
33:00
そうですね。よくそれはテストの使い場合だと実行実行可能という言い方をしますね。
自分で実行可能だとかって言い方をするのですと、テストでは本当に実行実行可能であることはすごく重要なことです。
かなりじゃあこれからAI、もうAI時代だと思うんですけど、すでに。
今からやっていくっていう場合においてはそういったテスト、こういった形でテストを用意して、
これが実現したいんだっていうのを頑張って多分テストで表現しないといけないかなと思うんですけど、
そのテストの構築自体もAIにサポートしてもらいながらやっていって、いいものを作っていくっていうのが一番現地点においては良さそうっていう感じです。
そうですね。私は結構よくやるのはテストコードを書き換えて、これ通るようにしてっていうふうに指示するやり方よくやるんですよね。
なのでそういうやり方をするっていうのも結構オススメな方法の一つです。日本語で頑張らないってことですね。
やっぱ検証可能にするんですね。本当に。
検証可能にするし、なるべくこれこれこうした後にこうなってこうしたいんだよみたいなことを口で説明するとやっぱ伝わらないんで、
そのテストを書いて、これこうして、これ次これ実行して、これ実行したらこうなるべきでしょ。
じゃあこれテスト通してっていうふうに言うと、AIはなるほどねってなってやってくれる。
ちなみに面白いことにテスト側が間違ってる場合はちゃんとテスト直してくれるんで、
意外と適当でもちゃんと指示は正確に伝わるっていう印象がありますね。
少しでも書いてるっていうか、糸を伝えるためのツールとしてテストを書いて、それを渡していくっていうのが重要そうってことですね。
そうですね。
ありがとうございます。じゃあちょっといい時間になったんで、テストについて前回から今回2回に分けて聞けたかなと思うんですけど、
テストに関してあと言いたいことあったりしますか、三宅さん。
私はですね、テストピラミッドを今回紹介したんですけど、実は最近テストトロフィーというのがブイブイ言わせていてですね、最近ではないか。
ブイブイ言わせてたね。
ぜひバトルしてみたいと思っているので、対戦者募集中です。
なるほど。テストに関して一家語ある方いたら、ぜひちょっとゲストとして出ていただいて、この場でディスカッションできればなというような感じですかね。
はい、そんな感じです。
ありがとうございます。
では今回はここまでにしたいと思います。
もっと詳しく教えてください。
クワラジではスーパーエンジニアである国明さんに、一般エンジニアである返徳が技術的な質問をしていく番組になっています。
今後もですね、いろいろなことを聞いていきたいなと思ってますので、お聞きのプラットフォームで高評価やフォローのほうをお願いします。
またですね、こんなことを国明さんに聞いてほしいっていうことがありましたら、あとはですね、国明さんとこんなことを話してみたいっていうような方がいましたらですね、
コメントとか、あとは何かしらでご連絡いただけると非常に嬉しいのでよろしくお願いします。
Xなどでハッシュタグクワラジでつぶやいてもらっても大丈夫ですので、感想などぜひぜひよろしくお願いします。
36:07
それでは今回もありがとうございました。
ありがとうございました。