どうすればうまくリファクタリングができるか

高橋寿一氏(以下、高橋):じゃあここでもう1回Q&Aタイムを取ります。

高木陽平氏(以下、高木):ありがとうございます。今Q&Aにまだ質問が上がっていないみたいなので、ちょっと私から質問します。リファクタリングをしなければいけないところって、逆に手をつけられないようなけっこう複雑怪奇な部分だと思うんです。そこらへんはどうすればうまくリファクタリングができるんでしょうっていう(笑)。

高橋:まず、日本人がすごくリファクタリングが嫌いな民族。勝手に民族と決定して言うんですが。使わないコードはやはりやらなくていいんですが、積極的にやってください。

例えば複雑度が20を超えると、修正成功確率は50〜60パーセントなんですね。複雑度が40になっていくと、成功確率は20パーセントとか30パーセント。ということは、複雑度が40を超えたところにリファクタリングしようがリファクタリングしまいが、バグの出る確率はイコールなんですよ。

なので、QAの人も含めてみなさんのチーム内でリファクタリングして失敗した人を、なるべく責めないであげてください。

高木:確かに。なかなか見えないサイドエフェクトみたいなものが。

高橋:そうなんです。結局そこから市場バグは出るので。バグが開発中に見つかったことに感謝をして、リファクタリングした人を賞賛したほうがいいと思います。

高木:なるほど。質問が来ました。「リファクタリングにかける工数とか期間は、イテレーション内のどのくらいの割合で行ったほうがよいですか」。

高橋:僕はみなさんが想像しているより、より大きな時間を取るべきだと思っています。なぜなら、やはりリファクタリングはギャンブルではないんですよ。なので、単体テストは必ず80パーセント、90パーセントまで持ってきてからリファクタリングをして、もう1回単体テストを走らせて、OKになってコミットするようなアクションをしなきゃいけないので。

往々の場合は単体テストが足りないので、リファクタリングの工数は、実はみなさんが思うより大きいです。なのでイテレーションの中でいかにユーザーストーリーを実装するかというのだけでイテレーションの計画を立てると、その計画は失敗します。

なので、イテレーションの計画の中では必ずリファクタリング、あと単体テストの工数を確実に入れたほうがいいと思います。

高木:そうなってくると、リファクタリング用のユーザーストーリーを作るとか、そういう話になってくるんですかね?

高橋:ユーザーストーリーということかどうかはわかりませんが、ランダムチャートの中にリファクタリングを入れたいとかね(笑)。

高木:ああ、なるほど。じゃあプロダクトバックログがあって、その他にリファクタリングの時間を置くみたいなイメージですか?

高橋:を置いても、僕は悪いアイデアじゃないと思います。

高木:承知いたしました。

イテレーションの進み具合でリファクタリングの割合は変わるのか

高木:リファクタリングするのも、イテレーションが進んでくるとその割合というのはやはり変わってくるんでしょうか。最初はみんなシンプルに作ろうと思って作っていくと思いますが、機能を追加するごとにあれもこれもといってだんだん複雑になってくるような気がするんですけれど。

高橋:だから組織の成長度合いにもよると思うんですよ。やはり複雑なソースコードをたくさん持っているところは積極的にリファクタリングをして、出荷して少ししたらリファクタリング期間を設ける。

成熟した組織になり機能追加した時に複雑度が20を超えたら、その担当者は自動的にリファクタリングしてください。「リファクタリングしないとプルリクのレビューがとおりませんよ」みたいな開発内のプロセスというのを、僕は決めるべきだと思います。

高木:では厳密にいうとコミットできなくしちゃうみたいな。そういうところまでいくんですかね?(笑)。

高橋:僕はソニー時代に、複雑度20以上のプルリクはそのままリバートするようなツールを作ったりしていました。

高木:そういうところがあるんですね。「素人な質問で申し訳ないですけど、複雑度はどのように測るのでしょうか」。

高橋:複雑度を測るツールがたぶんそこら中に転がっていると思うので、それを入れていただければいいかな。基本的にはif文の中にswitch文が入って、その中にif文が入っていると複雑ですよ、みたいなところがありますよね。

高木:そうですね。コードモニターとかそういうフリーのツールとかもあったりしますよね。

高橋:あります。

高木:Googleで調べるとけっこう出てくる。ただ、日本語のやつはあんまりないイメージですね。

高橋:そうかもしれないですね。

高木:英語のやつが多いかもしれないです。「あらためて、開発における必要なテストと、そのタイミングを知りたいです」。

高橋:開発に必要なテストはやはり単体テストと、ユーザーストーリーに対してイテレーション内でどうやってそれが担保しているかどうかをチェックすることだと思います。イテレーションは基本的には積み重ねていくので、その1つ前のイテレーションのユーザーストーリーが、このイテレーションのユーザーストーリーの中でコケているとそれは困るので。

だから、どんどんユーザーストーリーのテストが単体テストも含めて積み上がっていくので、最後のイテレーションではすべての単体テスト、すべてのユーザーストーリーのテストが完了することになります。

高木:デプロイパイプラインにそのあたりのテストを組み込んでいくイメージでしょうか。

高橋:そうですね。だからCI/CDのフレームワーク、例えばCircleCIの中に単体テストをフックするようなことはそんなに難しくないので、そこを入れていくかたちです。

高木:ありがとうございます。

アジャイル開発の中でのテスト中のバグ分析は不要なのか

高木:続きまして、「弊社はウォーターフォール開発ですが、アジャイル開発の中でのテスト中のバグ分析は不要なのか興味があります。これは個数ではなく、あくまで出荷した場合の障害レベルなどで分類して、中〜大規模、決済できないなどのみ抽出し、どのフェーズで食い止めるべきだったのかなどをチーム全体で検討・予防・学習を行うことはあるのかという点で気になっています。最終的にGoogleになるのが理想ではあるので、不要になるのかなとは思っています」。

高橋:できれば不要にしたいと思っています。バグ分析自体やはりすごくコストと時間がかかるものなので、チーム内でいったいどういうことをすると市場不具合が出なくなるのかを1つ1つ細かく定義していくって、僕はすごく重要だと思うんですよね。だからそれがイテレーションの中で……。レトロスペクティブってなんだっけ。

高木:振り返りですね。

高橋:振り返りでその話ができると、そのチームって品質に関してすごく洗練されているような印象を受けます。

高木:振り返りの中でプラクティスに組み込んでいくのが、アジャイル的なかたちなのでしょうかね。

高橋:そうですね。だから、自分たちの中で品質プラクティスをたくさん積み上げていくと、なんかわけわかんなくなる。ホワイトボードで10個くらい書くだけで、すごく品質が上がると思う。

高木:バグ分析ではありませんが、違うかたちでそれに相当するプラクティスを組み込んでいくという回答ですかね。

高橋:ええ。

高木:ありがとうございます。

“大きなクジラ”が他にいる可能性はないのか

高木:「バグの局所化ばかりを気にしていると、“大きなクジラ”が案外他のところにいたりしませんか」ということです。

高橋:「“大きなクジラ”は案外他のところにはいません」と言い切りたいですね。少なくとも僕はソニーとかマイクロソフト、大きな会社でほとんどの製品を見てきました。繰り返しになりますが、致命的な大きなクジラはだいたいもうみんなが予想(できる)ナンバーワンのところにあるんですよね。「やはりここから出たよね」みたいなね。

なので確かに例外はあるとは思いますが、僕らはビジネスでやっているから、ロケットを飛ばしたいわけではないので。死んでしまうのは致命的だから、全体を見たほうがいいとは思うんですけど。ビジネスソフトウェアということで考えると、大きなクジラがすごく予想外のところにいたとしても、そこは無視せざるを得ないのかなとは思っています。

高木:ビジネス領域でリスクを取るか/取らないかを判断していく。アジャイルに関して言うと、ある程度のリスクは取っていかないと、アジャイルには向いていかないよという話ですかね。

高橋:そうですね。だから、例えばその大きなクジラがリスクのあるところにいたらマズいわけですよ。リスク分析をして、「ここでは絶対バグが出てほしくないので、ここは特別に扱ってテストを厚くしましょう」という戦略でもいいと思います。

高木:リスク・フェイスド・テストを一部適用していくようなイメージですかね。

高橋:はい。

高木:ここもケース・バイ・ケースというかたちですね。ありがとうございます。

スプリント終了後のシナリオ的な結合テストは不要の認識でいいのか

高木:「スプリント終了後のシナリオ的な結合テストは不要ということで、理解は合っていますか」。

高橋:シナリオ的な結合テストをどう定義するかちょっとわかりませんが、結合テストは今僕の心の中ではなくなっています(笑)。

高木:ここの結合テストは定義が難しいですね。機能結合なのか、システム結合なのかでちょっと話が違ってくるような気がしています。スプリントレビューで一応全体的な動作確認はする話にはなっていると思うんですけど、そこである程度カバーをするイメージでしょうか?

高橋:そうですね。Vモデルでは、Vの左側をしっかり右でテストしましょうというやり方をしています。僕は、アジャイルになってテストはなるべく単体テストにまとめたりとかシステムテストの非機能のところにまとめて、テストのカテゴリーをある程度少なくすると。

高木:なので、2週間というイテレーションの中でやれることは限られているでしょう。その中で費用対効果、もしくは効率、もしくは効果を勘案して、その中で最大化していくしかないという考え方ですかね?

高橋:はい。

アジャイル開発の品質に関して上長を納得させる論理的な説明のコツ

高木:ありがとうございます。「プロダクトをリリースする時に品質分析はつきもので、アジャイル開発の品質に関して上長を納得させる論理的な説明のコツはありますか」。これは実用的ですね(笑)。「ウォーターフォールでは『バグ曲線などで論理的にバグが潰せているので大丈夫です』と言えるのですが」と。

高橋:上長を納得させるのは昭和の時代からすごくテーマではありました。そこに関しては、ウォーターフォール時代よりさらにメトリクスを取れる量が減ってきます。

組織においてユーザーストーリーに対してテストベース達成率を上長に説明したり、もしくは単体テストの結果とか、ミューテーションテストの結果というところをやるしかないのかな。

だから、すごく中途半端な答えしか僕は今のところはできないです。ただ、やはり僕としても会社としても、品質基準は今後すごく重要な緊急課題なので、なるべく弊社の状況をウォッチしていただければなと思います。

高木:リリース判定の品質指標、先ほどの定量化の文献がないというところに少しつながってくるんですかね?

高橋:はい。定量化の文献がないということは、2022年2月月の大学の先生との話し合いでわかったので、なるべく早い段階で「定量化の文献がないですよ」という、すごく後ろ向きな発表かなにかしたいなとは思っています(笑)。

高木:今のところはスプリントレビューにその上司を入れて、「動きますよね」というところをちょっと見てもらうぐらいなプラクティスなのでしょうかね?

高橋:そうですね。ウォーターフォールだと最後に上司が見て怒られるケースが多々あったと思うんですけれども(笑)。初めの段階からちゃんと上司に見てもらえるのは、たぶんアジャイルのメリットだと思います。

高木:なるほど。どちらかというと「ドキュメントより対話を」というアジャイル宣言を上司にも広げてもらうのが、今のところの回答になるんですかね?

高橋:はい。

高木:ありがとうございます。

「単体テストで大部分の品質を保証できる」という考えに至った経緯

高木:「単体テストで大部分の品質を保証できるという話と理解しましたが、なぜそう考えるに至ったかを教えていただきたいです」。

高橋:ソニー時代もマイクロソフト時代も、やはり市場不具合が出た時にバグ分析をするわけですよ。必ず出てくる答えが「レビューをちゃんとしましょう」もしくは「テストケースが足りませんでしたね」「じゃあ組み合わせテストを追加しましょう」みたいな話を僕はたくさん聞いていて、実はすごく違和感を持っていた。

僕自身、希有な存在っていう言い方はすごく嫌な言い方ですが、品質保証ができてソースコードがバリバリ読める珍しい人だったんですよ。

市場バグのほとんどのソースコードを見ました。そうしたら、僕の経験だと「単体テストで全部潰れるじゃん」っていうものばっかりだったの。「市場不具合はシステムテストじゃなくて単体テストで全部潰れるから、じゃあ単体テストをちゃんとやったほうがぜんぜん工数が安いじゃん」ということから、そういう結論に至りました。

高木:V字モデルでよく言われるのが、テストレベルによって検出できるバグの種類が違うという説明が多いと思いますが、そのあたりは当てはまらない? もしくは、神話だという話なのですか。

高橋:僕の理論だと、ほとんどのバグが単体テストで見つかると思っている。じゃあパフォーマンステストのバグはパフォーマンステストしても時間がないか。そうじゃないじゃないですか。「メモリが足りなくなるのはあなたがメモリチェックをしないからでしょう」みたいな言い方もできるので。

ただ、そうとは言い切れない部分もあると思うんです。なので、バグは単体テストで見つかるとメリットがあるので、なるべく単体テストで見つける。で、システムテストで見つけるバグを少なくするのが、たぶん王道だと思います。

高木:そういうテストレベルによって見つかるバグももしかしたらあるかもしれないんだけれど、ほとんどのものは単体テストで見つかるのであれば、単体テストで見つけたほうがお得じゃないかという話ですかね?

高橋:はい。

高木:ありがとうございます。

どのようなアプローチでリファクタリングをしてテスト実施をするのか

高木:「リファクタリングは主にコード中心の話になりがちですが、データモデル、ERB(embedded Ruby)から見直すということまでさかのぼるような場合は、DB変更、データ移行、回帰テストなど、ウォーターフォールの大掛かりな派生開発と似たようなことを考えた場合、どういうアプローチでリファクタリングをし、テスト実施をするのでしょうか。簡単なレベルだと、ERBを育てながらアプリケーション開発している場合、DBリファクタリングを絡めた開発で悩んでいます」。

高橋:この難しい質問に答えるのには、ごく時間が必要ですが、基本的にはアーキテクチャなんですよ。リファクタリングは複雑度を減らすこと。複雑度を減らすと品質が上がります。シンプルなことです。

だから、ファイルの長さを短くするようなリファクタリングは、品質にそのまま響きます。ただ、データベースみたいなかたちで。「じゃあデータとビューを別に持ちましょうね」というのも、またリファクタリングなんですよね。

そうすると品質もよくなるし、開発効率も上がっていく。今日の話はちょっと品質に寄った話だったので、実は開発効率を上げる、もしくはデバッグしやすくするようなリファクタリングはすごく重要です。

そこはいわゆるデザインパターンをみなさんでちゃんと理解して、どういうデザインで、どういうアーキテクチャでものを作っていくかを、ちょっとここの話から飛びますが、開発者チーム内で話し合ってもらえれば。

高木:デザインパターンのところ、アーキテクチャでそこらへんを防いでいくかたちですね。

テストや品質に関するおすすめの書籍やサイト

高木:ヘビーな質問の次にちょっとライトな質問で。「テストや品質に関するおすすめの書籍やサイトってありますか」。これは寿一さんの本を読んでいただくというのも回答ですね(笑)。今日紹介していただいた本を読んでください。まずはそこからですかね、はい(笑)。

「ソフトウェア開発ではなく、基盤構築のような環境構築系のプロジェクトでも応用できるのでしょうか。その場合、テストの網羅率はどのような考え方になりますか」。

高橋:Dockerとかっていう感じですかね。

高木:そうですね。基盤構築の環境構築系。これはIoTとか、プラットフォームとかそういう話ですかね。

高橋:いや、どちらにしろ単体テストというよりは、ただCI/CDみたいなかたちでもの作りはほぼ基盤系とかね。環境構築系といえばぜんぜん適用できるとは思います。

高木:はい。適用できるという回答です。

品質に視線を向けさせるためにできること

「UTを実行する実装者が機能実装でいっぱいいっぱいの場合、品質に視線を向けさせるためにはどうしたらいいでしょうか」。

高橋:すごく難しい質問で。僕が言ってもみなさんが(返事として)言うことは、例えば「そのイメージだと誰も言うことを聞いてくれない」です(笑)。

高木:はい(笑)。

高橋:逆らう開発者がたくさんいます。だから採った方法は2つあって。そこのチームに対して「ここからバグが出ていますよね」と、エビデンスで証明してあげる。

あと、その単体テストを書くエンジニアを例えば僕のチームから出してあげたりするような。太陽作戦みたいなところですね。あともう1つは北風作戦で、とりあえず致命的なバグが出るまで待っているみたいなね。

高木:なるほど(笑)。

高橋:実際に開発チームと開発のチームをマネージするマネージャーが、両方共単体テスト嫌いだったりするケースもあります。

ただ、五寸釘を打ってるじゃないですけれども、必ずそういうチームって致命的なバグを起こすので。で、致命的なバグを起こしたら、「どうです? 助けますよ?」って言うとだいたい素直に吐いてくれるので。やはり大人の世界ですよね。議論と実践ではなかなかいかないというのはあります。

高木:もしかしたらそこにミューテーションがワークしてくるのかもしれないですよね。

高橋:そうですね。だからまあ、あらゆる手を採って。基本的に僕ら品質の担当者って、その人が憎いわけじゃなくて、やはりバグのない製品を出したいわけなので。

そういう人を送ったりとか、ソースコード分析をしてあげて「ここからバグが出るよね」と言うと、やはり開発者も恥ずかしいんですよね。テストもしていないし。単体テストをしていなければソースコードがどんどん汚くなってくるので、「汚いですよね」って言うとなんとなく言うこと聞いてくれるわけです。

高木:もしかしたらQAの役割が減ってきた分、そちらの方面に力を使っていく方向になってくるんですかね?

高橋:そうですね。だから冒頭に言ったように、そっちに行くためにQAの人もやはりソースコードを理解するべきだし、マネジメントの人も、いわゆる開発者も、QAに対してもっともっと理解を深めてもらうことが、僕は今後重要になってくるかなと思います。

高木:今まではQAは摘出というところをやってきましたが、品質の作り込みにシフトしていくようなイメージですかね?

高橋:僕は“共に歩む”っていう、なんかすごく宗教っぽい言い方をします。バグを見つける集団ではなくて、一緒に品質を上げていく集団、チームになっていく。

高木:やはりQAはそこができるようなスキルを今後身に付けておかないと生き残れないという話ですね。ありがとうございます。

プロジェクトの特性に応じてどの試験に重点を置くと考えるのがよいか

高木:「複数者が絡むシステムを構築する場合は、認識誤りやインターフェイスミスを検知する必要があるため、インターフェイス試験が重要になると思っています。UTでは検出できないところがあると思いますが、このようなものはプロジェクトの特性に応じてどの試験に重点を置いて実施するのか考えながら進めていくのがよいのでしょうか」。

高橋:僕はUIが絡まない、end to endのAPIテストをけっこう多用します。なので、何度かAPIかはアーキテクチャに準拠して欲しいですけどね。だから、今日はすごく短い時間なので説明できませんでしたが、APIテストでやっているケースは多々あります。

だから単体テストもやらなきゃならない。残ったところで非機能のテストをやらなきゃならない。だからこういうケースだと、それにプラスAPIテストを追加するのは、悪いアイデアではないと思っています。

高木:先ほども話したマイクロサービスの疎結合を進めてくという話にも絡んでくるんですかね?

高橋:そうですね。APIテストとマイクロサービスの疎結合のテストは非常に似ている ので。チームの中で話し合いながら、それをうまくやっていければいい気がします。

高木:このあたりはアーキテクチャが絡んでくるところなんですね。 ありがとうございます。

まともな単体テストを書くコツ

では最後の質問になります。「まともな単体テストを書くコツはありますでしょうか」(笑)。

高橋:まあ、場数を踏んでいくので。これはすごくいい質問なんですよ。なぜなら、コードは書けるんだけど、まともに単体テストを書ける人はすごく少ないです。よく僕はコンサルに行ってすごく優秀な開発者とお話しするんですが、初めの質問は、「どうやって単体テストを書くんですか」から入るケースが非常に多いんです。

なので、単体テストを書くコツは、アメリカでも日本でも「単体テストの書き方」という本がたくさんあるので、そういう本を読みながら。ちょっとここで説明すると長くなっちゃうので。実は単体テストの書き方については、本の中にはすごくよくない本もあるので、Amazonの書評を見ながらいい本を2、3冊買って覚えてもらえると。

できればそれを自分のスキルだけじゃなくて、チーム内のレビュアーの中でそういうスキルをシェアしていくのが、やはり品質を上げるコツということだと思います。

高木:やるとしたら、先ほど言ったカバレッジの知識と、あとは期待値の確認ということで、その期待値を出すようなテスト技法の本というイメージですかね?

高橋:そうですね。

高木:ありがとうございます。すべての質問に回答できたかなと思うので、Q&Aはこれで終了とします。