Chapter 02

第二章 if から switch へ

kuramapommel
kuramapommel
2021.04.23に更新

if ~ else で表現する「場合」とその問題点

まずは if のおさらいから始めていきましょう

if 文で表現できる「場合」は 「 A か」「 A 以外か」 の2つだけですね
某ホスト界の帝王さんならこんなコードを書くでしょうか

function log(name: string) {
  if (name == 'ローランド') {
    console.log('俺か')
  } else {
    console.log('俺以外か')
  }
  
  return
}

彼であれば if 文だけで全てが語れてしまうかもしれませんが、実際のプロダクト開発においてはそれだけでは語ることのできないたくさんの複雑な仕様が存在します

たとえば、 「A か」「もしくは B か」「それ以外か」 というように別の「場合」が出てくることもあるでしょう
これを if ~ else で表現すると以下のようなコードになると思います

function log(name: string) {
  if (name == 'ローランド') {
    console.log('俺か')
  } else if (name == 'ぽめる') {
    console.log('もしくはぽめるか')
  } else {
    console.log('それ以外か')
  }
  
  return
}

ここで登場した else if ですが、この子には コードの読み手は評価式を上から順にひとつひとつ気をつけて確認しなければならない という可読性の問題があります
どういうことかというと、 1 回目の if の条件式と 2 回目の if の条件式は言語仕様上異なる観点の式を渡すことができてしまうため、
「もしかしたら name じゃないもので評価しているかもしれない」という疑いを持ちながら読まないといけないという問題があります

たとえばこんなコードです

function log(name: string) {
  if (name == 'ローランド') {
    console.log('俺か')
  } else if (age == 21) { // age は log 関数の外で定義された変数
    console.log('拳で')
  } else {
    console.log('それ以外か')
  }
  
  return
}

まあ、現実でこんなコードを書く人はいないでしょうし、コードレビューで弾かれるであろうということは一旦おいといて、 言語仕様上できてしまうということは読む際には気をつけなければならない ということになってしまいます

「場合」が増えるほどこの問題は大きくなっていきますが、プロダクトを成長させようとすると「場合」は必然に増えてしまうので、つまりはプロダクトが成長すればするほど問題が大きくなっていってしまいます

if の問題を解決する、複数の「場合」に対応するための switch ~ case

この問題を解決するために、大体のプログラミング言語は switch ~ case という解決策を用意してくれています
試しに先のコードを switch を用いて表現するのであれば、下記のようになるでしょうか

function log(name: string) {
  switch (name) {
    case 'ローランド':
      console.log('俺か')
      break
      
    case 'ぽめる':
      console.log('もしくはぽめるか')
      break
      
    default:
      console.log('それ以外か')
  }
  
  return
}

switch ~ case を利用することで、読み手はすべての「場合」に対して name で評価していることに確信が持てます

[余談] if や switch を使う場合に可読性を上げるテクニック

本書の内容にあまり関係ない余談ですが、 ifswitch を覚えたばかり初学者の方が明日から使える可読性向上テクニックがあるので紹介しておきます

まずは下記のコードをご確認ください

function useIf(name: string) {
  if (name == 'ローランド') {
    // なんかしらかのそこそこ長い処理
  }

  // ブロックを超えたここでは、何も処理せず return している
  return
}

function useSwitch(name: string) {
  switch (name) {
    case 'ローランド':
      // なんかしらかのそこそこ長い処理
      break
      
    // このあとも続く case 
  }

  // ブロックを超えたここでは、何も処理せず return している
  return
}

上記のコードを読むとき、読み手の人は ifswitch の条件に該当しなかった場合であっても、ブロックを超えた先に処理があるかもしれないと思い、その先のコードまで読もうとしてしまいます
しかし、見ていただいてわかるように、 ブロックを超えたあとに処理はなく、純粋に return しているだけとなります

これらの関数は下記のように書き直すことができます

function useIf(name: string) {
  if (name != 'ローランド') {
    // ローランドじゃないなら先を読む必要がないから、さっさと return してあげる
    return
  }

  // なんかしらかのそこそこ長い処理

  return
}

function useSwitch(name: string) {
  switch (name) {
    case 'ローランド':
      // なんかしらかのそこそこ長い処理
      
      // ローランドならこれ以上読む必要はないから、さっさと return してあげる
      return
      
    // このあとも続く case 
  }

  return
}

これは ガード節 と呼ばれる 読まなくてもいい部分を読ませない ための手法で、コードの可読性を上げるために有効なので覚えておくと良いでしょう