第3章 コードの不吉な臭い
いつリファクタリングをして、終了するかの判断の参考
- 不思議な名前
- クラスや変数などの名前で不明確なものがあったら名前を変更する
- 適切な名前が思いつかない場合は、設計が今一つの兆候になる
- 重複したコード
- 同じ箇所のコードが二箇所以上にある場合、一箇所にまとめる
- 同一クラスの複数のメソッド内に同じ式があるなど
- 同じ箇所のコードが二箇所以上にある場合、一箇所にまとめる
- 長い関数
- 短い関数ほどよい
- 昔は関数呼び出しにかかるオーバーヘッドが無視できなかったが、現代はほぼ問題ない
- 短く適切な名前の関数を作る
- 適切に命名をすると関数の分割に積極的になれる
- コメントが必要だと思ったときにわかりやすい名前をつけた関数に分割したりなど
- 適切に命名をすると関数の分割に積極的になれる
- 長いパラメーターリスト
- 混乱のもとになる
- クラスはパラメーターを減らすための手段
- 複数の関数群がパラメーターで渡される値を共有しているときに特に有効
- インスタンス変数的な漢字かな
- 複数の関数群がパラメーターで渡される値を共有しているときに特に有効
- グローバルなデータ
- グローバル変数など
- 変数のカプセル化して防ごう
- 少なくとも関数経由でアクセスするようにする
- 変更可能なデータ
- スコープが狭いうちは問題は少ないが、広くなると厄介なので不変なものにする
- 変更の偏り
- 一つのモジュールが異なる目的のために、異なる方法で変更される状況
- 単一責任の原則かな
- 変更の分散
- 変更を行うたびに、複数のモジュールが少しずつ書き換わる状況
- 特性の横恋慕
- あるモジュールの関数が内部のモジュールよりも、外部のモジュールの関数やデータ構造とやり取りしていること
- 何らかの値を計算するときに他のオブジェクトのgetメソッドを何回も呼び出しているなど
- データの群れ
- 群れをなしたデータはまとめるべき
- オブジェクトにするなど
- 群れをなしたデータはまとめるべき
- 基本データ型への執着
- 多くのプログラマは貨幣・座標・範囲などの基本的な型を導入するを嫌がる傾向にある
- データに適切な型をつけようね
- 重複したスイッチ文
- switch/case文やネストしたif/else文の形でコード上に同じ分岐ロジックが書かれていれば、不吉な臭い
- ループ
- filterやmapなどのパイプラインによるループの置き換えで、置き換えることができる
- 怠け者の要素
- メソッドが一つしかないクラスは葬り去ろう
- railsとかのフレームワークだと、必ずしもできるわけじゃなさそう
- 疑わしき一般化
- いつか必要になる機能を作っても結局は使われない
- 無用の長物なら削除しよう
- いつか必要になる機能を作っても結局は使われない
- 一時的属性
- 特定の状況でしか設定されないクラスは、理解しづらい
- 新しいクラスとしてまとめる
- メッセージ連鎖
- オブジェクトのメッセージの過剰な連鎖が起きている状態
- 連鎖を短くする
- 仲介人
- 過剰なカプセル化によって、メソッドの大半が別のオブジェクトに委譲してだけの状態
- 直接処理できるようにする
- インサイダー取引
- 別モジュールとのデータのやり取りがあまりにも活発だと、相互依存してしまう
- やり取りは最小限にするべき
- 巨大なクラス
- 一つのクラスが多くの仕事をしている場合は、大抵はインスタンス変数の持ちすぎ
- 関数の抽出をする
- クラスのインターフェース不一致
- インターフェースがおなじになるように振る舞いを適切なクラスに配置する
- データクラス
- get/setメソッド以外に何も持たないクラスは、データ保持用のクラス
- 大抵の場合、間違ったふるまいが定義されていることを示している
- 相続拒否
- サブクラスは親の属性と操作を継承するのが普通
- それらを必要としない場合、継承を見直す
- コメント
- コード内の処理の一部をコメントで説明が必要な場合は、何かがおかしい
- 関数の抽出や、関数名の変更をする
感想
実装中は同じ処理が3箇所とか言っていたけど、呼んでいるときは二箇所なのかな
お前のクラスは関数が多くて、見通しが悪いからもっとグローバル変数を使えって言うツイートを思い出した
rubyだとfrozen_string_literal
のマジックコメントとかもこの変更可能なデータを防ぐやつだな
switch文?ナニソレオイシイノ?
ループの話で、filterやmapのほうがループに比べて、関数ごとに影響範囲が閉じ込められるので個人的には好き
例: 3の倍数のみを取り出す処理
ループの場合
l = []
n = 1
while n < 100 do
l.append(n) if n % 3 == 0
n += 1
end
p l
パイプライン操作の場合
p (1..100).filter { |n| n % 3 == 0 }