emahiro/b.log

Drastically Repeat Yourself !!!!

テストを書くことについて個人的な考え

年末というのもあって色々振り返り記事を書いていきます。
一応他にもエントリを用意してますが、これで終わるかもしれません笑
振り返りも兼ねて思考を吐き出してるので、若干文章が拙いかもしれないのはご容赦ください。

Overview

とりあえず個人的振り返り記事第1弾はテストについてです。
自分の中で考えてた「テストを書く」ということについての考えをまとめておきます。
ちなみに自分は特にテストに詳しいわけでもなく、いつも実装をする中で普通に単体テスト(いけそうなら E2E テストも)を書いてる程度のエンジニアです。

ちなみに来年の今頃には全く違う考えを持ってるかもしれません。

TL;DR

ざっと僕がテストについて考えてることは テストはやっぱり書いた方がいいと思う ということです。

そう考えてる理由は以下です。

  • テストを書いた方が結果的に 色々と 速いと考えてること。
  • テストの 書き方 がわかること。書き方がわかることで見えてくるものがあること。

テストを書いた方が結果的に「色々と」速い

こう考えるのは以下のようなことがあるからかなーと思っています。

  • 思い切ったりリファクタリングができたり、実装ミスにいち早く気づける。
  • 単体テストでデバックを半自動化できる。
  • レビューで突っ込まれた時に「テストを書かない理由」を説明する方が時間がかかる。

思い切ったりリファクタリングができたり、実装ミスにいち早く気づける

まず1つ目ですが、まぁこれは言わなくてもわかることかなと思います。
振る舞いを変えずに実装の詳細に変更を加えた時に、その変更が他の箇所に影響を与えないかをすぐに検証できます。

単体テストでデバックを半自動化できる

僕は普段 Go で開発してることが多いので、 実装が意図した振る舞いになってるのかを go test ... でシュッとテストしてます。
(似たようなテストの機構がついてる言語が他にもあると思うので、これ自体は Go に限った話ではないですが。)

実装内容を単体でシュッとテストできる方法を身につけるといちいち local でサービスを立ち上げたりしなくていいので、デバックを効率化できます。(※)
というのもモノリスなアプリケーションだったりすると、local で動かすだけでも時間がかかったり、メモリをバカ喰い(主に鯨くんが)して他の作業に影響が出たりします。 (高いスペックのマシンを使わせてもらうべし、だとは思っていますがw)

※ これと関連して curl コマンドにも習熟してると API の検証がやりやすいです。

実装の中でクラウドベンダーのリソースにアクセスしてるケースもあってテストそのものができない(テスト回すたびに課金されたりとか嫌ですよね?)ものもあるかもしれませんが、最近はクラウドベンターもMockツールやエミュレーターを用意してくれているので、クラウドのリソースを使っている実装でも実はテストが簡単になりつつあります。 AWS だと公式のドキュメントで以下のようなものが用意されています。

aws.amazon.com

レビューで突っ込まれた時に「テストを書かない理由」を説明する方が時間がかかる

あと最後に大体テストがないとコードレビューで突っ込まれます(経験談
テストを書かない理由はまぁいくつかありますが(一つ後述します)、まぁ大体サボったりめんどかったりみたいなことがあって、書かなかったり、書き方がわからなくて書かない、みたいなことがあって、まぁ言っちゃうと客観的で妥当な理由がないんですよね。。。

僕は最初の方こそ「書かない理由」を探してたんですが、そのうち気づいたんですよ、書かない理由を説明するよりテスト書いたほうがレビューが approve されるのが早い(=ユーザーへの機能提供のスループットが上がる)、ということに...笑

これがわかって以来、僕はテストを書いてます。

「テストの書き方がわかる」

禅問答みたいな理由ですが、もうひとつの理由です。
昔の自分がそうだったんですが、テストを書かない理由の一つが「テストの書き方」がわからないってあると思うです。

テストに限らずなんでもそうですが、「やらないとやれるようにならない」のでテストを書く意味を先に考えるんじゃなくて、まず書いてみて、書き方を先に覚えてからなんでテスト書くのいいんだっけ?ってところを考えるのがいいと思います。テストを書いてるうちに、そもそもの「テストしやすい設計」というやつが頭に入ってくるようになると思います(テスタビリティが高いってやつですね。)

この辺は自分の経験談なので、N=1 ではあるんですが。

以上が僕がテストを書いた方がいいと考えてる理由ですが、例えば実装と単体テストが密に結合してしまうとアジリティが落ちるケースはあると思います。とはいえ、それは多分ある程度までは回避できると思います。というか普通に実装変更したらテストで落ちて欲しいですね。そのほうが思い切ってリファクタリングできるし、コードを書いてて怖くないかなと思います。

そしてテストの話でよく話されるのはスピードとのトレードオフの話ですが、それについては以下のスライドあたりで今年1年 たくさん語られるようになったんじゃないかなと思います。 (何度も改訂されてるのに毎回読んでしまいます。本当にすごいスライドだなと。)

speakerdeck.com

ちなみにテストと開発効率の話については所属してる企業のアドベントカレンダーにも書いてます (ちなみに僕は筆者の daisuzu さんにテストについてめっちゃ教わりました笑)

medium.com

脳死でテストを書く、という立場の是非について

僕は今のところ実装時にはほぼ脳死単体テストくらいはセットで書く事にしてます。

ソフトウェアエンジニアとして「脳死で」 XXX することへの違和感、嫌悪感は確かにあります。これはテストも例外ではないと思っています。
ただ、「実装においては最低でも単体テストは書いておく」ということ前提にして実装する癖をつけること、チームにおいては制約を設けることだけでも、後になって恩恵を受けることは多いと思うので、とりあえず書いておこうって思います

テストもプロダクションコードと同じでそれ自体が「プロダクトの資産であり歴史」になると思います(※) テストを書いたことでテストしやすい設計やコードの書き方について思いを馳せるようになったり、運用フェーズに入ってプロダクトでテストが書けずにデバックが捗らないなどのツラミにぶつかった時に「ここをこうすればいい」みたいなリファクタの指針みたいなものを手に入れることもできます。

※ ちなみに資産と捉える以上、それが負債になる日もある。(なぜなら資産は正負を問わないから。いわゆる技術的な負債ってやつが言葉としてはそれ)

まとめ

2020年終わりの自分のテストに対する考えをまとめてみました。
冒頭にも書いた通り、今時点の考えなので、半年後、1年後に全く違うことを言ってるかもしれません。

余談: 事業が優先されるケースでテストを書いてる暇なんかないんじゃないか?論争について

これもまぁある話かなと思っています。
1ヶ月後に残ってるかもわからないプロダクトのコードにテストを追加する意味あるのか?問題です。
僕もそんな状況に追い込まれたら流石にテストは書かないんじゃないかなと思いますし、というかそんなもの描いてる余裕は多分ないと思います笑
あとはなぜか数日後が締め切りのマーケ対応とかもそれですね。
運用フェーズに入ってるプロダクトでもこういういった類の話はあることかなとは思います。

こんなこと言ったら怒られそうなんですが、この問題について自分の現時点での考えをまとめておくと、そういう環境で求められる実装力はおそらく相当高いので、テストで気づけるような実装ミスを頻発するようなスキルではそういったスタートアップ的な環境では活躍できないんじゃないか、ということです(厳しい見方過ぎますかね..w。僕はとてもじゃないけどそんな環境に身を置けませんw)

数年前ならいざ知らず、市場が成熟し、ユーザーの目も肥えて、各種規制や制限が加わったことで事業運営自体の難易度も上がってる今は、スタートアップと呼ばれるフェーズの会社でも一定程度のプロダクトの品質は担保できて当然のように思われているので、そもそも品質への投資の優先度も上がっているはずです。

バグが起きても直せばいいっしょー、それよりユーザーに価値を提供する方が大事っしょ!っていう考えももちろん大事ですが、それはそのバグ(とそれに伴う影響と復旧までの時間を加味した全体影響)の深刻度によるという話だと思っていて、ミスっても早急にロールバックできるなら別にいいと思います。
ただ、そうじゃないならテスト書いておく、それも加味してスケジュール組む方が現状だと安全だし、そういった小さな品質保持への投資がプロダクトとユーザーのためになるんじゃないかなと思っています。

割と書かない理由の最たるもので上がってくる話かなと思ったので余談ですが書いておきました。