Skip to content

readable_code

kobayashiharuto edited this page Aug 7, 2021 · 6 revisions

リーダブルコードとは何か?

めちゃくちゃ if とか for とか使って 1000 行位あるごちゃごちゃしたアルゴリズムを見て、以下みたいな感想を述べる人がいます。
「すげーこんな複雑なコード書けるんだ!これを書いた人はさぞかし頭がいいに違いない!」

違います。

そんな複雑なコードをチームメンバーが書いてきたらどう思うか?
ちょっと仕様が変った時、そのコードは簡単に変えられるのか?
新人にそのコードをどう説明するのか?
そもそも書いた人自身も、1か月後に見たときスラスラ動作を理解できるのか?

人(自分も含む)に見られるものなんだから、わかりやすくなければ意味がありません。
わかりやすく書くことで、より効率的に、よりバグが起きにくいコードが書けるようになるのです。
「動けばいい」という考え方を卒業し、リーダブル(読みやすい)なコードを書くように心がけていきましょう。


読みづらいコード

以下の関数をパッと見て、何をしているかわかりますか?

func ch(a: String, b: String, c: String, d: String) -> Bool {
    var error = false
    if a == "" {
        error = true
    } else {
        if b == "" {
            error = true
        } else {
            if c == "" {
                error = true
            } else {
              if d == "algo123" {
                error = false
              } else {
                error = true
              }
            }
        }
    }
    return error 
}

正解は、引数の a, b, c の値が空でないかつ、dalgo123 という値が入っていたら true を返し、それ以外は false を返すというエラーチェック関数でした。

これを作った開発者は「メッセージ送信機能」を作ろうとしていて、メッセージのエラーチェックをしたかったようです。
メッセージには「メッセージ本文」「送信者の名前」「受信者の名前」が必要で、その 3つが欠けてないか確認する必要があったみたいですね。
さらに、パスワードとして設定してある algo123 と合っているか確認する必要もあったようです。

...そんなこと読み取れないですね、他人がこのコードを読んだら発狂してしまうでしょう。


さらにこの関数、読みにくいだけでなくバグを起こす可能性も孕んでいます。

これを使うときは以下のようになるわけですが、引数名が適当なのでパスワードをどこに書いていいかわかりません。

check(a: "hello!", b: "remi", c: "kobayashi", d: "algo123") // エラーなし

以下のように引数の場所を間違えてしまい、意図しない動作が発生するかもしれませんね...

check(a: "hello!", b: "remi", c: "algo123", d: "kobayashi") // 引数の場所を間違えるとエラーになる

エラー回避のためには、どの引数が何に対応しているか覚えておくか、いちいち関数の中身を確認しなくてはいけません

しかしこれは面倒です...


リーダブルコードに書き換える

それでは、これを以下のように書いたらどうでしょうか?

func messageErrorCheck(message: String, senderName: String, receiverName: String, password: String) -> Bool {
    if message == "" { 
      return true
    }
  
    if senderName == "" {
      return true
    }
  
    if receiverName == "" {
      return true
    }
  
    if password != "algo123" {
      return true
    }
  
    return false
}

エラーが起きたらさっさとリターンしてしまうことで、とてもわかりやすくなります(これをガード節と言います)
命名も適切に行なったので、動作だけでなく、これはメッセージのエラーを確認する処理なんだなってことも読み取れますよね?

処理としては全く同じものですが、適切に命名し、処理を見直すことでとても読みやすいコードになりました

以下のように使えるので、これなら引数を間違えて意図しない動作になってしまうこともないでしょう

check(message: "hello!", senderName: "remi", receiverName: "kobayashi", password: "algo123")

どうでしょうか?わかりやすいコードを書くことで、まったく同じ処理なのにバグが起きづらくなりました
こんなノリでコードは処理が同じであっても書き方次第で全然違うものになり得ます


さまざまな言語仕様はリーダブルコードのため

なぜ値の変えられない 定数 というものがわざわざ存在しているのでしょうか?
オブジェクト指向に触れたことある人なら、クラスprivate などの言語仕様に触れたと思います
なぜわざわざアクセスを制限する必要があるのでしょうか?

答えはリーダブルコードを書くためです。それらは人間がわかりやすいコードにするために作られてきたものなのです。

この節では、なぜ存在するかわかり辛い言語仕様たちをその使い道を一緒に解説することで、納得しながら理解していくことを目標としています

Clone this wiki locally