読みやすいコードを書く


僕はエンジニアを志している大学4年生(2020年6月現在)です。
内定先の会社の先輩に、誕生日プレゼントとして「リーダブルコード」を買っていただきました。
メモを取りながら3回くらい読んだので、それをまとめて記事にしてみます。

名前に情報を詰め込む

  • 明確な意味を示す単語を選ぶ
  • 汎用的で、誤解を招くような意味の単語を避ける

明確な意味を示す単語を選ぶ

  • get ではなく fetchdownload を選ぶ
  • size ではなく heightnum を選ぶ

汎用的で、誤解を招くような意味の単語を避ける

  • tmp
    • 一時的な保持が大切な変数にだけ使う
    • このような名前を使うときは、それ相応の理由を用意する
  • ループイテレータ(i, j, k)は基本的には問題ない
    • ただし、例えばクラブに所属しているユーザを調べるループなら、以下のような変数名が良い
      • club_i
      • member_i
      • user_i

誤解されない名前をつける

その名前が「他の意味と間違えられることはないだろうか?」と何度も自問自答する。

  • filter ではなく selectexclude を使う
  • 限界値を含めるときは minmax を使う
  • 範囲を指定するときは firstlast を使う
  • ブール値の変数名は、頭に次のような単語を付けると分かりやすい
    • is
    • has
    • can
    • should

美しさを意識する

  • 一貫性のあるレイアウトを使う
    • 一貫性のある改行位置にする
    • 並び方、順番に意味を持たせる
      • 対応するHTMLフォームのフィールドと同じ並び順
      • 「最重要」なものから重要度順
      • アルファベット順
  • 似ているコードは、似ているように見せる
    • 空白文字を使って、縦の線を真っ直ぐにする(引数の位置を揃える、など)
  • 関連するコードをまとめてブロックにする
    • 空行を使うことで、論理的な「段落」に分ける
    • 段落ごとに要約コメントを追加するのも有効

コメント

原則

  • コメントの目的は、書き手の意図を読み手に知らせること。
    • なぜ他のやり方ではなく、こうなっているのか
    • 懸念や欠陥と思われるもの
    • それにまつわる背景など
  • コードを見てすぐに分かることを、わざわざコメントに書かない
  • 優れたコード > ひどいコード + 優れたコメント
  • 読み手の立場になって考える
    • 質問されそうなこと、その答え
    • 間違える可能性のあること
    • 全体像についての簡単な解説
    • 関数やクラスなどについての要約
    • その他コードを理解するのに役立つあらゆる情報

正確で簡潔に

  • 曖昧な代名詞を避ける
    • そのそれ を具体的な表現に変える
  • 関数の説明に、実際の具体例を使うのは有効
    • 例)この引数に対して、この値を返す
  • 引数にコメントをつける(と分かりやすいこともある)

制御フローを読みやすくする

  • 条件式の引数の並び順
    • 左:調査対象、変化するもの
    • 右:比較対処、あまり変化しないもの
  • if / else ブロックの並び順
    • 条件は否定形よりも肯定形を使う
    • 単純な条件を先に書く。if と else が同じ画面に表示されて見やすい
    • 関心を引く、目立つ条件を先に書く
      • 具体的な値を使うときなど
  • 三項演算子はなるべく使わない
    • ただし、簡潔になるときは使っても問題ない
  • do / while ループを避ける
    • while ループで書き直せることが多い
  • ネストを浅くする
    • 早めに返してネストを削除する
      • 関数で複数のreturn文を使っても問題ない
    • continue でループ内部のネストを削除する

巨大な式を分割する

  • 式を表す変数を使う(説明変数)
  • 式を変数に代入しておく(要約変数)
  • ド・モルガンの法則を使う
    • not (A or B or C) = (not A) and (not B) and (not C)
    • not (A and B and C) = (not A) or (not B) or (not C)
  • 「頭が良い」コードに気をつける
    • 「頭が良い」=「一見だと分かりづらい」
    • あとで他の人が読むときに分かりにくくなる

式を表す変数を使う(説明変数)

例えば、以下の左辺は何を指しているか分かりづらい。

if line.split(':')[0].strip() == "root":

これをあらかじめ、説明された変数に代入しておく。

username = line.split(':')[0].strip()
if username == "root":

式を変数に代入しておく(要約変数)

以下の例では式は長くないが、もっと良くできる。

if (request.user.id == document.owner_id) {
    // ユーザはこの文書を編集できる
}

...

if (request.user.id != document.owner_id) {
    // 文書は読み取り専用
}

この式が言いたいことは「ユーザは文書を所持しているか?」である。
そこで、要約した変数を追加して、もっと明確なコードにすることができる。

final boolean user_owns_document = (request.user.id == document.owner_id);
if (user_owns_document) {
    // ユーザはこの文書を編集できる
}

...

if (!user_owns_document) {
    // 読み取り専用
}

変数と読みやすさ

  • 変数の数を減らす
    • 数が多いと追跡するのが難しくなる
  • 変数のスコープを小さくする
    • 変数のスコープが大きいと、把握する時間が長くなる
    • できるものは、ローカル変数に「格下げ」する
    • 大きなクラスを、小さなクラスに分割する
    • クロージャを使う
      • 変数を関数内に入れて、アクセスできる範囲を縮める
    • 使う直前で、変数を定義する
  • あまり変数を頻繁に変更しないようにする
    • 頻繁に変更されると、現在の値を把握するのが難しくなる
    • 一度だけ書き込むようにする
      • constfinal を使う
      • 「永続的に変更されない」変数は扱いやすい

一度に1つのことを

コードは1つずつタスクを行うようにしなければならない。

  1. コードが行っているタスクを全て列挙する
  2. それぞれのタスクをできるだけ異なる関数に分割する
  3. 分割できないものは、異なる領域に分割する

コードに思いを込める

おばあちゃんに分かるように説明できなければ、本当に理解したとは言えない
by アルバート・アインシュタイン

  1. コードの動作を簡単な言葉で同僚にも分かるように説明する
  2. その説明の中で使っているキーワードやフレーズに注目する
  3. その説明に合わせてコードを書く

短いコードを書く

  • 必要になりそうな機能の実装について悩まないようにする
    • YAGNI原則
      • 今の時点で必要のない機能は実装しない
      • 必要になったら実装する
  • 要求の分割
    • 最も簡単に問題を解決できるような要求を考える
    • 問題を解決できるのであれば、多少の厳密さは失われても問題ない
  • コードを小さく保つ
    • 重複コードを削除する
    • 未使用のコードや無用の機能を削除する

テストと読みやすさ

  • テストを読みやすくて保守しやすいものにする
    • 他のプログラマが安心してテストの追加や変更ができるように
  • エラーメッセージを読みやすくする
    • もし使えるのであれば、便利なアサーションメソッドを使うべき
    • 手作りのエラーメッセージを作る
  • テストの適切な入力値を選択する
    • 入力値を単純化する
    • 1つの機能に複数のテスト
      • 完璧な入力値を1つ作るよりも簡単で効果的で読みやすい
  • テストの機能に名前をつける
    • Test1() ではなく Test_SortAndFilterDocs() のようにする
  • テストに優しい開発をする
    • テストしやすいようにコードを設計する
      • 振る舞いごとに上手く分割される
      • 自然に良いコードが書けるようになる

おわりに

この「リーダブルコード」という本は、とても勉強になりました。
読みやすいコードを書くためのヒントが盛りだくさんでした。

ただ1つ思ったのは、知識があるだけでは良いコードは書けないだろうということです。
大切なことは、やはり多くのコードを書くこと、すなわち経験値だと思いました。
この本から学んだことを意識しながら、これから経験を積んでいきたいと思います。