早期returnは善か悪か ー 海外の反応は?

早期returnは可読性の味方なのか、それともアンチパターンなのか。海外のコミュニティや公式ドキュメントを手がかりに、賛否と背景を整理しました。あなたはどっち派!?

なぜ議論になるのか

同じ「関数からreturnする処理」でも「早期に戻る実装」(早期return派)と「単一出口で最後に戻る実装」(単一出口派)があり、可読性・保守性・安全性といった点で評価が割れています。X(旧Twitter)でも「ガード節で先に弾けばネストが浅くなって読みやすい」「出口は1つにすべき。後始末やログが散らばると危ない」「deferやfinallyがある言語なら早期returnが自然」「安全規格がある現場では単一出口が無難」といった声が交錯しています。さらに技術ブログやQ&Aでも、読みやすさを重視する立場と、後始末の一元化や規約順守を重視する立場がせめぎ合っています。

海外ではどうなっているのか

では、海外(英語圏)ではどんな議論がされているのでしょうか。Stack Overflowではもはや定番の議論になっているようで、例えばこのスレッド(Should a function have only one return statement?)やこのスレッド(Why should a function have only one exit-point?)で多数のレスがついています。Software Engineering Stack Exchangeでも同趣旨の質問が周期的に立ち上がり、過去回答の引用→新たな反論→折衷案の提示という流れが繰り返されています。「読みやすさを最優先する流儀」と「後始末や監査を一元化したい流儀」がせめぎ合っているのが実情です。

善か悪か…果たして結論はどっちなのでしょう。具体的にそれぞれの派閥の主張を見てみましょう。

早期return派

早期return派の代表的な主張は以下の通りです。

  • 可読性・ネスト削減
    前提違反や異常系を関数冒頭で「先に弾く(ガード節)」ことで、多段ifを避け、正常系を上から下へ一直線に読めるようにできる。また、レビューで意図を追いやすくなる。
  • テスト容易性・責務の明確化
    無効入力・権限不足・外部依存の失敗などを短い早期returnで分離すると、異常系テストが個別に書きやすく、関数の責務も見えやすくなる。結果として小関数化とも相性が良い。
  • 言語機能が後押し
    with(コンテキストマネージャ)や try/except により後始末が自動・明示できる言語では、出口が複数でも安全にできます。ログや計測はデコレータ等で入口/出口フックに寄せられるため、出口1つに依存しない設計が取りやすいです。

pythonでこれらの例を見てみましょう。

from pathlib import Path
import json

def load_user(email: str | None, path: str) -> dict | None:
    if not email:                      # ① 無効入力は先に戻る
        return None
    p = Path(path)
    if not p.is_file():                # ② 事前条件も先に戻る
        return None

    with p.open(encoding="utf-8") as f:  # 途中でreturnしても自動クローズ
        try:
            data = json.load(f)
        except json.JSONDecodeError:     # ③ 異常系はここで終了
            return None

    user = data.get(email)
    if not user or not user.get("active"):
        return None

    return user                         # ← ここまで正常系が一直線

with は「入り口で準備、出口で後片付け」を自動でやってくれる構文です。この出入りの挙動を提供するオブジェクトを コンテキストマネージャと呼び、__enter____exit__ を実装しています。with ブロックを抜けるときは、例外が起きても/途中で return しても必ず後片付けが走ります。

なるほど、たしかに正常系がスッと入ってくるわかりやすいコードですね。

単一出口派

単一出口派の代表的な主張は以下の通りです。

  • 後始末の一元化・漏れ防止
    ファイルやロック、トランザクションの解放・ロールバック・終了時ログなどを関数末尾に集約できるため、取りこぼしを避けやすいです。例外や分岐が増えても、最後で必ず片付ける方針を守れます。
  • ロギング/監査/デバッグの一点集中
    終了処理を1か所に置くと、ブレークポイントや計測、監査ログの出力をそこに集められます。出口が複数のときに発生しがちな「ある経路だけログが無い」を避けやすいです。
  • チーム規約・静的解析への適合
    「関数は単一の出口」とする社内コーディング標準や静的解析ルールに素直に従えるのが利点です。安全寄りの運用や長期保守の現場で好まれます。

同じくpythonでこれらの例を見てみましょう。

from pathlib import Path
import json
from typing import Optional

def load_user_single_exit(email: Optional[str], path: str) -> Optional[dict]:
    result: Optional[dict] = None
    f = None
    try:
        # 事前条件チェック(returnはせず、結果だけ決める)
        if email and Path(path).is_file():
            f = open(path, encoding="utf-8")
            try:
                data = json.load(f)
                user = data.get(email)
                if user and user.get("active"):
                    result = user
            except json.JSONDecodeError:
                pass  # 異常時は result を None のままにしておく
        # 条件を満たさない場合も result は None のまま
    finally:
        if f:
            f.close()            # 資源解放を1か所で確実に
        # ここに終了ログ・計測・監査フックなどを集約できる

    return result                # ← 返り値は最後の1回だけ

終了処理・ログ・計測が末尾にまとまるため、ある経路だけ実行されない事故を防ぎやすくなります。また、もしあればですが規約に沿いやすい書き方になります。C言語などでは解放漏れやログ取りこぼしを避けやすいかもしれません。

結局どっちが善でどっちが悪なの?

再び海外でどう言われているのか見てみましょう。


早期return を後押しする声

“The code reads well if the successful flow of control runs down the page, eliminating error cases as they arise.”
(成功パスを“下へ一直線”に書ける、という公式ガイダンス)

Go

“Always opportunistically return as soon as possible from the function. Once your work is done, get the heck out of there!”
(Jeff Atwood:仕事が終わったら即 return、を推奨)

Coding Horror

“the Err(err) branch expands to an early return.”
(Rust:? は“エラーなら早期return”に展開される)

doc.rust-lang.org

単一出口を推す声

“A function should have a single point of exit at the end.”
(MISRA C:関数は末尾の単一出口が望ましい)

kr.mathworks.com

“It is a preferred practice that all functions shall have just one exit point.”
(Barr Group 標準:単一出口を“推奨実務”とする)

Barr Group

“A single exit point simplifies debugging, reading, performance measuring and tuning, refactoring.”
(Stack Overflow:デバッグや計測を一点に集約できる)

Stack Overflow

ご覧のとおり、早期return を支持する公式/実務の言説と、単一出口を求める標準/規約の言説が並立しています。どちらを善とみなすかは、引用のとおり前提や目的(言語機能・安全規格・可観測性の設計)に強く左右されます。

善悪ではなく適材適所です

折衷・文脈依存を示す声

以上のような状況から「単純な引数チェックなどは早期returnで弾き、重い後始末は末尾に寄せる」といった折衷案(これとか)がしばしば提示されています。また、「出口を1つにすると監査や計測を集約しやすい」という意見と並んで、「入口/出口フック(デコレータ、AOP、ミドルウェア)を使えば出口の数に依存しない」という設計論も繰り返し登場します。要するに、どの言語機能・プラットフォームを備えているかが選択を左右する、という立場が広く共有されています。

結論、言語・業界/業種に依存する

  • 言語機能が強い場合(Go/Swift/Rust/Python など)
    defer/guard/?/with/try-finallyによって後始末を自動化/明示化できるため、早期returnで異常系を先出ししても安全に運用できます。
  • C/C系や既存資産が大きい現場
    例外や自動解放が薄いコードベースでは、解放・ロールバック・終了ログを末尾一点に集約したい動機が強く、単一出口が選ばれがちです(社内規約や静的解析ルール次第ですが)。
  • 安全クリティカル/組込み(車載・医療・産業制御)
    規格・標準・監査要件が明確に存在し(例えばこれ)、単一出口を前提とする方針がある場合はそちらを優先。レビューや監査の観点で出口一点主義が運用しやすいからです。安全・セキュア・高信頼の場合はこちらを採用します。
  • Web/業務アプリ/SaaS
    失敗を冒頭で素早く返す(バリデーション先出し)ほうが、可読性・レビュー効率・テスト設計の面でメリットが大きいことが多いです。ログやメトリクスは共通ミドルで担保し、出口数に依存しない運用を取ります。
  • 高並行・ロック多用の領域
    ロック解放はwith/using/deferなどスコープ終端で必ず後始末の仕組みがあるなら早期returnでも安全。仕組みが弱い/徹底できないなら単一出口+末尾集約が堅実です。

まとめると、言語機能・規格要件・アーキテクチャの三点セットで正解が変わります。
どちらかを教条的に禁ずるのではなく、プロジェクトの前提に合わせてデフォルト方針を決め、例外的にもう一方を使う——この適材適所が海外の実務的コンセンサスのようです。

これらの議論の共有もなしにいきなりレビューで指摘するのはなしですよ!

ペーパーレス化にお困りですか?

Windows用PDF編集ソフトAxelaNote(アクセラノート)は、PDFや画像に透明シートを重ねて書く方式なので、PDFを書き換えず、注釈禁止でも印刷禁止でも書き込めます。タブレットPCにもフル対応!今なら14日間無料です。

図面や原稿を扱う建築・製造業様から、レポートの採点をする先生まで広くご利用頂いております。

シェアする

フォローする