nunulkのプログラミング徒然日記

毎日暇なのでプログラミングの話題について書きたいことがあれば書いていきます。

ソフトウェアの内部品質に対するアプローチについて

はじめに

この記事について

最近 X で「ベテランエンジニアが設計にこだわりすぎてるせいでなかなかリリースできなくて困る」みたいなポスト(当該ポストが見つけられず、正確な表現は間違ってるかもしれません)を見て、思い当たる節があったので、自分の考えをまとめます。自分の中にあるていどの基準は持っているものの、現場ごとに毎回どうアプローチするか悩むこともあるので、そういうときのために自分で参考にしたいです(悩むことは必要なことですが、必要最低限にしたい、ということで)。

文脈

途中から参画したシニアエンジニアが、コードの内部品質を高めようとして、リファクタリングに時間をかけたり、コードレビューを厳しくしたりした結果、リリースまでにかかる時間が長くなってしまった、みたいなシチュエーションを想定しています。 もう少し細かくすると、

  • 既存のメンバーはあまり技術レベルが高くない
  • そのシニアエンジニアは自分が頑張らないとこのプロダクトの内部品質は上がっていかない、というような責任感とリーダーシップを持っている
  • メンバーはそれを好意的に受け取っている人とそうでない人に分かれている
  • ビジネスサイドはあまりいい印象を持っていない

みたいな状況にあると、仮定します。

解決したい問題

ソフトウェアの内部品質を維持あるいは向上させることと、リリースまでにかかる時間を維持あるいは遅延させないことをどうやってバランスすればいいか、一定の基準を定めたい。

前提:ソフトウェアの内部品質とリリース速度のバランス

一般的には「技術的負債」と表現される「内部品質を犠牲にして(借り入れて)リリースし、リリース後にそれが改善(回収)されずに残った状態」1とか、「Done is better than perfect. (多分動くと思うからリリースしようぜ)」というマーク・ザッカーバーグの言葉とか、とかく内部品質とリリース(の速さ)はトレードオフにされがちです。

一方で、内部品質とスピードはトレードオフの関係ではない、という言説もあります。むしろ、内部品質が高まればスピードが上がる関係である、というものです。

speakerdeck.com

私自身も、内部品質が低いとリリースまでにかかる時間が増すと感じていて、主に、ドキュメントがない、自動テストがない、コピペコードが多い、長い関数が多い、などの理由により、修正のコストが上がっていってしまう、というのは事実だろうと思います。

しかし、このスライドにあるとおり、

・内部品質がスピードを生み

・スピードが学びのループを生み

・学びのループが外部品質を生み

(中略)

・競争力が売上を生み

・売上が内部品質を育む

というのが真実だとするとなにも問題はなく、「内部品質第一」がとっくにコンセンサスになっているはずですが、現実に「内部品質を高めようとするとリリース速度が落ちるので困る」と考える人、あるいはそのような現象が中長期的に起きている、というのが事実だとすると、なにか見落としがあるんじゃないかと思うわけです。

いまは「品質と速度はトレードオフ関係である」という認識が「品質は速度に欠かせないパラメーターである」という認識へ移行している時期であり、過渡期である、ということなのかもしれませんが、だとしても、これだけ移行に時間がかかっているのはなぜか、ということです。

以上を前提として、私の認識を書いておくと、「品質と速度がトレードオフになってしまうのはそのように認識してしまう人間の認知バイアスのせい」ということなんじゃないか。だとすると、内部品質向上を目指す前にまずはそれらの認知バイアスをいかに取り除くかということにフォーカスしたほうがいいのではないか、というものです。

認知バイアスのせい?

上記のスライドで引用されている「メンバーの成長とその成長のために必要なフィードバックや学習の時間が秤にかけられているのではないか」という感覚は、私も持っています。

スピード感のために品質を落とすということはチームの成長を諦めるということ - ネットの海の片隅で

この記事の冒頭に書いたような文脈では、「成長や学習」に投資しないあるいはそれらを望まない集団の中に「品質が速度を生む」と考える人が加わることで起こるネガティブな反応が「困る」という感想になってしまうのかな、ということです。

「困る」というのは拒否反応なので、一時的なものかもしれません。そもそもそういう発想(学習や成長)がなかった、ということであれば、状況は徐々に改善していくのかもしれませんが、現状維持バイアスによって成長を拒んだり、確証バイアスによって品質から目を背けてしまったりすると、よりその拒否感が強くまた長引くかもしれません。

学習や成長を無意識にできる人っていうのはそうそういないんじゃないかと思っていて、個人だろうが組織だろうがまず第一に意思が必要ですし、それに加えて意図的に学習や成長ができるような計画なりデザインなりをしていかないと、成果を出すのは難しいものです。なので、学習や成長への拒否感をいかに反対方向へ切り替えていくか、というのが課題になるわけですが、個人的には非常に難しいと感じています。

投資に対する考え方

いままでの話はあくまでもエンジニア組織の話であって、ビジネスサイドは含めてないんですが、ビジネスサイド含めた組織レベルでの内部品質(=つまり学習や成長)に対する認識や態度となると、正直私には分からない部分が多いです。

これまで一緒に働いてきた人は、理解があって協力してくれる人、やんわり拒む人、あからさまに拒む人、などなどバラバラだった気がします。拒絶反応を示した人に対してはそれ以上深掘りしてないので分からないんですが、学習や成長は個人の問題であって、組織的に取り組むものではない、という認識があるのかもしれません。もっというと、エンジニアに比べると非エンジニアの人の組織観として、組織的な学習や成長が重要な要素である、という認識が薄いのかもしれません。

経営層の考えとして、内部品質の向上はいますぐビジネス上の成果として現れないもの、つまり投資であって、必要性は認識しているが、いまはそのときではない、という判断なんだろうと思います。

さらに、投資というのは無駄になってしまうことがある性質のものです。組織的に学習と成長への投資に取り組んだとしても成果を生まない(成果が出るまで時間がかかる)状態に陥ることがあると思います。

個人でも、自分自身への投資をしない人というのはたくさんいるので、それが組織レベルになったら増えるかっていうと増えないだろうな、という気はします。

意図的にせよ、そうでないにせよ、投資に対する考え方はひとつの価値観なので、内部品質にとどまらず、意欲的に投資する経営者(OR マネジャー OR リーダー)なのかどうか、という見極めは必要かもしれません。

内部品質に対するアプローチ

ようやく本題ですが、内部品質向上が全面的に歓迎されているわけではない、という状況において取りうるアプローチは2つ考えられて、

  1. リーダーに内部品質の重要性を説き、一任してもらってから自分の思ったとおりにやる
  2. リーダーの望む範囲内でやる

のどちらかかなと思います。

ここでいう「リーダー」とは、経営者かもしれないし、CTO かもしれないし、部長かもしれないし、テックリードかもしれないですが、要はプロダクトマネジメントに関する意思決定の権限を持っている人のことを指します(さすがに CTO がいる組織で、内部品質が蔑ろにされるってことはないと思いたいですが)。

どんな大きさであれ組織や集団はリーダー次第で、まずはリーダー自身が自分の度量や力量とどう向き合っているか、が鍵になります。意図的に投資を切り捨てているのか、手が回らなくて疎かになってしまっているのか、過去に取り組んだが失敗した経験があって二の足を踏んでいるのか、など、リーダーの考えや経験などをできるだけ理解する必要があるでしょう。

なので、最初は 1 のアプローチで試してみて、これはだめそうってなったら 2 にスイッチするっていうのが基本になるかと思います。が、仮に 2 になったとしても、すぐに状況改善を諦めるんじゃなくて、少しずつゴールをずらすことは可能だと考えています。

ゴールをずらす(内部品質基準を高める)ためには、まずは信頼を勝ち取ることが大事で、「この人が言うなら信じよう」と思ってもらえるかどうか。これまでの(他の現場での)実績は関係なく、あくまでも参画してからの積み上げです。以前のエントリーにも書きましたが、他人のマインドを変えるのは難しいので、時間と労力はかかると思います。ここは私自身のいちばんの課題といってもいいんですが、人間に対する粘り強さがなく、二、三度試してダメなら諦める傾向があります。どこまで粘り強く説得するか、というのは、相手を見てそのつど判断する必要はありますが、「これはダメかもな」と思ってからもう一押し、二押し、くらいは粘ってみようと思います。

あとは、どれだけチームメンバーを巻き込めるか。変更コストが高いことが認識されていれば比較的楽ではありますが、長いことその状態で仕事をしているとそれが当たり前になっていて、現状維持バイアスがあると、頭で分かっていてもどうしても拒絶反応が出てしまう、ということはあるのかな、と思います。

どこから手をつけるか

内部品質向上に投資していきましょうっていう気運になったのであれば、最初からリファクタリングに着手していけばいいでしょうが、そうでない場合、つまり少しずつ信頼を得ながらゴールをずらしていくほかない、となった場合には、信頼の得やすいところから少しずつ施策を広げていくことになります。

本当なら、効果を数字で出せるのがいちばんいいんでしょうけど、スクラム開発を導入してベロシティを測っているならまだしも、そうでない現場では難しいです(そして、往々にして内部品質向上に投資していない組織の場合、そうしたシステムは存在しません)。

なので、いきなり内部品質に手をつけるのではなく、まずはパフォーマンスチューニングから始めるといいのではないかと考えます。内部品質の低いプロダクトはたいてい SQL が非効率だったり、N+1 クエリがあったりしてパフォーマンスが悪い傾向があります。パフォーマンスの向上は外部品質にあたるので効果も見えやすいですし、改善してる感が非エンジニアにも伝わります。

次に、自動テストの整備です。最近は自動テストがない現場に入らないようにはしていますが、すでに導入済みであったとしても実行が遅い、テストケースの漏れが多い、など改善の余地はあるものです。デグレーションが起きているならまずはテストケースを拡充することを優先します。巨大なクラスや関数に対してテストが書けてないのであれば、スプラウトクラスやスプラウトメソッドを導入してテストしたい処理に対してテストを追加していきます。この辺は「リファクタリング」や「レガシーコード改善ガイド」などを読んでおけば、試行錯誤しながらできるようになっていくと思います。内部品質向上の価値が認められたのであれば、社内で勉強会などを開いてもいいかもしれません。

自動テストに関しては、できればテスト駆動開発を取り入れるなどして、リリースする前にリファクタリングを終わらせる文化にしていけるとなおいいです。テストがあれば、大胆に改善できます。もちろん、リファクタリングに時間をかけすぎるのも考えものですが、最初から品質の高いコードを生み出すのは難しいので、最初のうちはあるていど仕方ないでしょう。ペアプログラミングやモブプログラミングも取り入れつつ、スピードアップできるような仕組みも整えたいですね。

テスト駆動開発テストファースト)については以下のエントリも参照してください。

nunulk-blog-to-kill-time.hatenablog.com

そのソフトウェアについての学びを深めるにつれてリファクタリングを行うことで、得られた経験をプログラムに反映していくのです。 Ward Cunningham

https://t-wada.hatenablog.jp/entry/ward-explains-debt-metaphor

コードレビューに関して

個人的にはあまりコードレビューを厳しくしすぎるのはよくないと思っていて、重箱の隅をつつくような指摘はもちろんしませんし、ベターな書き方が仮にあったとしても、内部品質に対してそれほどのインパクトがないと判断できる場合は指摘しないことが多いです。これまでジュニアの人がコードレビューで大量の指摘を受けて凹んでいるのを何度か目にしてきましたが、それで向上する内部品質と、そのジュニアの人が受ける精神的ダメージを天秤にかけると、後者の悪影響のほうを懸念してしまうからです。

それよりはシニアの人がジュニアの人にコードレビューをしてもらう機会を作ることで、自分のコードを参考にしてもらい、次回似たような処理を書くことがあれば真似してもらい、本人が自発的に学習して成長していってもらうほうが、時間はかかりますが、プロダクトの健康とチームの健康のトータルで考えたときにはベネフィットが大きくなると思います。

おわりに

「ソフトウェアの内部品質を維持あるいは向上させることと、リリースまでにかかる時間を維持あるいは遅延させないことをどうやってバランスすればいいか」について考えてみました。品質が高まればスピードも上がる、というのは現実問題としてはなかなかすぐにその因果関係が見えてくるものではないと思っていて、マインドセットの変化や仕組みが伴わないといけないですし、技術の関係するところでもあるので、一定レベルまで引き上げるための時間も必要です。

今後ももしかすると似たような状況のチームに入ることがあるかもしれないので、現時点の方針としては、ここに書いたような考え方やシナリオをもとにして、チームやプロダクトの特性を加味しながら、いいやり方を模索していきたい所存です。


  1. ちなみに、技術的負債についてはまだ誤解している人がそれなりにいそうなので、こちらの記事を貼っておきます。https://t-wada.hatenablog.jp/entry/ward-explains-debt-metaphor