読みやすいコードとは?「リーダブルコード」で学ぶ3つの実践ポイント

はじめに

皆さんはコードを書いているときに「読みやすいコードになっているかな?」と悩んだことはあったでしょうか。

この記事では書籍紹介をしながら「読みやすいコード」にするための実践ポイントについて触れていきます。

書籍概要

書籍画像
リーダブルコード ―より良いコードを書くためのシンプルで実践的なテクニック
Dustin Boswell (著), Trevor Foucher (著), 須藤 功平 (解説), 角 征典 (翻訳)
※出典:オライリージャパン https://www.oreilly.co.jp/books/9784873115658/

今回読んだ書籍はこちらです。
色んな方から良書として取り上げられていまして、私も読んで学びを得られたので紹介します。

読みやすいコードの定義は?鍵は『最短時間で理解できる』

では、「読みやすいコード」の定義とは何でしょうか。
本書では読みやすさの基準について

コードは他の人が最短時間で理解できるように書かなければいけない。
『リーダブルコード』1章 1.2 読みやすさの基本定理 p.3 より

と記載されています。
なお、「他の人」には他者だけでなく未来の自分も含まれます。

「そんなことある?」と思われた方がいるかもしれません。
ですが、自分が書いたコードでも半年後、一年後に見ると「このコードなんだっけ?」となるものです。


読みやすいコードを書くための3つのポイント

本書を読んで個人的に学びになったと感じた点を大きく3点にまとめました。


1.命名を工夫する

変数・関数・クラスの命名について皆さんはどれだけ意識されているでしょうか。
本書では「2章 名前に情報を詰め込む」にて6つのテーマで紹介されており、個人的に重要と感じた3つに絞って考えていきます。

明確な単語を選ぶ

本書では明確な単語を選ぶ重要性について言及されています。
例えば「get」について

例えば、「get」はあまり明確な単語ではない。

def GetPage(url):
......
インターネットから取ってくるのであれば、FetchPage()やDownloadPage()のほうが明確だ。
※『リーダブルコード』2章 2.1 明確な単語を選ぶ p.10-11 より

と記載されています。

具体的な名前だと変数の役割や処理内容をイメージしやすくなるので命名は大事です。

getに変わる命名でいうと

・ファイル等のダウンロード →download〇〇
・計算結果を取得      →calcurate〇〇
・booleanを返すチェック処理 →check〇〇、is〇

といった命名にするとより分かりやすくなります。

getに限らず常に「より具体的な名前にできないか」を意識することが大事です。

名前に情報を追加する

「2章 2.4 名前に情報を追加する」では変数名に
 ・値の単位
 ・その他の重要な属性を追加する
といった情報を追加したほうが良いとされています。

具体例で考えてみましょう。
例えば単位や属性を追加するとこのような感じです。
 ・秒単位の時間:time→timeSecond
 ・税込み価格 :price→taxIncludedPrice

変更前の名前よりも「どのような変数なのか」が一目で分かりやすくなりました。

名前の長さを決める

「省略された変数名」を目にされた方は多いのではないでしょうか。
本書では「頭文字と省略形」について

ぼくたちの経験からすると、プロジェクト固有の省略形はダメだ。
......
新しいチームメイトはその名前の意味を理解できるだろうか?理解できるなら問題ない。
『リーダブルコード』2章 2.5 名前の長さを決める p.24 より

と記載されています。

確かに、プロジェクト内だけで通じる情報を省略形にしてしまうと誰かに聞かないと意味が分かりません。
誰かに聞かないと分からないならば、可読性が低いコードです。

例えば以下のように短縮した変数名を見てください。

amt(amountの略)
cal(calculateの略)
cat(categoryの略)

calだけだとcalenderといった単語に読める余地があるので、省略すると一目では分かりにくくなります。

もちろん、for文等で使われるループカウンタの変数(iの名前をよく目にします)のように短い名前でも問題ないケースもあります。

ですが、無闇に省略するよりは可読性を優先しましょう。

2.コメントの書き方

皆さんはコードを書く際にどれだけコメントを書かれているでしょうか。
本書ではコメントの目的は下記と定義されています。

コメントの目的は、書き手の意図を読み手に知らせることである。
※『リーダブルコード』5章 コメントすべきことを知る p.56 より

コメントを書くことでコード理解向上につながります。
いくつかポイントをおさえていきましょう。

「全体像」のコメント

コメントを書くポイントの一つとして

新しいチームメンバーにとって、最も難しいのは「全体像」の理解である。
※『リーダブルコード』5章 5.3 読み手の立場になって考える p.66 より

と記載されています。

コードを読み進めていけば処理内容を理解できます。
ですが、新しく現場に参画したときは分からないことばかりなのでコードを見ただけで全体像を把握するのは一苦労です。

処理の冒頭に要約コメントをつけると、全体像を把握して理解速度向上につながるので私も実践したい部分です。

コードの意図を書く

これはコメントを書く上で特に大事と考えている点です。
本書では

前章でも言ったけど、コメントというのはコードを書いているときに考えていたことを読み手に伝えるためのものだ。でも、コードの動作をそのまま書いているだけで、何も情報を追加していないコメントが多い。
※『リーダブルコード』6章 6.6 コードの意図を書く p.76 より

と記載されています。

コードの処理内容を理解できても意図や背景を読み取るのは難しいです。

例として下記のJavascriptのコードを見てください。

◆悪い例
for (let i = 0; i < 10; i++) {} // 10回ループする

◆良い例
for (let i = 0; i < 10; i++) {} // APIのレート制限(10req/sec)に合わせて上限を固定

「悪い例」のコメントは処理内容をそのまま書いているだけなので、有益なコメントではありません。

一方で、「良い例」のようにコードだけ見ても読み取れない意図・背景を書くと「なぜその実装となっているのか」を把握しやすくなります。
 

3.制御構文の書き方

三項演算子

Javascript等で使われる三項演算子をご存じでしょうか。
記述は下記の通りです。

条件 : Trueの処理 ? Falseの処理

if-else文を一行で書けるためコードの行数を削減できます。
ただ、三項演算子を使って必ずしも読みやすさ向上につながるとは限らないので、使いどころを意識する必要があります。

例としてJavascriptのコードを書いてみました。

// 例1.三項演算子で書いても問題ないコード(ログイン状態でボタン表示を切り替える)
const buttonText = isLoggedIn ? "ログアウト" : "ログイン";

// 例2.三項演算子で書くと見づらくなるコード
const buttonText = isLoggedIn ? (isAdmin ? "管理者ログアウト" : "ログアウト") : (isMaintenance ? "メンテ中" : "ログイン");

例1のようにシンプルな内容であれば、行数削減できて一目で見やすいです。
一方で、例2のようにネストが深くなってくると一行だと見づらくなってきます。

今まで三項演算子を見かけたときは、例1のようなシンプルな書き方で使われていることが多いです。

三項演算子の使いどころについて見ていくと

基本的には if/else を使おう。三項演算子はそれによって簡潔になるときにだけ使おう。
『リーダブルコード』7章 7.3 三項演算子 p.89 より

とあります。
行数削減より可読性を優先することが大事なので、三項演算子を使うときは注意しましょう。

ネストを浅くする

本書では「7.7 ネストを浅くする」でネスト(if文の中にif文を入れるといった入れ子構造)が深いコードについて触れています。

ネストが深いと読解に時間を要しますし、改修時に影響範囲を見落として不具合を生み出す温床になりえます。
※現場のコードレビューで「ネストが深いので見づらい」と指摘されないよう注意しましょう。

個人差はあるでしょうが、私は下記のように3階層のネストになってくると「ネスト深いなぁ」と感じます。

function calcuratePrice(basePrice, inStock, region, coupon, shippingFee = 0) {
  // 在庫があるか
  if (inStock) {
    // 送料込みの基準価格を作る
    let taxAndShippingIncludedPrice = basePrice + shippingFee;

    if (region === "JP") {
      // 国内税(例:10%)を適用
      taxAndShippingIncludedPrice = taxAndShippingIncludedPrice * 1.10;

      if (coupon && coupon.type === "percent") {
        // パーセントクーポンを適用(国内のみ有効)
        taxAndShippingIncludedPrice *= (1 - coupon.value / 100);
      }
    }
    return Math.round(taxAndShippingIncludedPrice);
  } else {
    // 在庫が無い時の処理
    return null;
  }
}

ネストを浅くする方法は、
 ・ガード節(早期return)
 ・処理の一部をメソッドに分ける
といった方法があります。

ガード節とは、処理の冒頭で「条件を満たさない場合」を先に判定し早期に処理を終了させる書き方です。
ガード節を使って上記の処理を直すと下記になります。

function calcuratePrice(basePrice, inStock, region, coupon, shippingFee = 0) {
  // ガード:在庫なしは即終了
  if (!inStock) {
    return null;
  }

  let taxAndShippingIncludedPrice = basePrice + shippingFee;

  // 国内ルール
  if (region === "JP") {
    taxAndShippingIncludedPrice *= 1.10; // 消費税 10%
    if (coupon?.type === "percent") {
      price *= (1 - coupon.value / 100);
    }
  }
  // 地域の税・クーポン規則があるならここに追記
  // else if (region === "EU") { taxAndShippingIncludedPrice *= 1.2; }

  return Math.round(taxAndShippingIncludedPrice);
}

ネストが浅くなり簡潔なコードになりました。

おわりに

いかがだったでしょうか。

『リーダブルコード』は他にも参考となるポイントがたくさん載っています。
より良いコードを書くため、ぜひ本書を手に取ってみてください。