ルール
避ける 深い 入れ子 レベル
深い ネスト は コード 難しい コードを 読みづらく そして 理解しにくい。
対応言語 45+はじめに
4レベル、5レベル、または6レベルの入れ子を持つコードは、開発を遅らせる認知的負担を生み出す。入れ子のレベルが上がるごとに、アクティブな条件、エラー・パス、ビジネス・ロジックを追跡するのが難しくなる。過剰な入れ子は、抽象化されていないことや、アーリーリターンやガード節を使用する機会がないことを示すことが多い。
なぜそれが重要なのか
コードの保守性とバグのリスク:深いネストは、ロジックを画面外に押し出す「矢印コード」を作り出し、コードレビューを遅らせる。開発者は、ネストされたコードを修正する際に、満たさなければならないすべての条件を見ることができないため、エッジケースを見逃してしまう。単体では正しく見える変更でも、数レベル上の前提を壊す可能性がある。
テストとデバッグの複雑さ:入れ子にするごとに、カバレッジに必要なテストケースが倍増し、指数関数的なパスの爆発を引き起こす。エラーのスタックトレースでは、どのような条件でエラーに至ったかがわからないため、バグの再現が困難になる。
コード例
非準拠:
function processOrder(order) {
if (order) {
if (order.items && order.items.length > 0) {
if (order.customer) {
if (order.customer.address) {
if (order.paymentMethod) {
if (validatePayment(order.paymentMethod)) {
return submitOrder(order);
}
}
}
}
}
}
return { error: 'Invalid order' };
}
なぜ間違っているのか:6段階の入れ子構造になっているため、実際のビジネスロジック(注文の送信)が一番下に埋もれているのを見るのが難しい。各条件チェックはさらにインデントされたレイヤーを追加し、どの特定のバリデーションが失敗したのかが表示されないため、エラー処理が不明確になっている。
✅ 準拠:
function processOrder(order) {
if (!order) {
return { error: 'Order is required' };
}
if (!order.items || order.items.length === 0) {
return { error: 'Order must contain items' };
}
if (!order.customer?.address) {
return { error: 'Customer address is required' };
}
if (!order.paymentMethod || !validatePayment(order.paymentMethod)) {
return { error: 'Invalid payment method' };
}
return submitOrder(order);
}
なぜこれが重要なのか:アーリーリターンを持つガード節は、ネストを単一レベルにフラット化する。各バリデーションは明示的で、特定のエラーメッセージを返します。ハッピーパス(注文の送信)は、ネストすることなく最後に見える。コードは自己文書化されており、既存の条件を壊すことなく簡単に変更できる。
結論
入れ子のレベルは、可能な限り3つ以下にする。アーリーリターン、ガード句、ヘルパー関数を使用して、深くネストした構造をフラットにする。3レベルを超える入れ子に遭遇したら、メソッドを抽出したり、条件を反転させたり、アプローチを見直したりしてリファクタリングする合図だ。フラットなコードは、深くネストしたものに比べて、読みやすく、テストしやすく、デバッグしやすく、保守しやすい。
.avif)
