プログラミング

リーダブルコード

mmmuser

良いコードというのは、どういうコードなのか。
ということで、今回はリーダブルコードを読んだのでまとめていきたいと思います。

1. 理解しやすいコード

  • コードは理解しやすくなければならない。
  • コードは他の人が最短期間で理解できるように書かなければならない。
  • コードは短くしたほうがいい。だけど「理解するまでにかかる時間」を短くするほうが大切

他の人がコードを読んでも、何をしているのか理解できるコードを書くことが大事。ここでいう他の人というのは、未来の自分も含めてということですね(゜゜)
かと言って、簡潔に短く書けばいいってものでもなく、それが逆に曖昧すぎて何をしているかわからなくなってしまわないようにというのが大切。

コードが短い ≠ 理解しやすいコード

2. 名前に情報を詰め込む

  • 明確な単語を選ぶ
    • 汎用的な名前を避ける(あるいは、使う状況を選ぶ)
    • 抽象的な名前よりも具体的な名前を使う
    • 接尾辞や接頭辞を使って情報を追加する
    • 名前の長さを決める
    • 名前のフォーマットで情報を伝える
    • チーム独自の省略規則はやめよう
  • tmp や retval などの汎用的な名前を避ける
  • 具体的な名前を使って、物事を詳細に説明する
  • 変数名に大切な情報を追加する
  • スコープの大きな変数には長い名前をつける
  • 大文字やアンダースコアなどに意味を含める

この辺りは自分自身とても苦手なのですが、まず日本語での説明文を考えてみるといいかもしれません。
どうしても汎用的な名前をつけがちになってしまいますが、具体的に、そして表現を豊かにすることが大切。

時間などの計測可能な値であれば、変数名に単位を入れると良さそうですね!

単語 代替案
send deliver, dispatch, announce, distribute, route
find search, extract, locate, recover
start launch, create, begin, open
make create, set up, build, generate, compose, add, new

3. 誤解されない名前

  • 名前が「他の意味と間違えられることはないだろうか?」と何度も自問自答する
  • 限界値を含めるときは min と max を使う
  • 範囲を指定するときは first と last を使う
  • 包含/排他的範囲には begin と end を使う
  • ブール値には is や has を使う
  • 複数の名前を検討する

最善の名前とは、誤解されない名前。
英単語には曖昧な表現も多いため、コードを読んでいるものに正しく情報が伝えられるような名前を付ける必要がある。
コードを他人が読んだときに意図を理解か、誤解を招かない名前かどうかを考えるのが大切。

4. 美しさ

  • 読み手が慣れているパターンと一貫性のあるレイアウトを使用する
  • 似ているコードは似ているように見せる
  • 関連するコードをまとめてブロックにする

インデントや空行などを用いて、「目に優しい」コードを心がける。
全体的に統一感のあるコードを書くことが大切。

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

  • コメントするべきでは「ない」ことを知る。
  • コードを書いているときの自分の考えを記録する。
  • 読み手の立場になって何が必要になるかを考える。

コードがわかりづらいから、コメントを書くという考えがそもそも間違っていて、
そんなわかりづらいコードなのであれば見直すべきということですね(゜゜)

優れたコード、優れた名前であればコメントも必要ない。コードから"すぐに"読み取れることをコメントに書かない。
なぜコードが他のやり方ではなくこうなっているのかや、コードの欠陥、定数の値にまつわる「背景」を記録するためのもの。

優れたコード > ひどいコード + 優れたコメント

6. コメントは正確で完結に

  • 複雑なものを指す可能性がある「それ」や「これ」などの代名詞を避ける
  • 関数の動作はできるだけ正確に説明する
  • コメントに含める入出力の実例を慎重に選ぶ
  • コードの意図は、詳細レベルではなく、高レベルで記述する
  • よくわからない引数にはインラインコメントを使用する
  • 多くの意味が詰め込まれた言葉や表現を使って、コメントを簡潔にかく(情報密度の高い言葉をつかう)

コメントを書く場合は、少ない文字数でも正確にかつわかりやすい文章を心がけて書くことが大切。

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

if/else ブロックの並び順

  • 条件は否定形よりも肯定形を使う。
  • 単純な条件を先に書く。if と else が同じ画面に表示されるので見やすい。
  • 関心を引く条件や目立つ条件を先に書く。

三項演算子

行数を短くするよりも、他の人が理解するのにかかる時間を短くする。
基本的には if/else を使い、三項演算子は簡潔になるときにだけ使う。

三項演算子が読みやすくて簡潔な例

time_str += (hour >= 12) ? "pm" : "am";

三項演算子だと読みにくい例

return exponent >= 0 ? mantissa * (1 << exponent) : mantissa / (1 << -exponent);

do/while ループを避ける

do/whileは行数が短くなるものの、「下から上」に読まなければならないので、読みづらいため使用を避ける。

関数から早く返す

関数で複数のreturnを使ってはいけないと思い込んでる人がいるが、大きな間違い。
returnを使って、早めに返すことでネストを削除したりコードをクリーンにしたりできる。

ネストを浅くする

ネストしているとコードを追うのが大変になってしまい、読みづらくなってしまう。
深いネストを避けるには「直線的」なコードを選択する。

8. 巨大な式を分割する

  • 巨大な式を分割できる。
  • 簡潔な名前で式を説明することで、コードを文書化できる。
  • コードの主要な「概念」を読み手が認識しやすくなる。

    説明変数

    式を表す変数(説明変数)を用いることで、式をわかりやすくする。

if line.split(':')[0].strip() == "root":
username = line.split(':')[0].strip()
if username == "root":

9. 変数と読みやすさ

  • 変数が多いと変数を追跡するのが難しくなる
  • 変数のスコープが大きいとスコープを把握するのに時間がかかる
  • 変数が頻繁に変更されると現在の値を把握するのが難しくなる

変数を削除する

コードが読みやすくならない変数を削除し、コードを簡潔で理解しやすいものにする。

中間結果を削除する

var remove_one = function (array, value_to_remove) {
  var index_to_remove = null;
  for (var i = 0; i < array.length; i += 1) {
    if (array[i] === value_to_remove) {
      index_to_remove = i;
      break;
    }
  }
  if (index_to_remove !== null) {
    array.splice(index_to_remove, 1);
  }
};

変数 index_to_remove は、中間結果を保持するためだけに使っているが、結果をそのまま使用すれば、index_to_removeは不要。

var remove_one = function (array, value_to_remove) {
  for (var i = 0; i < array.length; i += 1) {
    if (array[i] === value_to_remove) {
      array.splice(i, 1);
      return;
    }
  }
};

タスクはできるだけ早く完了するほうが良い。

制御フロー変数を削除する

boolean done = false;

while (/* condition */ && !done) {
  // 何らかの処理

  if(...) {
    done = true;
    continue;
  }
}

上記のdoneのような変数(制御フロー変数)はうまくプログラミングすれば削除できる。

while(/* condition */) {
  // 何らかの処理
  if (...) {
    break;
  }
}

グローバル変数は避ける

グローバル変数はどこでどのように使われるのか追跡するのが難しく、ローカル変数と衝突する恐れがあるため避けたほうがよい。

  • 邪魔な変数を削除する
  • 変数のスコープを小さくする
  • 一度だけ書き込む変数をつかう

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

  • 関数やコードブロックを見て「このコードの高レベルの目標は何か?」と自問する。
  • コードの各行に対して「高レベルの目標に直接的に効果があるのか? あるいは、無関係の下位問題を解決しているのか?」と自問する。
  • 無関係の下位問題を解決しているコードが相当量あれば、それらを抽出して別の関数にする。

プロジェクト固有のコードから汎用的なコードを分離するということ。

11. 一度に1つのことを

  • 一度に複数のことをしているコードは理解しにくい
  • 読みにくいコードがあれば、そこで行われているタスクをすべて列挙する
  • 一番難しいのはプログラムが行っていることを説明することである

「一度に 1 つのタスクを行う」 を心がける。
読みにくいコードがあれば、そこで行われているタスクをすべて列挙し、分割していく。
タスクをどのように分割するかよりも、分割するということが大切。

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

  • コードを書く前に、誰にでもわかるようにロジックを説明する文を考えてからコードを書く

複雑な実装ほど、目的が曖昧になってしまい遠回りをしてしまう。
何が目的で、目的を達成するためにどんな事が必要なのかを整理するためにも、一度文章で考えるのは大切ですね。

13. 短いコードを書く

最も読みやすいコードは何も書かれていないコード

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

14. テストと読みやすさ

  • 他のプログラマが安心してテストの追加や変更ができるように、テストコードを読みやすくする。

複雑な実装のテストほど、書きたくないですよね・・・^^;
あとでテストを書くつもりでコードを書くように意識してみると、自然とテストに優しいコードを設計できると感じます。

テストに優しいコード = いいコード

まとめ

今回はリーダブルコードのまとめでしたが、いかがでしたでしょうか?
私自身なかなかいいコードがどんなものか曖昧な部分があったので、この本はとても勉強になりました。

これを実際の業務でも活かせるよう、一つ一つ意識していきたいです。

AUTHOR
デロイト トーマツ ウェブサービス株式会社(DWS)
デロイト トーマツ ウェブサービス株式会社(DWS)
デロイト トーマツ ウェブサービス株式会社はアマゾン ウェブ サービス(AWS)に 専門性や実績を認定された公式パートナーです。
記事URLをコピーしました