もちもち備忘録

びぼーろく

リーダブルコードを読んで

こんにちは、こんばんは、おはようございます。
もちもちなあざらし、もちざらしです。

今日は初投稿の記事として、リーダブルコードの特に自分で気をつけよう!!勉強になった!!というエッセンスを簡単にまとめていきます。

www.oreilly.co.jp

リーダブルコードとは

まず簡単にリーダブルコードについての覚書です。
この本はみんな大好きO'REILLYから出ている名著で、ユーモラスな日本語でコードを良くするエッセンスを学ぶことができます。
具体例として、Python, JS, C++などの言語が出てきますが、基本的には言語に依存しない、汎用的なテクニックが記載されています。

私は普段とんでもコードを書いている自覚はありつつも、「どうすればもっとマシになるんだろう」「早く実装しなきゃ、ただでさえ遅いのに」「あぁ〜〜〜クソコード!!!無理!!!気持ち悪い!!!!けど書かなきゃ!!!!!」と発狂しながらコードを書き進めています。
そこで職場の綺麗なコードを書かれるハイパー先輩が貸してくださったのがこの一冊。
意外とさらっと読めるし自分のために大切なところにはポストイットを貼りたいタイプなので即ポチりました。

では、私のための備忘録の始まり始まり〜〜

自分が成長するための大切ポイント

第一部 表面上の改善

1. 名前に情報を埋め込もう

関数名・変数名をどうにかするためのコツ

  • 明確な単語を選ぶ
    • Getだけでなく、状況に応じてFetchやDownloadなどを使い分ける
  • tmp, retvalなど汎用的な名前は避ける
    • スコープが小さいなど明確な理由がある場合はOK
  • 具体的な名前で、物事を詳細に説明
    • ex) ServerCanStart() -> CanListenOnPort()
  • 変数名に大切な情報を追加
    • ex) ミリ秒を表す変数名には後ろに_ms
  • スコープの大きい変数には長い名前
    • スコープが数画面に及ぶ変数には1~2文字の暗号めいた名前はNG
  • 大文字や_などに意味を込める

2. 誤解されないための名前

危ない名前の具体例

  • filter()
    • 「選択する」ならselect()
    • 「除外する」ならexclude()
  • Clip(text, length)
    • 「最後からlength文字を削除」ならRemove()
    • 「最大length文字まで切り詰める」ならTruncate
    • length -> max_length
      • lengthもバイト数、文字数、単語数などがあるからmax_charsなど

その他コツ

  • 限界値にはmin, max
  • 範囲の指定にはfirst, last
    • lastは含む
  • 包含/排他的範囲にはbiginとend
    • endは含まれない
  • boolにはis, has, can, should, needなどをつける
  • get*()はメンバの値を返すだけ
  • size()は計算量O(1)とする

3. 綺麗な見た目

いい感じに綺麗に見えるためのコツ

  • 一貫性のある簡潔な改行位置
  • ヘルパーメソッドを使って何度も登場する長い文字列をどうにかする
    • テストケースの大切な部分が目立つ・追加が簡単になるなど、コードの構造などの改善にもつながる
  • 縦の線をまっすぐに揃える
    • 同じ複数の関数に渡す引数の頭の位置を一緒にする
  • 並べる順番がコードの正しさに響かない時は、意味のある順番に並べる
  • 宣言をブロックに並べる
  • コードを「段落」に分割する

4. 助かるコメント

コードからすぐにわかることをコメントするのはナンセンス
ひどいコードを補助するならコードを書き直せ
読み手の気持ちになって欲しいことを書いておこう

価値のあるコメントとは

  • お気持ち
    • 〇〇より△の方が10%速かった
    • ヒューリスティックだと単語が漏れることがあるが仕方ない。100%は難しい
    • 定数の値を決めた背景
  • コードの欠陥
    • TODO: あとで手をつける
      • TODO: 大きな問題
      • todo: 小さな問題
    • FIXME: 既知の不具合のあるコード
    • HACK: あまり綺麗でない解決策
    • XXX: 危険!大きな問題がある
  • ハマりそうなところ
  • 全体像
  • 要約

コメントの内容

  • 多くの意味が詰め込まれた言葉や表現を使って、コメントを簡潔に
  • 曖昧な代名詞を避けて
  • 歯切れはキレッキレで
  • 関数の動作は正確に
  • コメントに含める入出力の実例はコーナーケースを慎重に選択
  • コードの意図は詳細ではなく高レベルに記述
  • よくわからない引数にはインラインコメントを使用

第二部 ループとロジックの単純化

1. 読みやすい制御フロー

if文

  • 条件は否定系より肯定系
  • 単純な条件を先に
  • 目立つ条件を先に

ループ

  • do/whileループはwhileループに直せることが多い
  • 関数からは早く返す
    • 返せない時にはcontinue

2. 読みやすくするためのコードの分割

以下を使ってみよう

  • 説明変数:式を表す変数
    •   if line.split(':')[0].strip() == "root"
      

      の場合、左辺を他の文字列で置き換えたらそれが説明変数

  • 要約変数:ちょっと大きな塊・変数を多く含む式を、変数に代入
    •   if (request.user.id == document.owner_id)
      

      はuser_own_document = (request == document.owner_id)にするとわかりやすい

  • ド・モルガンの法則

3. 変数と読みやすさ

  • 不要な変数はできるだけ削除
    • 役に立たない一時変数
      • 式を分割していない
      • 明確になっていない
      • 一度しか使っていない
    • 中間結果
    • 制御フロー変数
      • doneなどのフラグ
  • 変数のスコープはできるだけ小さく
  • 変数への書き込みはできるだけ少なく

第三部 コードの再構成

  • プログラムの主目的と関係ない「無関係の下位問題」を抽出
    • util/などに再利用できるコードをまとめる
  • 一度に一つのことだけをやる
  • 最初にコードを言葉で説明して、それを元に綺麗な解決策を作る
  • 短いコードを書く
    • 汎用コードを作って利用し、重複をなくす
      • 標準ライブラリのすべての関数・モジュール・型の名前を呼んでみよう
    • 未使用・無用のコードや機能を削除する
    • プロジェクトをサブプロジェクトに分割する
    • コードを軽量で機敏にする

第四部 その他:テストコード

  • 最小のテストを作る
    • 「この状況と入力から、この振る舞いと出力を期待する」の形までまとめたコード
  • エラーメッセージを読みやすくする
    • 手作りで綺麗なフォーマット作るのもよし
  • 適切な入力値
    • 最も綺麗で単純な例を選ぶ
  • テストの機能に名前をつける
    • テストするクラス・関数・状況やバグがすぐに理解できる名前でまとめる
    • Test<関数名><状況>()など

おわりに

沢山書いてしまいましたが、とにかく読む人のことを考えて書くのが大事そうです! 目指せ、クソコードからの脱却!