技術改善をはじめよう

## はじめに

仕事が変わったとき、新しいプロジェクトに配属されたとき、技術書やカンファレンスで最新の開発手法を学んだとき、ふと目の前のコードが技術的に遅れている、と感じることがあるのではないでしょうか。

マイクロサービスやクラウドネイティブなどのアーキテクチャ構成、CI/CDや自動化、AI活用にDevOps、言語やフレームワークの新バージョン。次々と新技術が登場する中で、すべての面で最適な技術構成となっているプロジェクトのほうが稀なはずです。

ひとたび技術的な課題を感じると、目の前のコードに激怒し、このレガシーコードを取り除かねばという衝動に駆られ、今すぐにリファクタリング、技術改善を実施したくなるものです。

本記事は、そんな技術改善を衝動的に始めたくなったときに、一歩立ち止まって考え、プロジェクトとして真に意味のある技術改善を始めるための考慮事項を検討します。

技術改善を始めるべきと衝動に駆られる開発者と、プロジェクトや組織に携わる多くのステークホルダーの間には認識の差があることが多く、技術改善はただちに歓迎されるとは限りません。個別の改善内容ではなく、どうやって改善をするか、「コードや技術の領域ではない課題」を本記事では検討します。

### 対象読者

特に、既に開発組織をリードするエンジニアや、技術改善に責任を持つエンジニアというよりは[^1]、これからはじめて技術改善を始めたいと思う若手エンジニア向けの内容となっております。

[^1]: このような方々に私からアレコレ言うのはお門違いでしょう。

## 技術改善と認識のバイアス

まず、前提を一旦立ち止まって考えてみましょう。

「技術改善を実施すべき」と感じたとき、それは技術的に、あるいは客観的に正しい判断なのでしょうか？

実際のところ、正しい判断を妨げる典型的ないくつかのバイアスが存在します。これらを認知したうえで、正確な現状認識を作ることが技術改善を始める第一歩となるのです。

### 既知への誘導

#### 導入

詳しくない技術や未知のコードに直面したとき、人は無意識に「自分がよく知っていて安心できる構成」に引き寄せたくなるものです。慣れ親しんだアーキテクチャ、言語/フレームワーク、DBMS、クラウド...のほうが、未知のそれより、なんとなくいいものに思えるのではないでしょうか。

あるいは、自分が実装あるいは設計したコードであれば、その概要や背景情報を知っているため容易に理解することができます。そうでないコードをどの程度理解できるかは、現状の技術力とコードベースの品質によるところですが、少なくとも、未知のコードと自分の関与したコードの間では、理解度に大きな差が生じます。

そして、目の前に未知のコードや技術が存在するとき、現状のコードを書き換えることで、未知のコードを自分が実装あるいは設計した既知のコードへと昇格させることができるのです。

この自己中心的な行動は、多くの場合無意識的に、「今の〇〇技術は遅れている」とか「今のコードは品質が低い」という形で正当化されるわけです。

#### 解説

未知への恐怖と、既知への安心感というのはどこか本能的なものであり、その感覚自体を否定することはできません。程度の差はあれ、こうした志向は多くの人が持ち合わせているものでしょう。

しかし往々にして、こうした未知から既知への誘導は、技術改善という蓑をまとって正当化されることになります。このような種類の「技術改善」は、ある開発者にとっての自己満足にはなっても、プロジェクトやプロダクトに対しては恩恵がないという結果に終わります。

そのために、提案する技術改善が「全体のための変更」なのか「自分のための変更」なのかを常に問い、現状の技術や設計、新しい技術を理解し、客観的に説明することが必要です。後述しますが、現状の技術やコードベースの理解なしに、有効な技術改善を推進することは非常に難しいため、まず現状理解を進め、それから改めて始めたい技術改善が、バイアスなのか、技術的ないとなみなのかを判断しても無駄になることはないはずです。

また、他の開発者との会話やコミュニティ参加を通して、様々な新技術や意見に触れるのも、このバイアスを緩和するのに有益でしょう。

### 新技術への信仰

前セクションと類似しますが、「新しい技術はいいものだ」という思い込みもまた一般的なものです。

これもまた、ある種の進歩史観というか、本能的なものといえるでしょう。あるいは、一般に新技術に対しては批判的な人よりも好意的な人が集まりやすく、触れることになる情報にバイアスがあるという理由もあるかもしれません。

やはり公平な判断をするためには、新技術がどのようなものであるかを理解する、特に従来技術に全くよらない新技術というのは稀であり、そうした関連性や差異を理解すること。そして、未知の不具合や特定のユースケースへの適合性、開発終了などの、新技術に特有のリスクについて一定の考慮をすることが必要でしょう。

### 現状への過剰な批判

技術的な改善を始めるという提案は、現状への課題認識と一定の批判を含むことになります。これを推進しようとするほど、現状の実装がいかにひどいものであるか、間違っているかという過剰な批判に走りがちになります。

しかし、今あるプロダクトを形作り、収益を上げてきたのは目の前にあるその実装であることは紛れもない事実です。そして、異なるフェーズには異なる要件があり、ゆえに当時としては最適な技術的判断を繰り返した結果が現状である可能性もあります。

何より、これから技術改善を始めるにあたって協力を取り付けなければいけない人たちは、現状のコードを過去に実装し、現在まで保守してきた人たちである可能性が非常に大きいわけです。既存実装と開発の歴史に敬意を払い、現状を理解する姿勢を見せないことには技術改善を成功させるのは難しいでしょう。

もちろん、技術改善の出発点として現状の分析と課題把握が必要なことは事実です。時間的に不変な技術的な正解があると考えるより、技術全体と自分たちの情勢によって変化すると考える。また、最適解を選ぼうとするより、大きく外さない選択を狙う、といったマインドで立ち回ることで、過度な現状批判を避けることができるはずです。

## 技術改善とステークホルダー

ここまでの障壁を乗り越え、ある程度妥当に思われる技術改善を提案することになったとしましょう。ここからは、その先に待ち構える着手までの課題を取り上げます。

技術改善を始めることは、組織にとって往々にして大きな選択となります。ゆえに、現在の開発プロジェクトに関与する多くのステークホルダーを巻き込むことになるのです。しかし、異なるステークホルダーには異なる関心事項があり、これが技術改善を始める障壁になることもまた多いのです。

ここでは、「少し前の現場で実際にありそうな技術改善」を題材に、ケーススタディでこの壁をイメージし、解決策を考えてみます。

### シナリオの設定

時は2020年。あなたは、とあるB2B向けWebサービスの開発チームに配属されたばかりのエンジニア。サービス自体は顧客に提供されているものの、サービスの品質と開発体制に課題を感じます。

- テストコードや自動化されたテストが存在せず、すべて手作業で検証
- PRのレビューやリリース作業において動作検証に多くの時間が必要
- 本番環境での単純な不具合やリグレッションが定期的に発生

そこで、**テストコードによる単体/結合テストの記述と、テストの自動実行基盤およびそれに基づくPRレビュー/リリースの導入** を提案することにしました。新規実装にはテストコードを義務化し、既存実装にも順次テストコードを追加していく想定です。また、コンテナ環境で実施されたテストがすべて通過するPR/リリースのみが承認されるようにします。

簡単に言うとテスト自動化とかCIとか呼ばれるやつですね。現代から見るとこの提案はとても自然、当たり前のように思われるかもしれません。

### 提案への反対意見

しかし、この提案には多くの関係者から反対や懸念の意見が出ることになります。

#### ①「売上に貢献しない改善より新機能に注力を」

最初の意見は事業側のマネージャーからのこんな声です

> 今はサービスの成長が最優先事項でしょ？新機能が出れば既存顧客からの売上増も見込めるし、競合サービスへの差別化にもなる。売り上げに貢献しない技術改善より、新機能開発に注力してほしい。

##### 背景と事情

これは、プロダクトの売り上げや顧客からの反応に関心がある層から想定される意見です。こうした立場では、技術的な知識や専門用語の理解が浅く、技術面の重要性が伝わりにくいか軽視されている傾向にあります。また、金額などの定量的な数値目標に追われており、長期的かつ定量しにくい技術改善の提案には否定的な印象を持たれる、というケースもあるでしょう。

とはいえ、ソフトウェア開発の生産性や品質は最終的にはこうした立場にもインパクトがあるものになります。現状の課題や、それを放置した場合のリスクを理解してもらうとともに、一定折り合いをつけることがキーになるでしょう。

##### 解決策の例

- 「不具合についての苦情が平均10件来ている」「テスト自動化でリリースが2週間短縮できる」など、プロダクト的な視点での利点を定量的に説明します
- 改善内容や長期的な価値を平易に説明します。比喩的な表現や技術的に正確を尽くすとはいえない表現が必要かもしれません
- 開発するプロダクトがどのような方法・理由でユーザーに支持されている、あるいはされていないのかを把握します。それと今回のプロジェクトを関連付けることができる可能性もあります。
- 機能開発と技術改善の間での作業時間のバランスを取り、機能開発が停滞するわけではないことを説明します

#### ②「新しい仕組みで障害発生したら本末転倒」

今度は、インフラ側の責任者からの声です。

> テストコードの追加やそのためのリファクタリングで障害が起きるんじゃないの？障害対応はコストも大きいし、ビルド環境に何か追加するとなると権限の問題もある。リスクがあることはやらない方がいい。

##### 背景と事情

変更によるリスクは未知であり、恐ろしく感じられるために、現状維持を選択したくなる心理的な要素があります。加えて、不具合・障害対応は突然に時間を取られ、しかも先が見えない中優先度の高い作業となり、計画できるタスクよりも負荷が高くなります。

もちろん外部視点でも、プロダクトが利用できないこと、データの消失や破損は信頼を失う大きなリスクとなります。

一方で、このケースにはリスクの問題点だけでなく、組織構造や責任分界点の設定といった問題も隠れています。アプリケーションコードに関心がある推進者と、基盤の安定運用やセキュリティに関心があるインフラ側で目線が合っていない可能性が高いです。結果的に、テスト自動化の恩恵と負担が均等に分配されていないと感じているのかもしれません。

##### 解決策の例

- リスクを整理し、低減策を検討します。リスクの可能性と影響度を検討し、整理することで、未知が薄れ安心感が出ます
  - リスクが少ない部分からはじめたり、残るリスクの対策として動作確認を設計したり、切り戻し手順を用意・検証したりすることで、リスクを軽減できます
- テスト自動化は成功すれば障害発生リスクを下げられるものです。今後のコード増加なども考慮し、現状維持に存在するリスクを意識します
- インフラ側の関心事項や懸念、要望について収集・調整し、計画に含めるよう心がけます
  - テスト自動化によって追加で発生する作業や負担について、会話・整理し、(少なくとも短期的には)作業の一部または全部を巻き取るのも手です

#### ③「テスト基盤のコストを払う価値は？」

開発側の予算管理者からはこんな声が

> テスト基盤で使うインスタンスの価格って結構高いんじゃない？こんなにコストを投入して、それだけの恩恵があると約束できるのか。

##### 背景と事情

ソフトウェア開発が事業である以上、何かにコストを掛けるには妥当性や計画性が必要です。そのコストを使う必要性が本当にあるのか、その使い方は正当なのか、どれだけの効果が得られるのか、といった事項に対する説明責任のようなものが提案側にあるといえます。

なお、コスト面について意見が出た場合でも「お金を使うな」「もっと安くしろ」という意味ではないケースも実は多いでしょう。コストを変えることではなく、平均的なケースとワーストケースでどの程度の価格・内訳になるか見込みを示し、そのうえでコスト以上の恩恵があることを客観的に説明することが必要です。

##### 解決策の例
- かかる費用をシミュレーションし、内訳を示します。ソフトウェア関係では従量課金も多いですが、ある程度上限を見積もっておくと安心感が出ます
- 逆に、テストによって削減される工数や、品質向上の価値を金額で計算してみましょう。それが費用を上回るのであれば、やる意味があると客観的に示すことができます
  - 逆に、直接にコストを削減することを目的とする技術改善の場合は関係性が逆になります。
- 想像以上に人間のリソースは高コストであることに留意します。個人から見て非常に高いように思われても効率化につながる改善は価値が高いことも多いですし、逆にコスト削減の技術改善は作業時間を加味すると赤字になることもあります。

#### ④「既存メンバーがテスト書けるわけない」

一方、身内の開発組織からも懸念の声が。開発チームのリーダーを務めるエンジニアからは

> 今までテスト文化なかったし、うちのメンバーは経験ゼロ。テストコードの書き方とかテスト基盤の運用とか教えないといけないでしょ？今でも忙しいのにテストも運用していくのか、想像もつかないんだけど？

##### 背景と事情

今まで知らなかった技術へ踏み出すのはやはり難しいことです。そして、それには個人差があり、つまりすべての開発者が新しい知識を学ぶことに積極的だというわけではないのです。技術改善を志す技術派にはそれは相容れない姿勢かもしれませんが、何より人を変えるのは難しいのです。

加えて、そうした現実を受容し、その現実をエンジニアリングの対象として捉え、一定の品質のもと期日までに開発プロジェクトを「何とかする」ことがエンジニアリングであるという側面もあります。このような意見を出した本人が新技術に消極的とは限らず、チームとしてのエンジニアリングをみているかもしれません。

##### 解決策の例

- 新しい技術・開発体制に移行するためのドキュメントを制作したり、学習に役立つ書籍・動画などのリソースを示して移行パスを簡単にします。勉強会や輪読会などを企画し、ハードルを下げつつ知識を平準化していくのも有効です
- まず、推進者本人からテストの導入を開始し、続いて賛成派のメンバーや既に一定の経験があるメンバーにもテストを書いてもらいましょう。段階的に実績を作り、課題を洗い出し解消していくことでスムーズに移行することができます
- 最後のフェーズとして、開発組織全体の決定としてテストを導入する必要があります。こうした技術的統制が取れるよう事前準備を進めていくとよいでしょう

#### ⑤「テストが遅い・変な失敗で止まると困る」

開発メンバーからは

> 必要な機能の他にテストコードも書いて、レビューのたびにCIが30分も回って...いや、勘弁して。実装が間違ってないのにテストが落ちて「またこのパターンか...」みたいな偽陽性が出るのも、開発現場の足を引っ張るんだけど。

##### 背景と事情

技術改善としてテスト自動化を導入する、という判断が決定されると、その決定が撤回されるまでの間継続的に、テストの実装や運用が続くことになります。また、それが組織的な選択である以上、一定の強制力が生まれます。これは、技術改善が変化であることと合わせて、忌避感を生みやすい原因になります。

実際の開発メンバーは、この変更で最も直接に影響を受ける可能性が高いわけで、実際の開発業務を考慮したすり合わせ、何より当事者意識を共有することが双方にとって重要になるはずです。毎回30分必要で偽陽性が意識されてしまう場合、そもそもテストとして不備があるといえますが、こうした点は見過ごされがちになります。

##### 解決策の例
- 技術改善の構想や目標について、早い段階から会話します。実際の開発の状況や課題を得ることは構想を現実的かつ有効にできますし、目標を共有することで理解が形成されやすくなるはずです
  - テスト実行時間や偽陽性が開発生産性に影響することがこの場合理解できます。そもそも提案する技術改善が技術的に妥当であるために、こうした問題に取り組み改善自体をよりよいものにする必要性が明らかになります
  - 導入後も状況を確認できるよう、実行時間や偽陽性について継続的にモニタリングするとよいでしょう
- テストの記述方針や運用、Q&Aなどの役立つドキュメントを作成したり、実際に少数のコードにテストを実装しておくなどすることで、作業を簡単にします

### 反対意見の価値

シナリオでの反対意見の例をみて気分が悪くなった人もいるかもしれませんが、こうした反対意見が出るのは悪いことではありません。むしろ、それぞれの発言者は自身のタスクや責務に忠実であるがゆえにこうした反対意見が出るのだともいえます。

むしろ、こうした反対意見が出ない場合こそ、例示したような反対意見を想定してみるといいでしょう。それによって、技術改善の提案はより合理的でかつ多くの関係者にとって反発のないものにブラッシュアップされるからです。

こうした反対意見を受け止め、提案する技術改善を多角的に分析し、その価値を説明する。そのプロセスの中で、今は不要な改善を発見し提案から取り除いたり、あるいは現状維持という判断を行うことで、ユーザーやプロダクト、開発組織にとっての価値を最大化できるわけです。

## 反対意見を乗り越えるために

前節で例示したような反対意見に対して、丸腰で立ち向かっていくのは無謀という他ありません。多くの場合、着地点が見つからないことになってしまうでしょう。反対意見が出そうな雰囲気を感じたら、しっかり準備をすることが必要です。

### 知識

まず、提案する技術内容について深く理解することが求められます。往々にして、「テックカンファレンスで聞いた」「本でチラっと見た」「前職でやってた気がする」くらいの浅い理解度の状態から、技術改善をはじめたいというストーリーはスタートします。が、この理解度では先に進めないことは明らかです。自分が主体的に説明できる程度まで、理解度を高めましょう。

### 現状把握

提案する技術について理解度を高めた、あるいは理解していたとしても、それだけでは提案の説得力は今ひとつです。その技術が自分たちにとって有用であることを説明する、あるいは、より有用になるように技術改善をカスタマイズしていく必要があります。

そのために、今のチームにおける課題認識や事例を把握することが有効になります。各開発者の現状の認識や、直近で発生した開発メンバーの困りごとやインシデントについてアンテナを張り、情報収集を続けることで、技術改善の提案にとって有効な情報を得ることができるでしょう。

また、提案を客観的に納得できるものにするためには、定量的な指標があることが重要です。テストを改善したいならば、現状のテストのカバレッジの低さ、リグレッションテストにかかる工数、リリースまでの期間、インシデント事例などが武器になります。こうした指標を地道に集めていくことが、最終的には近道になります。

### 人間関係

技術改善に熱心な開発者が嫌いそうなテーマですが、人の要素も避けられないことでしょう。技術改善として遊撃的なポジションを取るにはある程度の信頼度が必要ですし、それを波及させるには影響力も必要です。

これについてはあまり飛び道具はないように思われます。やるべきことをやり、できそうなことを積極的に拾っていく。ある程度の時間も必要になるかもしれません。

## 技術改善プロジェクトの進行

反対意見を乗り越えるための準備ができたら、次は実際にプロジェクトを開始することになります。
ここでは、できるだけ反対意見によって阻まれにくく、かつ開発組織にとって真に価値のある技術改善をできるだけ順調かつ低リスクに進めるための、技術改善プロジェクトのすすめ方のステップについて検討します。

### 合意形成

これはもしかすると準備段階に入るかもしれませんが、技術改善の実施についてゆるやかに合意形成をすることが必要になります。

いきなり実施について合意形成するのは難しい場合が多いのは前の節でみてきた通りです。これは技術改善が完全に否定されているような気分を覚えるかもしれませんが、案外そうでもないことが多いのです。

まずは技術改善を始めるための動機である課題感についてから合意形成してみましょう。あなたがその課題を認識しているということは、おそらく他にもその課題を認識している開発者が一定数存在するはずです。そうした人たちと、まずはその課題が存在し、可能なら解決されるべきであることについて会話します。

そのうえで、まずは後述するように小規模・実験的・個人的に提案する技術改善を実施してみることの合意を目指しましょう。あくまで、将来はより大きなビジョンをみているけれど、まずは小さく始めてみるのだと合意すれば、スムーズに進むはずです。もしうまく行かないときは、今が時期ではないのかもしれません。しかるべき時期をうかがって再試行すると成功したりします。

### 実験的導入

技術改善とプロダクト開発は、どこか遠い存在のように感じらますが、プロダクト開発におけるプラクティスは技術改善プロジェクトにおいても有効なことが多いように思われます。

プロダクト開発が最小限のアプリケーション、MVPからスタートするように、技術改善も最小限の改善からスタートすると成功しやすいです。ただし、プロダクト開発と同様に、その技術改善によって達成したいゴール、ビジョンが理解でき、その成果が評価可能であることが重要です。そのうえで影響範囲も小さい計画を頑張って作成する必要があります。

そうした計画に対して、まずは少量の時間で、1人または少人数で取り組んでみます。そうして、事例を作り、この技術改善が果たして見積もり通りの効果があるのか、今の開発組織において現実的なのかといった事項を見極めていきます。

### 本格運用

実験的導入が成功したならば、この技術改善を本格的に導入することができます。ここでは、実験的導入で得た知見などをドキュメントとして横展開したり、技術改善が一過性のブームではなく継続的に運用されるよう指標や運用方針を設計する必要があります。

どこかのフェーズで、今までの主体的に今回の技術改善を推進する立ち回りから、そのプロセスを平準化し身を引いていく時期がやってくることでしょう。これに成功したときが、技術改善プロジェクトの１つの区切りといえるかもしれません。

## さいごに

日々様々なプラクティスが生まれ、提唱され、流行するテック業界ですが、案外こうした技術改善プロジェクトの立ち上げについて書かれたものは少ないように思われます。この記事が、技術改善をはじめようと志し、そしてその困難に直面した人たちの助けになれば幸いです。