Aikido

コードの重複をなくす方法:技術的負債を減らす

ロジックのバグ

ルール
排除する 明らかな ファイル内の 重複を排除する。
重複する コード ブロック を増やす メンテナンス
負担 そして を増加させます。 リスク リスク 一貫性のない 更新の不整合リスク。
対応言語 45+

はじめに

一つのファイル内にコピーペーストされたコードは、メンテナンスの悪夢を生み、それは時間の経過とともに悪化する。同じロジックが複数の場所に存在する場合、バグフィックスや機能アップデートはその都度行わなければならない。開発者は、必然的に重複の1つを見逃してしまい、どのコードパスを実行するかによって、同じ操作でも結果が異なるという一貫性のない動作につながります。重複したロジックは一見同じに見えるが、注意深く比較して初めて違いが出てくるため、この矛盾のデバッグは難しい。

なぜそれが重要なのか

バグの伝播:重複したコードにバグが存在する場合、ある場所のバグを修正しても、すべての場所でバグが修正されるわけではない。開発者は、複製が他の場所に存在することに気づかずに、最初に発生したバグを修正し、異なる条件下でバグを有効なままにしてしまう。

メンテナンスの負担:ブロックが重複するたびに、メンテナンス・コストが倍増する。ロジックを変更するには、すべてのコピーを見つけ、更新する必要があり、ファイルが大きくなるにつれて、重複を追跡することが難しくなります。

コード例

非準拠:

class OrderProcessor {
    async processStandardOrder(order) {
        if (!order.items || order.items.length === 0) {
            throw new Error('Order must have items');
        }
        const total = order.items.reduce((sum, item) => 
            sum + (item.price * item.quantity), 0);
        const tax = total * 0.08;
        const finalAmount = total + tax;
        return { total: finalAmount, tax };
    }
    
    async processExpressOrder(order) {
        if (!order.items || order.items.length === 0) {
            throw new Error('Order must have items');
        }
        const total = order.items.reduce((sum, item) => 
            sum + (item.price * item.quantity), 0);
        const tax = total * 0.08;
        const expressfee = 15.99;
        const finalAmount = total + tax + expressFee;
        return { total: finalAmount, tax, expressFee };
    }
}

誤りの理由:検証ロジックと合計計算が重複している。税率が変更されたり、バリデーションが強化されたりすると、両方のメソッドを更新する必要があります。開発者は、一方の方法で税計算を更新しても、もう一方の方法を忘れてしまうかもしれません。

✅ 準拠:

class OrderProcessor {
    validateOrder(order) {
        if (!order.items || order.items.length === 0) {
            throw new Error('Order must have items');
        }
    }
    
    calculateSubtotal(items) {
        return items.reduce((sum, item) => 
            sum + (item.price * item.quantity), 0);
    }
    
    calculateTax(amount) {
        return amount * 0.08;
    }
    
    async processStandardOrder(order) {
        this.validateOrder(order);
        const subtotal = this.calculateSubtotal(order.items);
        const tax = this.calculateTax(subtotal);
        return { total: subtotal + tax, tax };
    }
    
    async processExpressOrder(order) {
        this.validateOrder(order);
        const subtotal = this.calculateSubtotal(order.items);
        const tax = this.calculateTax(subtotal);
        const expressFee = 15.99;
        return { total: subtotal + tax + expressFee, tax, expressFee };
    }
}

なぜこれが重要なのか:バリデーション、計算、税金のロジックは単一のメソッドに集約されています。税率を変更することは、1つのメソッドを修正することを意味します。各ヘルパーメソッドは独立してテストすることができ、両方の注文タイプは改善やバグ修正を自動的に継承します。

結論

ファイル内の重複は、多くの場合、最も簡単に修正でき、すぐに効果が得られます。重複しているロジックに気づいたら、すぐにヘルパー関数やメソッドに移しましょう。3つのルールとは、コードが3回出てきたら、リファクタリングの時期であるというものです。重複がファイル全体に広がるのを待ってから対処してはいけません。

よくある質問

ご質問は?

リファクタリングの前に、どの程度の重複を許容できるか?

似たようなコードが3回出てきたら、それを抜き出す。ただし、判断は慎重に。複雑な重複ブロックが2つあれば、即座に抽出する必要があるかもしれないが、単純な変数宣言が3つあれば、そうではないかもしれない。変更の可能性と矛盾のコストを考慮する。セキュリティ上重要なロジックや複雑なビジネスルールは、直ちに重複排除すべきである。

重複するコードに小さなバリエーションがある場合はどうするのか?

相違点をパラメータ化する。つのコードブロックが変数の値だけ異なる場合は、それらを共有関数にパラメータとして渡す。ロジックの流れが微妙に異なる場合は、ストラテジーパターンや、適切なデフォルト値を持つオプショナルパラメータを使用する。複雑な抽象化で意図がわからなくなるよりも、明確な差異がある重複の方が良い場合もあるので、DRYの原則と可読性のバランスをとること。

コードが長くなっても、重複を抽出すべきなのか?

通常はそうだ。たとえ総行数が増えたとしても、重複したコードをインライン化するよりも、説明的な名前を持つ関数の方が意図が明確になることが多い。一点保守の利点は、簡潔性の懸念を上回ります。しかし、コードを読むのに複数の関数呼び出しの間を飛び越えなければならないような、過度な間接化を引き起こす場合は、抽象化が適切かどうか再考してください。

大きなファイルで重複するコードを特定するには?

繰り返されるif条件、同じループ、似たような関数構造など、コピーペーストのパターンを探してください。多くのIDEは構造の重複を強調表示します。コードレビューの際、ファイルを読んでいて見覚えのあるコードがあれば、それを検索する。ファイル内の重複は、手作業で検査するのが一番早いことが多い。リファクタリングするときは、ファイル内で近くにある重複から始める。

重複したエラー処理コードについては?

エラー処理を再利用可能な関数に抽出するか、デコレーターやミドルウェアのパターンを使う。複数の関数が同じtry-catch構造を共有し、同じエラーロギングと変換を行うのであれば、それは排除する価値のある重複です。一貫性のあるロギング、再試行、フォールバック動作で操作をラップするエラー処理ユーティリティを作成し、エラー処理ロジックを繰り返す代わりにそれらのユーティリティを使用する。

積極的に変更するつもりのないレガシーコードの重複をリファクタリングする価値はあるだろうか?

ボーイスカウトのルールを適用する:コードを見つけたときよりもきれいに残す。関数を修正していて、同じファイル内で重複していることに気づいたら、変更の一部として修正すること。技術的負債が新機能をブロックしているのでなければ、レガシーコードに対して大規模なリファクタリングPRを作成しないこと。通常の開発で少しずつ改善していくほうが、より持続可能である。

そもそも重複を防ぐには?

コードをコピーペーストする前に、代わりに関数を抽出すべきかどうかを尋ねる。コードレビューの際に、重複するパターンにフラグを立て、抽出を要求する。2回以上繰り返される操作にはヘルパー関数を要求するなど、重複を防ぐチーム規約を確立する。重複を特にチェックするコードレビューチェックリストを使用する。予防は改善よりも簡単である。

まずは無料で体験

コード、クラウド、ランタイムを1つの中央システムでセキュアに。
脆弱性を迅速に発見し、自動的に修正。

クレジットカードは不要。