私は、既存の関数に余分なパラメータ(または新しい有効な値)を追加することで新しい動作をカバーすることができますが、コードを多かれ少なかれ "明らかに同じ"既存のケースでは、関数を変更することにそれほど大きな危険はありません。例えば
、古いコード:
def utf8len(s):
return len(s.encode('utf8')) # or maybe something more memory-efficient
新しいユースケース - 私はnullオブジェクトパターンを使用したスタイルでいくつかのコードを書いているので、私はutf8len(None)
が例外をスローするのではなくNone
を返すようにしたいです。そう、私は新しい機能utf8len_nullobjectpattern
を定義することができ、それは非常に迅速非常に迷惑を得るために起こっている:
def utf8len(s):
if s != None:
return len(s.encode('utf8')) # old code path is untouched
else:
return None # new code path introduced
を次にutf8len
ためのユニットテストが不完全であったとしても、私は私がのために行動を変更していないことを賭けることができますNone
以外の入力。また、誰もutf8len
に頼ってNone
入力の例外をスローしていないことを確認する必要があります。これは、(1)ドキュメンテーションやテストの質の問題です。 (2)人々が実際に定義されたインターフェースに注意を払うのか、それとも単にソースを使うのか。後者の場合、私はサイトを呼び出す必要がありますが、物事がうまくいけば、私はほとんどしません。
許可された古い入力が「明らかに同じ」と扱われるかどうかは、修正されるコードの割合は実際には問題ではありません。古い関数本体の全体が表示されているので、私は意図的に簡単な例を選んだが、それを見たときに知っていると思う。もう1つの例は、固定の値を提供するだけのデフォルトのパラメータを使用して設定可能なものを作成する(おそらく、値を取得するために使用された値または依存関係を渡すことによって)ものです。古い固定されたもののすべてのインスタンスは、新しいパラメータに置き換えられます(そのため、変更が何を意味するのかをdiffで確認するのはかなり簡単です)。少なくとものテストでは、あなたが愚かな誤植で古い入力を壊していないことを確信しているので、テストカバレッジに全面的な信頼を置かなくても前進することができます。
もちろん、包括的なテストが必要ですが、必ずしもそうであるとは限りません。また、2つの競合するメンテナンス命令があります。1 - コードを重複しないでください。バグがある場合、または将来変更する必要がある場合、バグ/現在の動作が重複しているためです。 2 - オープン/クローズドの原則は、少し高めですが、基本的には「働くものを書いてそれに触れないでください」と言います。 1は、これら2つの同様の操作の間でコードを共有するようにリファクタリングする必要があると言います.2はいいえ、あなたは古いものを出荷しました。この新しいものに使用可能かどうか、 。
関数が複雑で、関数の10%しか変更できない場合は、それをリファクタリングする必要があります。 –
理想的には、既存の機能を壊さずに自信を持って修正できる十分なテストがあることです。だから、ここで質問することさえあるという事実は、テストが本当に十分ではないと前提しています。答えは、「私たちはテストをしています。私たちが好きなこと全てをやる時間がない "、"ぞっとする "。 –