¶ 単体テストのモックに対する疑問
ちょっと国分けさん聞きたいんですけど単体テストってどこまでモックすればいいかっていつも迷うんですよね 外部APIはもちろんMockするかなとは思うんですけどじゃあデータベースはとかあとは他の関数はとかどこまでMockしていくのかみたいなことが結構毎回迷ってて 結局ですね、箇所によっては過剰なモックになってしまってないかなというのが若干不安なんですよね。 ここら辺は国分けさんの単体テストについてどう考えていたりします?
¶ 単体テストの原則と間接入出力
単体テストっていうのはちょっといろいろ定義があるんですよすごく定義が混乱しているのでこれは私なりの理解で話すっていうふうな前置きをしておきます 単体テストっていうのは原則的にすべての間接入出力っていうものを目指しますこの間接入出力というのは引数や戻り値以外で振る舞いを特徴付けるもの 例えばグローバル変数とかファイルへの書き込みってよく皆さんコードで書きますよねそれってグローバル変数が変われば振る舞いって変わるわけですよね例えば関数の戻り値が変わったりとかいろんなことが変わるわけですなのでこのテストするときには 意図した入力によって意図した出力が出てくることを確認しているわけですから入力が変わっちゃうと出力が変わっちゃって大変なわけですよグローバル変数とかだから大変なわけですよね なのでこういうときってグローバル変数をスタブっていうMockで置き換える必要があって例えばファイルで書き込むときとかにはどんなものが書かれているのかなっていうのをスパイっていうので観測する必要がある基本的にはこの間接入出録っていうものを 操作したり観測したりそのためにすべて木工するってことが大原則です
それはあれですかね具体的に言うと副作用みたいな話なんですかね関数の副作用で発生する何らかだったりあとは環境要因のところだったりということなんですかね
副作用は関節の出力の部分ですねグローバル変数とかを操作しちゃったモドリッジ以外に状態を変えちゃったとかっていうのが副作用と言われていてこれが関節出力にあたります で他の関数とかがグローバル変数書き換えちゃったって場合はこれ間接入力であたりますねあの今までその期待していた状態が変わってしまったっていうのが起こってしまうのでこういうものはだいたい全部単体テストではモックするということです
そう聞くとほぼほぼ全てモックするんじゃないと思っちゃいますけどそれは間違ってはないっていう話なんですかね
¶ 純粋関数とモックの必要性
これはちょっと面白いんですけど例えばFizBuzz関数を例に話をしていきましょうFizBuzz関数のまず副作用がないバージョンから話をしていこうと思います フィズバズ関数っていうのは例えば1を与えると文字列で1が返ってくる2を与えると文字列で2が返ってくる3を与えるとフィズが返ってきて5を与えるとバズが返ってくる そして15を与えるとフィズバスが返ってくるこんな感じの関数ですよねこれって数字を与えると文字列が返ってくるっていう純粋な関数なわけですこれってモックス量値がありますかね間接輸出力が全くありません
ないですよね
これが一番テストが簡単な状態です えっと単に呼び出すだけですから
純粋な関数と呼ばれるものですか
そういうことです
Thank you.
ここから例えばユーザーが入れた数字をフィズバス関数通してコンソールに書き出すみたいなことを考えるとこれがだんだんモックが必要になる っていうのはユーザーがどんな入力をするかってわからないですよねそれを標準入力とかから受け取らなきゃいけないこの標準入力に何を与えればいいのかっていう時にだんだんと間接入力が見えてきます引数じゃないですよねだって そうなるとここにスタブっていうものを用意してさせてあげる必要がある問題なのはじゃあフィズバス関数がユーザーお客様 入力を受け付けるバージョンにしたらあっという間に間接に輸出力が増えてしまったってことが今回の問題なわけでここから すごく大事なことが透けて見えますどうしても間接実力でできちゃうんですよできちゃうんだけどこれを持ってるオブジェクトと持ってないオブジェクトに分離するってことをするとテストが簡単な部品とテストの難しい部品に分けることができますね 1つだと全部テストが難しかったっていう状態だったのに分けてあげるとテストが簡単な部品が出てくるってことが見えてくるわけです
すごい雑な例を挙げるとメイン関数多分これ聞いてる人たちの中でも初心者の頃には絶対に書いたことあるだろうなと思うんですけどメイン関数にすべてをぶち込む あれっていうのは確実に複数作用もあるし関節入出力というのがいっぱいある関数なのですごくテストがしづらい木をいっぱい書かないといけないというようなところですかね
¶ 設計の「スメル」とテスト容易性
そういうふうな関数をよく最長不等関数とかって言い方をしますけどそういうものっていうのはすごくテストが大変なのでモックがある時っていうのはつまり実は設計分割の仕方に問題があるってことを示唆してるんですね
単体テストの問題ではなくて、Mockしづらいなというか、これMockめちゃくちゃ悩むんだけどここまでやっていいのかなみたいなのは、そもそも設計が悪いですよっていう。 警告信号が出てるよみたいな感じなんですね
そうですねよくスメルって言い方をしますけど本当に石鹸のスメルが出ているというような状態ですねスメルは匂いってやつで要するに臭いというわけですね
めちゃくちゃわかりやすいですねその中信号
基本的に何かMockがめちゃくちゃ必要になったなっていう時は自分の設計が間違ってるかもしれないってことを疑ってくださいこれがすごく大事なコードからの助けてって声なんですよねなんかMock必要になっちゃってるんだけど設計間違ったらいいとかっていうのを ここ本当は副作用を分離できるオブジェクトがあったりしていいっていう風なのがコードが叫んでるわけですそれをよく聞いてあげて設計を分けてあげると簡単にテストが簡単な部品とそうじゃない部品に分けることができるので全体としてはテストが簡単になる
なんかそのコードが叫んでるっていうのがちょっと面白い表現かなと思って国分けさんどういう立場で叫んでるんですよみたいなこと言ってるのかなっていうのが若干面白かったなと思うんですけど そういうサインを見逃さずにちゃんと分割しましょうねっていうようなお話です
そうですねただ何でもかんでも分割すればいいっていうわけじゃないですよ例えばさっきのメイン関数にいっぱい書いてあるのを1行1行関数にしてライン1関数ライン2関数みたいなのをしたら別にそれは何も嬉しくないわけです なのでちょうど木が少なくなるようなところで分割されるってことがすごく大事なポイントになってくるんですね
なるほどじゃあ分割にも思想というか設計があるよというようなお話でその指針となるのが テストの書きやすさロックができる限り少ないような形で分割するとより良くなるよというような話だ
おっしゃる通りです
確かになんとなく経験則上もそんな気がするなという気がしますねなんかこの関数っていうか ここの部分はすごい描きやすいんだけどもここの部分はちょっと描きづらいなというのが設計から見て取れるみたいなのはかなりわかりやすいところかな 思うんですけどその時にじゃあどういう形で実際にこう具体的ななんかもし例があったらわかりやすいかなと思うんですけどこういう分割方法あるよみたいなあったりするんです
¶ 責務に応じたコンポーネント分割
さっきのFizBuzz関数にしましょうFizBuzz関数はユーザーから標準入力から何か数字を受け取って標準出力にFizBuzzなり数字なりを返すというものがあったとします こうするとこれ3つのパーツに分けることができます一つはユーザーが入れた部分その数字なりはABCとか入れられたら数字じゃないんで弾くとかっていう部分がありますねこれが入力を担当するコンポーネット こいつは間接入出力を直接出力に変えてあげるという役割を持ちますそうするとユーザーが標準力にAとかBとか打ったりとか1とか2とか打った時にちゃんと数字だけが返ってくるよねそうじゃないものはエラーで弾いて後ろに通さないよねっていうことを
責任とするまず入力部分になりますそしてその入力部分から受け取った数字っていうのをFizzBuzz関数 さっきの整数を受け取って文字列の関数に組み合わせて最後に標準出力に書き出す部分ですね数字がもらったら標準出力に書き出す部分でこの3つのパーツに分けると 2つはそれぞれ関節入力が必要もう1つは関節出力が必要なんだけど真ん中のフィザバス関数には関節入出力が全くないって状態を作れますね なのでこれが嬉しい状態ということです
なるほどじゃあコンポーネント単位でちゃんと分けましょうねっていうのとあとコンポーネント単位でちゃんと責務を分割しましょうという話ですね設計原則としては
一つその責務の多さっていうのを見分ける指標があります それはすごく簡単で直接入力出力の数と間接入出力の数これを全部合算するっていうのがだいたい積分の大きさを示すパロメーターです
なるほどじゃあ依存しているものの数ですね
そうですね依存しているものの数もあるんですがその引数とか依存してないものとかの数も含まれているので単純にその入出力の規模空間がどれぐらい大きいかっていうことを
¶ サイクロマティック複雑度とカバレッジ
なるほどじゃあそれを数え上げていって 多すぎるよねみたいなのになったら 責務として大きすぎるっていう話になる これって見分けるツールとか実際あったりするんですかね例えば前回話したリントだと 言語によっては引数の数が多すぎるとリンドで起こるみたいなルールがあったりすると思うんですけどそれが該当するんです
それも回答しますね 引数の数もそうだしあとは もう一つ今言ったのは一つ簡単な見分け方ですね入出力の規模大きさを示すものもう一つはサイクロマティック複雑度と呼ばれているものがよく使われていて サイクロマティック複雑度って要するに何か関数とかを一つ入れると数字がポッと出てくるんですねこれが大きいほど複雑であるってことを示すんですけど この複雑になるっていうことは一体ちょっと実はテストと関係があるのでこの話をしていますこれ実はテストケース必要なテストケース数の上限を与えてるんですね
なるほど、サイクロマティックなんでしたっけ?
ご視聴ありがとうございました これはえっと C1っていうモーラ率があってこれは分岐モーラと呼ばれているものですねifの方に前の部分を通るのとelseの部分を通る全部の通り方を通りましたそうすると100%になるのがC1と呼ばれているものです このCはモーラを達成するテストケース数がありますね例えばif文が中に1個だけある関数があったとしましょうそうすると そこにEUの部分とELSEの部分があるからこれは2本テストケースが必要なわけですなのでサイクロマティック複雑度は大体2位ぐらいです というふうにものがあってこれがあんまりに増えすぎるとテストの数が増えていくのがわかりますねテストが大変になってくるわけですそうすると やっぱりなんかおかしいぞ設計おかしいぞもっと分割してっていう悲鳴が聞こえるってことなわけですね
それはあれですかねそのカバレッジ っていう単語でも表現されるというかよくテストのレポートとかに書かれることあるかなと思うんですけどそれが該当思想なんですかね
それが回答しますカバレッジってすごく皆さん嫌な思い出がありませんか?カバレッジ80%達成しろなと言われてううううううううデストになんか実装は1日で終わったのにデストに3日かかってるみたいなとかって
単純にテストコードの方が多くなる率高いので大変
大抵めっちゃもっくりしませんか
めっちゃモックする
これは実は何がいけなかったかっていうと本体の設計のまずさをテスト側でカバーしてあげようとするからこういうことが起こるんですね
ちょっと歪なんですねじゃあ 本当は設計を直せばテストはもっと書きやすくなってテストコード自体もスッキリするのに 設計のところは臭いところに蓋をしてテストで頑張って根性によるカバーをしようとしている状態
そうだからモックがめっちゃ必要でモックってそのモック準備するコードがいっぱい必要じゃないですか 例えばMockitとか使った時とかってこれが与えられた時にこれをリターンするみたいなとか全部そのテストのセットアップ部分で入れますよねあれめっちゃ大変ですよね
レイルズとか Rスペックのヘルパーとかにいっぱい書いてあるんですけどロックの設定とかがだいたいどれが読み込まれてるのかわからなくなるんですよね後々
かなり大変ですあれはそうRスペックのヘルパーの悪いところですそれでも隠してしまう RスペックRスペックなりの思想があるのでそればっかりが悪いばっかりじゃないんですけど後から見た時の理解のしやすさという意味ではちょっと不利な選択ですね
ちなみにさっきちょっと話戻ってサイクロマティック複雑度ですかねそれってなんか出すツールとかってあったりするんですか
例えば今話したルビーだとルボコップっていう静的解析リントが有名だと思うんですけど ルボコップは確かサイクロマティック複雑度でこれを超えると警告するみたいな感じの設定をかけて
ですよなるほどじゃあリントに組み込まれているものなんですね
練習込まれてます
¶ オープン・クローズド原則と変更の影響
リントとテストとりわけ単体テストに関してはかなり密接というか結構関係する間側にありそうですね単体テストを ちなみに話が変わって単体テストってさっきのカバレッジの話に近しいんですけどいっぱい書けば いっぱいいみたいな世界線ともちょっと違うなと思っててそのカバレッジを100%にたどり着ければいいって話じゃないかなと思う いっぱい書けば書くほど次辛くなるのってリファクタリングした時になんかテストが起きてなんかいっぱい落ちてしまった このテスト本当に意味があるのかなみたいなのが結構経験則としてあって このテスト落ちてるけど別にいいんじゃねみたいなじゃあ削除するかみたいなとか結構ありがちかなと思うんですけどそこら辺との単体テストの関係性とかってなんかあったりするんですけど
はいここはめちゃくちゃありますこれはですねえっと簡単ですと消されちゃうんですけど消してるってことは既存の振る舞いのこの部分がいらなくなったよっていうことなんですよね だから実はいろんなコンポーネントの部品の使用コンポーネントに一個一個クラスとかに使用って書きますよねJavaDockみたいなのとかで書いたりとか例えばPythonとかのDockStringっていうのでちょっと上のところに3つダブルコート入れて なんかこの監査、こんなことある監査ですよみたいな書きますよねあれが全部そのコンポーネントの仕様にあたるものであれが実はテストしているものなんですけどそれがいらなくなったそれをめちゃくちゃ変えたはちゃめちゃに変えたということなんですね そういう時にテストが真っ赤になるというのはその通りでそれだけ既存の振る舞いを壊しちゃったということなんですねこれ自体は別に悪いことではないですちゃんと壊れているということを教えてくれたら
ただ問題なのは壊れちゃったなんでこんなに壊れちゃったの他に方法はなかったのっていうことが一番大事なわけです実はここからもちょっと見えてくるものがありますね何かやっぱり分割の仕方を間違えてるんじゃないか っていうところに行き着くわけです
Thank you.
それは既存の設計がですかねそれともリファクトした結果がですかね
それは既存の設計ですね
Mm-hmm.
これはどう捉えたらいいかというとよくオブジェクト思考とかの原則で拡張に対して開き 変更に対して閉じろっていう風な格言がありますねこれはオープンクローズプリンシュプルって言われてるやつで有名なオブジェクト思考の設計原則の一つ これはテストから見るとすごくシンプルな原則になっていて何か変更したくなった時にテスト件数をいっぱい変更したくなるような設計はダメだぞって これはテストケースを変えないで変更が振る舞いが変わるそしてでもそんなこと言ったら機能追加できないじゃないですかあれ機能追加したいのに振る舞い変えちゃいけないってことはどうしたらいいんだってなっちゃいますよね ここに面白いのがあって実は新しいコンポーネントを追加してそいつに差し替えるだけで動くっていう風にしてあげれば既存のテストケース何も壊れないじゃんっていう考え方がこのオープンプリンシプルなんです
なるほど じゃあガバッと変えちゃえばいいじゃないかという話なんですねそのコンポーネントが 振る舞いが変わるのであれば名前もちゃんと適するものをつけて設計し直して差し替えできるような形を保っていると一番健全だよというような話なんです
そういうことです よくこういうふうに言うと伝わりやすいかもしれませんねあるオブジェクトの一部だけを変えたいってのは一体どういうことなのかってことなわけですよ例えばさっきのフィズバス関数の4の時だけホゲホゲみたいな感じにしたいっていうニーズが あるとすると一体これは何なんだって話なわけですねそれって実はこういう風に変えたい部分が存在するってことは実はそこの部分を切り出していればそこの部分の交換で済んだわけですね読んで部分だけを 判定して出力する関数が1個あったとしましょうそしたらそこの部品の交換だけで済んだはずですね実は変更したい箇所が一部だけだってことはもっと分割できるよっていうスメールなんですよ
¶ 未来を見据えた設計とビジネス感覚
とはいえあれですよね最初から1の関数2の関数3の関数4の関数みたいな形で最初から分割できているともあまり思えない 無駄な分割かなと思うんですけどそこの辺の分岐みたいなのあったりするんですか
えっとこれはすごく難しくてえっと
そうですね
仕様にいくつかのレイヤーがあるっていうのを意識すると伝わりやすいかもしれませんね これちょっとすごく難しい話なので ちょっと丁寧に追っていきたいと思いますまず使用っていうのはレイヤーがあります 例えば我々が普段よくエンドツインテストとかで書いてる仕様ってありますね何かユーザーがウェブ画面のどっかのボタンをクリックするそうするとある画面が表示されてそこでまたそのボタンをクリックする こういう風な仕様のトップレベルの仕様って言い方をしていてこれは要するにユーザーに見える仕様です
それに比べると例えば先ほど言ったJavadocとかPyceのドックストリングとかに書いている小さなクラスの仕様とかっていうのはユーザーには見えてないわけですよね大抵 これはコンポーネント仕様と考える仕様。一番下のレイヤーの仕様です。 で、このコンポーレント仕様っていうのはちっちゃくしようと思えばいくらでもちっちゃくできるわけですよ。例えばさっきのFizBuzz関数でいうと1だけは使う関数とか2だけは使う関数っていうのが こういう関数をいっぱい作ることは全然できるんですねただそうすると仕様をこの1っていう関数を呼び出すだけのちょっとこう
コンポーネントが何個かくっついた仕様っていうのも考えることができてこういう風な仕様っていうのをいっぱい考えなきゃいけないですね中間の仕様っていうのを この中華の塩がいっぱいできてくるとすごく大変になってくるんですその度に結合テストを書かなきゃいけなくなってしまうなのであんまり変なくっつき方するようなのは作りたくないねっていうのがあって分けすぎるのもよくないねってことなんですね なのでどれだけくっつけて意味のある仕様にできるかっていう部分のレイヤー数をある程度小さく保つってことがすごく大事
なるほどもちろん現実世界何らかのプロダクトサービスを作る上での目的におけるプログラミング言語を使って実装しているわけ ですから現世界の何らかの課題を解決するサービス そういった仕様っていうのももちろんひも付いてくるかなとは思うんですけどそこが変わったらなんかこう結構ガラッと変わりそうなのでね一番小さいところ 仕様に関してもコンポーネントの仕様に関してもそういったところもあるがまあできそういった
ところを
加味しつつちょっと未来見据えつつどういう分割方法がいいかなっていうのはそのプロダクトごとサービスごとに適切なものを考えていくっていうのが重要だよね
お話もそうですめちゃくちゃ重要で特に私が何かを設計するときに必ず聞くのは1年後の展望は何ですかとか3年後の展望は何ですかどんな仕様を入れる可能性がありますかということを必ず聞きますそれによって拡張ポイントが変わってくるんですよ
全然違いますよね
全然違います でも結構よくその設計を見ていると今の課題は何かってだけにフォーカスしちゃってる人たちがすごく多いとそうするとやっぱり本当はここの部分だけ変わるかもしれないっていう部分の設計の気づきっていうのを 見逃してしまうんですねなので未来に渡ってこういう変更があるかもしれないっていうことのその精度を高めておくことってすごく大事ですねいい設計をする上でそれが実は設計においてめちゃくちゃ重要な要素の一つなんです
一番最初は開発を始める前もしくは新しい開発を始める前にどういう展望校のこれからの将来性のビジネスとしてこういうことをやっていきたいみたいなのが おそらくそんな確実なものを求めているわけではないとは思うんですけどこういうことを考えているファットレベルでもいいのでそういうのがあると 本当に一番細かい例だと単体テストができる設計にまで影響を及ぼしかねないというようなことなんですねそこのビジネス要件です
これはすごく重要な原則なんですけど設計っていうのはいつだって賭けなんですよ それは未来にこういうことがあると思うだからここに拡張ポイントを作っておこうこれは負ける時と勝つ時の両方があります勝つ時は未来その予想が当たって確かにそこの 仕様が変わったときに部品の交換だけで済みましたこれは大勝利
Mm-hmm.
なんですけど負けるときあります実はお客様本当はこういうの必要だと思ってたんだけど実は違うのが必要だったんだよってことが後で分かっちゃって賭けに負けることがありますつまり用意していた拡張ポイントが使われなかった そうすると無駄な複雑性を持ち込んだだけということになりますねなのでこれは負けたということになりますで設計っていつだってこういう博打なんですよ なので一番大事なのは勝率を高めることですなのでいろんないい情報その経営者がどういうことを考えているのかなとかそういうところからここに拡張ポイントを入れた方が良さそうだなっていうところを察して
¶ エンジニアの責務と設計負債
作っていくっていうのが実は設計ですごく重要な部分ですそれが単体テストでいろいろ真っ赤にしないための秘訣なんですね
なるほど、ちょっとかなり単体テストの話から、エンジニアとしての在り方というか、 ビジネスマンとしてのあり方みたいな話になってきたかと思うんですけどとりわけエンジニアリングエンジニアとして責務を負ってるわけですよね我々は そのプロダクトをより良い方向性により良いものを作っていくそして将来にわたってセキュリティだったりとか拡張性も持たせる 技術的不採用をできる限り残さないように拡張できるようにしていくというのが我々エンジニアの責務だとしたらちゃんとビジネス要件的なところは なるだけ把握しておかないとそもそもお仕事できませんよねという提言でもありそうです本当に
その通りですだから実はそのリファクタリングというよりかは機能追加とかで単体テストが真っ赤になってしまうってことはあなたは賭けに負けてますってことを単体テストから突きつけられてしまってるんですね
いやなんかこれ聞いてる人の中でも耳痛い人いるんじゃないかなと思いますね本当にさっき国分さんが言ってくれた今のことにのみ集中してしまうって結構ありがちかなと思ってて本当に この案件をできる限り早く終わらせることに集中するみたいなのは間違いではないと思うんですけどとはいえ これが2年3年続くサービスなのであれば絶対的に未来の設計みたいなところは絶対見ておかないといけないというところですね じゃあ今やっぱ単体テストを書いてて書きづらいなーっていうのは本当にもう設計が悪いよというような話なので今すぐその設計のところから見直した方がいいよっていうお話ですね
¶ レガシーコード改善の戦略と書籍
そうですね。で、こういうふうなことを私はよくいろんな人に言って、短大テスト辛いんだよって言われた時には設計がだいたいマスイんですよ。設計のスメルが見えてるんですよって話をよくするんですね。 こうすると必ず言われることがありますじゃあどうやってそれを解消していけばいいんですかってことを必ず聞かれますそうですよねそれがですね 遠い道のりなんですよ 一度この状態になってしまうとすごく遠い道のりになるんです まず最初にやらなきゃいけないのはだいたいそういう現場ってその単体テストが不十分だったりだとかすることがあるんでそして仕様も分かってないってことも結構あるんでまずは仕様化テストっていうのを書いて
その仕様がどうなったのかってことを発掘してですねそこの上にリファクタリングっていうのをちょっとずつかけていってやっていくんですけどリファクタリングするとさっき言ったように単体テスト最初はめっちゃ壊れちゃうわけですよだから 最初は単体テストをほとんど消しちゃって結合レイヤーのテストだけ残してとかっていうのはなんかすごい遠い道のりが長い道のりがあるんですねなんでこれを あの端的にこの30分間とかいう時間で説明しきることがなかなか難しくておすすめの本だけ紹介しておきます レガシーコード改善ガイドという本があります
レガシー構造の改善ガイド
海鮮ガイド帯にすごくいいこと書いてあるんですよテストのないコードはレガシーコードだって書いてあってて実は隠れたテスト本なんです
ちなみにその中ではどういった具体例なんですかね。なんかここ良かったよポイントとかってあったりします。
えっとですね一度テストとかに苦しんだことある人は目次だけでグッとくると思います目次の中にもうどうしたらいいかわかりませんみたいな もうこれ以上嫌だみたいなこととかが僕自のどこら辺だったかなにあってそれとか見るとこういう風にやっていくといいんだよっていう風なのがすごく親切にその道が書いてあるのでぜひその
素晴らしい
テストとかに悩んでる方はレガシー行動改善ガイド読んでみるといいと思います
¶ テストを「書かない」選択と技術的負債
これをお聞きの方は概要欄の方にAmazonのリンク貼っておきますのでそちらからちょっと見てみてくださいヘガシーコード改善ガイドですね Are you up to diamond? ちなみに今の本の話でもあった通りテストがないほどっていうのは全てレガシーであるというような 話ってある通りテストって絶対書かないといけないものなんですかね
それはすごくいい質問ですね。私はテストが書かない方がいいっていう状況はあると思っています。 例えば書き捨てのプロトタイプの プロジェクトに向かってなかった時にそれもなるべく小さなものであればテストを書かない方がむしろ生産的だと思います実際に動かして試してみる方が早いんですね なんだけどそれが多分例えば長い間保守されるとかっていう時につまり書き捨てじゃなくなってしまった時とかは ここの振る舞いってどうなんだっけとかって忘れちゃいますよねそういう時にはテストがドキュメントとして残っていてほしいってことはあるんですけどすごく短期の寿命のプロダクトだったりする場合はテストを書いてる時間があるんだったらその書き捨てのプロダクト プログラムをより良くしていく方に時間を使った方がきっといいでしょうね
Mm-hmm.
っていうと、さっきテストというのは、設計がいい設計になっているかどうかというのを確認する術でもあるかなと。 あれ聞いてと思ったんですけど書き捨ての場合は設計云々よりもそのプロダクトに価値があるかどうかの検証の方が最優先事項だから設計よりかは 作ってフィードバックをもらう方が重要だよねっていうところですかね書き捨ての場合は
そういうことです 書き捨てのやつにプラグイン機構とか作るのってしょうがありえないじゃないですか フラグ品作っていったら何するんだっていう話になるわけですねそういうものは直接書いちゃった方が悪いわけですよそういう風な設計 して分割するポイントを作っておくってことはほとんど損なわけですね無駄な複雑性を持ち込むことにしかなってないっていうのがあってやっぱり設計って未来に向かっての賭けっていう未来に生きる生き物なんですよね設計って常に だから未来のないプロダクトって言い方だからすごく短期でその寿命を終えるプロダクトっていうのはやっぱり設計とかよりかはそのプロダクト自身の価値を磨くって方にきっとシフトした方が私は有益だと思っています
Oh. 他にテストを書かない方が良さそうな例とかあったりするんです
えっとですねちょっとそのバリエーションその短期のバリエーションなんですけど書き捨て以外にもありますえっと半死半生のプロジェクトで1ヶ月後にこのプロダクトが残ってるかわからないみたいな状況のプロジェクトってよくあるじゃないですか
ありますそういう
ところでいい設計を作ろう単体テストで 進めるを築けるになろうっていうことなんてしてる場合じゃないですよね お客様に少しでも喜ばれる行動を追加して多少バグがあったとしても 追加してそれで収益を伸ばしてその生存ラインに生き延びるってことが大事になってくるわけですその時にはテストとか設計とかそんなこと言ってる暇ではない暇ないって感じになると思いますね
そこからそういったプロジェクトがあったとしてKPIとかを無事達成して その後も残り続けることになりましたとその時点ではテストもちろんないわけですよねもちろん設計も良くないというか最短経路線に行ったので としてあの存在するとただ今後2,3年ぐらい続きそうっていう未来が 瞬間からさっき言っていたどうしようか設計どうしようかというところの議論をしっかりしていかないといけないというフェーズに入ってくるんですかね
その通りですこれをすごくいい言葉で表した人がいるんですね技術的不才っていう言葉でこれを表現しました今のって先に前がりそうなんですね未来に苦しむかもしれないけれど お金を前借りしてプロジェクトを生き延びさせてその間にバツ当てるんだってことをやろうとしたわけですよ前借りなわけですよねそれで負債を積んでそれで生き延びたらラッキーなわけですよそうするしか方法なかったわけですから借金をして生き延びた そしたら借金返済が続いてくるというのはその通りですねただその借金をしなければ生き延びられなかったわけだからそれは必要な経費になりますね
逆に言えばそうなったらちゃんと設計のことについて議論しましょうというお話でもありますよね
はいその通りですそこからだんだん始まってきます
なるほどエンジニアリングが始まっていくんですねどんどんここから
¶ 設計が始まる瞬間とリスナーへ
やっぱり未来があるって分かった瞬間に設計が始まるんですよじゃあその未来に何を描くんだどこに拡張ポイントを入れるんだって話が出てくるわけですからそして 過去の負債ですね過去にベタッとモノリスみたいに作っちゃったそれをどうテストできる状態にしていくかってことが大事になってくるのでそこでやっと設計の話が始まります
単体テストそのお話というよりかはやはりもう本当にどれだけ未来性があるか未来が予測可能ではないからこそ不確実性が高いプロダクト こそできる限りの設計を頑張ってして未来にも生き残りやすい単体テストを書きやすいものをやっていく設計にするのが一番プロダクトにとって重要 かなり重要な話かなと思いました今全然こんな結論になるなぁとは全く思ってなかったので単体テストの話をした時には設計が重要という話です ちなみにこのテストの話でかなり膨大かなと思うんですけど まだ話し足りないところとかってあったりする
実はさっきスタブとかも スパイって話をしましたよねでなんかスパイそんな聞いたことないじゃんもっくなんじゃないの全部もっくなんじゃないとかっていう話あったと思うんですよ俺に実はこういう風なものを定義も実はまた混乱していて その中の定義の一つを私は取り上げたんですね他のやつとかもちょっと興味あったりしませんかっていうのは話したりない部分ですかね
なるほどじゃあちょっとそういう細かい部分の話は次回ですかね 3回目にちょっと撮っておきたいなと思いますのでいい時間になりますのでちょっと今回はここまでにしたいなと思いますなんか最後国分けさんの単体テストのここまでの話の中で最後言いたいことありますか
そうですね私の今までの話の中に多分難しかったことはあると思います仕様とかの話はすごく難しかったんじゃないかなと思うのでぜひここわかんないこれがどうなのとかってことはぜひお便りとして来ること私はすごく 皆さんにお願いしたいですぜひ分からないところとか仕様どうしたらいいのとかテストってどうなのとかっていう話をお便りとしていただければ私ぜひそれ回答したいのでよろしくお願いします
ということで今回はここまでにしたいと思いますもっと詳しく教えてくださいラジオ略してクワラジではスーパーエンジニアである 一般エンジニアであるヘンテコが有益な質問をしていく番組になっています 今後もですね色々なことを と思ってますのでお的なプラットフォームで高評価を頃 また先ほどくにあげさんからあった通りくにあげさんにこんなこと聞いてほしいみたいなことがありましたら なと思いますのでよろしくお願いします ぜひぜひお願いしますそれでは今回もありがとうございました
ありがとうございました。
