他の誰かが書いた3500行の長さのC関数があり、リグレッションを発生させずに分解する必要があります。それはCにあるので、私が直面する主な問題は変数の状態を維持することです。たとえば、コードのごく一部を別の関数に分割する場合、10個の引数を渡す必要があります。それらのいくつかは、実際には新しい関数のコード内で変更されます。だから効果的に私はそれらへのポインタを渡す必要があります。とても散らかってしまいます。そのようなリファクタリングに対処するためのより良い方法はありますか?「ベストプラクティス」はありますか?
6 に答える
ユニットテスト。3つ以下の変数(1つの変数が最適)に依存するコードの小さな部分を抽出し、それから地獄をテストします。元の関数のそのコードを新しい関数の呼び出しに置き換えます。
- 各関数は、コードを調べることで簡単に理解できる1つのことを実行する必要があります。
- 10個の変数を渡す代わりに、それらを構造体に入れて渡します。
私の意見では、あなたができる最善のことは、その機能を徹底的に研究し、その内部を完全に理解することです。この関数には多くのアンチパターンが含まれている可能性が高いので、リファクタリングは試みません。関数がどのように機能するかを理解したら(これは多くの時間を想定できることを理解しています)、破棄します。必要な同等の小さな関数を最初から書き直します。
複数のサブ関数間で共有されるローカル変数を構造体にパックし、構造体を渡しますか?
あなたはCで立ち往生していますか?このような関数をC++クラスに変換することがあります。そこでは、一部(またはすべて)のローカル変数をメンバー変数に変換します。この手順が完了すると、コードの一部をメンバー変数で機能するメソッドに簡単に分割できます。
実際には、これは次のような関数を意味します。
... do_xxx(...)
{
.. some thousand lines of code...
}
次のように変換できます。
class xxx_handler
{
public:
xxx_handler(...);
... run(...)
{
part1();
part2();
part3();
return ...;
}
private:
// Member variables goes here.
};
// New replacement function.
... do_xxx(...)
{
xxx_handler handler(...);
return handler.run(...);
}
関数の一部を独立した関数として取り出すための最初のステップとして、最初に行うことの1つは、「関数グローバル」一時変数をより狭い範囲に移動することです。
int temp;
temp = 5;
while(temp > 0) {...}
...
temp = open(...);
if (temp < 0) {...}
に変換
{
int temp = 5;
while(temp > 0) {...}
}
...
{
int temp = open(...);
if (temp < 0) {...}
}
その後、各{}
ブロックを個別の関数に移動する方が簡単です。これにより、明確に定義された1つのことが実行されます。
ただし、単体テストを行った後の最も重要なガイドラインは、「チェリーピッキング」(gitなど)をサポートするバージョン管理を使用することです。頻繁にコミットします。基本的には、何かをリファクタリングした後にコンパイルするたびに、実際に機能するときに再度コミットします(または、最初のコミットバージョンを使用したくない場合は、前のコミットを修正します)。何かを壊した後にロールバックする必要がある場合は、バージョン管理の差分ツールとチェリーピッキングの使用方法を学びます。