4
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

早期リターンは正義か悪か

4
Posted at

はじめに

実装していると、こんな議論にぶつかることがあります。

  • returnが多いと読みにくいのでは?
  • ifをネストするより早期リターンの方が良い?
  • コーディング規約的にどうなの?

この記事では早期リターンについて整理します。

早期リターン(Early Return)

早期リターンとは、条件を満たさない場合に処理を続けず、早めに return する書き方です。

public int Calc(int x)
{
    if (x < 0)
    {
        return 0;
    }

    return x * 2;
}

特徴は以下です。

  • 異常系・前提条件を先に処理
  • 正常系を一直線で書ける
  • ネストを減らせる

早期リターンのメリット

1. 可読性が大きく向上する

ネストが深い例
if (user != null)
{
    if (user.IsEnabled)
    {
        if (user.Age >= 20)
        {
            Register(user);
        }
    }
}
早期リターンを使った例
if (user == null) return;
if (!user.IsEnabled) return;
if (user.Age < 20) return;

Register(user);
  • 「この処理が実行される条件」が一瞬で分かる

2. ガード節(Guard Clause)

public void Register(User user)
{
    if (user == null)
        throw new ArgumentNullException(nameof(user));

    if (!user.IsActive)
        return;

    // 正常系
}
  • 前提条件が明確になる
  • 仕様がコードとして残る
  • テスト観点も作りやすい

3. 修正時の事故を減らせる

追加仕様:20歳未満は処理をしない(20歳未満の場合はログを出力する)

変更前
public void Process(User user)
{
    if (user != null)
    {
        if (user.IsActive)
        {
            Execute(user);
        }
    }
}
変更後(if / else の対応ミス)
public void Process(User user)
{
    if (user != null)
    {
        if (user.IsActive)
        {
            if (user.Age >= 20)
            {
                Execute(user);
            }
        }
        else
        {
            Log("Too young");
        }
    }
}

早期リターンを使っていると…

変更前(早期リターン)
if (user == null)
{
    return;
}
if (!user.IsActive)
{
    return;
}

Execute(user);
変更後(早期リターン)
if (user == null)
{
    return;
}
if (!user.IsActive)
{
    return;
}
if (user.Age < 20)
{
    Log("Too young");
    return;
}

Execute(user);

ネストが深いコードは、

  • if / else の対応ミス
  • 条件追加時の影響範囲拡大

が起きがちです。
早期リターンは「条件ごとに独立した行」になるため、変更時の影響範囲が小さくなります。

早期リターンの注意点

1. 後処理・リソース解放に注意

Disposeされない
public void ProcessFile(string path)
{
    var reader = new StreamReader(path);

    if (reader.BaseStream.Length == 0) return;

    var text = reader.ReadToEnd();
    Console.WriteLine(text);

    reader.Dispose();
}

  • return に到達すると Dispose() が呼ばれない

対策

対策①:using を使う
public void ProcessFile(string path)
{

    using (var reader = new StreamReader(path))
    {
        if (reader.BaseStream.Length == 0) return;
        
        var text = reader.ReadToEnd();
        Console.WriteLine(text);
    }
}
対策②:try / finally を使う
public void ProcessFile(string path)
{
    StreamReader reader = null;

    try
    {
        reader = new StreamReader(path);
        
        if (reader.BaseStream.Length == 0) return;

        var text = reader.ReadToEnd();
        Console.WriteLine(text);
    }
    finally
    {
        reader?.Dispose();
    }
}

2. ログや共通処理が抜けやすい

終了ログが残らない
public IActionResult UpdateUser(User user)
{
    _logger.LogInformation("User update requested");
    
    if (user == null) return BadRequest();
    if (!ModelState.IsValid) return BadRequest(ModelState);
    
    // 更新処理
    Update(user);

    _logger.LogInformation("User update completed");

    return Ok();
}
  • 早期リターンの時、終了ログが残らない

対策

対策:終了ログを finally に集約
public IActionResult UpdateUser(User user)
{
    _logger.LogInformation("User update requested");
    
    try
    {
        if (user == null) return BadRequest();
        if (!ModelState.IsValid) return BadRequest(ModelState);

        Update(user);
        return Ok();
    }
    finally
    {
        _logger.LogInformation("User update completed");
    }
}

まとめ

早期リターンが向いているケース

  • 引数チェック
  • 権限チェック
  • nullチェック
  • 異常系処理
  • 正常系が一本

早期リターンが向いていないケース

  • 複雑な状態遷移 ⇒ 流れが追いづらい
  • 後処理が多い ⇒ return 抜け事故
  • ビジネスルール分岐 ⇒ if/else の方が明確

実務でおすすめのルール

  • 異常系・前提条件は早期リターン
  • 正常系はネストさせない
  • 後処理がある場合は try-finally を使う

おわりに

早期リターンは可読性を高め、異常系や前提条件を明確にする強力なテクニックです。
その意味では、間違いなく「正義」です。

一方で、後処理や共通処理を考慮せずに多用すると、リソースリークやログ欠落といった事故を招きます。
その瞬間、早期リターンは「悪」になります。

チーム開発において重要なのは早期リターンを「禁止すること」でも「無条件に推奨すること」でもなく、どこで使うかをルールとして共有することです。

早期リターンは万能ではない。
だが、使わない理由を探す時間ほど無駄なものはない。

正しく使えば早期リターンはコードを守る「正義の味方」になります。

4
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?