リーダブルコード俺俺メモ①第一部 表面上の改善
最近コードを量産することが多いので、リーダブルコードを読む。
コードは今まで我流だったし、コードを書く機会がそこまで多くなかったので会社でレビューを受けた回数も少ないため一回ちゃんとしないとなぁというのがモチベーション。
自己認識としては、変数名がやばい(後で読み返したとき、自分でも一瞬なんだっけこれ?ってなる)。
完全に俺俺メモなので、各章毎に個人的にできてないことや意識しておくことのみをメモ書き程度の書き方で羅列する。適宜自分なりの解釈や、記事などから引用した内容も書くためリーダブルコード自体には書いてないこと(注釈で「自己解釈」と書いている行)も入るので注意。
また、プログラマーではないので、あまり使わない部分もあるため節によっては飛ばしている。

リーダブルコード ―より良いコードを書くためのシンプルで実践的なテクニック (Theory in practice)
- 作者:Dustin Boswell,Trevor Foucher
- 発売日: 2012/06/23
- メディア: 単行本(ソフトカバー)
1章. 理解しやすいコード
読みやすさの基本定理
コードは他の人が最短時間で理解できるように書かなければいけない。「他の人」というのは少し時間が経ったときの自分も含める。 例えば、そのコードを別のときに流用することもあるし、何かしらの修正が発生したときに改めて読む必要があるが、そのときにできるだけ思い出す時間をかけないためにも必要となる。 また、「理解できる」というのは、他の人が変更を加えたりバグを見つけることができるレベルを指す。
2章.名前に情報を詰め込む
変数名や関数名などの「名前」は短いコメントだと考える。つまり、良い名前は多くの情報を伝えることができるので名前に情報を詰め込む必要がある。
明確な単語を選ぶ
抽象的な単語は避ける。
例えば、get
は何を取得してくるかわからないが、fetch
やdownload
なら何かしらのデータを外部から取ってくるニュアンスが伝わる。
他には、size
は何のサイズかわからんので、heigh
, numbers
などをつける。
また、stop
はkill
やpouse
の方がより細かい停止のニュアンスがわかる。
tmpやretvalなど汎用的な名前を避ける
tmp
やhoge
、retval
(return valueの略)といった特に意味がない単語は避けて、より明確な単語にする。
明確な単語となることで、その部分で何がしたいかが明確になるのでバグなどを見つけやすくなる。
コメントでいいのでは?と思うかもしれないが、多くの場合コメントは宣言時に添えるため宣言時以降で使用する場合はそのコメントを読まない。そのため、明確な名前がついていると宣言時以降でも間違いや勘違いをした使い方を避けることができる*1。
ただし、tmp
に関しては例えば変数の入れ替え時など「この変数は他に役割がない(一時的な値の退避など、直後の1回こっきりでしか使わない一時的なもの)」という情報、つまりtmp
という単語の意味自体が意味がある場合などは使用してもよい。
# python # bがaより大きい場合、aとbを入れ替える # 変数上書きが発生するので、一時的に値を退避するためにtmpを使う if a < b tmp = a a = b b = a
ただし、そのような機会は少ないしつい甘えた使い方をしそうなのでtmp
を使用したときは「本当にtmp
でいいか?」と自問しよう*2。
イテレータ
i
,j
,k
などはそのものがイテレータだという意味になるので使用してもよい。
ただし、例えばi
,j
,k
が同じループ内で入り乱れているときはどのときにi
でj
でk
かを一見して判別するのが難しい。つまり、 i
と間違えてj
を使っていても気づきづらい。
そのため、例えばmemberを表すのがi
、clubを表すのがj
ならば、member_i
, club_i
(どちらもi
に統一)にするとより良い(記事中では略したmi
,ci
も勧めているがm
ってなんだっけ?ってなったりmember
mother
で頭文字が被ることがあとでわかったときに書き直しが生まれそうなので使わない方がいいと思う)。
本書では書いていないが、例えばmembers
リストから中身を取り出すイテレーションのときにi
ではなくmember
を使っているコードをよく見る。これは、member
がイテレータなのかどうかパッと見でわからないからあまり良くない、ということになる?*3
# python # i, jを使う(△) for i in members for j in clubs print(i) print(j) # sを除外した単語を使う(△) for member in members for club in clubs print(member) print(club) # 明示的なイテレータを使う(◎) for member_i in members for club_i in clubs print(member_i) print(club_i)
抽象的な名前を避ける
例えば、ServerCanStart
の場合、サーバーの何かをスタートできるようにする関数ということはわかるが何をStartできるかがよくわからない。
そのため、CanListenOnPort
に変えることで「PortをListenできるようにStartする」ことが明示される。
重要な情報を加える
知らせなければ使い方を誤りやすいような場合は、情報に追加する。フォーマットや時間(sec?ms?)、状態(変換前?後?)などは誤りやすい。
例えば、id
のフォーマットがhex(16進法)ならばhex_id
、時間の単位がms(ミリセコンド)で入っている(別の単位だと勘違いしたときn倍大きい数値になってしまう)ならduration_ms
とする、など。
ただし、必ず付けるのではなく、間違った場合にバグが起きそうな場合のみ付ける。
名前の長さ
名前はある程度長くてもコード補完があるのであまり問題にならない。
また、単語の省略は人によってわからないことがあるので、一般的なもの以外は省略しない方が無難。例えば、manageをmngは一般的ではないが、stringをstr、documentをdoc、evalutationnをevalは一般的。
命名規則
エンティティ毎で記法を変えることで、エンティティ情報を伝える。例えば、クラス名はキャメルケース(CamelCase
)、変数名はスネークケース(snake_case
)、定数の変数は全て大文字CONSTANT_NAME
、クラスのメンバ変数は接尾に_を入れるなど。このあたりは会社や言語によって変わったりより詳細定義があるので注意。
誤解されない名前
常にその名前が誤解されないか意識する。
例えば、filter
は除外されたのか選択されたのかわからないので、前者ならselect
後者ならexclude
をつけたほうが明確。
他にも、clip(切り抜き)
もremove(削除)
or truncate(切り捨て)
)、 length(長さ)
もmax_length(最大の長さ)
or min_length(最小の長さ)
など。
範囲
条件を指定するときの範囲は未満(<
)なのか以下(<=
)なのかは統一する。基本的にはmin
max
がついた名前とセットで使うと思うので、以上/以下(<=
, >=
)を使う*4。
また、文脈によっては限界値となるmin
max
ではなく、包括的な意味のfirst
last
やbegin
end
などでも良い。なお、star
に対応するend
は「超えたら終わる」のか、「超える手前で終わる」のか曖昧なので使わない。
bool値
true, falseの意味を明確にしないといけない。
例えば、xxx_flg
に対するよくある批判として**「xxxになったときにフラグが立つのか、xxxするため(xxxする必要がある)のフラグ(xxxでないときにフラグが立つ)のかわからんから使うな」というのがある。例えば、start_flg
は「スタートしてたら1」「スタートする必要があると1」どちらでも解釈できる。*5。
そのため、is_xxx
has_xxx
can_xxx
should_xxx
などをつけると明確になる。
4章. 美しさ
コードを読みやすくするには余白・配置・順序を意識する必要がある。
原則としては以下の3つがある。
- 読み手が慣れているパターンと一貫性のあるレイアウトを使う
- 似ているコードは似ているように見せる
- 関連するコードをまとめてブロックにする
5章. コメントするべきことを知る
コメントの目的は正確には「コードの動作を説明する」ではなく、「書き手の意図を読み手に知らせる」ことである。
コメントをするべきではないこと
コメントは画面を占拠するので、占拠するだけの価値をもたせる。つまり、コードからすぐにわかることはコメントをしない必要がある。ポイントは「すぐに」。
例えば、以下のようなコードはコードを読めばコメントの内容は「すぐに」わかる。
# python # 2番目の`*`以降を全て削除 name = '*'.join(line.split('*')[:2]
コードの処理をコメントしているだけのような「コメントのためのコメント」をしない。例えば、n = xxx.method(a,b)
に対するコメントで「オブジェクトxxxに引数a,bを入れたメソッドZを適用してhogeな処理をしてnに格納する」はコードを記述しているだけ。
「価値のあるコメント」としては、「fugaな処理(処理内容の意図)をおこなう」「もしaがxxxなら、piyoが起き、違う場合puyoが返る(渡す値の違いによる例示)」のようにするべき。
コメントは不適切な名前の穴埋めではない。つまり、適切な変数名をつけていれば、コメントの多くは不必要となる。
そのため、名前に表せれない注意点や細かい部分などをコメントにする(次に見出しで詳細)。
自分の考えを記録する
優れたコメントは考えを記録するためにある。
そのコードに対して試したこと(最適化など)や、何故それをおこなうか(何故必要か)、足りてない部分(コード未整理や足りない機能など)といったことを書くことで、他の人がそのコードを読むときに理解が進み、無駄なことを考えなくてすむ。
また、定数にコメントをつけることでなぜその値を定数にしているか という、値の背景がわかるため、考慮漏れなどを防ぐことができる。
読み手の立場になって考える
プロジェクトに熟知していない人にもわかるように書く。
質問されそうなことを想像する
何故このコードを書いたか背景がわかりづらい部分は読者が疑問に思う場合が多い。
例えば、別の簡単なやり方がありそうなのに、何故このような方法で行っているかなど
ハマりそうな罠を告知する
このコードを読んで勘違いしそうなこと、コードを間違えて使いそうなこと、使用時に考慮しなければいけないこと はなにか。これらを前もって予告することで、罠を回避することができる。
例えば、処理に時間がかかる部分や、特定条件では使用できない、など。
全体像へのコメント
新しくプロジェクトに参加した人にとって、全体像を理解することが最も難しい。
そのため、そのコードファイルに対して「どのようなことをおこなうためのコードが書いたファイルなのか」という全体像を記述するとファイルの立ち位置への理解が進む*6。
また、これはファイル単位だけでなく関数やClass単位、それぞれの塊単位でも同様に「どのようなことをおこなうための関数なのか」を書くと良い。このあたりは、各有名ライブラリのソースコードを読むと関数やClassへの要約コメントの書き方の勉強になる*7。
6章.コメントは正確で簡潔に
コメントは領域に対する情報の比率が高くなければいけない
曖昧な代名詞を避ける
これ、それ、あれなどの代名詞は指す言葉が曖昧になるし、どれを指すか解釈しなければいけないのでできるだけ使わない。
入出力のコーナーケースに実例を使う
入力(引数)や出力(返り値)がどういうときにどうなるか、実例を交える。