1. 概要(Overview)
Replace Nested Conditional with Guard Clauses は、
深いネスト(if の入れ子)を 早期リターン(ガード節) に置き換え、ロジックをフラットにするリファクタリングです。
目的:ネストを解消して「正常系」を主役にし、読みやすさと意図の明確さ を高める。
2. 適用シーン(When to Use)
- 前提条件・例外条件・早期終了があるのに、内側にネスト されている
- 「正常系ロジック」が
elseの深い位置に押し込まれている -
ifが何段にも重なり、右へ右へ とコードが食い込んでいる(indent hell)
3. 手順(Mechanics / Steps)
- 異常系・例外系・早期終了の条件を特定する
- それらを 関数冒頭のガード節(
return/throwなど)に引き上げる - 残った本筋(正常系)を ネストなしで直線的 に記述する
- 必要に応じて Decompose Conditional / Extract Method で条件名や処理名を付ける
4. Kotlin 例(Before → After)
Before:ネストが深く読みにくい
fun payAmount(e: Employee): Int {
if (!e.isDead) {
if (!e.isSeparated) {
if (!e.isRetired) {
return e.baseSalary + e.bonus
} else {
return e.pension
}
} else {
return 0
}
} else {
return 0
}
}
- 異常系(死亡・離職)が外側、正常系が最深部に押し込まれている。
After:ガード節でフラットに
fun payAmount(e: Employee): Int {
if (e.isDead) return 0
if (e.isSeparated) return 0
if (e.isRetired) return e.pension
return e.baseSalary + e.bonus
}
- 早期リターンで分岐が一直線に。正常系が最後に残り、意図が明瞭。
After(名前で意図を表す:補助テク併用)
fun payAmount(e: Employee): Int {
if (isNotPayable(e)) return 0
if (e.isRetired) return e.pension
return regularPay(e)
}
private fun isNotPayable(e: Employee) = e.isDead || e.isSeparated
private fun regularPay(e: Employee) = e.baseSalary + e.bonus
- 条件と処理に名前を与え、自己文書化 を強化。
5. 効果(Benefits)
- ネスト解消で 可読性・追跡性 が大幅向上
- 早期終了により バグの混入ポイント(抜け道・見落とし)を減らせる
- 正常系ロジックが前面に出て、意図がすぐ分かる
- 変更時に影響範囲を把握しやすく、保守性が向上
6. 注意点(Pitfalls)
- 早期リターンを乱用すると 出口が増えすぎ て逆に読みにくくなることがある
- 規約として「関数の早期リターンは2〜3箇所まで」などチーム合意があると安心
- リソース解放やトランザクション管理がある関数では、
複数リターンが 後処理漏れ を招かないようuse {}やtry/finallyを併用 - 例外系を
returnにするかthrowにするかは ドメインの意味 で選ぶ- 入力不備は例外、支払い対象外は
return 0など
- 入力不備は例外、支払い対象外は
まとめ
-
Replace Nested Conditional with Guard Clauses は、
異常系を冒頭で早期終了させ、正常系をフラットに記述するテクニック - 効果:読みやすさ・意図の明確さ・保守性 の向上
- 基本思想:「まず抜け道をふさぐ」→「本筋をまっすぐ書く」