リーダブルコードを読んで実践したいと思ったこと feat. ChatGPT
先日、会社の技術書ライブラリーで『リーダブルコード』を借りた。 実務でわりと大きめのソースコードを触っていて、可読性って大事だなと感じたのがきっかけだ。
今のところ8割ほど読み終えた段階なのだけど、すぐに実践できる内容でとてもありがたかった。これは良いなと思ったポイントを忘れないうちに書いておく。
説明変数を入れる
8章 p.100で登場する概念。サンプルコードとしては以下のように書かれている。
if line.split(':')[0].strip() == "root": ...
このコードは一体何をしようとしているんだろう?ぱっと見では分からない。
これならどうだろうか。
username = line.split(':')[0].strip() if username == "root": ...
なるほど、ある文字列を整形したものがusernameで、それがrootであるかを見ているんだなと分かる。
これまでは命名を意識するのはメソッドを定義する時がほとんどだった。 例のような初見だと何をしようとしているのか分かりづらい処理に対しては、概念を説明する変数を定義してあげればいいんだなと勉強になった。
でもコードの行数が増えるよね?
大前提として1章 p.4に重要なことが書かれている。
コードは短くしたほうがいい。だけど、「理解するまでにかかる時間」を短くするほうが大切だ。
メソッドチェーンなどを駆使して、複雑な処理を1行で書くのがクールなのかもと思っていた時期もあったけど、実務で保守・改修を経験したことで、考えが変わった。
今はエディタが優秀なので、行数が長くなってもメソッドジャンプや文字列検索で必要な情報に素早く辿りつけるのもあり、行数を短くすることに固執して可読性を損なうのはナンセンスなように思う。
もちろん、不必要に冗長な書き方をしないようには気をつけたい。ここはまだまだ技術力不足の面があるので精進したいところ。
無関係の下位問題を抽出する
10章 p.129からp.141まで丸々この手法について書かれている。サンプルコードを手で書き写すのも疲れてきたので、ChatGPTさんにお手伝いしてもらうことにする。
質問
Rubyを使用して、一つの長いメソッドから無関係の下位問題を抽出するサンプルコードを、beforeとafterで二つ提示してください。リーダブルコードのQiita記事を参照してください。
回答
以下は、Rubyの一つの長いメソッドから無関係の下位問題を抽出するサンプルコードの例です。
Before
def send_email_to_users(users) users.each do |user| if user.active? if user.email_confirmed? if user.subscribed_to_newsletter? NewsletterMailer.send_newsletter(user) end end end end end
このコードは、ユーザーのアクティブ状態、メールアドレスの確認状態、およびニュースレターの購読状態を確認し、ニュースレターを購読しているアクティブなユーザーにニュースレターを送信します。
しかし、このコードはネストが深くなっており、理解しにくく、テストも困難です。
そこで、以下のように無関係の下位問題を抽出することで、コードを改善することができます。
After
def send_email_to_users(users) subscribed_users = subscribed_and_active_users(users) subscribed_users.each do |user| NewsletterMailer.send_newsletter(user) end end def subscribed_and_active_users(users) users.select do |user| user.active? && user.email_confirmed? && user.subscribed_to_newsletter? end end
この改善されたコードでは、send_email_to_users
メソッドは、ニュースレターを購読しているアクティブなユーザーに対してのみsubscribed_and_active_users
メソッドを使って絞り込んでいます。
subscribed_and_active_users
メソッドは、アクティブでメールアドレスが確認され、かつニュースレターを購読しているユーザーを選択します。これにより、コードが読みやすくなり、テストも容易になります。
お分かりいただけただろうか
beforeの例では、send_email_to_usersメソッド内で2つのことをやろうとしていた。
- メールを送っても良いユーザーか判定する
- メールを送信する
「ユーザーの状態確認」は、「メールを送信する」という高レベルの目標(本当にやりたいこと)とは無関係の下位問題であるとChatGPTさんは言ってます。
このように下位問題を切り分けることで、このメソッドで最も重要な「メールを送る」という処理に素早くフォーカスをあてられるようになった。つまり読みやすい。
ちなみにリーダブルコードでは、「与えられた地点から最も近い場所を見つける」関数内で、「2つの距離の球面距離を算出する」という下位問題を抽出する例が挙げられていた。(こっちの例の方が適切かも)
ともあれ、ChatGPTさんありがとうございました。
まとめ
リーダブルコードにはここで書いた2つの手法以外にも、すぐ実践できてかつ効果的な手法がたくさん紹介されている。リーダブルコードのまとめ記事はQiitaを始めとしてたくさん良質なものがあるので、n番煎じ感が否めないが、自身の学びを強化するのと「これをやっていきます」という決意表明的な意味で書いてみた。
本記事とは関係ないけど、個人開発でChatGPTさんにコードレビューしてもらいたい。
また最後まで読んだら感想書くかもしれません。おわり。