読書ログ

【読書ログ】レガシーコードからの脱却 5/16更新

1章 最善の道標はない

RC版の検証に2週間かかる手動テストも、2分以内に終わる自動テストに変えることができる。(ただし、プロセスを見直す事ができれば。)

レガシーコードとはテストのないコード。

ウォーターフォールモデルは建設や製造では理にかなっている。ただし、ソフトウェア開発は製造プロセスではない(その場その時にならないと必要なものがわからない)。また、結合時に不具合が見つかったり、プロジェクトの後半で見つかった新たな要件やアイデアを取り込む必要が出た時に大きなコストがかかる。

レシピはアレンジができる、公式はより厳密なもの。未知の領域ではアレンジができることが求められる。開発者が行動の結果を受け取るまでに時間がかかってしまう状態から逃れるためには刺激と反応をできる限り近づける。

コメントを書く場合も「なぜ」そうしているのかと理由を書く。「何」かはノイズになるどころか嘘になることもある。

成果に影響を与えられないという無力感はやる気を削ぐ。尊敬が人を巻き込む。

プロセスは創造性に影響しない。ソフトウェア開発は創造的なプロセス。

タスクの見積もりは難しい事が多い。未知のものはわからない。(プロセスに頼ろうとしてはいけない)

ソフトウェアの性質とそれ自体が時間の経過によって変化するものであることを理解することで、変化に強いソフトウェアが作れるようになる。業界が抱える問題を直視することが大切。

完璧な道標、共通の知識体系が存在せず、多くの人がレガシーコードとの付き合い方を理解していない。ウォーターフォールの問題点の指摘。

2章 CHAOSレポート

業界で一番多く引用される調査は、スタンディッシュグループのCHAOSレポート。

レポートでは成功の定義を「当初指定した機能を予算内・納期通りに完成させること」としており、プロジェクトの成功率は1/3程度としている。

経験的に成功率が高すぎるのではないかという疑問から、その定義を改めて考えるとPMの見積もり能力が高いことは言えそうではある。また成功とされるプロジェクトに成功とは言えないものも含まれそうということがわかる。(例えば、納入後1週間後にクラッシュしても、それによって顧客から二度と発注が来なくなっても成功と言えてしまうのだろうか)

成功率を下げる要因は3つ。コードの変更(変更できないコードを書いていないか)、バグの修正(バグが見つけづらい状態になっていないか、潜在化した不具合もより早く発見できるか)、複雑さの扱い(NISTの調査によれば機能の内45%は全く使われないことがある。またコストのかからない小規模な機能追加も保守の観点から未来のコストとなることがある)。

以降の章以降で新しいアイデアを確認していく。

保守に対する考えの甘さ(特に未来のコスト)は、新機能の開発が好きで楽しくて、ついしてしまいがちですが良く考えた方が良い(機能の内45%は全く使われないなどもあり)と思いました。

3章 アジャイル

「顧客満足を最優先し、価値あるソフトウェアを早く継続的に提供する」

よりプロセスを少なくし、開発者が集中してより良い方法を適用しやすくする。(品質を保証するためにプロセスを増やすのではなく)

よりよい方法(テスト駆動開発、ペアプロなど)を取り入れることで、デプロイ、運用、拡張が容易になり、変更可能なソフトウェアが開発しやすくなった。

ソフトウェア開発は多くの人にとって直感に反したもの。

あらゆる問題に対応できるようなスキルは習得できない。ソフトウェア開発では、芸術と技術のバランスを保ちながら開発者は様々な技術を活用することが求められる。固有の問題に対して固有の解決策が必要になる。

技術的卓越性を求める。9つの技術プラクティスとその背後にある原則について次の章以降で確認する。

4章 原則とプラクティス

専門家がすることを理解し実行すると再現できる可能性が高い。コードの品質を高く保つからこそコードを書くのも速い。

ピカソも守破離を実践していた。筆者はテクニックを原則とプラクティスに分類すると良いと考えているとのこと。

第一原理(単一責務の原則、オープン・クローズドの原則など)を学ぶこと。原則は強力だが、実現方法までは説明しない、明言されないこともある。原則は正しいことをするためのガイドになる。

プラクティス(原則を実現する方法)は、ほとんどの場合に価値があり、学ぶ/教えるのが容易、考えなくてもできるくらいシンプルであること。

必要なことをすべて予測するよりも、必要になった時に対応できるようにしておくこと。

使用されるソフトウェアは変更が必要になるため、変更ができるように書かれるべき。

良いコードの答え、また一貫した普遍的な合意形成はできていない。

5章 1:手順よりも概要を伝える

できるか < やるべきか

理解や解釈は人それぞれ、正しく伝わっているのか。伝言ゲームで正しく認識を揃えられるのか。(顧客→営業→開発者→顧客)

開発者はなぜ、誰のためのものかが知りたい。顧客や営業は、具体的なやり方を伝えるのはやめる。

プロダクトオーナー(PO)がいると良い。プロダクトがどうあるべきかを一番良く理解し、最終権力者がすべき。開発者の疑問に明確で直接的な回答ができる必要がある。いちばん重要なものを確実に作り、そうでないものは今すぐ作らなくても良いことにする。(そして葬り去ることで無駄な時間を減らす)

ストーリー(「何」が「何のため」に「誰のため」に存在するか)で説明する。1つの機能の1つの種類のユーザのために1つの理由を語る。「開発を発見のプロセスにする」(開発をしながら本当に必要な機能を見定める)

POは受け入れ基準、開発者と議論をする際の詳細の温度感。自動化された受け入れテストを利用することは、振る舞いを定義することが、全員が同じ考えを持ったことを意味すること。

プロダクトオーナーの7つの戦略(SME、開発を発見のために利用する、開発者がストーリーを理解できるようにする、何が欲しいのかを説明する、質問のレスポンスは早く、依存性は取り除き優先順位を設定する、リファクタリングを推奨する)

より良いストーリーを書くための7つの戦略(自分の事としてではなくプレースホルダーとして見る、目的(どのように利用されるか)に注目、ペルソナを利用する、機能が必要な理由を知る、追加は後からシンプルに始める、エッジケースを書き留める、受け入れ基準を明確にする)

6章 2:正しいサイズで

正しいサイズで対応する。大きすぎず小さすぎず、扱えるサイズに。

より短い期間でより実験的に選択肢を選べるように、短い期間で正しそうかを確認することで誤りをすぐに見つけ修正できる。

製造ならば並列化によって、独立したラインで作業可能であれば、ラインを2倍すれば生産性も2倍になる。ソフトウェアはそうではない。情報の伝達や調整に時間がかかる。

リリースサイクルが長くなるほどウォーターフォールを強制されることになる。そして、ストーリーから統合までを効率的に進めることよりも、タスクの種類ごとに作業をまとめる傾向がある。

小さいタスクはリスクが少なく、より多くのフィードバックをもたらす。そして、理解しやすく、見積もりしやすく、実装しやすく、テストしやすい。

分割の重要なスキルの一つ。複雑である場合、複数のことが混ざっている場合が多い。その場合、既知と未知を分類して対処する。未知の対処は、既知とするか、カプセル化しあとで対処する。

新機能を追加する上でのリスクを減らす唯一の方法は、できたらシステムに完全に統合してしまうこと。

行動可能な建設的なフィードバックが重要(高速な自動ビルド(3時間ではなく3秒以内に結果を返すような)。高速なテスト環境。(20秒ごとにテストを実行するような))

始めから正しく進めるのは難しい。間違いを許容できる環境と、間違いのコストと間違いを減らす方法を理解することが最速の道。

ビジネスでは価値とリスクの2つに着目すること。

バックログを作り、並び替える。そのプロセスも柔軟にしておく。

一般的な作業項目(タスク)を分解し、4時間ほどで終わるようなものにする。稼働率が100%の高速道路は駐車場のように見えるはず。著者は50%前後が理想的と示す。つまり、8時間作業時間がある場合はタスクは一つ(4時間)対応できたら理想。(それも「理想」であり本当に価値を生み出せていたら驚くべきこと。機械ではなく人間だから。)

明確な受け入れ基準と完成の定義が用意された4時間程度でできる小さなタスクを完成させること。ビジネスと開発で対話をする機会としても2週間のイテレーションが有効。同期の機会がないと対話ができなくなってしまうことがある。

生産性の計測ではなく、プロダクトとプロセスで価値の創出と計測を行う。進捗を計測する7つの戦略(価値実現までの時間、コーディングの時間、欠陥密度、欠陥検出、機能ごとの顧客価値、機能が提供されいない場合のコスト、フィードバックループの効率)

機能が簡潔に分解されることで目的が明確、評価しやすいものに保つことができ、保守しやすくなる。機能を分割する7つの戦略(複数のことを要素に、既知と未知に分離、未知に絞り込む、受け入れ基準を利用して分割、依存関係を最小に、意図は1つに、テスト可能に保つ)

7章 継続的な統合

面倒なことを回避するのではなく順応する。

インフラの問題。ソフトウェアをビルドしながら統合する。

ビルドサーバが心臓のように意識しなくてもコードの追加に合わせてリビルドとテストを実行する。

完了には三段階ある。(何らかの結果が得られたこと、ビルドに統合された状態、クリーンで保守可能な状態。)

ビルドは1から2秒で実行されるようにする。(システムを正しく分離できていればシステム全体をビルドし直す必要はないはず。)良いユニットテストを書き、テストすべきもののみ実行される状態。

既存プロジェクトをどのように導くか、プロジェクトを初める時も7.6は読み直したい。

実践するためのインフラの7つの戦略。(ビルドに必要なものすべてをバージョン管理にうする。ワンクリックでコンパイル、自動テスト、ビルドサーバで追加のテストが実行できるようにする。継続的な統合。受け入れ基準の明確化。テスト可能なコード。テストカバレッジを維持する。ビルドが壊れたらすぐに治す。)

リスクを減らすための7つの戦略。(継続的な結合。ブランチを避けリリース前の統合を減らす。自動テストを採用、運用する。リスクの特定。価値がわかる最低限必要なものを作る。頻繁な検証。)

8章 協力

ソフトウェア開発は世界で最も協働的な活動の一つである。

共通の認識が重要で品質、完成の意味を共有し、設計のための共通言語も必要になる。

ペアプロ(プログラミングは一人でするものと思いこんでいるが、極めて高いレベル(2つの頭で取り組むことでより早くより高品質)でタスクを進めることができる。一人では容易でないことも達成できる。(起電力や重量上げのと同じことが言える。)

メリット(チームで知識が早く共有できる。過度な属人化、専門化を避けることができる。より深い考察、指導する機会、学び助け合う、コードの共同所有が促される。一人で書くよりも不具合が少なく、コードも洗練される。保守コストを減らすことができる。ペアプロで失われる時間も50パーセントではなく15パーセントほどとのこと。さらに余計な割り込みが減り、集中力を保ちやすい環境になる。)コードレビューで一度に多くのコードを読むよりも一行ずつ、逐次的に確認できるアイデア。(書き終えたらコードレビューの機会も設けたほうが良い)

コードそのものがスタイルガイドになれば良い。(標準文章は必要ない。)

ペアプロの進め方はタイマーを使用したり、感覚的に良さそうなタイミングを見つけたり、お互いにテスト・クリーンにするを繰り返す。30分を超えない程度にする。

組み方は、完全にランダム、強みと弱み、経験のギャップを考慮するなどがある。ストロングスタイルペアリングもある。

またペアプロの導入として、バディプログラミング(業務時間の最後にお互いのコードをレヴューし合う)という方法もある。

他にもスパイク(未知の課題解決のために複数人の開発者で時間を決めて調査する。)や、スウォーミング(チーム全体、または複数のメンバーで構成されるグループで同一の問題に同時に取り組む)、モブ(普段から一緒になって単一のストーリーに取り組む。アリの群れのように仕事を分解して進める)などがある。

スパイクは未知の探求を始める前に疑問、目的、ゴールを決めて進めると良い。

イテレーションやリリースごとの振り返り(レトロスペクティブ)も改善を促す良い機会。同じ失敗を防ぎ、学びがある。(KPT)

8.8は少し考えが広がるような面白いことが書いてあった。(秘密結社)

8.9、姿勢の一つとして、メンターであり、メンティーでいること。モデルケースを見つけ、また自分が相手の中でそうなることで、お互いに良いところを利用し合うことができ、よりよくなれる。好循環に入る一つの流れがイメージできる。

ペアプロの7つの戦略(やってみる、参加する、頻繁な交代を心がける、一日中をオンにする、様々な単位の組み合わせを試す、ペアプロの価値をチームで見つける、計測しペアリングの価値を確認する)

振り返りの7つの戦略(小さな改善を繰り返し成果を積み重ねる、人ではなくプロセスが問題、なぜを5回問う、根本の原因を解決する、全員で取り組む、改善に必要な権限を与え変化をサポートする、成果のために進捗を測る)

9章 CLEAN

オブジェクトは特性・責任が明確で、実装が隠蔽され、状態を自身で管理し、定義は一度。

凝集性(Cohesive):コードの副作用を減らす。クラス・メソッドは単一の責任を持つべき。レイヤー(抽象化レベルを表現する)、命名(定義したものの名前を付ける)、コンポジション(複雑なものをモデル化する際の構成の仕方そのこと)。クラスはオブジェクトのふるまいを定義する。オブジェクトは何をするかを表す表現。名前は理解の手がかりになるがそれ自体は定義ではない。

疎結合(Loosely Coupled):テストが容易になる。依存が間接的で、依存性を持たせる場合はつなぎ目を用意して対応する(密結合しない)。良い結合か悪い結合かは一概に言い切れない。一つの判断基準は、意図的なものか、意図せずそうなったのか。悪い結合は品質の低いコードで現れる。APIを共有するのではなく、それぞれが必要な部分を内部的に使うAPIを複数作り隠蔽する。多くの場合、正しい設計であれば品質も上がる。(良い設計は他の箇所の品質を犠牲にすることを強いるわけでない。)

カプセル化(Encapsulated):簡単に拡張できるようになる。インターフェイスを実装と切り離すこと。(する事と仕方を切り離すこと。)そうすることでモジュール化され扱いやすくなる。顧客視点、開発者視点から設計したり開発することができ両方とも大切だが、順序が重要。全体像から、それぞれのコンポーネントがそれは何で、なぜあるのかを問うことから始めるとコード内に簡単に場所が作れる。カプセル化できるものには、関係性、プロセス、ふるまいの変化などがある。また、依存が少なければ少ないほどコードの変更は簡単。そして、必要に応じて公開する。必要なものだけを公開し、それ以外は隠し、問題の解決に必要なときだけ公開する。(一般的に隠しているものを公開する方が簡単、公開しているものを隠すのに比べれば。)呼び出し側の視点で設計するようになることで、引数と戻り値が明確になり、正確に理解しやすくなる。それ自体がドキュメントにもなり、システムの相互作用の副作用を減らすことにもつながる。

断定的(Assertive):ソフトウェアがモジュール化される。ふるまいの配置と適切な責任を決める上で価値のある基準。オブジェクトは権威的であり、自分自身の責任を持ち、自分自身を管理する。(断定的でない場合、他のオブジェクトを参照したり、複数のオブジェクトをまたがって正しい仕事をさせるために同期が必要になる。効率が良くないだけでなく、カプセル化を破壊してしまう)

非冗長(Nonredundant):保守の問題を減らす。冗長さを含まない。冗長とは意図が繰り返すこと。(つまり同一のコードがあっても、冗長な場合もそうでない場合もある。)様々な形(関係、概念、プロセスなど)がある。意図しない(ミッションクリティカルな場合以外)冗長性は保守上の問題になり、コストがかかる。

これら(CLEAN)は、それぞれが関係しあっているため、一つでも改善すればほかも一緒に改善が進む。テストを書くとき、設計をするとき、アプローチの検証のスコア化にも役に立つ。

開発中に学習した内容をコードに反映しなかった時に起きる「技術的負債」ほど、開発を遅く、見積もりを狂わせるものはない。プロの料理人の「私には汚くする時間がない」の言葉と同じように、できる限りきれいに、高品質なコードを書くことで、最高のソフトウェアを顧客に届ける事ができる。

コードの品質を上げる7つの戦略(品質とは明確で理解しやすく拡張が簡単である、プラクティス(機能開発を重視し凝集性のある目的をもたせた開発)の共有、必要なものを求めるために明確な受け入れ基準を持つ、最善のトレードオフを繰り返すことを理解する、カプセル化する、何をするかを示す(説明的・能動的・肯定的な)命名をする、テスト可能に保つ)

保守しやすいコードを書く7つの戦略(コードの共同所有、開発プロセスを通じてリファクタリングを行う、タスクはできる限りペアで進める、コードレビューを頻繁に行う、他の開発者から学ぶ、書籍から新たな手法を学ぶ、コードの読み書きの経験を積む)

10章 テスト

テストの種類は大きく3つある。受け入れテストは、(顧客テストとも呼ばれる。)開発者がPOや顧客と対話をし、ストーリや例外を把握し、受け入れ基準を定義し、必要なだけ確実に進めることができる。Cucumber、SpecFlow、Gherkinや、受け入れテスト駆動開発(ATDD)がある。ユニットテストは、内部ドキュメントとしても機能する、ストーリーよりも小さなユニットをテストする。それ以外のテストとして、QAテストがある(結合テストなど)。開発プロセスも含め、依存関係をできる限り切り離し、ユニットテストで済ませることが望ましい。そして、できる限りテスト(リリース候補の検証も含め)は自動化する。

QAテストの種類はリスクによって異なる。不具合の発見から修正されるまで時間が経てば立つほどコストは急増する。ふるまいを表す方法としてテストファーストで開発することで意味のあるテストとその土台が手に入る。ただし、QA作業の置き換えにはならない。また、ユニットテストも万能ではなく、実際の動作を確認する必要があるもの、設計を変更できない場合などテストが困難な場合がある。

テスト駆動開発は、仮設を立てながら、あらゆる観察可能なふるまいの単位でテストを書く。テストを先に書くと頻繁にフィードバックが得られる、テストは後に書くよりも先に書いた方が簡単に書ける(書き直しも少なくて済む)、テスト可能なコードが書ける。ユニットテストと呼ぶが、ユニットは関数やクラスではなく、ふるまいの単位を指す。ふるまいが変わらない場合、テストは書き直す必要がない。また、テスト駆動開発は、素早い反応が得られる。刺激と反応の結びつきは刺激に対して素早い反応が必要。マーチン・ファウラーのリファクタリングはすべての開発者が読むべき。テストがあることでリファクタリングをサポートできる。10章では、テスト可能なコードを書く、テストの書き方を学び、その価値を学んだ。

優れた受け入れテストの7つの戦略(プロダクトの価値を明確にする、要求が誰が何のためのものか知る、基準を自動化する、エッジケースを表す、ユースケースによる具体化とそれによる一般化と抽象化、受け入れ基準とふるまいを分離する、各テストを固有で独立した一意のものにする)

優れたユニットテストの6つの戦略(呼び出し側の視点、テストで振る舞いを表す、テストは一意にする、テストをパスするためのコードのみ書く、テストで振る舞いを作る、リファクタリング(コード・テスト))

11章 テストによるふるまいの明示

「テスト駆動開発していないから、テスト駆動開発をする時間がない」

レッドとグリーンとリファクタ。レッドはテストが失敗していることを意味している。それ以前のスタブの作成などは、レッドよりも前の段階。

JUnit(テストのフレームワーク)を利用したテストの書き方の例が紹介されていた。Personクラスを作る例は、初めに具体的な値を用意してから、存在しないクラスをIDEの機能で解決しながらクラスを作成しダミーの値を入れ、テストが失敗する(レッド)ところまでを確認した。続いて、ふるまいを実装し想定した動作になるとグリーン(テストが成功する)を確認した。さらにPersonの年齢の値について例外を設定しふるまいを追加した。例を同じ理由で成功・失敗するテストの重複を避ける。著者はテストは仕様と捉え、例外の前提となるような定数(最大や最小)についてもテストとして明確に記述し、定数の変更(仕様の変更)を検出(エラーが発生することによって)できるようにする。

テスト(例ではアサーションに3つの値を設定した)があることで、ユニットテストを実行するだけで、仕様が正しいかの確認ができる。仕様書が古い(実装の乖離している)などの難しい判断を避けることができ、生きた仕様であるといえる。

テスト駆動開発とQAは同時に行わない。開発段階ではふるまいを、QAでは開発段階では考えつかないようなケースを確実にカバーする。QAの考え方でテストを書くのはコードが動くようになってから。また、QAテストを追加するほどビルドが遅くなる可能性があるため、コードが機能するようになってから追加する。

良いテストは既知の理由で失敗し一意であること。(ただテストの数が多ければよいわけでない。)テストも冗長にならないようにする。(コードをリファクタリングする時に一緒にリファクタリングする。問題があった時にテストが本当の問題を隠すことがないようにする。)

ユニットテストのコードカバレッジ率の標準は100%。(この値を目標として80%などと下げると、抜け道を生むきっかけになる。)テストを書くのが難しいということはコードも複雑であり、テスト駆動開発にすることで、自然と複雑なコードを防ぎ、単純なコードを書くことができる。

ユニットテストが構文エラー(コンパイラエラー)と概念的なエラーのギャップを埋める。バグはテストがないために存在する。バグ修正の際には再現するテストを書いてからバグを修正する。

モック(実際のオブジェクトの代役)を使用したワークフローテストは、コードと外部の依存関係の相互作用の検証(呼び出しや引数が正しいかの確認)に使える。

ユニットテストはセーフティネットだ。心理的な保証となり、試行錯誤を安心して行うことができ、自由な実験をサポートし、既存のコードの維持コストを抑えられる。

テストを仕様にする7つの戦略(定数化による仕様の明示、意図が明解な名前のヘルパーメソッドを作る、重要な事柄は明解な名前の変数する、ふるまい(実装ではない)に基づき命名しテストする、ワークフロー(外部の依存関係などは)をモックを使ってテストする、冗長なテストは削る、要件を具体化し正確な例を使用する)

システムがどのように意図、想定して作られているかが明確に文章化され、貴重な資産となる。

バグ修正の7つの戦略(バグを作らない、早期発見、見つけやすい設計、原因を探す時にできる限り正しく絞り込む、バグはユニットテスト不足と捉える、欠陥からプロセスを修正する、バグを生み出した環境からその原因を学び改善する姿勢)

12章 最後に設計する

コードの変更のしやすさを妨げるも(知りすぎることによるカプセル化の欠如、過度(無意味・深すぎる)な継承の活用、抽象化を欠いた具体的すぎる実装、インラインコードの乱用、適切でない依存、オブジェクトのインスタンス化のタイミングや方法の選定が不十分)

持続可能なコードを書くための5つの考え方(使われていないコード(コメントアウト、未使用の変数・関数)を消す、名前の更新、判断の集約、抽象化の活用、クラスの整頓(過不足なく利用範囲において完全であるか))

コーディング中はテストに合格するようにふるまいを調整し問題解決方法を探し、クリーニング中はテストでサポートされているコードを理解しやすいように調整し、保守可能にする。そうして改善のスパイラルに入る。技術的負債の返し方は、短期的にはテスト駆動開発でリファクタリングのタイミングで対応し、長期的には定期的なリファクタリングのタイミングで対応する。

コードは書かれる回数の10倍読まれる。コードは自分のためではなく他の人たちのために書く。何回も書き直される。コメントはコードの理由(なぜそうなっているか)を伝えるために使う。コードがしていることはコードが示すべき。(例外:ドキュメントが不十分なAPIを使用する場合など)

コードを読みやすく、保守しやすくするために、観点の一貫性を保つ。仕方(具体的な方法)ではなく、目的を最小限の単位(論理回路)とその抽象(意味のある単位のまとまり)で階層化する。

循環複雑度を減らし、バグの確率を減らす。(条件分岐を無くすことはできなくとも少ない方が良い。)オブジェクトの生成(インスタンス化)と利用のフェーズを分けると良い場合がある。ポリモーフィズムによって実施して欲しい命令の名前が分かれば内容の詳細を知る必要はない。分離することで、生成と利用のそれぞれが正しいかを確認すれば良いためテストも容易になる。

より良い設計を自然に生み出すために反復開発をし設計を創発する。テストファーストな開発によって、原則、プラクティス、技術的負債に注意を払いながら、漸進的に作ることで、作り込み過ぎない、そのときに考えることができより良い設計にたどり着ける。

創発設計を実践するための4つの戦略(多くの分野の理解を深める(オブジェクト指向設計、デザインパターン、テスト駆動開発、リファクタリング)、CLEANなコードを書く、より良い設計を選択する、この姿勢を習慣にする)

コードをクリーンする6つの戦略(コードが語るようにする、接合部を作る、クラス・メソッドの凝集性を高める、判断の集約、ポリモーフィズムを活用する、生成のカプセル化)

13章 リファクタリング

リファクタリングの価値はコスト(後からコードを理解する時、ユニットテストを追加する時、新しい機能を追加する時、さらなるリファクタリングを実施する時)を削減できること。

技術的負債は基本的に累積する。時間やタイミングなどで修正が難しいこともあるが、トレードオフを意識し、コードに問題がある場合も出荷する場合がある。

レガシーコードであっても、コードの品質に関係なく価値を提供し続けられている場合がある。要求が変わり価値を提供できなくなった時、変更が必要になる。テストを追加してからコードを修正することで、安全・安価に変更できる。良い習慣を身につけ(悪いコードのリファクタリングから学ぶ)、不可解なことは先送りにし、価値あるソフトウェアの開発に集中する。

4つのテクニック

  • ピンニングテスト:粗め(最低限必要なサポートが得られる程度)のテストを書く。(開発者が小さな変更を積み重ね品質を落としたものに対抗するには、)品質を少しづつ向上させるように小さなコードの変更を続ける。
  • 依存性注入:依存関係(使用するオブジェクト)を生成せず、注入する。コードをテストしやすくするために、依存関係は切り離す。
  • ストラングラーパターン:インタフェースを活用し、古いサービスをラップした形で新しいサービスを作り、徐々に置き換える。
  • ブランチの運用:バージョン管理から不要なブランチを無くす。ブランチを作らずに対応できるものはブランチを作らない。(例えば、インタフェースとフィーチャーフラグによって機能を新旧で切り替える。)

変化に対応するため、顧客が変更しやすいものを変更しやすくするために、4つのテクニックを使用し、対応する。