web-dev-qa-db-ja.com

品質を向上させることを期待してコードをミニリファクタリングすることは有用ですか、それともあまりメリットがない「コードを移動する」だけですか?

「すべて」を1か所で行うモノリシックコードに出くわしました。データベースからデータをロードし、HTMLマークアップを表示し、ルーター、コントローラー、アクションとして機能します。私はSRP移動データベースコードを独自のファイルに適用し始め、物事に適切な名前を付けましたが、すべて見栄えは良かったのですが、なぜこれを行っているのか疑問に思い始めました。

なぜリファクタリングするのですか?目的は何ですか?役に立たないの?メリットは何ですか?ほとんどの場合、モノリシックファイルをそのまま残しましたが、いくつかの作業を行う必要がある領域に関連する小さな部分のみをリファクタリングしたことに注意してください。

元のコード:

具体的な例を示すために、このコードスニペットに出くわしました。これは、既知の製品IDまたはユーザーが選択したバージョンIDのいずれかによって製品仕様をロードします。

if ($verid)
    $sql1 = "SELECT * FROM product_spec WHERE id = " . clean_input($verid);
else
    $sql1 = "SELECT * FROM product_spec WHERE product_id = " . clean_input($productid) ;
$result1 = query($sql1);
$row1 = fetch_array($result1);
/* html markup follows */

リファクタリング:

コードのこの特定の部分の変更を必要とするいくつかの作業を行っているため、リポジトリパターンを使用するように変更し、オブジェクト指向のMySQL機能を使用するようにアップグレードしました。

//some implementation details omitted 
$this->repository = new SpecRepository($mysql);
if ($verid)
    $row1 = $this->repository->getSpecByVersion($verid);
else 
    $row1 = $this->repository->getSpecByProductId($productid);
/* html markup follows to be refactored or left alone till another time*/

//added new class:
class SpecRepository extends MySqlRepository
{

    function getSpecByVersion(int $verid)
    {
        return $this->getMySql()->paramQuery("
            SELECT * FROM product_spec WHERE id = ?
        ", $verid)->getSingleArray();
    }

    function getSpecByProductId(int $productid)
    {
        return $this->getMySql()->paramQuery("
            SELECT * FROM product_spec WHERE product_id = ?
        ", $productid)->getSingleArray();
    }
}

これを実行する必要がありますか?

変更を振り返ると、コードはまだ存在しています。機能は同じですが、ファイルではなく、名前や場所が異なり、手続き型ではなくオブジェクト指向のスタイルを使用しています。実際、リファクタリングされたコードは、同じ機能を持っているにもかかわらず、はるかに肥大化しているように見えるのは面白いことです。

「リファクタリングの理由がわからない場合は、しないでください」という回答もあると思いますが、おそらく同意するかもしれません。私の理由は、時間の経過とともにコードの品質を向上させることです(そして私の希望は、SRPやその他の原則に従ってそれを実現することです)。

これらは十分な理由ですか、それともこの方法で「コードの再配置」に時間を費やしていますか?これを全体的にリファクタリングすることは、正直に言うと水を踏むような感じがします。時間がかかり、SRPに関してはより「分離」されますが、私の意図に反して、私は驚くべき改善を行っているようには感じません。したがって、リファクタリングではなく、コードを以前のままにしておくことが最善かどうかについて議論します。

そもそもなぜリファクタリングしたのですか?

私の場合、新しい製品ラインに新しい機能を追加しているので、類似の製品ラインの既存のコード構造に従うか、独自のコード構造を作成する必要があります。

12
Dennis

あなたが示した具体的な例では、少なくともまだ、リファクタリングは必要なかったかもしれません。しかし、将来、より面倒なコードの可能性があり、それがより長くて退屈なリファクタリングにつながる可能性があることがわかりました。そのため、イニシアチブを取り、クリーンアップしました。

ここで得た利点は、少なくとも私の見地からは、コードベースを知らない人として理解しやすいコードであったとも言えます。


一般に:

リファクタリングにより、他の開発者がコードを理解しやすくなりますか?

リファクタリングによってコードの拡張が容易になりますか?

リファクタリングによってコードの保守が容易になりますか?

リファクタリングはデバッグを容易にしますか?

これらのいずれかに対する答えが「はい」である場合、それはそれだけの価値があり、それは単なる「コードの移動」以上のものでした。

これらすべてに対する答えが「いいえ」である場合、多分それをリファクタリングする必要はなかったでしょう。

コードベースの最終的なサイズmightは、LoCの観点からは大きくなります(ただし、リファクタリングによっては、冗長なコードを合理化することでコードベースを縮小できる場合があります)。

モノリスを分解する場合、リファクタリングは肥大化します。

しかし、あなたはすでに利益を見つけました。

"私の場合、新しい製品ラインに新しい機能を追加しています。"

モノを壊さずにモノリスに機能を追加することは非常に簡単ではありません。

同じコードがデータを取得してマークアップを実行していると言いました。特定の状況で表示するために選択および操作している列を変更するまでは、すばらしいです。突然、特定のケースでマークアップコードが機能しなくなり、する必要があるリファクタリングします。

9
Deacon

そのプロジェクトで数か月または数年も作業する必要があることがわかっている場合は、リファクタリングを検討します。あちこちに変更を加える必要がある場合は、コードを移動したいという衝動に抵抗します。

リファクタリングを行うための推奨される方法は、何らかの自動テストを含む基本コードがある場合です。それでも、以前と同じように機能するように、変更内容に細心の注意を払う必要があります。本来予定している領域以外のバグを提供すると、すぐに信頼が失われます。

私は次の理由でリファクタリングを重視しています:

  • コードをよく理解している
  • 重複したコードを削除するので、1か所にバグがある場合でも、コードがコピーアンドペーストされた場所をすべて探す必要はありません。
  • 明確に定義された役割を持つクラスを作成します。たとえば、同じリポジトリを再利用して、HTMLページ、XMLフィード、またはバックグラウンドジョブをハイドレートできます。これは、データベースアクセスコードがHTMLクラスにのみ存在する場合は不可能でした。
  • 変数、メソッド、クラス、モジュール、フォルダーの名前を現在の現実と一致しない場合は変更します。変数名、メソッド名を介してコードをcomment
  • 単体テストとリファクタリングを組み合わせて複雑なバグを解決します
  • モジュールやパッケージ全体を置き換える柔軟性があります。現在のORMが古くなっている、バグがある、または保守されていない場合、プロジェクト全体に広がっていなければ、ORMを置き換えるほうが簡単です。
  • お客様への提案につながる新しい機能や改善点を発見しました。
  • 再利用可能なコンポーネントを作成しました。これは、そのプロジェクトで行われた作業を別のクライアント/プロジェクトで再利用できたので、最大の利点の1つでした。
  • 私はしばしば、最も馬鹿げた、ハードコードされた、奇抜なソリューションから始め、詳細を知ったら、後でそれをリファクタリングします。この後の瞬間は今日か、おそらく数日後かもしれません。ソリューションにarchitect時間をかけすぎたくありません。これは、書き込み中に発生します-コードを前後に書き換えます。

完璧な世界では、リファクタリングは単体テスト、統合テストなどで検証する必要があります。ない場合は、追加してみてください。また、一部のIDEは大いに役立つかもしれません。私は通常、費用のかかるプラグインを使用します。リファクタリングにほとんど時間をかけず、それについて非常に効率的になりたいです。

バグも紹介しました。一部のQAがare you guys doing refactoring? because everything stopped working!これはチームが受け入れなければならないリスクであり、常にそれについて透明性を持たなければなりません。

何年にもわたって、継続的なリファクタリングによって生産性が向上することがわかりました。新しい機能を追加する方がはるかに簡単でした。また、コードベースが製品の進化に適応していない場合に頻繁に発生したように、大規模な再構築では全体を書き換える必要はありませんでした。また、それは楽しいです。

2
Adrian Iftode

私の意見では、リファクタリングは良い投資です。

そうしないと、すぐに技術的な負債が発生します(未解決の問題、特定の条件下でのみ機能する不良コードなど)。ソフトウェアが保守できなくなるまで、技術的負債はすぐにますます大きくなります。

しかし、リファクタリングを機能させるには、テストにも投資する必要があります。自動テストを作成する必要があります。理想的には、単体テストと統合テストが必要です。これにより、既存のコードを壊すことがなくなります。

上司や同僚を説得する必要がある場合は、アジャイルメソッド(SCRUMなど)とテスト駆動開発に関する本を読んでください。

1
bernie

自問しなければならないのは、「メリットはあるのか」ということではありません。しかし、「この仕事に誰が支払うのか?」

私たちはみな、日末までに認識されたメリットについて議論することができますが、それらのメリットを信じ、変更の代価を支払うのに十分な価値があると顧客が考えている場合を除いて、それらを行うべきではありません。

開発チームのどこかにいると、コードを確認してリファクタリングして「より良い」ものにするのは簡単すぎる。しかし、製品が既に機能しているときに「より良いコード」に価値を置くことは、本当に難しいことです。

「新機能のより迅速な開発」のようなものは、コストを削減するだけなので、それを削減することはできません。あなたは売り上げを生み出す必要があります。

1
Ewan