2
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

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章 「分/時間カウンタ」を設計・実装する

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

参考

リーダブルコード

2
4
0

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
  3. You can use dark theme
What you can do with signing up
2
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?