リファクタリング自爆奥義集

こんにちは、リファクタリングが大好きな[ミノ駆動](https://twitter.com/MinoDriven)です。
この記事は [READYFORアドベントカレンダー2021](https://qiita.com/advent-calendar/2021/readyfor) 、13日目の記事です。

# これはなに？

コードが複雑化し、技術的負債が蓄積していくと、コードの変更が難しくなり、開発生産性が低下していきます。技術的負債の解消にはリファクタリングが必要です。

しかし、リファクタリングの実施には数々の罠やハードルがあります。
下手すると逆に負債を作り込んでしまうといった、自爆技をやりかねません。

この記事は、リファクタリングのアンチパターンと、その対策をまとめたものです。

# この記事のゴール

- リファクタリングには様々なアンチパターンがあることを知る。
- アンチパターンにハマらないためのアプローチを知る。
- リファクタリングの効果を高めるにあたり、何のために実施するのか意義を理解する。

# 前提知識

なぜ自爆技となるのか、自爆だと理解するのに必要な前提知識を挙げます。

## 変更容易性

ソフトウェア品質特性のひとつです。
どれだけ素早く正確にコード変更しやすいかを表します。

変更容易性が高いほど、仕様変更時に楽に素早くコード変更できます。
逆に低いと、コードが複雑、難解で、バグを埋め込みやすく、コード変更が大変になります。

つまり、変更容易性が低いほど**将来の開発コストが増大します。 ←★ココ重要★**

## レガシーコード

「レガシーコード」の解釈には諸説ありますが、本記事では変更容易性の低いコードを「レガシーコード」と呼称します。

## 技術的負債

レガシーコードの蓄積度合い、またはレガシーコードそのものを指します。
レガシーコードが増えて変更容易性が低下していく様を「技術的負債がたまっていく」と呼んだりします。

## リファクタリング

外から見た挙動を変えずに、内部のロジック構造を整理することをリファクタリングといいます。
技術的負債の解消にはリファクタリングが必要です。
**変更容易性の高い構造がリファクタリングのゴールになります。 ←★ココ重要★**

# ★爆発★ リファクタリング自爆奥義一覧 ★炎上★

では、自爆奥義を10例ご紹介します。

## ◆奥義１ : 逆リファクタリング

「俺はこのスタイルの方がやりやすいから」
のセリフとともに、高品質なコードを低凝集密結合な低品質コードにわざわざ「リファクタリング」してしまうケースがあります。
奥義『逆リファクタリング』です。

### 【大事な観点】あるべき構造を設計するスキルが必要

リファクタリングのゴールは「変更容易性の高い構造」です。
したがって、どういう構造が変更容易性が高いのか、設計知識が必要です。

### 【自爆原因】設計スキルが不十分

変更容易性の高い構造に関する知識が浅い場合に陥ります。
すると、アテにならない勘と経験に基づいて、「この方が良さげだから」となんとなく好みの実装スタイルに流れてしまうのです。

### 【対策】スキルアップ、設計方針の目線合わせ

設計スキルを高めましょう。

リファクタリングする前に、どういう構造をゴールとするのか、設計方針の目線合わせをしましょう。
どういう構造がマズいのか、課題を共有することが目線合わせのポイントです。

社内勉強会を実施すると、スキル向上と目線合わせを同時に進められます。

中には根拠不明な自己スタイルに固執する方もおられますが、
その場合、自己スタイルによって課題がどう解決されるのか議論すると良いでしょう。

## ◆奥義２ : 無理矢理デザインパターンを適用

デザインパターンを覚えたての方がよく陥りがちです。
デザインパターンを無理に適用し、かえって負債化してしまうケースです。

### 【大事な観点】パターンによって効果は違う

デザインパターンは、発揮する効果がそれぞれ異なります。
いくつか例を列挙します。

|パターン|効果|
|:--|:--|
|Strategy|条件分岐のコピペを削減する。|
|Factory|生成に関する知識を凝集する。<br>他のロジックを生成知識で汚さずに済む。|
|First Class Collection|リストの操作や制約条件を高凝集にする。|

### 【対策】必ず課題と効果を確認すること

リファクタリング対象のコードに、どんな課題があるか確認しましょう。
課題に相応しいデザインパターンがあるならば、適用して良いでしょう。

デザインパターンを適用した場合、期待通りの効果が発揮されたかどうかを確認してください。
たとえばStrategyパターンは、条件分岐のコピペコードを削減する効果があります。
Strategyパターン適用後、分岐コピペがあまり減らなかったのであれば、設計を見直しましょう。

## ◆奥義３ : 共通化しちゃいけない箇所を共通化

重複コードがあると、仕様変更時に重複箇所を全て修正しなければならなくなります。修正漏れがあるとバグ化します。
重複解消のため、処理を共通化することがよくあります。

しかし共通化してはいけないものがあります。
そうしたコードを無理に共通化すると密結合に陥り、逆に変更容易性が低下します。

私が制作した動画「共通化の罠」でその弊害が描かれています。

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">クソコード動画「共通化の罠」 <a href="https://t.co/MM750CNXc2">pic.twitter.com/MM750CNXc2</a></p>&mdash; ミノ駆動 (@MinoDriven) <a href="https://twitter.com/MinoDriven/status/1127539251761909760?ref_src=twsrc%5Etfw">May 12, 2019</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

### 【対策】ビジネス概念をDRYにすること

有名なソフトウェア原則に、DRY原則があります。
DRY原則は「コードの重複を許すな」といった解釈で広まっているようですが、そうではありません。

「知識の重複を許すな」すなわち
「ビジネス概念の重複を許すな」が主旨として近いです。

DRYにすべきはビジネス概念単位です。
**同じようなロジック、似ているロジックであっても、概念が違えばDRYにすべきではないのです。**
詳しくは下記記事で解説しています。

https://qiita.com/MinoDriven/items/76307b1b066467cbfd6a

## ◆奥義４ : どこが負債か分からない

負債があるのに負債だと認識できず、
リファクタリングが中途半端になってしまうケースです。

また、このケースに陥っているときは、負債の判断基準が人によってバラバラであることが多いです。
負債を見えている側と見えていない側とで争いが起こることも考えられます。

「それは負債ではない」
「考えすぎだ」
「神経質すぎる」

といったセリフまで飛び出たりします。

### 【大事な観点】あるべき構造を知ってはじめて負債を認知できる

たとえ話をします。

- 内角が全て直角
- 四辺の長さが全て等しい

この条件を満たす四角形が正方形ですね。
この条件を知っているからこそ、どこか角度が直角でなかったり、辺の長さが等しくない四角形を見たときに、「これは正方形ではない」と我々は判断できます。

このたとえ話と同様に、変更容易性の高い構造の理想形を知って、はじめて負債が明瞭に認知できるようになるのです。
理想形を知らないと負債の認知が困難なのです。

### 【対策】スキルアップ、設計方針の目線合わせ

奥義1の対策と同様に、設計スキル向上と目線合わせをしましょう。

## ◆奥義５ : 名前をリファクタしない

ロジック構造は整理するものの、クラスやメソッドの名前まで見直されないケースがあります。
リファクタリングが不十分になってしまいます。

名前は、関心事に密接な関わりがあります。
**名前は、クラスやメソッドの分割単位を左右します。**
名前がザルだと構造がいびつになってしまいます。

名前もリファクタリングしましょう。
弊害と対策について詳しくは下記記事で解説しています。

https://qiita.com/MinoDriven/items/37599172b2cd27c38a33

また、目的ベースで命名すると、良い設計を導きやすいです。
詳しくは下記スライドの目的駆動名前設計をご参照ください。

https://speakerdeck.com/minodriven/buisiness-purpose-system-design

## ◆奥義６ : 機能変更と同時にやってしまう

機能変更でコード修正している最中に、リファクタリングしたくなることがあります。
しかし機能変更とリファクタリングを同時にやると、どちらによるコード修正なのか後から分からなくなってしまいます。保守の際混乱します。

### 【対策】機能変更とリファクタリングは分けて行うこと

機能変更とリファクタリングは、最低でもコミットを分けましょう。

また、バグ修正も機能変更といえます。
バグがある箇所をリファクタする場合、正確にはバグの挙動も変えずにリファクタしなければなりません。

この場合、まずバグ修正してからリファクタしましょう。
バグありきのコードより、バグのないコードをリファクタした方が、あるべき構造に近づけられます。
バグ修正が困難な場合、まずバグの挙動を変えずにリファクタし、その後バグ修正しましょう。

## ◆奥義７ : 事情を考慮せずにリファクタリングを強行する

一見レガシーコードに見えても、なんらかの都合でそうせざるを得ない形になっているコードがあります。
たとえばよくあるのが、パフォーマンス的な都合があるコードです。
パフォーマンス最適化したコードは、プリミティブ型だけで構成されていることが多く、負債に見えてしまいがちです。

こうしたコードを闇雲にリファクタすると、問題化します。

### 【対策】事前調査する、理由をコメントしておく

リファクタして良いものかどうか事前調査や聞き取りは最低限しましょう。
また、何らかの事情によりリファクタされたくないコードがある場合、コードに理由をコメントしておきましょう。

## ◆奥義８ : テストコードがなくてリファクタできない

安全にリファクタリングを進めるにはテストコードが必要です。
しかしレガシーコードにはテストコードがないことが多いです。
するとリファクタリングできなくて詰みそうになります。

### 【大事な観点】テストコード以外にも方法はある

「リファクタリングにはテストコード必須」が、広く一般的な認識です。
ですが、テストコードは安全にリファクタするための手段のひとつに過ぎません（強力かつ主要な手段ではあります）。
他にも手段はいろいろあります。

### 【対策例】IDEのメソッド抽出

IntelliJ IDEAやVisual StudioなどのIDEには、様々なリファクタリング機能があります。

その内のひとつに「メソッド抽出」があります。
指定した範囲のロジックをメソッドとして切り出す機能です。
メソッド抽出を使うと、等価なロジックを機械的に安全にメソッドとして切り出すことができます。

メソッド抽出を使う場合、小さく切り出すのがポイントです。
テストコードを書けるレベルの小さなコードとして切り出すのです。
すると、切り出したメソッドに対してテストコードを書けるようになります。

テストで保護されるので、そこから更にコードを整理できます。
メソッド抽出と、切り出したメソッドへのテストコード実装を繰り返すことで、**リファクタリング可能なコードが増えていきます。**

注意点としては、大きな単位でメソッド抽出しないことです。
テストコードの実装が困難になります。

また、メソッド抽出もコード変更であることに変わりありません。
したがって、メソッド抽出によるコード変更は、テストのないコードをリファクタする補助であることを、チームで約束しましょう。

### 【備考】他の方法も知りたい場合

[書籍『レガシーコード改善ガイド』](https://www.amazon.co.jp/dp/4798116831)には、テストがないコードをどうリファクタするかについて様々なノウハウの記載されています。

## ◆奥義９ : 効果的でない箇所をリファクタリング

将来的にほとんど全く変更されそうにない箇所を頑張ってリファクタしてしまうケースです。
このリファクタリングはほとんど効果を発揮できず、コストがムダになります。

### 【大事な観点】リファクタリングには費用対効果がある

リファクタリングは将来の変更コストを低減するものです。
したがって、たとえレガシーコードであっても、安定して動作しており、仕様変更がほぼ発生しない箇所を一生懸命リファクタしても、変更コストの低減にはほとんど寄与しません。

将来的に頻繁に変更が生じる箇所ほど、リファクタリングの費用対効果が高いです。

### 【対策】変更頻度が長期的に高くなりそうな箇所を狙う

変更頻度が長期的に高くなりそうなコードが、リファクタすべき対象です。
それがどのコードか見定める必要があります。

競争優位性が高い箇所、顧客のニーズが高い箇所は仕様変更が起こりやすく、変更頻度が高いです。
ドメイン駆動設計では、競争優位性の高い事業領域をコアドメインと定めていいます。
コアドメインに関係するロジックをリファクタしましょう。


## ◆奥義１０ : 「あとでリファクタリングしよう」

「今は機能変更で忙しいから、あとでリファクタしよう」と棚上げされることが多いです。
しかし、そうしたケースではほとんど大抵リファクタされることはありません。
余裕が生じたタイミングで、間髪入れず次の機能開発にアサインされることが多いからです。

また、いざリファクタリングに着手しようにも、いつやるか、どこからやるか、必要な工数は…などを都度気にしがちです。検討に時間が食い潰されてしまいます。

### 【原因】リファクタリングの優先度が低い

機能開発が最優先で、リファクタリングはどうしても後手に回りがちです。
しかしリファクタしなくて良いわけではありません。
変更容易性が低下し、機能開発が満足にできなくなるほどの生産性低下が危惧されます。

### 【対策例】リファクタリング専門チームを作る

弊社READYFORでは、リファクタリングや設計を専門とするチームを立ち上げ、取り組んでいます。
私はこのチームでドメインモデリングやアーキテクチャの評価、リファクタリングを専門で実施しています。

負債が確実に解消されるよう他チームへの設計面でのサポートの他、解消困難な負債に関しては私が直々に再設計＆リファクタリングを遂行しています。

**専門チームをつくることで、リファクタリングの優先度が低下しなくなります。**

また、リファクタリング用の工数をスプリントに積むことで、確実にリファクタリングを実施している企業さんもあるようです。

# まとめ

以上、リファクタリング自爆奥義を紹介しました。

下記記事にあるように、2025年以降、技術的負債によって毎年12兆円（東京オリンピックの費用の3~4倍の金額！）もの損害が生じるとのこと。

https://qiita.com/hirokidaichi/items/64b444a89410190d965f

こうした巨額の損失が予想されているにもかかわらず、技術的負債がなかなか解消されないのは、本記事で挙げたような数々のアンチパターンが、要因の一部になっているかもしれません。

本記事が負債解消の一助となるなら幸いです。