Martin Fowlerは、新しい機能を追加する前にリファクタリングを行うべきだと言っています (元のプログラムが適切に構成されていない場合)。
したがって、私たちは皆、この汚れたコードベースをリファクタリングしたいと考えています。それは確かです。また、コードの単体テストを行わないと、微妙なバグが非常に簡単に発生することもわかっています。
しかし、それは大きなコードベースです。これに完全なテスト スイートを追加するのは現実的ではないようです。
この場合、あなたはどうしますか?
Martin Fowlerは、新しい機能を追加する前にリファクタリングを行うべきだと言っています (元のプログラムが適切に構成されていない場合)。
したがって、私たちは皆、この汚れたコードベースをリファクタリングしたいと考えています。それは確かです。また、コードの単体テストを行わないと、微妙なバグが非常に簡単に発生することもわかっています。
しかし、それは大きなコードベースです。これに完全なテスト スイートを追加するのは現実的ではないようです。
この場合、あなたはどうしますか?
私の提案は、できるだけ触らず、必要なものを追加することです。特に締め切りが厳しい場合は、十分に一人で去るのが最善であることがわかりました.
単体テストがあれば話は別ですが、コードを変更すると、蜘蛛の巣に触れるようなものになる可能性があります。1 つのことを変更すると、他のすべてに影響を与える可能性があります。
Michael Feathers著の「 Working effective with legacy code」という本をお勧めします。多くの現実的な例が含まれており、レガシー コード ビーストに取り組むための優れたテクニックを示しています。
リファクタリングするコードに単体テストを追加します。
Repose's Trickle Theory の Rands を参照してください。これは、彼が膨大な数のバグで遭遇した同様の問題です。彼の推薦:
私のアドバイスは次のとおりです。
単体テストが存在しない場合、または指定された時間枠内に適切なカバレッジで追加するのが非常に難しい場合は、定期的なテストに依存する必要があります。理論的には、あなたが話しているこの大きくて汚いコードベースは、過去しばらくの間、使用に適していると見なされてきました。その決定を行うために、プログラマーテスト、QAテスト、または顧客によって行われたある種のテストのいずれかがありました。あなたはそれがどのように行われたか、何が行われたか、あなたが行う変更をカバーするのに十分であるかどうかを知り、そしてそれを再び行うというコミットメントに加えて、製品が良くなるまで新しいコードに必要なテストを取得したいと思います足りる。
単体テストはプログラマーにとって素晴らしいサービスですが、そこにあるテストの種類は単体テストだけではありません。
それをどちらかまたは両方の命題と考えないでください。単体テストを追加することで付加価値が得られます。いくつかのテストを追加する利点を得るために、スイート全体を追加する必要はありません。
過去 2 年間、私はほとんどこの状況に悩まされてきたので、私はこのような状況に陥ることがよくあります。
正しいアプローチは、技術的な側面よりも、社会的および組織的な側面に大きく依存します。あなたの仕事は、組織に価値を生み出すことです。リファクタリングがコスト以上の価値を生み出すのであれば、それを売ることができるはずです。私の場合、主な要因は次のとおりです。
問題のプロジェクトの予想される所有権。 近い将来、この特定のソフトウェアの重要な利害関係者になることを期待している場合、それは、悪いコードベースにさらに広範な変更を加えることを支持する議論です。ドライブバイ機能を追加する場合は、より無干渉のアプローチを採用してください。
変更の複雑さ。 コードベースに非常に複雑な変更を加えている場合 (「汚れた」コードベースの典型的なケースであり、そのようなソースは一般に密結合でまとまりがありません)、リファクタリングが必要になる可能性が高くなります。このような変更は、コードの忍者であることの結果でもありません。あなたが行っている変更について。これは、変更しているコードベースの「悪さ」にも関連しています。密結合でまとまりのない混乱に対して、最も単純な単体テストを作成することさえ事実上不可能です。(私は経験から話します。私がほぼ行き詰まったプロジェクトの 1 つは、生成されたコードを除いて、12 個のファイルで約 20,000 行の長さでした。アプリ全体は、「Form1」と呼ばれる単一のクラスでした。これは、開発者が部分的なクラス機能。)
組織の監督。 組織の監視の強さと厳しさがここで発揮されます。あなたのグループが実際にコード レビューなどのいくつかのコア ベスト プラクティスを実行し、リップ サービスを提供するだけではない場合、私は大規模なリファクタリングを行わない傾向があります。あなたが行ったいくつかの変更のいずれにも望ましくない副作用がないことを確認するために、別の新鮮な目でチェックする別のペアがあるため、値のトレードオフはおそらく、できるだけ触らないことを優先して重視されます。同様に、より厳格な監視は、変更要求で厳密に要求されていない変更を行う「ゲリラ」コード戦術に眉をひそめる可能性が高くなります。
あなたの上司。 上司があなたの味方である場合は、コードベースの価値を長期的に改善できる可能性がはるかに高くなります。特に、今後の予算時間の観点から現在のコストの増加を正当化できる場合はなおさらです。あなたの上司は、全体像におけるこのソフトウェアの役割について、あなたよりも優れた視点を持っていることを忘れないでください。10 人または 20 人しか使用しないソフトウェアの場合、1 万人または 2 万人が使用するソフトウェアに必要な長期的なメンテナンスの改善は必要ありません。
このような時間の投資を検討する際に答えなければならない重要な質問は、「価値はどこにあるのか?」ということです。次に、その値を追跡する必要があります。
まず、変更するパーツのテストを追加します。次に、正気の人にとって意味のあるものになるまでコードをリファクタリングします。第三に、必要な変更を加えます。
Fowler はまた、テストの安全性なしには決してリファクタリングしないことを示唆しています。しかし、どのようにしてこれらのテストを実施するのでしょうか? で、どこまで行くの?
以前に推奨された本 ( Michael Feathers によるLegacy Code を効果的に使用する) は、このテーマに関する決定的な著作です。
もっと早く読む必要がありますか?Michael の同名の以前の記事 (PDF)をご覧ください。
その多くは言語に依存します。静的に型付けされた言語を使用している場合は、おそらく単体テストなしで済むでしょう。私はあなたが説明していることを正確に行う多くの仕事に取り組んできました.
かなりの量の作業 (たとえば、1 人年または 3 人で 4 か月) の場合は、誰かにコードを分解して最初に分析してもらいたいと思うでしょう。
動的言語の場合は、より問題が大きくなります。ある程度の単体テストが必要になります。おそらく、触れる必要がある領域に単体テストを追加できます。
私が静的言語と動的言語を区別しているのは、静的に型付けされた言語でリファクタリングを行う方がはるかに簡単であるためです。Ruby が嫌いというわけではありません。ROR にも 1 年間費やしました。ただ、彼らには異なるアプローチが必要だと思います。
どこかから始めなければなりません。できるところにテストを追加することから始めて、作業を進めながらテスト スイートを構築できます。何もしない「ばかげた」テストがいくつかあるとしても、コードの一部をテストできるだけで、何かがわかります。
一連のテストを追加することが実際的でない場合は、コードベースに重大な問題があります。
新しいコードを追加して、それがうまくいくことを期待するのは悪いことです。
テストを書き、ベースをリファクタリングし、新しいコードを追加します。テストできなければ、それが正しいかどうかはわかりません。
できるだけ触れないでください。そして祈ってください。
私は他の人に同意します。できるだけ触れないようにします。しかしまた、あなたが触れようとしている新しい機能や既存の機能の単体テストをいつでも書き始めることができます。最初から既存のコード ベースを 100% テストするために、単体テストを作成する必要があるとは誰も言いません。