1つのメソッドシグネチャを変更しましたが、現在25,000以上のエラーがあります。今何?


166

私は最近、非常に大きなアプリケーション(15M loc)で作業している新しい仕事を始めました。私の以前の仕事では、同様に大きなアプリケーションがありましたが、(良くも悪くも)OSGiを使用しました。これは、アプリケーションを独立して変更、コンパイル、デプロイできる多数のマイクロサービスに分割することを意味しました。新しいアプリケーションは、たった2つの.dllを備えた1つの大きなコードベースにすぎません。

ですから、このクラスのインターフェースを変更する必要があります。それが上司が私に要求したことだからです。彼らは当初、あまり一般化されていないいくつかの仮定でそれを書きました。しばらくの間、リファクタリングの問題は非常に密に結合されているため回避していました。インターフェイスを変更しましたが、現在25000以上のエラーがあります。エラーの一部は、「XYZPriceCalculator」のような重要な名前のクラスにあり、これは本当に壊れてはいけません。しかし、すべてのエラーが解決されるまで、アプリケーションを起動して動作するかどうかを確認することはできません。また、ユニットテストの多くは、そのインターフェイスを直接参照するか、そのインターフェイスを参照する基本クラスに結合されるため、それらを修正するだけでも非常に大きなタスクです。さらに、これらのすべてのピースがどのように組み合わされるかについては本当にわからないので、たとえ始めたとしても、物が壊れた場合にどのように見えるかはよくわかりません。

私は最後の仕事でこのような問題に本当に直面したことはありません。私は何をしますか?


7
エラーの種類と「このクラス」が何であるかについての詳細情報を提供する必要がありますが、読者は気にしません。
-whatsisname

137
VSに表示される「25000以上のエラー」などの数値は、しばしば間違っています。いくつかのエラーがありますが、よく使用されるdllのビルドが壊れると、他のビルドも失敗し、天文学的なエラー番号が発生します。私は常に、エラーリストではなくビルド出力にある最初のエラーメッセージから修正を開始します。
ベルンハルトヒラー

13
変更したメソッドの前後の署名を確認したいと思います。ところで-25kのエラーは、あまりにも多くの対処が必要とは思えません。面倒なはい、恐ろしい、はい、管理不能、いいえ。
jmoreno

46
パブリックインターフェイスは契約です。そのような契約を破らないでください-新しい契約を作成してください。
マシューリード

6
25000エラー!?ヒューストン、問題が発生しました。間違いなく変更を元に戻して上司に相談し、新しいインターフェイスをすべて作成する必要があるかもしれないことを説明してください。
コードウィスパラー

回答:


349

25000のエラーは基本的に「触らない」ことを意味します。元に戻します。目的のインターフェイスを持つ新しいクラスを作成し、クラスのコンシューマーを新しいクラスにゆっくりと移動します。言語に応じて、古いクラスを非推奨としてマークすることができます。これにより、あらゆる種類のコンパイラ警告が発生する可能性がありますが、実際にはビルドを壊しません。

残念ながら、これらのことは古いコードベースで起こります。ゆっくりと物事を改善することを除いて、あなたがそれについてできることはあまりありません。新しいクラスを作成するときは、適切にテストし、SOLID原則を使用して作成し、将来変更しやすくするようにしてください。


79
必ずしも新しいクラスである必要はありません。言語や状況に応じて、それが機能、インタフェース、特性、などであるかもしれない
ジャン・ヒューデック

33
また、古いインターフェイスを新しいインターフェイスの互換性ラッパーに置き換えることができる場合にも役立ちます。
1月Hudec

79
時々、25000のエラーは実際に私たちがそれに触れることをあえてしないことを
mouviciel

13
@theDmi:私は同意します。1回の変更と25kのエラーは最大で2.5kの変更を意味する可能性が高く、それが約250であることは驚くことではありません。
jmoreno

33
これらの25000エラーはすべて、1回の変更で修正できる場合があります。巨大な階層の基本クラスを壊すと、派生クラスのすべてが無効なベースに関するエラーを吐き出し、それらのクラスの使用はすべて存在しないクラスに関するエラーを吐き出します。それが「getName」だったと想像してください。引数。「HasAName」実装クラスのオーバーライドは機能せず(エラー)、それを継承するものはすべてエラー(1000クラスすべて)を生成し、それらのインスタンスを作成するたびに(クラスごとに24x平均)。修正は... 1行です。
-Yakk

80

リファクタリングで分割して征服する

多くの場合、実行する必要がある変更を小さなステップに分割すると、ソフトウェアをまったく壊さない方法でほとんどの小さなステップを実行できるので役立ちます。リファクタリングツールは、このようなタスクに非常に役立ちます。

割る

最初に、達成したい変更に要約される可能な最小の変更を(LoCの変更ではなく、論理的な変更の観点から)特定します。特に、純粋なリファクタリングであり、ツールで実行できるステップを分離するようにしてください

征服する

あなたのような複雑なケースでは、一度に1つの小さなリファクタリングを実行してから問題を休ませることが理にかなっている場合があります。これにより、すべての継続的インテグレーションシステムが変更を検証でき、テストチームも同様に確認できます。これにより、実行する手順が検証されます。

特定のリファクタリングを実行するには、変更するメソッドの呼び出しサイトが25,000ある場合のツールサポートが絶対に必要です。検索と置換も機能するかもしれませんが、このような重大なケースでは、それが怖いでしょう。

たとえば、C#では、Resharperを使用してメソッドの署名変更できます。変更が十分に単純な場合(たとえば、新しいパラメーターを追加する場合)は、コンパイルエラーが発生する呼び出しサイトで使用する値を指定できます。

すぐにエラーのないコードベースになり、すべての単体テストを実行できます。これはリファクタリングのみであるため、合格します。

メソッドのシグネチャが適切に見えたら、Resharperが引数として新しく導入されたパラメーターに追加した値を変更できます。これはもはやリファクタリングではありませんが、エラーのないコードベースがあり、変更する各行の後にテストを実行できます。

時々それは動作しません

これは、あなたのような多くのコールサイトがあるような場合に非常に便利なアプローチです。そして、あなたは現在動作しているソフトウェアを持っているので、署名を少し変更するために小さなリファクタリング手順を実行してから、別の手順を実行することが可能かもしれません。

残念ながら、署名の変更が複雑すぎて小さな変更に分解できない場合は機能しません。しかし、これはまれです。問題をより小さな問題に分割すること、通常、それ可能であることを示しています。


12
この。可能であれば(安全に)リファクタリングします。そうでなければ、適切な移行が必要です。
-sleske

3
そして、何でも好きな場合は、(たとえば)メソッドシグネチャをローカルで変更してから結果のエラーを「修正」するのではなく、IDEの組み込みリファクタリングツールを使用してください。
KlaymenDK

36

上司と仕事を明確にして、プロのソフトウェア開発者としての問題とあなたのニーズを彼が理解できるようにします。

あなたがチームの一員である場合、主任開発者を探して助言を求めてください。

幸運を。


15
これは私が取る最初のステップです-「私は後輩であり、上司から何かをするように言われ、今では本当に大きなエラーメッセージが表示されますが、上司はそれについて教えてくれませんでした。」ステップ1:「やあボス、やったんだけど、今は25kエラーが出る。それは起こるはずなのか...」
16年

28

触らないでください。何もコミットしないでください。

代わりに、椅子に座って「Heeeeelp !!!!!」と叫んでください。できるだけ大声で。

そうではありませんが、先輩にアドバイスを求めてください。25,000のエラーがある場合、エラーを修正するのではなく、エラーの原因を修正します。そして、上級の同僚は、25,000のエラーを伴うことなく、上司が望む変更を行う方法をアドバイスできるはずです。これを行うにはさまざまな方法がありますが、良い方法は特定の状況によって異なります。

そして、上司があなたの先輩に同じ変更をするように言ったのかもしれませんが、彼らは「いいえ」と言いました。何が起こるか知っていたからです。それがあなたに仕事が与えられた理由です。


2
これは間違いなく覚えておくべき重要なことです。新しい従業員が本当に大いに意欲的である場合、彼らは5バイトのメモリアドバンテージを獲得するだけの本当に大きなタスクを実行するのに十分な勤勉(だまされやすい)かもしれません。
グレートダック

@TheGreatDuck:どこでも使用されているインターフェイスと、どこでも間違っているインターフェイスを見たことがないと教えてください。確かに。
ジョシュア

@Joshuaは、私が言ったこととは関係ありません。マイナーなバグを修正することは、それが常に10,000行以上のコードを書き換えることを意味するという最も賢いアイデアではないことがあります。残念ながら、新しい従業員は、上司に感銘を与えてそれを成し遂げるためにそのコードを書き直して仕事の外で10徹夜する人を引くほどだまされやすいかもしれません。もちろん、それは素晴らしいことですが、時には十分である場合もあります。バグの存在を受け入れる必要があります。
グレートダック

1
@Joshua btw、この質問は私のよくある質問のフィードに載っていたので、私はこのコミュニティに参加しました。このような大規模な設計の経験はありません。この人の意見に同意しました。
グレートダック

22

強化されたAPIを単純に変更することはできません。それらを本当に変更する必要がある場合は、それらを非推奨(言語が許す限り)として注釈を付けて文書化し、代わりに使用するAPIを文書化します。古いAPIは、リファクタリングの時間予算に応じて、おそらく非常にゆっくりと段階的に廃止できます。


10

評価する

この変更が必要かどうか、または新しいメソッドを追加して他のメソッドを廃止できるかどうかを評価します。

進む

変更が必要な場合; その後、移行計画が必要です。

最初のステップは、新しいメソッドを導入し、古いメソッドに引数をマッサージさせて、新しいメソッドを呼び出せるようにすることです。これには、いくつかのハードコーディングが必要になる場合があります。それはいいです。

これはコミットポイントです。すべてのテストが成功、コミット、プッシュすることを確認してください。

移行する

忙しい仕事は、古いメソッドのすべての呼び出し元を新しいメソッドに移行しています。ありがたいことに、フォワーダーのおかげで徐々に行うことができます。

どうぞ ツールを使用して支援することをためらわないでください(sed最も基本的で、他にもあります)。

古いメソッドを非推奨としてマークします(新しいメソッドへの切り替えのヒント付き)。これは、何かを忘れたかどうかを確認するのに役立ち、これに取り組んでいる間に同僚が古いメソッドへの呼び出しを導入する場合に役立ちます。

これはコミットポイント(またはいくつかのコミットポイント)です。すべてのテストが成功、コミット、プッシュすることを確認します。

削除する

しばらく経った後(たぶん1日程度)、古いメソッドを削除します。


4
sedおそらく悪い考えです...実際に言語を「理解」し、意図しない大幅な変更を行わないものの方が優れています。
-wizzwizz4

1
@ wizzwizz4:残念ながら、実際にC ++に十分な言語を理解するツールはほとんど見つかりませんでした。ほとんどのツールは名前の変更に対応しているようで、それだけです。確かに、正確なメソッド呼び出しのみの名前変更(および、オーバーロードや関連のない類似の名前のメソッド呼び出しではない)はすでに印象的ですが、より複雑なものには不十分です。少なくとも、(1)引数をシャッフルする、(2)与えられた引数に変換を適用する(呼び出し.c_str()など)、新しい引数を導入する機能が必要になります。sedちょっと動作しますが、コンパイラは後で問題をキャッチします。
マチューM.

1
sed(またはedすることができますこの種のものには適して-限り、あなたがコミットする前に、正しく差分を確認して。
トビーSpeight

これはhtmlのTCRRです。:)
ダニエルスプリンガー

8

メソッドシグネチャの変更が単なる名前の変更である場合、簡単な解決策は、ツールを使用して、問題のメソッドを参照する25,000クラスの変更を自動化することです。

コードを手動で編集しただけで、すべてのエラーが発生したと思います。また、Java(OSGiへの参照を参照)に精通していることを前提としているため、たとえばEclipse(使用しているプログラミング環境はわかりませんが、他の環境には同様のリファクタリングツールがあります)では、「リファクタリング->名前変更」を使用できますメソッドへのすべての参照を更新します。これにより、エラーがなくなります。

メソッドのシグネチャを単に名前変更(パラメータの数またはタイプを変更)する以外の方法で変更する場合は、「リファクタリング->メソッドシグネチャの変更」を使用できます。ただし、他の回答が示唆するように、より注意する必要がある可能性があります。また、変更の種類に関係なく、ビジーなコードベースでこれらのすべての変更をコミットするタスクでもあります。


2
OPは、OSGiが以前の職務にあったと特に述べたので、ここではあまり関係ありません。
CVn

3
@MichaelKjörlingOPが以前の仕事でJavaプログラマーだった場合、この仕事でもJavaプログラマーである可能性があります。
リッチ

@MichaelKjörlingOPはJavaに精通しているため、リファクタリングにEclipseを使用して、具体的な推奨事項を伝えたいと思いました。OPが実際に現在のプロジェクトにJavaを使用しているかどうかはそれほど重要ではないと思いますが、答えを明確にする必要があります。ありがとう。
MikkelRJ

6

ここで私の貢献。

私は最近、非常に大きなアプリケーション(1500万行のコード)に取り組んでいる新しい仕事を始めました。

あなたはおそらくプロジェクトとその「機能」に精通していないでしょう。1行のコードを入力する前に、プロジェクトに精通していることが重要です。変更をロールバックして、コードの分析から始めてください。(少なくとも影響を受けるもの)

既存のソリューションを理解することで、どこから始めようとしているのかをより正確に把握できます。ソリューションのコンテキストとその重要性。

@Gregが指摘したように、既存のコードをテストして、比較する有効な参照を持つようにする必要があります(回帰テスト)。ソリューションは、既存のものとまったく同じ結果を生成できる必要があります。この段階では、結果が正しいかどうかは気しないでください。最初の目標は、バグを修正するのではなく、リファクタリングすることです。既存のソリューションに「2 + 2 = 42」と表示されている場合は、ソリューションもそうである必要があります。例外がスローされない場合は、例外もスローしないでください。nullを返す場合は、nullも返す必要があります。等々。そうしないと、25,000行のコードが危険にさらされます。

これは 、レトロ互換性のためです。

どうして?なぜなら、今のところ、それはリファクタリングの成功を保証する独自の方法だからです。

また、ユニットテストの多くは、そのインターフェイスを直接参照するか、そのインターフェイスを参照する基本クラスに結合されます。

レトロ互換性を保証する方法が急務であるため、ここが最初の課題です。単体テスト用のコンポーネントを分離します。

これらの25k行のコードは、既存のコードの可能な結果を​​想定して作成されたことに留意してください。契約のこの部分を破らなければ、最終的な解決策の半分になります。もしそうなら、力はあなたと一緒かもしれません

新しい「契約」を設計して実装したら、古い「契約」を置き換えます。それを非推奨にするか、取り出してください。

バグのリファクタリングと修正は別のタスクであるため、バグを残すことをお勧めします。それらを一緒に進めようとすると、両方で失敗する可能性があります。バグを見つけたと思うかもしれませんが、それらは「機能」である可能性があります。(1分間)そのままにしておきます。

25k行のコードは、たった1つのタスクに集中するのに十分な問題のように思えます。

最初のタスクが完了したら。これらのバグ/機能を上司に公開します。

最後に、@ Stephenが言ったように:

ゆっくりと物事を改善することを除いて、あなたがそれについてできることはあまりありません。新しいクラスを作成するときは、それらを適切にテストし、SOLID原則を使用て作成し、将来変更しやすくするようにしてください。


5

試して。

他の誰もがリファクタリングの方法を推奨しているため、影響はほとんどありません。しかし、そのような多くのエラーにより、わずか10行のコード(おそらく可能)でリファクタリングに成功した場合でも、コードを書き換える必要がなくても、25,000のコードフローに影響を与えています。

そのため、次に行うことは、回帰テストスイートが確実に合格することです。そして、もしあなたが持っていないなら、それを作るでしょう。包括的なリグレッションテストスイートをモノリシックプロジェクトに追加するのは退屈に聞こえますが、リリース候補の信頼性を高め、スイートが適切に自動化されている場合はリリース候補を迅速にリリースする良い方法です。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.