# リファクタリング 第1章、第2章 ## 第1章 リファクタリングー最初の例 ### リファクタリングの第一歩 劇団の会計プログラムを例に 例に登場する劇団の会計プログラムでは、作品種別(悲劇・喜劇)と観客数により徴収する料金を決定する。また、利用実績に応じたポイント加算サービスの計算も行う。 このプログラムでは、ドル・セントの算出式を100倍の数で表しており、文字列の切り出しを用いて小数点を打つ方式であった。 #### プログラムの問題点 * 計算結果を文字列の切り出しでアウトプットしているため、HTML印刷要件追加等の拡張により、文字列を連結した全ての箇所に条件文の入力が生じる。 * 上記の問題解決のための、コピー・ペーストによる二度手間が生じる。 * 演目数増加などの変更要求に対応できない。 #### リファクタリングの方法 1. **テスト群を作り上げる**:システムが大きくなるほど、ちょっとした変更で動かなくなってしまう事も。テストフレームワークを用意して、開発環境のコマンド一つでまとめて実行できるようにする。成功は緑、失敗は赤で表示する。 2. **実際に修正する**:様々な手法で綺麗なコードへの変更を目指す。 3. **修正の度にテストする**:修正が終わるとすかさずテストを行う。こまめに行う事でバグの発見も容易になる。 4. **git, github等に保存する**:成功状態をリポジトリに保存し、いつでも戻れるようにする。  ### リファクタリングの手法 #### 関数の抽出 最終的に必要な処理ではない、その処理を実現するための処理は、**一つの関数にまとめて抽出してしまうのが良い。** 関数の抽出は、リファクタリングの基本手法の一つである。 例では、料金を計算する処理を、関数amountFor(aPerformance)を定義して処理を記述し、返り値で結果を返すようにしている。 Java等では自動化されていることも多い。 #### 第一引数の名前変更 JavaScriptの場合、名前から型が分かると便利である。 型の名前を引数に入れたり、特定の役割以外の変数名に対し不定冠詞を先頭につけたりして、コーディング規約に合わせる。 **変数名はコードを明快にするためのカギである。** #### 問い合わせによる一時変数の置き換え 配列からの抽出等、繰り返し必要なメソッドをメイン処理から切り分けて関数を抽出する。そしてメイン処理から関数を呼び出すようにすることで、値の取り出しを繰り返さずに済む。 #### 変数のインライン化 余計な変数宣言による値設定を削除し、そのまま直接値設定を書き込む。 const a = b() let thisAmount ammountfor(perf, a→**b()**) (b()を直接引数に書くことで、余計な一時変数が不要となる。 これを**変数のインライン化**という。 #### 関数宣言の変更 関数宣言を変更することで、ローカルスコープの変数が無くなる。 #### ステートメントのスライド 変数宣言を利用する箇所の直前に移動させる。 #### フェーズの分離 前半フェーズで計算処理、後半フェーズで出力処理を行い、処理を分割する。 前半フェーズで中間的なデータ構造を作り、それを後半フェーズに渡す。 #### パイプラインによるループの置き換え ループの代わりに、パイプライン方式を使って明示的にパラメータを渡せるようにする。 #### ポリモーフィズムによる条件記述の置き換え ポリモーフィズムの性質を利用して、条件記述の存在を明示し、動的に料金変更などを行えるようにする。 ## 第2章 リファクタリングの原則 ### リファクタリングの定義 リファクタリングは、名詞と動詞の2種類の用法がある。 * 名詞としてのリファクタリング:**外部から見たときの振る舞いを保ちつつ、理解や修正が簡単になるように、ソフトウェアの内部構造を変化させること。** * 動詞としてのリファクタリング:**一連のリファクタリングを適用して、外部から見た振る舞いの変更無しにソフトウェアを再構築すること。** リファクタリングは、振る舞いを保ちつつ、**小さなステップで修正を積み重ねていく**ことで成り立つ。 リファクタリングはコードの「再構築」の中でも、特定のものを指すのである。 また、外部から見たときの振る舞いが同じであれば良く、内部的な処理方法や処理速度は変わっても良い。 リファクタリングは、コードを理解や修正が容易になるように変化させていく目的を最優先に実行される。 ### 二つの帽子 二つの帽子は、Kent Beck氏が考案した考え方である。 **機能追加の時は機能追加に専念。**(既存のコードを変更してはならない) **リファクタリングの時はリファクタリングに専念。**(機能追加してはならない) 今どちらの作業をしているのかを把握しておき、**二つの帽子(機能追加とリファクタリング)を適宜かぶり直して、** 各作業に専念すべきである。 ### リファクタリングを行う理由 #### ソフトウェア設計を改善するため リファクタリング無しでは、プログラムの内部設計(アーキテクチャ)は徐々に劣化していく。 1. 短期的な目的達成のため、全体設計を無視して開発する。 2. 1を繰り返すうちに、徐々に複雑化しコードが構造を失っていく。 3. 設計が把握しづらくなると、コードの質は急速に劣化し維持困難に陥る。 こうした問題を解決するためには、リファクタリングの定期的な実施が望ましい。 設計を壊す最大の原因は、**重複の多さ**である。リファクタリングでは重複を取り除き、必要なコードがただ一回のみ書かれた状態を取り戻す。 #### ソフトウェアを理解しやすくするため コードはコンピューターが理解しさえすればよいものではない。 **後から他者が読んだ際に分かりやすくなければならない。** コードを読む際に**理解すべき情報を将来の自分を含む開発者に教えてあげる**のも大切である。 #### バグの発見を助けるため コードが理解しやすいと、バグも見つけやすい。 リファクタリングで理解しやすいコードに変えると、バグも発見しやすくなる。 #### プログラミングを早めるため コードの内部構造が分かりやすいと、機能追加時にどこに追加すべきかが明確になるため、コーディングスピードが速くなる。 逆にコードの設計が悪いとコーディングスピードは停滞する。 両者の違いは、プロジェクトの後半ほど顕著になる。 リファクタリングにより、その都度設計を行いカイゼンしていくことができる。 ### いつリファクタリングをするべきか #### 三度目の法則 重複の作業に気づいたら、意識しつつも作業を続けるが、 三度目に同じ作業をしていると気づいたときにリファクタリングを行う。 #### 機能追加の準備のためのリファクタリング 機能を追加する前に、追加を容易にするためのリファクタリングを行うと良い。 同様にバグ修正も、機能を追加する前段階で実施するのが良い。 #### 理解のためのリファクタリング 他者のコードや昔に書いたコードを扱う際に構造が複雑だと、理解に苦しんでしまう。 そこで、リファクタリングによって頭の中の理解をコードに移し替えて、実際に動かしてテストしていく。 コードの中に理解を移動させることで、今後コードを参照する際にも意図が伝わるようになる。 #### ゴミ拾いのためのリファクタリング 理解はできるが書き方がイマイチな場合のリファクタリングである。 リファクタリングが容易な場合はすぐに書き換えてしまい、時間がかかる場合はメモを残して後で実行する。 時間に追われていても、少しづつのカイゼンが必ず効果を発揮するのである。 #### 計画されたリファクタリングと、機に応じたリファクタリング 以上のリファクタリングは、機に応じたものである。修正箇所を見つけたら適宜修正を行う。 プログラミングとリファクタリングは不可分な作業なのである。 酷いコードだけでなく、素晴らしいコードもまた、多くのリファクタリングが必要である。 一方で、役割を分けてずっとリファクタリングに専念させるようなやり方はあまり価値がない。 #### 長期のリファクタリング リファクタリングの必要期間が長期にわたる場合も同様で、リファクタリングに短期集中で専念させるのではなく、 長期的に少しずつリファクタリングをしていくのが良い。 #### コードレビュー時のリファクタリング コードレビューは、知識を経験者から初心者へと伝達したり、チーム全体にシステムの特質を周知させることができる。 このコードレビューをより良くするのがリファクタリングである。 コードをある程度理解してどうすべきかを考え、実際にリファクタリングを行う事で、その結果から多くのフィードバックを得られるのである。 ペアプログラミングは、一対一でコードレビューとリファクタリングを同時に行う方法である。 #### 管理者を説得するには プロダクトオーナー等の管理者が、リファクタリングを良しとしないことがある。 しかし、リファクタリングをしないと悪化する一方であるため、プロダクトオーナーに言わずともリファクタリングを開始する。 開発者は問題解決に最も早い方法を選択するため、リファクタリングを実行することになるのである。 #### リファクタリングを避ける時 * API等、既に機能として完成している時 * 最初から書き直した方が望ましい時 ### リファクタリングの問題点 #### 新機能の実装が遅くなる リファクタリングを行えば、当然機能追加の時間が削られてしまう。 ただ、リファクタリングの目的は開発スピードを上げていくことであるため、中長期的に見てリファクタリングは必要である。 むしろ、リファクタリング不足の方が、過多よりも圧倒的に多い。 懸念は美しいコードや、素晴らしいプラクティスという道徳的な理由でリファクタリングが正当化されてしまうことである。 あくまでスピードを上げるため、新機能の追加やバグの修正を早めるためであることは忘れてはならない。 #### コードの所有権 リファクタリング時に、コード一部または全部の所有権が他者にあり、容易に手が付けられない場合がある。 メンバーに細かく所有権が設定されており、他者が変更不可といった場合もある。 こうした場合は、他チームの変更を分岐したブランチのコミットとして呼び出し、担当チームに受け入れてもらう方法がある。 チームが関数の呼び出し側を変更でき、古い関数の定義はコミット時に削除されるようになる。 #### ブランチ メンバーは個別ブランチで開発を進めて、最後にリリース可能な段階でマスターブランチにマージするやり方である。 しかし、これでは個別ブランチでの開発が長いほどマスターへのマージが大変困難となってしまう。 そこで、短い間隔でマージを行っていくのが継続的インテグレーションの考え方である。 最低でも1日1回はマージを行い、複雑さを大幅に軽減できる。 この継続的インテグレーションの最大のメリットは、リファクタリングと協調できるためである。 これまでの個別ブランチ開発だと、リファクタリングがマージの困難さを上げてしまうデメリットがあったが、 継続的インテグレーションだと相乗効果をもたらす。 #### テスト リファクタリングは細かく行う事で、バグの発見をしやすくなるメリットがあるが、その実現にはいかに早くバグを発見できるかにかかっている。 そこで必要なのが自己テストコードである。混入したバグを素早く発見するのに役立つ。 また、自動化されたリファクタリングを行う事で、テストを走らせなくともリファクタリング結果を信用できる。 #### レガシーコード 他人に書かれた古いコードをリファクタリングすれば、多くの部分が改善される。 そのためにも、テストコードを追加していくのが望ましいが、テストコード追加を想定していないレガシーコードのテストを書くのは容易ではない。 レガシーコード改善ガイドを読み、そのガイダンスに従うのが一番の近道だが、システムをテストの保護下に行う作業はテスト無しで行わなくてはならない。 この場合、自動化されたリファクタリングが救世主となる。 なお、レガシーコードを一気に変えるべきではない。これまでと同様に少しずつ取り組み、完結したものとなるべきである。 #### データベース データベース・リファクタリングが行える。 データアクセスコードの構造的な変更や、データ移行のためのスクリプトを簡単に構成できるようになる。 こちらでも少しずつ変更し、完結させることが重要である。また、処理の移行も徐々に行うべきである。 ### リファクタリングとアーキテクチャ、そしてYagni リファクタリングがアーキテクチャに与える最も大きな影響は、要求の変化にしなやかに対応できる優れた設計のコードベースを作り上げる方法を示したことである。 来る将来を予測して全部実装するのではなく、現在分かっている要求のみを解決するソフトウェアを構築する。 リファクタリングによって、アーキテクチャを新たな要件に適合させるのである。この設計手法はインクリメンタルな設計や、Yagniなどと呼ばれる。 ### リファクタリングとソフトウェア開発プロセス エクストリーム・プログラミングに代表されるアジャイル開発は、多くのプロジェクトで行われている。 一方、ほとんどのアジャイル開発は「名ばかり」である。 真のアジャイル開発を行うためには、リファクタリングが通常の作業の一部になることに適合する必要がある。 そのためのプラクティスが自己テストコード、継続的インテグレーション、リファクタリング、そしてYagniである。 ### リファクタリングとパフォーマンス リファクタリングはしばしばプログラムの実行速度を落としてしまう。 この問題を解決するためには、チューニングしやすい形のソフトウェアを作り、十分な速度が出るまで段階的にチューニングしていく方法である。 一般的な方法は3つある。 1. 実行スケジューリングを利用する:リアルタイム性が高いシステムでは必須。 2. パフォーマンスを重視する:ほとんどの時間がごく一部の処理に集中してしまい、作業が進まない。 3. パフォーマンスチューニングを重視する:パフォーマンスは気にせず作り、後からチューニングを行う。 実行スケジューリングを行わない場合、3が最も望ましい。ここでも少しずつ変更し、完結させることの積み重ねが重要である。 ### リファクタリングの起源 言葉の起源は不明だが、古くからコードの整理作業は行われてきた。 現在のリファクタリングのスタイルを生み出したのが、1980年頃のKent Beck氏と、Ward Cunningham氏であった。 Smalltalkでは、リファクタリング環境が充実しており、非常に効率よくソフトウェア開発が行えていた。 両氏はこうした動的な開発環境に最も合致したプロセスを追求してきた。このプロセスは、エクストリーム・プログラミングと呼ばれている。 また、Ralph Johnson氏はリファクタリングが効率的で柔軟なフレームワークづくりにどう役立つかを研究してきた。 同氏の教えを受けたBill Opdyke氏は、リファクタリングの潜在的な可能性を見抜き、Smalltalk以外にも応用できると考えた。 このBill氏の論文が初期の最もまとまったリファクタリングの研究成果として名を残している。 さらに、John Brant、Don Roberts両氏による初のリファクタリングツール作成に繋がった。 ### 自動化されたリファクタリング リファクタリングは業界に定着し、Java界隈を中心に、自動リファクタリングツールが多く開発されていった。 現在ではecripseやIntelliJ、Vidual Studio Code等の主要エディタにリファクタリング機能が標準搭載されている。 自動リファクタリング機能では、構文木を解析し、リファクタリングを行っている。 ###### tags: `読書`