はじめに
どうも、最近未経験からエンジニア転職をしたもきおです。
現役エンジニアの方にオススメされる本で一番紹介されると言っても過言ではない本が「リーダブルコード」。私自身も未経験時代から読んでみたはいいものの後半にいくにつれ「あれ?思ったよりムズくね?初心者向けじゃないやん」と思い本を閉じてしまいました。
今回入社後改めてCTOにおすすめしていただき、読み切ったのでここでアウトプットしていきたいと思います。
そもそもなぜ読むのが難しいと感じるのか
「リーダブルコード読むのが難しいとか何いってんの??」という方はこの章を読む必要がないかなと思いますが少なからずこの本が難しいと感じる人は一定数いるのかなと思っております。
この本を自分が難しいと感じた理由としては2点。
1.サンプルコードがJavaScriptやC++やらJava、Pythonやらで記載されており、自分が学習していないコードで記載されているため読むのが億劫になる。
2.読んだのはいいものの具体的にどう使用していけばいいのかわからない
この2点に注目し、せっかくなので今回言語は初学者がよく学習しているRubyに置き換えて記述。かんたんな実務経験を含め、実際どうやって活きてきたかを踏まえて記述していきたいと思います。と言っても最初の方は特に長文コードがないのであんまり本文と変わらないと思いますが笑
- 第二回はこちらから
1章 理解しやすいコード
1章は本書の概念的なことが記載されていました。
この本で最も重要なこと。それは
・コードは理解しやすくしなければならない
ということ。「いや、それ当たり前やん」と思いますが意外とこれってできてない。とりわけ未経験だと個人開発が多いのでとりあえずコードが動けばいいとか他者が読みやすいようにとか意識してコードって書いてないんですよね。
「第三者が読んで理解しやすいかな?」とか「将来の自分がこのコードを読んで理解できるかな?」とかそういった思いで普段からコードを書くだけで、きっとコードの質が変わってくるのかなと思いました。
そして具体的にどうすれば理解しやすいコードを書けるのかというと少し具体性をもったポイントが記載されていました。それは
・コードは他の人が最短時間で理解できるようにしなければならない
ということです。当時の自分はハッとさせられました。優れたコードや理解しやすいコードはとにかくコードを短くし、冗長じゃないコードを記載したほうが良いコードなのかなと思っていたからです。
最短時間で理解できるコードとはどういうコードなの?ということですが、基本的には短いコードの方が理解するのに時間がかからないのは前提。パット見で理解できるコードという感じですかね。
すぐに理解できるコードであればコードが長くなっても大丈夫ということのようです。
例えば下記のような三項演算子などはいい例です。
exponent >= 0 ? mantissa * (1 << exponent) : mantissa / (1 << -exponent)
ここで言いたいであろうことは一行が長くなってしまっており、三項演算子だとそもそも気が付きにくいしコードは短くかけたのに理解するのには時間がかかってしまっているということなんだと思います。
一方三項演算子を使用しない場合は以下
if exponent >= 0
mantissa * (1 << exponent)
else
mantissa / (1 << -exponent)
end
こちらのほうがぱっと見理解しやすいのではないでしょうか?このように簡潔に記述するよりもコードが長くなってしまうが理解するのに時間がかからなくなることもあります。
三項演算子の具体的な記述方法を知りたい方は下記参照
でもめんどくさくない?
確かに他人のために理解しやすいコードを考えるのはめんどくさいと思うかもしれません。
自分自身も思ったことは何度かあります笑
しかし良いコードを書くことによってチーム開発効率の向上、バグの少ないコードを作り出せる、更には将来の自分がそのコードを改修することもあり、将来の自分のためでもあります。
そう思うと良いコードを書きたいと思ってきませんか?
1章のまとめ
・このコードは第三者が見て理解しやすいコードかということをを常に意識しコードを書く
・コードは他の人が最短時間で理解できるようにしなければならない
・基本コードは短いほうが良い。しかし「コードを理解するまでにかかる時間」を短くするほうが大切
2章 名前に情報を詰め込む
この章からより実践的な記述法が記載されていました。
クラス名、メソッド名、変数名などプログラミングにおいて命名する機会は多いと思います。
個人的に命名する際に必要かなと思うポイントは
- 明確な単語を選ぶ
- tmpやretvalなどの汎用的な名前を避ける
- メソッドの本質を考えた上で命名する
ここら辺を説明していきたいと思います。
2.1 明確な単語を選ぶ
名前を付ける際に「get」とかは使われがちだけどあまり明確な単語ではないらしい
def GetPage(url)
これだurlをどこから取ってくるのか分からない。データベースから?インターネットから?
なので仮にインターネットから取ってくるとしたら以下の命名の方が明確。
def DownloadPage()
このように、より明確な単語を使うとメソッド名だけでおおよそどんなことをするのかが理解できるとのこと。
英語の類義語は沢山あるのでより明確な単語がないか毎回調べて確認してみることが大切だと感じました。本書だと大替案として以下が記載されてました。
単語 | 代替案 |
---|---|
send | deliver,dispatch,announce,distribute,route |
find | search,etract,locate,recover |
start | launch,create,begin,open |
make | create,set up,build,generate,compose,add,new |
気取った言い回しよりも明確で正確の方が良い
これは非常に大事だなと実務を通じて感じているのですが、明確な単語を選ぼうとして気取った言い回しになってしまい逆にパッと見て理解しにくい命名になってしまうことは多々ありました。
よくありがちなのが直訳した単語をそのまま使用してしまい、理解しにくい命名になってしまうこと。
例えば営業本部直下を定数として命名する場合、「sales_division_directly」としていましたが「sales_division_under」の方がより明確だということでそちらが採用されました。
2.2 tmpやretvalなどの汎用的な名前を避ける
tmpはテンプレート(templateやtemporaryなど)、retvalは戻り値(return_val)の略的な感じで定義されていることがあるが、テンプレート、戻り値と言われても「で?そりゃそうだよね」って思われるのがオチ。
いい名前というのは変数の目的や値を表すものだ。と本書には記載されています。つまりどんなテンプレートなのか、どういった戻り値なのかまで深ぼった上で命名する必要があるとのこと。よって基本的にはこのような汎用的な名前を避ける必要がありますが、以下のように情報の一時的な保管として変数定義する場合は汎用的な名前を付けても問題ないとのこと。
if (right < left)
tmp = right
right = left
left = tmp
end
このように数行にしか影響を与えない変数であればtmpという命名でも問題ない。しかし今のところ実務でこのような場面に直面したことはないので基本的には汎用的な単語は使用しない方が良さそうですね。
あとループ文でよくi、j、kなどをイテレータとして使われることもあるがこれは問題ないらしい。しかし自分の感覚としてはある程度意味を持たせた命名をした方が良さそうだなと実務を通じて感じています。例えば以下
grouped_promotion_by_influencer.each |i|
influencer = i.account
end
これだとどう言ったものをループしているのかが少しわかりにくい。
grouped_promotion_by_influencer.each |promotion|
influencer = promotion.account
end
これであればpromotionをループさせていることがわかりやすくなり、ループ処理内の理解を深めやすいのかなと思いました。
2.3 メソッドの本質を考えた上で命名する
これは個人的に大切だと思ったのですがこのメソッドは何をするメソッドなのか、メソッドの本質を考えた上で命名する方が良い命名になるのではないかと感じました。
実務で実際にあった例をご紹介します。あるアイコンを三日間のみ表示したいのでアイコンを表示してから三日間以上経っているかどうかを判定するメソッドを作成することになりました。そこで自分は以下の判定メソッドを作成しました。
def display_for_3days?
Date.today < created_at + 3.day
end
作成日から三日以内であればtrueが返るメソッドが作成できました。
「三日間表示している?」的な感じで命名してみたのですが、三日間だけ表示するというのは全体として行いたいアクションであり、このメソッドを使用して全体として行いたいアクションを実装したいのです。
従ってこのメソッドでやっていることは「作成日から三日以内かどうか」を判定するメソッドなので以下のメソッド名に落ち着きました。
def within_3days_from_created?
Date.today < created_at + 3.day
end
これで「作成してから三日以内かどうか?」を判定するための本質的な部分を表すメソッド名になったかなと思います。
2章のまとめ
- 直訳だけでなく類義語まで調べ、より明確な単語はないか模索する。その際に気取った言い回し以外で正確で分かり易い単語も探してみる。
- 汎用的、つまり名前自体に情報が詰め込まれていない単語はなるべく避ける。
- そのメソッド自体が何をするメソッドなのか、メソッドの本質を考えた上で命名する。
3章 誤解されない名前
この章はさらに実践的な例が沢山紹介されていました。2章の明確な単語を使用するのと似たような感じかなと思いますが英単語は一つの単語が色んな意味を持つので他の人が読んで誤解される可能性がないかを常に考える必要がありそうです。ここは引用させてもらいましたがこの章で役に立ちそうなのは以下のポイントでした。
- 名前が「他の意味と間違えられることはないだろうか?」と何度も自問自答する
- 限界値を示すときは min_ max_を使う
- 範囲を示すときは first_ last_を使う
- 包括的範囲には begin_ end_ を使う
限界値、範囲などは特に色々な単語で表現できてしまうので上記を使用して誤解されるのを防ぎましょうと本書では記述されていました。自身もこれらの単語を使用していきたいと思います。
あとがき
いかがでしたでしょうか?今回はリーダブルコード1~3章を要約していきました。未経験から転職し半年程経ちましたがまだまだ命名には苦労しています笑
良い命名をするためにはまず少しでも良い名前を付けたいという意識と他の人に命名をレビューしてもらうのが一番の近道ではないかなと思いました。なので少しでも命名に納得がいかなかったら先輩にこの命名で問題ないか確認してもらっています。今後4章以降も要約していきたいと思いますのでまたご覧いただけますと幸いです。