🧹

リファクタリングにおける重要なポイント1&2

2023/04/07に公開

リファクタリングにおける重要なポイント1&2

はじめに

リファクタリング(第2版)を読んでみて、重要なポイントを簡潔に記載しました。
第1章から第2章の内容です。

1. リファクタリングする

機能追加の前にまずはリファクタリング

機能を加えづらいプログラムに新規に機能を追加しなければ行けない場合は、
まず機能追加が簡単になるようにリファクタリングしたほうがいい。

テスト必須

リファクタリングに入る前にテスト群を用意しておくこと。
テストはリファクタリングに不可欠である。
人間が作業する以上、間違いを犯す可能性があり、意図せず他の部分も
壊してしまう危険性があるため。

1. 関数の分割

長い関数をリファクタリングするときは関数を分割する。
関数を分割することで処理に名前をつけることができる(関数名)

1.1. 変更後はすぐにテスト

変更を行ったあとはすかさずテスト!
テストが完了したらCommitしておくと、テスト完了時点まで容易に戻すことができる。

1.2. 戻り値の変数名

戻り値の変数名はresultに統一すると戻り値だと分かりやすい。

2. ローカル変数を減らす

ローカルスコープの変数が減ることでメソッドの抽出が楽になるため。
ローカルスコープの変数は関数などに切り出してインライン化するといい。
何度も関数が呼ばれてしまうが、パフォーマンス的には大した問題はない。

2.1. パフォーマンス

読みやすさ > パフォーマンス

ほとんどの場合、コードが読みやすいほうが後から
パフォーマンスを最適化しやすいため。

3. フェーズの分離

一つのコードが異なる2つの処理を行っている場合は別々のモジュールに分割するといい。
変更が必要になったときに別々に対処できる。(片方だけ変更すればいい場合があるかも)
例えば、精算機能において料金計算と出力処理を分けておくと、出力の種類が増えたときは出力処理だけに対して追加を行えば良い

3.1. 増えるコード量

リファクタリングで増えたコード量は結果的に分かりやすいコードになっていてば問題ない。

4. 型をつける

複雑な条件をクラスやポリモーフィズムに置き換えるとより明快になる。

function mammalNameJa(mammal) {
  switch (mammal.type) {
    case 'human':
      return '人間'
    case 'whale':
      return 'くじら'
  }
}

class Mammal {
}

class Human extends Mammal {
  get nameJa() {
    return '人間'
  }
}

4.1. ポリモーフィズムとは

オブジェクト指向プログラミングにおける概念で、同じインターフェースを実装する複数のクラスが異なる動作をすることができる能力を指します。つまり、同じメソッド名を持つメソッドが、異なるクラスで異なる動作をすることができます。

例えば、動物という抽象的なクラスがあり、そのサブクラスとして犬と猫があるとします。動物クラスには「鳴く」というメソッドが定義されていますが、犬と猫が鳴く方法は異なります。しかし、犬と猫はともに動物であり、鳴くという共通の機能を持っているため、動物クラスに定義された「鳴く」というメソッドを実装することで、犬と猫がそれぞれ異なる方法で鳴くことができます。このように、ポリモーフィズムを利用することで、同じインターフェースを持つクラスが異なる動作をすることができ、柔軟性の高いプログラムを実現することができます。

まとめ

良いコードとは変更がどれだけ容易かで決まる

2. リファクタリングの原則

2.1 リファクタリングの定義

リファクタリングとは

外部から見た振る舞いを変えず、理解や修正が簡単になるようにソフトウェアの内部構造を変化させること。

外部から見た振る舞い = 同じ動きをする

非常に小さいステップの組み合わせでリファクタリングはできているため、
コードが壊れている期間を極めて短くする必要がある。

2.2. 2つの帽子

機能追加リファクタリングは同時に行わないこと。
リファクタリングしたあとに機能追加をするというように2つの帽子を切り替える。

2.3. リファクタリングを行う理由

負のスパイラルを防ぐため

リファクタリングしないと、内部構造が劣化してく
※短期的な目標を達成するためだけに内部構造を十分に把握せず変更するなどが原因
⇓
コードの構造を失う
⇓
設計を把握することが難しくなる
⇓
構造を維持できなくなり急速に劣化する

2.4. リファクタリングはソフトウェアを理解しやすくする

プログラムに動かすことに必死で将来のプログラマのことを考えないのは問題
リファクタリングすることで将来のプログラマの工数を削減できるよ

2.5. リファクタリングはバグの発見を助ける

コードが見やすい = バグを発見しやすい

2.6. リファクタリングはプログラミングを速める

内部の設計が優れていれば、どこをどのように変更すればいいかを
すぐに把握できる。

デザインスタミナ仮説

設計を入念に行うほど、スタミナを付けることができ、
長期的に速いペースで開発していくことができる

2.7. いつリファクタリングすべきか

三度目の法則

最初は単純に作業を行う。二度目に以前に似たようなことをしていると気づいたときは重複を意識しつつもとにかく作業を続けてもいい。三度目に同じようなことをしていると気づいたときにリファクタリングを行う。

準備のためのリファクタリング

機能追加の前はリファクタリングするのにうってつけ。
追加する必要がある箇所やバグが減ったりといいことが多い。

理解のためのリファクタリング

コードに手を加える前にまず何を行っているかを理解する必要がある。
理解しづらいときはひと目で分かるようにリファクタリングできないかを考える。

コードを読んで理解する

理解をコードに落とし込む

ゴミ拾いのためのリファクタリング

コードが何をしているかわかるが書き方が今ひとつのときのリファクタリングがある。
この変更が容易な場合はすぐに修正してしまい、
そうでない場合はメモを残して今のタスクの次に実行するといい。
ゴミ拾いのように少しづつ行っていけばいずれはきれいになる。

計画されたリファクタリングと機に応じたリファクタリング

ひどいコードはもちろん、良いコードも状況に合わせてリファクタリングする必要がある。

計画的に長期的にリファクタリングすることはまれで
ほとんどは目立たず、気に応じて行われる。

新規機能の追加とリファクタリングのコミットを分ける??

分けると別々にレビューできるが、
新規追加と密接に結びついている場合はリファクタリングを行われた
背景がわかりづらくなってしまう。

長期のリファクタリング

巨大なリファクタリングが必要な場合は、チームをリファクタリングに専念させるのではなく
直近の2〜3週間で問題を徐々に解決していくことをチームで合意することが有効。
改善したい方向にチームを少しづつ持っていく。

コードレビュー

コードレビューにより他人からリファクタリングのアイディアをもらうことができる。

管理者を説得するには

管理者はリファクタリングを価値を生まない作業と思い込んでいる場合がある
この場合は「管理者に黙ってリファクタリングする」

リファクタリングしてから新規機能を追加したほうが早い場合があるので
開発者の責任で決定するといい。

リファクタリングを避ける時

書き直すかリファクタリングをするかは決めるのは難しい。
判断には経験が必要。

2.8. リファクタリングの問題点

リファクタリングは新機能の実装を遅らせる?

リファクタリングの目的は少ない労力で多くの価値を生み出すため
プログラミングの速度を上げることにある。

コードの所有権

コードを変更する責任を明確にし、品質を維持するために一人に責任を与えることが重要である。役割分担やレビューにより、情報共有が促進され、品質の向上につながる。

リファクタリングとアーキテクチャ、 そして Yagni

不要な機能を回避し、最小限のアーキテクチャを設計することで、簡潔かつ堅牢なコードを保証するというものです。リファクタリングによりアーキテクチャを改善し、YAGNI(You Ain't Gonna Need It)に従って必要な機能のみを実装することが重要です。

Discussion