give IT a try

プログラミング、リモートワーク、田舎暮らし、音楽、etc.

僕が考える「良いコード」

こんなコードだとわかりやすい

僕が考える良いコードの特徴(条件)を挙げてみると、

  • ぱっと見たら、だいたい何をやっているのかがわかるメソッド名
  • ぱっと見たら、だいたい中身が何なのか想像がつく変数名
  • ぱっと見たら、だいたい何をやっているのかが把握できるメソッドの内の処理フロー
  • 驚きが少ないメソッド
  • 副作用が少ないメソッド(責務が1つしかないメソッド)
  • DRY原則を守っているコード

だいたいこんな感じ。

つまり「すんなり読めて、すんなりわかるコード」が理想。

プログラムが小さいうちや、一人で開発しているうちは「汚くてわかりにくいコード」であっても「自分さえわかればOK」で済んじゃうけど、プログラムの規模が大きくなったり、複数人で開発するようになると、「汚くてわかりにくいコード」は絶望的に開発効率を下げる。

こんなコードはわかりにくい

たとえば上の反対で、

  • メソッド名だけ見ても何をやっているのか想像が付かないメソッド
  • 変数名だけ見ても中身が何なのか想像が付かない変数
  • 複雑怪奇で巨大迷路みたいなメソッド実装
  • 「まさかこんなところでこんなことを!?」と思うようなサプライズがふんだんに盛り込まれたメソッド
  • メソッド名に反して「あれもこれもそれも」全部やろうとするとメソッド
  • あちこちにほぼ同じコードが埋め込まれていて、「まだ他にもあるんじゃないか」と疑心暗鬼になってしまうコード

みたいなコードだと、隅から隅までコードを読まないと仕様や挙動が理解できない。

小さなプログラムならまだしも、大きなプログラムになると「隅から隅まで読んで理解する」というのはあまりにも時間を浪費してしまう。

なので、「すんなり読めて、すんなりわかるコード」になっていることが大事。

業務ではコードを書く時間よりも読む時間の方が多い、だから……

「すんなり読めて、すんなりわかるコード」なら多少規模が大きくても、「だいたいこういうふうに作ってるのね〜」「今回の機能追加はこのへんを触ればOKね〜」というのが比較的すぐわかる。

もちろん、ある程度の規模になってくるといくらがんばっても「すんなり」では済まない場合も増えてくるけど、それでも最初に挙げた特徴を兼ね備えたコードとそうでないコードでは、開発効率に雲泥の差が出てくる。

業務ではコードを書く時間よりも読む時間の方が多いので、読む時間を節約できるコードになっていることの方が重要。

「すんなりわかるコード」を書くにはいろんな配慮が必要になるので時間がかかるけど(注:ここではリファクタリングも書く時間に含みます)、将来の「読む」時間を節約できるなら、「書く」ためにかけた時間はペイできるはず。

まとめ

20年もプログラマをやっていると、コードレビューしたときにこれまでの経験から「むむ、この実装だと将来痛い目を見るぞ?」という嗅覚が働くようになってきました。

で、その嗅覚をある程度言語化すると最初に挙げたような条件になるのかな〜と思って、このエントリを書いてみました。

おまけ:良いコードの書き方を学ぶのに役立つ参考文献

「良いコードと悪いコードって具体的にどんなのよ!?」という具体例を知りたい場合は以下のリンクを参考にしてみてください。

書籍で良いコードの書き方を学ぶ

定番中の定番、リーダブルコード。

ただし、僕はあまりちゃんとリーダブルコードは読んでなくて、CODE COMPLETEっていう本をがっつり読み込みました。

あと、まだ最後まで読み切ってないのですが、最近買った「プログラマー脳」という本もどういう理屈で人間の脳はコードを理解できるのか(もしくは理解しにくくなるのか)ということを解説してあってなかなか面白かったです。

リファクタリングやDRY原則の原典に触れる

今となっては「リファクタリング」や「DRY」といった用語は、みんな当たり前のように知っていますが、あらためて「リファクタリングとはなんぞや」「DRYとはなんぞや」というのを原典で学び直すのも良いかもしれません。

抽象化の概念を理解する

ぱっと見たら、だいたいわかるメソッド名や変数名を付けるためには、処理やデータをほどよく抽象化して考えるスキルが必要になります。フィヨルドブートキャンプで生徒さんを教えていると、ときどきこの「抽象化」が苦手な生徒さんを見かけるので、そういう場合は「そもそも抽象って何?」というのを以下の本で学んでもらっています。

具体と抽象

具体と抽象

Amazon

抽象化の理解についてはこちらの記事もお勧めです。

bootcamp.fjord.jp

「名前重要」を肝に銘じる

Rubyのパパ、Matzの座右の銘は「名前重要」です。名前重要、ほんまそれ。
xn--97-273ae6a4irb6e2hsoiozc2g4b8082p.com

でも「いい名前」を考えるのはとっても大変😣

品詞に気を付ける

動詞や名詞の使い分けがぐちゃぐちゃだと、「メソッドだと思ったのに変数だった」とか「変数だと思ったらメソッドだった」みたいな誤解を生じさせやすいです。(()が省略できるRubyなんかは特に)

qiita.com

インスタンス変数を適切に使う

「どのメソッドからでも読み書きできる便利なグローバル変数」としてインスタンス変数を使うと、カオスを招きます。

qiita.com

qiita.com

不必要に名前を略さない

「オレオレ略語」は第三者に「何これ?ようわからん」という疑問を抱かせる原因になります。

blog.jnito.com

適切な例外処理を行う

勝手に例外を握りつぶしたり、現代版のGOTO文として例外を発生させたりするのも、「驚き」や処理フローのわかりづらさを招きます。

qiita.com


コメントはいつでも書けばいい、というものではない

コメントはたくさん書いた方がわかりやすくなるはず、と思うかもしれませんが、必ずしもそうではありません。
コメントを書くことのデメリットも把握しておきましょう。

qiita.com

配列の添え字に意味を持たせない

配列の添え字に意味を持たせてしまうと、一気にわかりにくくて、もろいプログラムになります。
qiita.com

配列の二人三脚をしない

「この2つの配列には過不足なく同じ件数のデータが入ってるはず」という希望的観測に基づいたコードを書くのは避けましょう。
qiita.com

メソッドは呼ばれる側を後ろに定義した方が読みやすい、かも

好みがわかれるかもしれませんが、個人的にはメソッドは呼ぶ側を手前に、呼ばれる側を後ろに定義した方が読みやすいと感じています。

qiita.com

マトリョーシカメソッドを避ける

コールスタックを不必要に深くしたようなメソッド設計だと、処理の概要が把握しづらくなります。
blog.jnito.com

無味無臭な名前を避ける

過度に抽象化すると無味無臭なメソッド名や変数名が生まれます。あくまで「ほどよい抽象化」が大事です。

コンピュータが理解できるコードと人間が理解できるコードは別

コンピュータ(コンパイラ)を満足させたから自分も満足、ではいけません。

テストコードはあえてDRYを捨てる

DRY原則は大事ですが、テストコードではほどほどにしないと読みづらいテストコードができあがります。

業務における「読む時間の多さ」をイメージする

まだ業務でコードを書いたことがない人は、以下の記事を読むと書く時間より読む時間の方が多くなる理由が理解できると思います。

qiita.com

僕が今まで見てきたひどいコード

僕は人一倍コードの可読性や保守性を気にするタイプなのですが、それは今まで何度もひどいコードのせいでひどい目に遭ってきたせいです……。

blog.jnito.com

その他
  • 変数の寿命は極力短くする
  • person = find_user のように左辺と右辺で微妙に違う名前を付けない
  • 変数はなるべくイミュータブルに扱う(破壊的変更をなるべく避ける)
  • 変数(または引数)の再代入を避ける
  • メソッドの途中でreturnするときは、なるべくガード節(早期リターン)に限定する(ループ処理におけるnextやbreakも同様)
  • シャドーイングを避ける(既存のメソッド名と同じ名前のローカル変数を作らない)
  • check_xxxというメソッド名を避ける(checkだと何をどうチェックするのかわからない)

あわせて読みたい

このエントリの続編として、きれいなコードを書く「だけ」ではすんなり読み解くことができない大きなコードベースの場合、どういった方法で書き手の意図やコードの背景を残すことができるのか、というお話を書いてみました。

blog.jnito.com