LoginSignup
4

More than 3 years have passed since last update.

リーダブルコード覚え書き

Last updated at Posted at 2020-03-20

経緯

  • およそ7年前にも読んだことがある
  • その時の感想。「普通の当たり前のことが書いてあるな」
  • 仕事でコードレビューをする機会が多くなる
  • コードレビュー大変さを知る。同時に読みやすいコードの大切さを実感する
  • 読みやすさとは?
  • もう一度、リーダブルコードを読もう
  • 何度も見返せるようにポイントをまとめる

第1章 読みやすさの基本原理

  • 他の人が最短時間で理解できること
  • 理解するのに時間が短縮されれば生産性も上がる

第Ⅰ部 表面上の改善

第2章 名前に情報を詰め込む

  • 変数名は短いコメントだと思え
  • 曖昧な単語は避け、明確で正確な名前をつける
  • 「カラフル」な単語を探す。状況に合わせて適切な単語を選ぶ。
send: deliver, dispatch(発送する), announce, distribute, route(発送する)  
find: search, extract, locate, recover(取り出す)  
make: create, set up, build, generate, compose(構成する), add, new
  • tmpretval などの汎用的な名前を避ける
  • でも本当に tmp (生存時間が数行の一時的な情報の保管)なら tmp でも全然良し
  • スコープが短ければ短い変数名(1文字とか)でも良い。逆にスコープが大きい場合は、短い名前はNG
  • ループイテレータのインデックス i, j, k も複数のイテレータがある場合は説明的な名前にするよ良い ( club_i, members_i, users_i )
if (clubs[club_i].members[members_i] == users[users_i]) {
  • 汎用的な名前を使われているのは、ほとんど怠慢。少しだけでも時間を使って名前を考える習慣を
  • 変数名に大切な情報を追加する。ミリ秒を表す変数名には後ろに _ms をつける
  • 不要な単語は省略。convertToString()toString() で十分伝わる
  • 大文字やアンダースコアに意味を含める。クラスのメンバ変数にアンダースコアをつける offset_

3章 誤解されない名前

  • filter, length, limit など曖昧な単語を使用しない
  • filter => select (選択する) or exclude (除外する)
  • clip => remove (最後) or truncate (周辺を除去)
  • length => max_length
  • 限界値を含める時は max, min
  • 包含的範囲は first, last
  • 包含/排他的範囲は begin, end
  • bool値は頭に is, has, can, should

4章 美しさ

コードを読みやすくするための余白・配置・順序についての3つの原則

1. 読み手が慣れているパタンと一貫性のあるレイアウトを使う
  • これはLintに任せる
2. 似ているコードは似せてるように見せる
  • 複数のコードブロックで同じようなことをしていたら、シルエットも同じようにする

    例)同じ処理をしている箇所をメソッドにまとめる

  • 「見た目をよく」することで表面上の改善だけでなく、コードの構造の改善にもなる

3. 関連するコードをまとめてブロックする
  • 宣言をブロックにまとめる
  • コードを段落に分割する。空行を使って大きなブロックを論理的な「段落」に分ける

5章 コメントすべきことを知る

コメントすべきでない

  • コードからすぐに抽出できるコメント
  • ひどい変数や関数の名前はコメントをつけずに名前を変える

記録すべき自分の考え

  • なぜコードが他のやり方ではなくこうなっているのか
  • コードの欠陥に記法を使って示す FIXME: TODO:
  • 定数にコメントする。マジックナンバーにまつわる背景。

読み手の立場になって考える

  • 質問されそうなことを想像する
  • ハマりそうな罠を告知する
  • 平均的な読み手が驚くような動作は文書化しておく
  • ファイルやクラスには「全体像」のコメントを書く
  • 読み手が細部に捕われないように、コードブロックにコメントをつけて概要をまとめる

6章 コメントは正確に簡潔に

  • 複数の物を指す可能性がある「それ」や「これ」などの代名詞を避ける
  • 関数の動作はできるだけ正確に説明する
  • 入出力のコーナーケースに実例を使う
  • コードの意図は、詳細レベルではなく、高レベルで記述する
  • よくわからない引数にはインラインコメントを使う Funciton(/* arg = *? ...)
  • 多くの意味が詰め込まれた用語や表現を追加って、コメントを簡潔に保つ

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

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

  • 条件式の並び順は、左側「調査対象」の式。変化する。右側「比較対象」の式。あまり変化しない。
  • 英語の文章として自然な感じで
Good
if (length >= 10)

while (bytes_received < bytes_expected)
Bad
if (10 <= length)

while (bytes_expected > bytes_received)

8章 巨大な式を分割する

  • 説明変数:式の意味を説明してくれる変数
Before
if line.split(':')[0].strip() == "root": 
After
username = line.split(':')[0].strip()
if username == "root": 
  • 要約変数:大きなコードの塊を小さな名前に置き換えて、管理や把握を簡単にする変数
Before
if (request.user.id == document.owner_id) {
// ユーザはこの文書を編集できる
}

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

if (user_owns_document) {
// ユーザはこの文書を編集できる
}

if (!user_owns_document) {
// 文書は読み取り専用
}
  • 短絡評価の悪用
Before
assert((!(bucket = FindBucket(key))) || !bucket->IsOccupied());

たった1行のコードだけど、しばらく立ち止まって考えなきゃいけない感じ。

After
bucket = FindBucket(key);
if (bucket != NULL) assert(!bucket->IsOccupied());

全く同じものだけど、ずっと理解しやすくなった。

9章 変数と読みやすさ

  • 中間結果の変数を削除する
  • 制御フロー変数を削除する
  • 変数のスコープを縮める。 クロージャ(JS)を使って、プライベート変数を作る
  • 変数定義の位置を下げる。 関数の先頭に変数定義をまとめるのではなく、変数を使う直前に移動する

第Ⅲ部 コードの再構成

10章 無関係の下位問題を抽出する

  • 無関係の下位問題を積極的に抽出して見つけて抽出すること
  1. 「このコードの高レベルの目標は何か?」と自問
  2. 「高レベルの目標に直接的に効果があるのか?あるいは、無関係の下位問題を解決しているのか?」と自問
  3. 無関係の下位問題を解決しているコードが相当量あれば、それらを抽出して別の関数にする。
  • 抽出された関数は完全に自己完結しているので、自分がどのように使われているか知らない。再利用性が高い
  • 純粋なユーティリティコード
  • 抽出されたコードが独立していれば、そのコードの改善が楽になる
  • インタフェースが複雑なライブラリはラッパーしてシンプルにする
  • やりすぎ注意。小さな関数を作りすぎて、実行パスがあっちこっちに行って逆に読みにくくなる

11章 一度に1つのことを

  • コードをデフラグする
  • 一度に複数のことをするコードは理解しにくい
  • コードは1つずつタスクを行うようにしなければいけない
  • 「関数は一度に1つのことを行うべき」という考え方と同じ
  • 読みにくいコードがあれば、そこで行われているタスクを全て列挙する
  • そのタスクごとにコードを分割する

コードのデフラグイメージ図
コードのデフラグ

12章 コードに思いを込める

  • おばあちゃんにがわかるように説明できなければ、本当に理解したとは言えない --アルバート・アインシュタイン
  • コードを簡単な言葉で説明する
  1. コードの動作を簡単な言葉で同僚にもわかるように説明する
  2. その説明の中で使っているキーワードやフレーズに注目する
  3. その説明にあわせてコードを書く
  • 問題や設計をうまく言葉で説明できないのであれば、何かを見落としているか、詳細が明確になっていないということ
  • プログラム(あるいは自分の考え)を言葉にすることで明確な形になる
  • 説明で使っている単語やフレーズをよく見れば、分割する下位問題がどこにあるかわかる

13章 短いコードを書く

  • 最も読みやすいコードは、何も書かれていないコードだ
  • 不必要な機能をプロダクトから削除する。過剰な機能は持たせない
  • 最も簡単に問題を解決できるような要求を考える
  • 定期的にすべての API を読んで、標準ライブラリに慣れ親しんでおく
  • ライブラリの再利用
  • 車輪の再発明をしない

14章 テストの読みやすさ

  • 新しいテストの追加や
  • テストのトップレベルはできるだけ簡潔にする。入出力のテストはコード1行で記述できるとよい
  • テストが失敗したらバグの発見や修正がしやすいようなエラーメッセージを表示する(適切なアサーション関数を使用する)
  • テストに有効な最も単純な入力値を使う
  • テスト関数に説明的な名前をつけて、何をテストしているのかを明らかにする

15章 「分/時間カウンタ」を設計・実装する

  • 時間バケツの実装は読むだけでは理解できなかった
  • 自分でコードを書いてみると良いと思う

参考

リーダブルコード

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
What you can do with signing up
4