リーダブルコードはSIerや客先常駐して開発しているエンジニアにとってとても役に立つコーディング指針である。本書の内容を実践しながらコードを書いていくことで、間違いなくコード品質はアップする。保守しやすいコード群が出来上がるため、エンジニアにとってもエンドユーザにとってもメリットがある。
1章 理解しやすいコード
読みやすさの基本定理 コードは他の人が最短時間で理解できるように書かなければならない
これが全エンジニアの指標とすべき、良いコードの定義。つまり、読みやすく、理解しやすいコードが良いコードですよ。ということ。
動けばいいという考えでコーディングするエンジニアもよく見かけますが、動くというのは大前提で、動く上で読みやすく、理解しやすいコードを書きましょう。
この本に出てくるテクニックや方法はすべてこの「読みやすく理解しやすくなければいけない」という原則から生じている。
2章 名前に情報を詰め込む
本章のテーマは「名前に情報を詰め込む」だった。つまり、名前を見ただけで情報を読み取れるようにすることだ。
・明確な単語を選ぶ
・tmpやretvalなどの汎用的な名前を避ける
・抽象的な名前より具体的な名前を使う
・名前に情報を追加する
どんなプロジェクトでも使えますね。必ず遭遇するものです。私もこの間のプロジェクトで、Base64エンコードした値をPOSTする処理があったのですが、Contoller -> Service -> Serivce内のメソッドと渡していく中で、「あれ?これってデコードされてるんだっけ?」とこんがらがったことがあります。単位をつける、属性を追加するというので、かなり読みやすくなると感じました。レビューする人にとっても絶対に分かりやすくなりますよね。
3章 誤解されない名前
最善の名前とは、誤解されない名前である。つまり、君のコードを読んでいる人が、君の意図を正しく理解できるということだ。
4章 美しさ
一貫性のあるスタイルは「正しい」スタイルよりも大切だ。
誰もが美しいコードを見るのが好きだ。一貫性と意味のあるやり方でコードを「整形」すれば、すばやく簡単にコードを読むことができる。
開発現場で美しく見せようと空白を追加したり、適宜改行しても、フォーマッタがかかってぐちゃぐちゃになるということはよくあります。なんとかしたいですね。但し、フォーマッタを全メンバ同じをの使うことで、メンバ間での一貫性はとれることは大きなメリットです。
無フォーマットで全員個性的なコードスタイルになるよりは、工夫したフォーマットが崩れる方がまだましでしょう、フォーマッタはちゃんと入れましょうね。
5章 コメントすべきことを知る
コメントの目的とは、コードの意図を読み手に理解してもらうことである。
コメントすべきでは「ない」こと:
・コードからすぐに抽出できること。
・ひどいコードを補う補助的なコメント。コードを修正すること。
記録すべき自分の考え:
・なぜコードが他のやり方ではなくこうなっているのか。
・コードの欠陥をTODOを使って示す。
・定数の値にまつわる「背景」。
読み手の立場になって考える:
・コードを読んだ人が「えっ?」と思うところを予想してコメントをつける。
・平均的な読み手が驚くような動作は文書化しておく。
・ファイルやクラスには「全体像」のコメントを書く。
・読み手が細部にとらわれないように、コードブロックにコメントをつけて概要をまとめる
私はコメントは大事だと思っています。以前、途中から参画した開発案件で、「最初はみんな無コメントですすめていたが、途中でわからなくなってきたので、みんなコメントを書くようにした」と言っていました。コメント必須ですよ。
特に私は処理のまとまりごとに概要コメントがあって欲しいと思っています。ここからは何するところ、ここからは何するところというコメントです。それが設計書のコメントと一致していれば、必ず読みやすく理解しやすくなるはずです。
6章 コメントは正確で簡潔に
5章でコメントの重要性を理解したところで、6章ではどんなコメントを書くかを説明している。少ない文字数で多くの正確な情報が詰まっているのが良いコメント。
小さな領域にできるだけ多くの情報を詰め込んだコメントを書くことについて説明した。具体的なヒントを以下に挙げる。
・複数のものを指す可能性がある「それ」や「これ」などの代名詞を避ける。
・関数の動作はできるだけ正確に説明する。
・コメントに含める入出力の実例を慎重に選ぶ。
・コードの意図は、詳細レベルではなく、高レベルで記述する。
・多くの意味が詰め込まれた言葉や表現を使って、コメントを簡潔に保つ。
7章 制御フローを読みやすくする
コードの制御フローを読みやすくするために君ができることはいくつもある。
・比較を書くときは、変化する値を左に、より安定した値を右に配置する。
・if/else文のブロックは、肯定系・単純・目立つものを先に処理する。
・ガード節(関数の上部で単純な条件を先に処理するもの)が便利だ。
8章 巨大な式を分割する
巨大な式を一度に理解しようと思うと難しい。最も簡単な方法は「説明変数」を導入することだ。大きな式の値を保持する説明変数には、3つの利点がある。
・巨大な式を分割できる。
・簡潔な名前で指揮を説明することで、コードを文書化できる。
・コードの主要な「概念」を読み手が認識しやすくなる。
9章 変数を削除する
プログラムの変数はすぐに増えるので、いずれ追跡できなくなる。変数を減らして、できるだけ「軽量」にすれば、コードは読みやすくなる。
・邪悪な変数を削除する。
・変数のスコープをできるだけ小さくする。
・一度だけ書き込み変数を使う。(constやfinalを使う)
10章 無関係の下位問題を抽出する
本章を簡単にまとめると、プロジェクト固有のコードから汎用コードを分離するということだ。ほとんどのコードは汎用化できる。一般的な問題を解決するライブラリやヘルパーを作っていけば、プログラムに固有の小さな核だけが残る。
この章は現場でもすぐに意識して改善できる内容。ユーティリティメソッド(XxxUtil)に切り出していこうということ。
上級PGだと、「こんなメソッドないかな~?」って探すと思います。そしてなかったら、気の利いたPGだと共通メソッド化してあげるのではないでしょうか。でも多くのPGは、共通メソッドに入れるのがめんどくさいので、クラス内でプライベートメソッド化するに留めたり、さらにめんどうだからそのままコーディングしちゃうんですよね・・・。
共通部品を作る人は「こんな引数を受け取るのもあったら誰か使うかも!」「引数にフォーマットを受け取れるような汎用的なのを作っておけば、みんなハッピーになる!」って考えて、あらかじめ提供してあげて欲しいですね。
無関係の下位問題を共通メソッドに切り出して残ったのが、画面/機能固有の本質的なコード、上位問題になります。
11章 一度の1つのこと
読みにくいコードがあれば、そこで行われているタスクをすべて列挙する。そこには別の関数(やクラス)に分割できるタスクがあるだろう。それ以外は、関数の論理的な「段落」になる。タスクをどのように分割するかよりも、分割するということが大切なのだ。
コードが読みにくく、理解しにくいものであれば、コードをメソッドに切り出して分割していこうという話でした。また、分割するタスクの粒度にこだわる必要はなく、まず分割してコードの見通しをよくする=読みやすく理解しやすくするということが大事ということです。
どこかの案件のコード規則に「1メソッドは○○行以内に」というのがあった。○○行以内に納めようとすると、長すぎるコードは存在し得ず、分割していくしかないので、この章のヒントが自然と適用されそうです。
12章 コードに想いを込める
おばあちゃんがわかるように説明できなければ、本当に理解したとは言えない。-アルバート・アインシュタイン
本章では、プログラムのことを簡単な言葉で説明する技法について説明した。説明する(声に出して)ことでコードがより自然になっていく。この技法は思っているよりも簡単だが非常に強力だ。説明で使っている単語やフレーズをよく見れば、分割する下位問題がどこにあるかがわかる。
if文がネストしたり、elseが続いたり、条件文に!否定が使われていると、コードは考えないと理解しにくくなる。そういうときは、プログラマの頭もフル回転していることが多いです。そういうコードは良く考え直して、簡単なロジックにできないか検討しようという話です。
本当はもっと単純なif文にできるんじゃないか?と考えてみること。そのときに、声に出して誰かに説明してみるというのが効果的とのことです。
私はよくロジックが複雑になってきたら、ノートに書き出します。そうすると、ロジックの袋小路から抜け出せ、一歩外から見ることができて、「ああ、このロジックってこういうことだったのね」と単純化が見つかることが多いですよ。
13章 短いコードを書く
本章では、できるだけコードを書かないことについて説明した。新しいコードには、テストや文書や保守が必要になる。また、コードが増えると「重く」なるし、開発も難しくなる。
新しいコードを書かないようにするには、
・不必要な機能をプロダクトから削除する。過剰な機能は持たせない。
・最も簡単に問題を解決できるような要求を考える。
・定期的にすべてのAPIを読んで、標準ライブラリに慣れ親しんでおく。
できるだけコードを書かないというのは、機能レベルで有効で私はいつも考えています。「本当にこの機能いるの?」「本当にそのバグは対応する必要がるの?」と着手する前に考えます。
もしバグがあったとしても、業務運用で回避できる場合は、優先度は低くできるはずです。プロジェクトによっては、結合テスト以降のバグを「やるやら判断(やるかやらないかの判断)」せずに全部直そうとしていました。私はびっくりしました。
見つかったバグを全部直そうとすると日が暮れるのが明らかだったからです。割り当てられたバグが、直さなくてよくなると、一気に問題解決で、膨大な時間が手に入ります。それによって、本当に直さなくてはいけないバグや緊急じゃないけど重要なことに着手できますからね。
コードレベルでも同じことを考えましょう。CSVを読み込んでDTOに変換するということを実装しようとしていないか(CsvMapperというクラスがあります!)、DTOの詰め替えを手動でやっていないか(ModelMapperやObjectMapperがあります)など、提供されているライブラリを知っているか否かで大きな差になります。
14章 テストと読みやすさ
テストコードでも読みやすさが大切だ。テストが読みやすければ、テストが書きやすくなり、みんながテストを追加しやすくなる。また、本物のコードをテストしやすく設計すれば、コードの設計が全体的に改善できる。
テストを改善する点をまとめておこう。
・テストのトップレベルはできるだけ簡潔にする。入出力のテストコードは1行で記述できるといい。
・テストが失敗したらバグの発見や修正がしやすいようなエラーメッセージを表示する。
・テストに有効なもっとも単純な入力値を使う。
・テスト関数に説明てきな名前をつけて、何をテストしているのかを明らかにする。特に、新しいテストの追加や修正を簡単にすることが大切だ。
私は自動テスト(JUnit)をうまく書けません。JUnitを全機能実装したのはもう5年ぐらい前です…。JUnitが一貫して実装されていて、有効に使われている現場を見たことがありません。ここは別途勉強していきたいです。
テスト関数につける良い名前の例
sortAndFilterDocs という リストをソートするメソッドに対するテスト
×void Test1(){}
○ void Test_SortAndFilterDocs_BasicSorting()
○ void Test_SortAndFilterDocs_NegativeValues()
このように、「Test_<関数名>_<状況>()」とするのが良いらしい。
JUnitを組むとして、メソッドは上から順に 値をセットして実行して結果を確認みたいな3部構成になるのをよく見かけます。しかし、本書では・・・
void Test_SortAndFilterDocs_BasicSorting(){
checkScoresBeforeAfter("1,2,-1,3", "3,2,1"); // ソート
checkScoresBeforeAfter("0,-0.1,-10", "0"); // マイナスは削除
checkScoresBeforeAfter("1,-2,1,-2", "1,1"); // 重複は許可
checkScoresBeforeAfter("", ""); // 空の入力は許可
}
checkScoresBeforeAfter メソッドに値セット、実行、結果確認を書き、それをいろんなパターンで呼び出す。
引用はしないが、14.8 テストにやさしい開発にも非常に良いことが書いてある。JUnit嫌いなエンジニアは一読の価値あり。
15章 「分/時間カウンタ」を設計・実装する
割愛します。1~14章の内容を使って部品を組み立てるという内容でした。
まとめと感想
これまでQiitaで読んだ断片だったり、困ったときに調べたことが多かった。「いかに楽をするか?」「いかにわかりやすいコードにするか?」を日頃からやっているエンジニアなら、「自然とやってる」内容が多いと思う。
この本の内容を取り込んでいくことで、間違いなく分かりやすく読みやすいコード群ができてくるので、プログラマ―本人にとっても、レビュアーにとっても、責任者である開発リーダーにとっても、システムを受け取る顧客にとってもメリットのある話である。
レビューする立場になった人は、レビュー指摘の根拠としても使える。開発リーダーにとっては、良いコードとは何か?を示すためにも使える。初級プログラマーにとっては、自分のスキルアップにも最適である。
超有名本なので、改めて自分が紹介するまでもないが、とても良い本です。全プログラマー必読の一冊じゃないでしょうか。
リーダブルコード より良いコードを書くためのシンプルで実践的なテクニ (Theory in practice) [ ダスティン・ボズウェル ]posted with カエレバ楽天市場AmazonYahooショッピング