プログラミングの魔物

エラー、バグ、仕様変更と戦うブログ

リファクタリングの原則

リファクタリング 2章

リファクタリングの重要な原則を改めて振り返り、リファクタリングを実践する上で考慮すべき点をみる。
一応ノートを取りながら読んでみたけど、ほとんど概念だから読むだけでもよかった。

リファクタリングの定義

  • 名詞としての定義

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

  • 動詞としての定義

「一連のリファクタリングを行なって、外部から見た振る舞いの変更なしに、ソフトウェアを再構築すること」

リファクタリングする(動詞)のに何時間も費やすことがある。その中には何十ものリファクタリング(名詞)が含まれるかもしれない。

2つの帽子

  • 機能追加を行う時には既存コードを変更しない。拡張に専念する。テストの追加によって進度を測る。
  • リファクタリング中に機能を追加しない。原則としてテストの追加をしない(機能追加の段階で漏れていた場合やインターフェースの変更時を除く)

どちらを行なっているのかを常に意識する。

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

ソフトウェア設計が向上する

短期的な修正や全体を把握せずに機能を追加した場合、ソフトウェアの構造は崩れていく。次第にコードを読んで設計を把握することも難しくなる。
これに対してリファクタリングはコードを整えていく作業となる。コードを整理することで健全性を保つことができる。

不健全なコードでは同じ処理を行うのに余計にコードを書くことになる。重複したコードを排除することは設計を良くする際の重要事項と言える。
重複しているコードを減らしてもパフォーマンスが改善するとは限らない。しかし見通しが良くなると修正がしやすくなる。

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

  • CPUサイクルを減らすより構造の理解にかかる時間を減らしたほうがプロジェクトは円滑に進む
  • リファクタリングの対象は動作するものの、うまく構造化されていないコード
  • あとで読んでも分かるようにしておけば、設計の詳細を覚えている必要はなくなる
  • コードの不明な部分をリファクタリングすると、テスト結果によって自分の理解の正しさを確認できる

リファクタリングはバグを見つけ出す

  • コードが理解できるようになると、バグが見つけやすくなる

リファクタリングでより速くプログラミングできる

  • ラピッドな開発にはすぐれた設計が不可欠
  • まずい設計はバグ修正に時間がかかる。重複した部分で修正が見つかればドブさらいを始める必要性が出てくる
  • すぐれた設計はソフトウェア開発のスピードを一定に保つ。リファクタリングは設計が劣化するのを防ぎつつ、さらに改善する

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

3度目の法則

  • 最初は単純に作業する
  • 2度目に「以前と似たようなことをしている」と気づいた場合は重複や無駄を意識しつつも作業を進めていい
  • 3度目に同じようなことをしていたらリファクタリングする

機能追加の時にリファクタリングする

  • 機能を追加する前にリファクタリングすることで、コードの理解を深めると共に仕様の変更に備える

バグフィックスの時にリファクタリングする

コードレビューの時にリファクタリングする

  • 他人のコードをリファクタリングしながら読むことで理解が深まる
  • どのようになるのか実際に見ながら読み進めることができる

リファクタリングは何故有効か

  • プログラムには2つの価値がある。「今何ができるか」「将来何ができるようになるか」
  • プログラミング中は「今」だけに集中しがち。しかし実際には後々修正や機能追加が行われる事が多い
  • リファクタリングは過去を洗いなおして将来を見据えた設計に変えることができる
  • 昨日の自分が未熟でも今日変えればいい。明日には今日の自分が未熟だったと思うかもしれない。そうなればまた修正すればいい

プログラムを難しくする要因(リファクタリングすべきポイント

  • 読みにくいプログラムは変更しにくい
  • ロジックが重複しているプログラムは変更しにくい
  • 機能追加に伴い、既存のコード修正が必要になるプログラムは変更しにくい
  • 複雑な条件分岐の多いプログラムは変更しにくい

つまり、コードが読みやすく、1箇所のみにロジックが書かれ、既存の動作に影響を与えずに変更できて、条件分岐が簡潔に表現できていれば理想的なプログラム
リファクタリングすることでその理想へ近づけることができる。

管理者を説得するには

  • 品質を気にする管理者にはレビューの過程でリファクタリングを採用することでバグを減らすことができると説く
  • スケジュールを気にする管理者には黙ってリファクタリングする(筆者の経験から説明する必要もなくリファクタリングがラピッドな開発に有効だから)

間接層とリファクタリング

  • リファクタリングは間接的な部分を加える。大きなオブジェクトや長いメソッドをより細かい単位へと分割する
  • しかし間接層は諸刃の刃。間接層が多くなると委譲を繰り返しプログラムが読みにくくなる。間接層は最小限に絞り込む
  • すべての関節層が悪ではない。ただしい間接層は価値をもたらす
  1. ロジックの共有を可能にする。複数の箇所から参照されるメソッドやスーパークラスのメソッド
  2. 図と実装を独立して説明できる。クラスやメソッドの命名には開発者の意図が表現される
  3. 変更を分離する。修正が必要な部分だけをサブクラスに分けることができる
  4. 条件分岐をポリモーフィズムで表現する。条件分岐を柔軟かつ明確に表現できる
  • リファクタリングはゲームのようなもの。システムの振る舞いを保ったまま、より理想的な設計に近づける
  • まず間接層のメリットを必要としている部分を突き止め、現在の処理を変えずに作りこんでいく
  • 机上での設計には柔軟性に限界がある。骨組みが硬すぎると依存する。
  • 時にリファクタリングで役に立たない間接層を取り外すこともある。以前は意味があったものでも不要になれば除去する
  • 上であげた4項目以外にも、同じ品質を得るのにより少ない間接層で済んでいるかもポイント

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

  • どのような場合に限界が生じるかはまだハッキリとわかっていない

データーベース

  • まず問題となるのはデーターベース。データーベースに依存してるアプリケーションでは、危険の伴うデーターベーススキーマの変更が関わってくる
  • オブジェクト指向でないデーターベースでこの問題に対処するには、オブジェクトモデルとデーターベースモデルの間にソフトウェアによる分離の層を設ける
  • 分離することで2つのモデルの変更を独立して扱えるようになる
  • リファクタリングにかぎらず複数のデーターベースを同時に扱う場合や複雑なケースでは有用
  • 中間層から作り始める必要はない。
  • オブジェクト指向データーベースはバージョンアップ時にデータ構造の変化に対して注意する

インターフェースの変更

  • オブジェクト指向の重要な利点として、ソフトウェアの実装とインターフェースを独立して変更できるというものがある。インターフェースを変更すると様々な影響が起きる
  • リファクタリングが躊躇される多くの理由はインターフェースの変更を伴うこと。
  • メソッドを呼び出しているソースを全て把握できるなら変更しても問題ない。しかし、検索・変更ができない場合は問題となる(公布済みインターフェース)
  • 1度インターフェースが公布されたら安全に変更して呼び出し側を修正すればいいというわけにはいかなくなる
  • 公布済みインターフェースが変更された場合には利用者側が対処できるまで古いインターフェースとの両立を維持する必要がある。
  • JavaObjective-Cの場合は推奨されていないことを示すため古いインターフェースにdeprecatedタグを利用したりする。

リファクタリングしにく設計

  • リファクタリングを行う前にどの程度の作業量かを検討しながら行う。容易そうな時には検討に時間をかけず、とにかく単純な方法を採用する
  • 逆にリファクタリングが難しいと感じられる場合には、時間をかけて検討する

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

リファクタリングしてはいけない場合もある

  • 変更するより書きなおしたほうが速いケース。既存のコードが壊滅的で、1から作りなおしたほうが速いこともある
  • 既存のコードが動かない時は書き直せる。バグだらけの状態ではリファクタリングも難しいが、ほぼ正しく動作する場合にはリファクタリング可能
  • 妥協案としてソフトウェアをカプセル化された部分に分けてリファクタリングするという方法もある
  • 期限が迫っている時にはリファクタリングしない

リファクタリングと設計

  • ソフトウェアの設計は移ろいやすい。
  • リファクタリングは事前設計の代わりになる。事前の設計をほとんど行わずまず動作するものを作り、リファクタリングで形を整える
  • リファクタリングを採用すると事前設計で完璧な策を用意する必要がなくなる。問題の本質が見えた時点で設計を柔軟に変えることができる
  • 仕様変更などで設計が変わることを恐れなくて済むようになる

何も作り出さないことに掛けた時間

  • 推測ではなく実際に計測することが大事
  • 本質を掴まない限り十中八九推測は間違っている

リファクタリングとパフォーマンス

  • リファクタリングでパフォーマンスが落ちることもある。純粋な設計のため安易にハードウェアを増強することはNG
  • リファクタリングはチューニングしやすい形にすることもできる。速いソフトウェアを作るには最初にチューニングしやすいものを作って段階的にチューニングする

速いソフトウェアを作る方法

  1. 時間分割。時間とメモリ量というリソースの観点から各コンポーネントが制限を超えないようにする
  2. パフォーマンスを常に意識する。すべてのプログラマが高速化を目指す。あまりうまく行かない。パフォーマンスを上げるために設計がわかりにくくなり開発効率が落ちる
  3. パフォーマンスを落とす原因を中心にチューニングする。パフォーマンスを落とす原因はごく一部の処理に集中している。すべてのコードで最適化を行なっても90%は無駄になる。
  • 第3のアプローチではまずプログラムを整理された形で作り、チューニングの段階で初めてパフォーマンスを考慮する
  • 該当プログラムが実際にメモリと時間をどのように消費しているかをプロファイラで計測
  • パフォーマンス上のホットスポットを見つけたら、その部分についてリファクタリングと同じように小さなステップで最適化を行う

メモ

この記事で読み進めている本

リファクタリング―プログラムの体質改善テクニック (Object Technology Series)

リファクタリング―プログラムの体質改善テクニック (Object Technology Series)

  • 作者: マーチンファウラー,Martin Fowler,児玉公信,平澤章,友野晶夫,梅沢真史
  • 出版社/メーカー: ピアソンエデュケーション
  • 発売日: 2000/05
  • メディア: 単行本
  • 購入: 91人 クリック: 3,033回
  • この商品を含むブログ (295件) を見る