リーダブルコードを読んで学んだこと
今更感はありますが、リーダーブルコードをエンジニア 3 年目にして最後まで読んだので、その読んだことから学んだことをアウトプットします。
リーダーブルコード自体、書籍としては厚いものではなく、あまり時間が取れない人でも数週間あれば読み切れるボリュームです。
しかし、私がエンジニアとしてのキャリアをスタートさせた際は、読み切ることができませんでした。
その理由は、なぜこのコードが良くないのかというコードの良し悪しを判断できていなかったからです。
しかし、エンジニアとして 2 年間、さまざまなコードに触れてきました。
難解な読みにくいコード、できるエンジニアが書いた読みやすいコードを体験することで、自分なりにこれが保守性の高いコードなのかと感覚を掴むことができるようになりました。
今回はそういった新しい発見を見つけること、既存の知識の再確認としてリーダーブルコードを読みました。
読みやすいコードとは
読みやすいコードというのは長いとか短いとかではなく、コードを読んですぐ理解できるかどうかが重要です。
例えば、行数にこだわり1行でゴチャゴチャ書かれていることがありますが、それが必ずしも優れているとは限りません。
他の人にとってわかりやすければ、数行で記述する方が良い時もあることは理解しなければなりません。
特に三項演算子とかで起きやすく、if 文で書く方が理解しやすい時もあります。
下記は、サンプルコードです。
time_str += (hour >= 12) ? "pm" : "am";
if (hour >= 12) {
time_str += "pm";
} else {
time_str += "am";
}
変数の決め方
変数名なんてこだわる必要はないと考える人もいますが、変数名こそ時間をかけて理解しやすい変数名にすることが他の人がコードを読むのを助けてくれます。
「他の人」というのは自分以外の人でもありますが、数ヶ月先の自分になる可能性もあります。
自分のコードによって理解に苦しめられることがないよう、保守性の高く読みやすいコードを書くことはとても重要なのです。
変数名を確認し、パッと何を意味しているのかがわからない変数名は最適ではありません。
名前は一種の情報である以上、その名前が分かりやすくするべきです。
例えば、よく使われている「get」や「find」は名前としては抽象的になっています。
- どこから取得(get)してくるのかが分からない
- 何を find(探す)のか分からない
ただ、長すぎるのも良くありません。
意味不明な命名を補うかのように「findFromXxx()」と名前をつける可能性もありますが、短い名前の中でで的確な意味を伝える必要があります。
この命名については、さまざまな意見があるはずですので、下記などを参考にすると良いです。とても丁寧に書かれていました。
コードの見た目を美しくする方法
- 縦のラインを揃える
- 繰り返しのコメントは 1 つ目だけに記載し、残りは省略できるようにする
- コードの順番は順不同であっても意味のある並びに統一しておく
コードを整列することで、typo とかに気づきやすくなる。
コードに「コメント」が残されている箇所もあります。
このコメントは、コードからすぐわかることをわざわざコメントとして残さないようにしましょう。
コメントを記述する注意点として下記を挙げていました。
- 意味のないコメント記載を避ける
- 人によってはコメントは全く不要で、コードから読み取れると考える人もいる
- 関数名がひどいから、その酷さをコメントで補うのは避けること
- 関数名の見直しが最優先
- 定数など、値が決まっている背景などをコメントに残すとなぜこの値になったのかがわかるようになる
- 「これ」や「あれ」といった代名詞を使わないようにすること
比較文
どちらを比較するか
if (length > 10)
if ( 10 < length)
上記に記載したコードの if 文はどちらも同じことを意味していますが、どちらが見やすいでしょうか。
多くの人は前者の方が読みやすいと感じるはずです。
比較文は、変数を左に記述し、固定値を右に書くことがよさそうです。
これは日本語で考えても、「もし長さが 10 以上だったら」と、比較対象を先に持ってくる方が理解しやすいですので。
そして比較ではできるだけ、否定系を避けるようにしましょう。
早期return
また、if 文の条件部はガード節を使って早期 return で書くようにしましょう。
これは多くの書籍共通で記述されていることでした。
書き方のコツについてはこちらの記事がとても参考になりました。
- 条件に当てはまらないもの
- if ~else if ~ else を一文で書くよりもそれぞれで if 文を書くようにする
早期リターンをすることでネストの if 文が減ったり、条件追加もやりやすいです。
if文のネスト
やはり if のネストは基本的に避けるべきです。
なぜなら、ネストの処理時、私たちは常に外側の if を意識した状態でコードを読まなければなりません。
if (response == 'success') {
alert('');
} else {
alert('error 発生');
}
上記の状態から、追加でユーザー権限も見ることになった場合はどうしましょう。
下記のように追加するとネストが発生します。
コードに追記した時にはここに入れるべきとわかりますが、一旦俯瞰してみると if のネストはわかりにくいです。
if (response == 'success') {
if (user.role !== 'admin' ) {
alert('権限 error 発生');
}
alert('');
} else {
alert('error 発生');
}
コードを追加する時は、本当にここに追加して全体的に読みやすいのかを立ち止まることが必要です。
変数について
- 説明変数
- 要約変数
巨大な式やメソッドチェインが発生する値は、上記を使うと良いと書いてああります。
その理由を下記にサンプルコードとして例を示します。
if response.data.user.split(':')[0] == 'admin
上記ではぱっと見、何の判定をしているのか判断できません。
const userRole = response.data.user.split(':')[0];
if userRole == 'admin
一度変数に格納し、それを条件文で利用する方がユーザー権限を見ているというのがわかりやすいですね。
このように変数を使うか使わないかについては、俯瞰してコードを読み、すぐ頭に入ってくるかを考える必要がありそうです。
そして、変数の書き込みだけは一度にしましょう。
不変にしておかないと、思わぬ副作用の発生可能性が高いです。
無関係な下位問題を積極的に見つけて抽出
当該書籍で「無関係な下位問題を積極的に見つけて抽出する」という言葉が出てきました。
無関係な下記問題
とは、コードの目的に関係ないものは切り出すという意味だったのです。
例えば、ケーキを準備するのに 1 つの関数で下記工程があるとします。
- シフォンケーキの作る工程
- ホイップを作る工程
- 飾り付けをする工程
この3工程が1つの関数に入っているとわかりにくいので、それぞれを 1 つの関数として作り、大元の関数で呼び出すような方法が良いということでした。
また、汎用的なコードもいろんなところで使うのは便利になるので切り出そうということも書いてあります。
コードが独立することによるメリットは下記です。
- 改修が楽になる
- 機能追加、読みやすさ向上
結論読みやすいコードってどんなコード
コードは読む量が多いと理解するのに時間がかかってしまいます。
究極として、最も読みやすいコードは何も書かれていないコードということです。
そのため、機能実装では不要な機能
と欠かせない機能
に分け、どの処理は必要なのかを明確にする必要があります。
つまり、コードを小さく保つことが大切です。
コードを小さく保つというのは、下記を意味します。
- 重複するコードを削除して汎用的なコードを作る
- 未使用コードは容赦なく削除する
- コードの重量を意識
- ライブラリや用意されてる関数を活かす
まとめ
改めて読むと基本的なことばかりなのですが、実践できていることは少ないです。
まだまだ道半ばのエンジニアです。そして本を読んだからといって出来るようになるわけではありません。
本で学んだことを実業務でも活かせるかが重要ですので、引き続きインプットとアウトプットを継続していきたいです。
Discussion