
保守・運用フェーズなら特にね、エンジニアはねリーダブルコード読まないとね / いしとさん
プロローグ
ミニマリストは部屋を不要な物を捨てて
必要な物のみで生活している方が多いです。
ミニマリストのかたは実生活を
より良く快適、または効率的に
リファクタしているようなものなので
サービスの土台となるコードも綺麗にかけそうだなぁと思っています。
以前リーダブルコードを読み、「他人が理解しやすいコード」という
ふんわりとした認識のまま時が過ぎてしまったのですが、
読んだ内容をブログにアウトプットしておこうと考え
今実行に移している最中です。
それでは書いていきます!
リーダブルコードはこちら
リーダブルコード ―より良いコードを書くためのシンプルで実践的なテクニック (Theory in practice)
リーダブルコード:1, 2章のまとめ
タイトル「リーダブルコード」の意味
- リーダブル:readable =>「可読」
- コード:code => 「コード」
つまり、「読むことが可能なコード」というタイトルですね。
「より良いコードを書くためのシンプルで実践的なテクニック」という部分も踏まえても
そういうことでしょう。
因みになんですが「readable」をGoogle先生に発音してもらうと
「リーダボゥ」または「リーダボー」と聞こえました。
リーダブルコードの考え方
- 他人が最短で理解しやすいコードを書くのが良さそう!
1人だけでコードを書くのであれば、自分だけ分かれば良いですが
開発後の保守運用のシーンで同じdeveloperが保守するとは限らない。
保守運用をする時点で、はじめから他人が理解しやすいコードを書いていれば
その分、保守・運用のdeveloperも対応しやすい。
ナレッジシェアの時間が減少できる。
また数ヶ月後の自分のコードに頭を悩ませる可能性もある。
コード量を減らすよりも理解にかかるまでの時間を減らそう
- コードは短いほうが良いですが、それ以上に理解する時間を減らすほうが良いよ!
変数名に情報を詰め込む
例えば「indxs」という
変数名に出会ったことがあります。
これだけだと「インデックスの複数形?」「何のインデックス?」
とレビュー指摘をしたことがあります。
実際には「カードを選択できるセレクトボックスの値のインデックス」の
配列でした。
「select_box_card_indices」などの
ほうが分かりやすいかもしれません。
ただ、配列の値は
文字列で入っているのか数値で入っているのか
ちょっと微妙ではあります。
- 明確な単語を選ぶ
- 汎用的な名前を避ける
- 抽象的な名前よりも具体的な名前を使う
- 接尾辞や接頭辞を使って情報を追加する
- 名前の長さを決める
- 名前のフォーマットで情報を伝える
変数名を1つ決める前に上記を意識するだけで
後々のリファクタリングする際でも
役立つでしょう。
tempやretvalなどの名前は理解の速度を低下させる
さきほどの例の「indxs」もそうですが、
わかりにくい名前は理解に時間がかかります。
「temp/retval」よりは、そのものの値や目的などの名前をつけましょう。
tempなどを使ってよいシーンは、生成してから使われる間が
2行以下で済むような場合らしいのですが、
それでも名前はしっかり付けたほうが良いとも思います。
(考えるくせをつけるためにも)
名前と目的を一致させよう
「run_locally」という名前の変数名が定義されていました。
これだけだとなんだろう?と思うはずです。
以下の内容をコメントが書かれていたとします。
「これはlocalで動かすとログを出力したりする目的で書きました。」
そしたら、理解はできますが、そもそも変数名と目的が合っていません。
目的に沿った名前をつけてあげましょう。
名前に情報を追加しましょう
例えば、鈴木一郎さんと鈴木二郎さんがいたとしましょう。
鈴木一郎さんの情報を取得する際に
変数名が「suzuki_san」などとはしないでしょう。
「suzuki_ichiro_san」などにしないとどちらか分からなくなります。
「size」も何のサイズですか?
「index」も何のインデックスですか?
と疑問が生じるので付加情報を追加してあげましょう。
ざっくりですが
「size_min」
「selected_card_index」
などなど。
重要な情報も追加する
「password」はパスワードが入っていそうですが、
暗号化前なのかどうかわかりません
暗号化前であれば「plaintext_password」などが良いそうです。
変数名は長すぎるのは良くないけれど、短すぎても良くない。
長いものとしては「convert_to_int」などは「to_int」など書けば
int型に変換しているんだなぁとわかります。
ただ、目的を表現するために長い変数名を
つけることも致し方ないときもあるのかなと思います。
最初の例のように「indxs」など短すぎても良くないことはこれまでの内容から
心で理解した気分です。
リーダブルコード:3章のまとめ
誤解されない名前
他の意味と間違えてしまう名前をつけてはいけません
誤解した経験
仕事で実際に「なんでしょう?」と思うことがあった。
メソッド名でしたが「update_add」と書いてありました。
ぱっと見て「何か追加するのかな?」と思ったのですが
処理を読んだ結果「住所を更新する」でした。
「update_address」と書いてくれ…
とこんな感じで誤解を生じさせるようなものは良くない。
名前「filter」を使うのであれば目的に沿って
「select」か「exclude」など明確にすること。
限界値を意識した変数名
- 限界値を使うときは「max/min」
範囲の指定を意識した変数名
- 範囲の指定を使うときは「first/last」
包括的な範囲を意識した変数名
- 範囲を包括的にするときは「begin/end」
真偽値の変数名
- bool値は先頭に「bool」を使わないようにしよう
複数の名前を考えてドメインに合わせて決めよう!
名前を決めるうえで似たような単語が出てくることがある。
- stop :止まる
- end :終わる
- finish :最後までやりきる
- complete :完璧に終わる
- terminate:行き止まりまでいって終わる。通話がおわりアフターコールサービス(顧客がこんなこと言ってたというものをメモする)までやって終了するみたいな。
このようなときにドメインや目的に対して明確なものを選択しよう。
他が無駄になることはなく、考えるという点でも成長できるので
迷ったら全部書いてみて、目的に応じて検討するほうが良い。
リーダブルコード:4章のまとめ
美しさ
「一貫性のあるコードは、正しいコードよりも大切な考えです」
さっと流し読みできるコードは美しい
- publicメソッドはpublicとしてまとめられている
- privateメソッドはprivateメソッドとしてまとめられている。
- 定数は定数でまとめられている
など、しっかりまとめられているほうがすっきりする。
privateメソッドのなかで突如、定数を定義していたりすると
美しくない。
実生活に例えると、お風呂用の洗剤が
衣類の収納ケースに置いてあったりして「なんでこんなところに?」と
似たような感覚である。
お風呂用の洗剤であれば、バスルームまたは
それに近い収納に置いたほうが正しい場所と言えるでしょう。
一貫性のある簡潔な改行位置は綺麗
あんまりこういうコードはありませんが
極端に例をあげると以下でしょう。
# 美しくない
top5 = [ 1, 2, 3, 4, 5]
normal = [6,7,8,9,10]
# 美しい
top5 = [1, 2, 3, 4, 5]
nomal = [6, 7, 8, 9, 10]
# イコールがずれているけれど、まぁ読める
top5 = [1, 2, 3, 4, 5]
nomal = [6, 7, 8, 9, 10]
書籍だともっと詳細ですが、こういうところを意識できれば
書籍で言っている別のレイヤーのことも応用できると思いました。
メソッドも綺麗に整列するメリット
- 重複したコードを削除することができる!
- 表面上の修正ではなくコードの構造も綺麗にすることができる!
- テストの重要な部分やテストケースの追加を考えやすくできる!
縦の線を真っ直ぐにするとバグを発見しやすい
例えばこんなコードだと、縦の線だけで3行目に何かおかしいとわかります。
request.post.get("あ")
request.post.get("い")
equest.post.get("う")
request.post.get("え")
request.post.get("お")
縦の線を合わせるメリットです。
並びも意識する
# 直したくなる並び
request.post.get("あ")
request.post.get("お")
request.post.get("い")
request.post.get("え")
request.post.get("う")
「あいうえお」が一般的ですが「あおいえう」だと違和感があり、
直したくないですか?となる。
ボイトレとかだとこういう発声もありますが、
実際プログラミングをするうえでは、
重要なものだったり何かのキーをきっかけに
並び替えたほうが美しいです。
# 直した並び
request.post.get("あ")
request.post.get("い")
request.post.get("う")
request.post.get("え")
request.post.get("お")
宣言をブロックにまとめる
例えば定数を定義しているときに
BEEF = "牛肉"
APPLE = "りんご"
ORANGE = "オレンジ"
HOUSE_MEET = "馬肉"
PORK = "豚肉"
CHICKEN_MEET = "鶏肉"
こういう風に書かれていたら
BEEF = "牛肉"
HOUSE_MEET = "馬肉"
PORK = "豚肉"
CHICKEN_MEET = "鶏肉"
APPLE = "りんご"
ORANGE = "オレンジ"
上記のようにグループ分けしたほうが綺麗ですよね。
というお話。
途中空行を入れているが、「間」も読みさすさでは大切です。
「空行要らない」という方もいますが、
コードでもメールの文章でもそうですが、
空行は合ったほうが読みやすいです。
以下はものすごく適当なメールの文章ですが、
長ければ長いほど、空行を入れたほうが読みやすくなります。
株式会社XXX 鈴木様
お疲れ様です佐藤です。
これこれの件でご相談があります。
本日15時にてこのような事象が発生しており
確認している最中です。
よろしくお願いいたします。
株式会社XXX 鈴木様
お疲れ様です佐藤です。
これこれの件でご相談があります。
本日15時にてこのような事象が発生しており
確認している最中です。
よろしくお願いいたします。
リーダブルコード:5章のまとめ
コメントをすべき内容を理解しよう!
コメントは書き手の意図や目的を読み手に知らせるメッセージ
コメントを書く内容
- ファイルやクラスなどに関する概要
- TODO: あとで直す。FIXME:ここバグっているよ
- 定数を付けた背景
コメントを書かない内容
こんな感じ
require 'date'
#本日を定義した!!
today = Date.today
わかるよ~!コメント不要だよ~!
コードをいろんな人がみて、ぱっと何をやっているか分かる内容については
コメントは不要です。
コメントで補足することも大切
例えばリトライ処理を3回に設定している理由はなんですか?
みたいに思うこともあると思います。
何だこのマジックナンバー!PRにもcommitコメントにも
コードのコメントにも説明がない。
うわdeveloper離任してもういない。
ガチのマジックナンバーだ!とか、経験あるかと思います。
未来の誰かが迷わないように、補足すべきコメントは
書いて置いたほうがよさそうですね。マジックナンバーとかは特に。
PRを作成する前に
コードレビューをお願いする前に
レビュアーが「え?これなに?」と思うようなところには
あらかじめコメントを残しておくのはありです。
リーダブルコード:6章のまとめ
コメントはシンプルかつ正確に
コメントはそのドメインに関して高レベルに書く!
コメントの内容に「これ」とか「それ」とか使わずに正確に書く!
コメントの改行
メソッドの仮引数が複数ある場合
具体的な例を各シーンとしては極端ですがこんな感じ
# x_mounts:XXの売り上げの金額
# y_mounts:YYの売り上げの金額
def calculate_total_amount(x_mounts, y_mounts)
# 売上額(XとY)を計算する
def calculate_total_amount(x_mounts, y_mounts)
これはコメントを書かなくても良さそうですが、
例としてはこんなニュアンスで短く1行で
書けるならそれでいきましょうということ。
曖昧な言葉をコメントで使わないように
- あれ
- これ
- この
- その
- あれ
- そこの
などは何を指しているのか分からないため、
使わないようにしましょうとのこと。
コメントの詳細
仮引数のcsvはヘッダが含まれた状態なのか含まれていない状態なのか
などを書いたほうが良さそうです。(まぁ大体含まれていますが)
以前ヘッダを考慮せずに後輩がロジックを書いてバグを発生させていたので
なんとなくそのことを思い出しました。
コードの意図を書く
チェーンメソッドなどは一応
結果、どうなるのかという意図を書いておくと
わかりやすい。ただ、一つ一つのメソッドを読んで理解することは可能ではある。
理解する時間を短縮するというリーダブルコードの目的としては
コメントも大切ということで。
文章の如く長いコメントになってしまったら?
なるべく簡略化できるような言葉に変換してみましょう。
これは「要するに?」とか自問自答するとコメントもシンプルかつ簡略化できそうです。
リーダブルコード:7章のまとめ
制御フローを読みやすくする
ifやループなどの制御構文を
プログラミングでは必ずと
言っていいほど使うシーンがあります。
そんななかでネストとかが深くなってしまったり、
条件が分かりづらくなってしまうことがあります。
この章ではそんな風にならないような
テクニックなどが記載してあります。
条件式の引数の並び順
左が変化する範囲が広いもの、右が変化の範囲が少ないもの
# rubyで1~10の範囲で5以上だと何か出力する
age = rand(10)
if age >= 5
p "うぇい"
end
1~10のうちランダムで決まるageよりも5のほうが変化は少ないため
5を右に置くみたいな感じ。
ちなみにマジックナンバーになってしまうので、
5は定数にするかコメントを残したほうが良いぞ。たぶん。
条件は肯定から使ったほうが読みやすいらしい
if,elseをセットで使う際は条件を肯定、または関心の強いものを使う
# 肯定の条件が先
train = "新幹線"
if train == "新幹線"
p train
else
p "新幹線ちゃう"
end
# 否定の条件が先
train = "新幹線"
if train != "新幹線"
p "新幹線ちゃう"
else
p "新幹線"
end
これは肯定のほうが読みやすいですね。
どうしても否定を先に使うシーンもどこかでありそうですね。
unlessを多用すると読み間違える可能性が高そうなので
あんまり使いたくないかな。
三項演算子を使うシーンは限られる
「if (条件) ? trueを返すぜ: falseを返すぜ 」
ifを一行で書ける三項演算子ですが、
これは文字数の少ないときには使ったほうが読みやすくなる。
条件が複雑だったり、戻り値(返り値)が複雑なものは
可読性が下がる可能性がありますので
シンプルに書きたいときだけ使います。
do ~ loopは避けよう
あんまり使わないのですが、
「do ~ loop」は
最後にループから抜ける条件が書いてあります。
ただ、最初に条件を書いたほうが読みやすいので
whileだけで良さそうですねとのこと。
GoTo文はスパゲティになるから使わないほうがいいよ!
GoTo文はC言語以外でほとんど使わないらしい。
わたしも業務で使ったことがない。
GoTo内でいろいろと上のメソッドなどに飛ばすと
スパゲティコードになる確率があがるらしい。
そこで私はツッコミをいれたくなった。
「人生はGoTo文みたい。条件だらけなのに、止まらないじゃん・・・」
と。
ネストを深くならないためにガード節を使おう!
保険のシステムを触った時に、
if (正しい場合)
何かしらの処理
if (正しい場合)
何かしらの処理
if (正しい場合)
何かしらの処理
if (正しい場合)
何かしらの処理をしてtrueをreturn
こんな処理が多用されていて発狂した記憶がある。
「何だこのコードは!」とプロパさんに聞いてみたら
聞いたプロパさんが書いたコードだった。
if (正しくない場合)
return false
end
何かしらの処理
if (正しくない場合)
return false
end
何かしらの処理
と書き換えた記憶がある。
ガード節大事だなぁ結構意識していた。
リーダブルコード:8章のまとめ
制御フローを読みやすくする
巨大な式は分割するかシンプルに直そう!
ドモルガンの法則を使えそうなら使おう!
巨大な式は分割できるならしよう!
変数が3つ以上ある条件が3つ続くよう場合、
何か工夫できないか考えてみよう。
- ドモルガンの法則を使う
- 共通の条件をまとめて変数に入れて条件の変数を少なくする
条件式に変数が多ければ多いほど、
読みにくくなるので要注意。
むしろリファクタリングするときに
複雑なロジックをみつけたら
テストコードなどがあった場合は積極的に
リファクタリングすると社内から喜ばれそうだ!
リーダブルコード:9章のまとめ
変数の読みやすさ
- 中途半端に変数を使わないようにしよう!
- 変数の宣言はできるだけ少ないほうが良い!
途中でたまに無駄に変数に置き換えていませんか?
# 例えば
now = Date.today
today = now
# これってこういう風にかけますよね。
today = Date.today
説明変数として意味のあるものは変数としても良いと思いますが
その変数要らないよね?というものは
書かないほうが読みやすいですね。
グローバル変数は使わない!変数は一度だけ書き込もう
グローバル変数はどこでどういう値に変化しているか
分からずバグの温床になりかねません。
極力使わないようにしましょう。
つかってもインスタンス変数とかクラスでしか使わないように
スコープをしっかり意識して使いましょう。
JavaScriptでは本書だと少し仕様が古かったのでvarの例でしたが
今(2022年時点)ではvarもあんまり使わず
letかconstを使いますが、letもそんなに使うこともなく
constをできるだけ使ったほうが良さそうですね。
リーダブルコード:10章のまとめ
無関係の下位問題を抽出する
これは何の話かというと
メソッド内のステップ数が多い場合は
そのメソッド内で新しくメソッドを作ったほうが
読みやすくなるよというお話でした。
メソッド内で簡単な処理かつグループ分けできるものは
積極的にprivateメソッドなどに切り分けることで
すっきりします。
切り分けたものがサービス全体で利用できるのであれば
ユーティリティクラスに書いていって
他のエンジニアの助けにもなるでしょう。
注意すること
AメソッドでBメソッドを呼び、
BメソッドからCメソッドを呼び、
CメソッドからDメソッドを読んでしまった場合は
メソッド飛びすぎ問題が発生して
コードを読むうえで行ったり来たりすることになります。
その場合は、メソッド切り分けすぎという状態となるので
気をつけましょう。
リーダブルコード:11章のまとめ
一度に1つのことを
何かの値を探索したり、
条件によって値を変更することが複数ある場合は
if文のなかに三項演算子を入れるのはNG。
条件を複雑にしないで
別のところ(メソッドをつくるなど)で
必要な要素を集めてから
1つの条件だけに集中する。
タスクは1つのことに集中
if文のなかでif文をさらに使うようなシーンは
複雑になりやすいので
分解できる要素は別メソッドに切り分けて
分解して1つのことに集中させうよう。
デフォルト値を最初に設定する
if文を3つ書いて必要な値を設定するが
全てのif文の条件に当てはまらないときもある。
そのときは最終的に固定値を入れて戻すような
仕様だった場合は、最初に固定値を入れておく。
別々の変数で目的を達成する
そのメソッドで必要な物をいっぺんに出す必要はなく
複数の変数に 「求めている答えA + 求めている答えB 」
と連結して答えを出す。求めている答えAとBは同じif文で書くことも可能ですが
別々のif文で変数にいれておいたほうがはるかに読みやすい。
リーダブルコード:12章のまとめ
コードに思いをこめる
おばあちゃんでも小学校の高学年のひとにも理解できる説明できれば、
あなたはそのロジックを理解できている。
権限の有無などがあればコメントに書いて明確にする
権限などによって条件を弾く場合は
否定を使うより、権限の説明を補足し、
権限を主体に処理を書いたほうが良さそう。
複雑な処理はライブラリーが担保してくれるかもしれない
ロジックが複雑になっても便利なライブラリーを使うことで
シンプルにできる可能性がある。
まずは「OSS活動している皆様どうもありがとうございます。」
ただ先立つものが発生しない以上、
メンテナンスなどがされておらず
ライブラリーによっては脆弱性などが発見されることが
多々ある。
ロジックに悩んだ時のテクニック
- 文章として説明をしてみる
- ラバーダッキングをしてみる
ロジックに何か漏れがないかを確認するときは
文章で説明を書いてみる。
そこで仕様通りかどうか、漏れがないかなどを確認する。
(その説明はテストケースなどをかけば漏れが減りそう)
アヒルのおもちゃを置いて、アヒルにロジックについて
相談してみると、言葉にして説明することで、
頭の中のもやもやしたものを整理する。
アウトプットしてみて、何か思いつくかもしれない。
リーダブルコード:13章のまとめ
短いコードを書く
一番良いのは「コードを書かないこと」らしい。
どういう意味かというと、不要な要件についてのロジックは書かないで良い。
コードを書けば書くほど、量が増えれば増えるほど、
メンテナンスコストがかかってしまうから。
書かないまたは、短くかけることに集中する。
コードを書くことは最後の手段?
もしかしたらこの章は
「サービスのなかでその機能必要?今も必要?今後必要?」
というものを考えてくださいと言っているみたいだった。
私自身がゆるミニマリストなのでこの考えは大好きです。
「YAGNIの法則」ですね。
不要なコードは削除する
長年利用しているサービスなどでドメインの仕様が変わると
ちょくちょく使っていないメソッドなどが散見される。
なぜ残っているかはわからないが、テストコードを書いていないので
消すことで重大な問題が起きないか不安だったとか。
単純に調査する時間がないとか。
そういうものもあれば、緊急して修正をしていて
リファクタリングする暇がなかったなどが
多いのだと思う。
私は
- この変数は使われているのか、
- 変なところで宣言していないか
- 宣言してすぐに使われているか
- このプライべートメソッドはどこで呼び出されているか
- 実は親クラスから呼び出されていないか(Rubyとか)
などを調べては積極的にリファクタリングしています。
リーダブルコード:14章のまとめ
テストと読みやすさ
テストコードは他のエンジニアが追加・変更しやすいようにつくる
この章はテストコードを書く人やQAエンジニアになりたい人は
必読でした。(どの章もエンジニアは必読だとは思いますが)
読みやすいテストコードとは?
- テストケースは、一つのメソッドに全部詰め込まない。
- 1つ1つの責務を最小にして作る。
- テストケースの説明は長くなっても構わない。
- テストコードは仕様書と一緒
- 同じ結果となるものの、引数をランダムに作り無駄なテストをしない。
update(1,2)update(2,4)が同じ結果だとしたらどちらかでOK - 閾値などのテストはしておいたほうが良い。
- 正常系だけではなく異常系のテストもしっかりかこう。
- エラーメッセージは読みやすくすると修正しやすい
エラーメッセージなどはユーザに出すメッセージもそうですが
大切ですよね。
向こうのサイトのメンテナンスなどでエラーが発生しているにもかかわらず
「あなたの設定を見直してください」なんてでたら
ユーザは解決できないですもんね。
テストを読んで思い出したこと
そういえば昔、SESの面談で「何か質問ありますか?」
と聞かれ、「テストはどうしていますか?テストコードなどはありますか?」
と聞いた。
すると、「テストコード?必要なんですか?なんか意味ある?」と
おじさんに言われました。
「テストコードで仕様とかも理解しやすいですし、3回以上サービスをリリースするようなことがあれば、テストコードのほうが時間も短縮できます。」
と言いました。
おじさん「1回でちゃんと作れば問題ないですよね?」とのこと。
これ以上お話すると相手を否定しかねないので、
「そうですね!」と言い、面談終了後、こちらからお断りました。
後々、その会社の平均残業時間を見ると
月28.0hと結構残業していました。
また、別の面談をしたときにSIerで
独自フレームワークを作っていました。
独自フレームワークがあること自体はすごいなぁと思うのですが
その独自フレームワークはテストコードはなかったです。
「テストはどうするんですか?」と質問したところ
「勘のいいテスターが見つける」と言っていました。
HSPのひとは私含めてバグを見つけやすいのですが、
流石にお断りました。
が、上の人がその案件をOKしてしまい、
26時過ぎまでお仕事をする地獄をみました。
「何回キャプチャとらなきゃいけなんだ・・・」と。
ただ、そのプロジェクトが終わった時に
「言うことを聞いていれば良かった。すみませんでした。」
と上司に謝られました。時間は戻ってこない。
リーダブルコード:15章のまとめ
分/時間カウンタを設計する
プログラムを設計するうえで
もちろん短いコードで書くことができればそれで良いけれど、
秒数などの正確な情報は長いコードのほうが
安全だったりする。
15章は1~14章の大切な要素を振り返っている感じ
- 変数名を修正
- コメントを修正
- メソッドの切り出し
- 他の方法はないか検討
- 他の方法も実装後に安全性はどうかの吟味
などなどの解説でした。
コード量が増えても、
読みやすいケースもあります。
短いコードでも他の人には理解しにくかったり、
期待値が微妙にずれたり、テストコードが書きにくかったり
そんなケースもあるので。
「他人が理解しやすいコード」がやはり原点として
コードを書くべきということが蘇った。
リーダブルコードの感想おわり!
以上、リーダブルコードの感想でした。
ぜひ読んでみてください!
保守運用フェーズなら合わせて読んでおきたい本も紹介しておきます。
>> Amazonリンク