名前に情報を詰め込む
明確な単語をつかう
dataやinformationなど単語から何も伝わってこない命名は避けるべき。
→ 迷ったら類似辞典を使う。
名前に情報を追加する
前提として**「名前は短いコメントのようなもの」**と考える。
絶対に知らせなくてはならない大切な情報があれば「単語」を変数名に追加する。
名前の長さ
長すぎたり短すぎる命名は避けるべきだが、それをどこまで真に受けるべきか。
例えば、識別子のスコープ(その名前が見えるコードの行数)が小さければ短い命名でも良い。
→ コードを理解するのに必要な情報がすぐそばにあるため。
不要な単語を捨てる
例えば
ConvertToInteger()
# これを
ToInteger()
# こうしても問題はない
誤解されない名前
最善の名前とは、誤解されない名前。
つまり自分のコードを読んでいる人が、自分の意図を正しく理解できるということ。
名前を決める前に、反対意見を考えるなどして「誤解されない名前かどうか」を想像してみる。
命名リファクタリングの例
length
→ max_length
これもバイト数なのか、文字数なのか、単語数なのか分かりにくい。
そのため、文字数を意味している場合は
length
→ max_length
→ max_chars
とする。
限界値を決めるときはmaxやminを使う
例えばショッピングカートに10点までしか商品が入らないとき
CART_TOO_BIG_LIMIT = 10
このとき、限界値を明確にするためには
MAX_ITEMS_IN_CART = 10
とするべき。
複数の名前を検討する
「この機能を知らない人が見たらどうなるか」を常に想像しなければならない。
例: copy
experiment_id: 101
copy: 100
# これを下のようにすると分かりやすい
# copy_element: 100
copyだけだと「この実験を100回コピーする」なのか「これは100回目のコピーだ」なのかが分からない。
他の実験を参照している言葉だと明確にするにはcopy_elementとすると良い。
美しさ
優れたコードは「目に優しいもの」でなくてはならない。
見た目が優れているコードのほうが使いやすいのは明らか。考えてみれば、プログラミングの時間のほとんどは「コードを読む時間」といえる。
-
一貫性のある改行
複数のコードブロックで同じようなことをしていたら、シルエットも同じようなものにする。 -
縦の線を真っ直ぐにする
コードの列を整列すれば、概要が把握しやすくなる。 -
一貫性と意味のある並び
ある場所でABCDのように並んでいたものを、他の場所でBCDAのように並べてはいけない。意味のある順番を選んで、常にその順番を守る。
コメント
コメントの目的は「書き手の意図を読み手に知らせること」である。
自分がコードを書いているときに、自分の頭の中にある大切な情報は、誰かがコードを読むときには失われてしまう。
コメントすべきでないこと
-
コードからすぐに分かることをコメントに書かない。(価値のないコメント)
-
ひどい名前の埋め合わせにコメントを書いてはならない。
優れたコード > ひどいコード + 優れたコメント
自分の考えを記録する
良いコメントの例
# このクラスは汚くなってきている
# サブクラス'○○'を作って整理した方がよいかもしれない
# TODO: もっと高速なアルゴリズムを使う
# 合理的な限界値。人間はこんなに読めない。
const int MAX_RSS_SUBSCRIPTIONS = 1000;
# このファイルには、ファイルシステムに関する便利なインターフェースを提供
# するヘルパー関数が含まれている。ファイルのパーミッションなどを扱う。
# 注意: このコードはリストの重複を処理できない(実装が難しいので)。
# 所在地を正規化する (例: "Avenue" -> "Ave.")。
よく使うコメントの記法
# TODO: あとで手をつける
# FIXME: 既知の不具合があることを知らせる
# HACK: あまりキレイじゃない解決策
# XXX: 大きな問題あり
大切なのは**「これからこのコードをどうしたいのかを自由にコメントに書く」こと**。そういったコメントを書くことで、コードの品質は情報を知らせたり、改善の方向を示したりできる。
読み手の立場になって考える
読み手 = プロジェクトを自分のように熟知していない人のこと。
- 質問されそうなこと想像する。
- 「このコードを見てビックリすることは何だろう?どんな風に間違えて使う可能性があるだろう?」と自分に問いかける。
制御フロー
条件やループなどの制御フローがないコードは読みやすい。他の場所に飛んだり枝分かれしたりするのは複雑なので、コードがすぐに分かりにくくなってしまう。
比較を書くとき
if (length >= 10)
# 上の方が見やすい
if (10 <= length)
上記のどっちが読みやすいかという指針は
左側: 「調査対象の式」変化する。
右側: 「比較対象の式」あまり変化しない。
ネストを浅くする
ネストが深いコードは、読み手が「精神的スタック」に条件をプッシュしなければならず、理解しにくくなってしまう。
コードを変更するときは、自分が初めてそのコードを見たような新鮮な気持ちで全体を見る。
変数と読みやすさ
- 変数が多いと変数を追跡するのが難しくなる
- 変数のスコープが大きいと、スコープを把握する時間が長くなる
- 変数が頻繁に変更されると、現在の値を把握するのが難しくなる
役に立たない一時変数
now = datetime.datetime.now()
root_message.last_view_time = now
このnowを使う意味はない。
- 複雑な式を分解していない
- より明確になっていない。datetime.datetime.now()のままでも十分に明確といえる。
- 一度しか使っていないので、重複コードの削除になっていない。
変数のスコープを縮める
グローバル変数に限らずすべての変数の「スコープを縮める」のはよい考えといえる。
→ 変数のことが見えるコードの行数をできるだけ減らす。
→ 一度に考えなければならない変数を減らせるから。
変数は一度だけ書き込む
「生きている」変数が多いとコードが理解しづらい。変数が絶えず変更され続けるコードはもっと理解しづらい。
→ 変数は一度だけ書き込む。
→ 「永続的に変更されない変数」は扱いやすい。
無関係の下位問題を抽出する
簡単にいうとプロジェクト固有のコードから汎用コードを分離するということ。
一般的な問題を解決するライブラリやヘルパー関数を作っていけば、プログラムに固有の小さな核だけが残る。
一度に一つのことを
読みにくいコードがあれば、そこで行われているタスクをすべて列挙する。
そこには別の関数(やクラス)に分割できるタスクがあるはず。
それ以外は、関数の論理的な「段落」となる。
タスクをどのように分割するかよりも、分割するということが大切。
さいごに
名著「リーダブルコード」の個人的まとめを作成しました。
あくまで自習用まとめなので、詳細なコード例や説明は、直接書籍を購入し読んでみてください。