可読性について リーダブルコード Part3(コードの再構築)
Editor's Notes
- 今回ページ数としては少ないですが、内容としてはかなり凝縮されたPartになっております。
- これらを書籍に書かれていたこと+普段茶谷さんなどから教えて頂いている事や実務を通して学んだことを織り交ぜながら進めて行きたいと思います。
- まず最初に「無関係の下位問題を抽出する」についてです。要するに単一責任の原則で、1メソッド1責任で命名以上のことをしないように、メソッドがファットにならないようにです。もし命名以上の処理をしていたらそれは、別メソッドで切り出すべきです。
- こちらは実例になり、画像のコードは原文ままのメソッドになります。メソッドで行われていることといたしましては、与えられた緯度経度に最も近いarrayの要素を返すというというメソッドなのですが、それに対して、「2つの地点をラジアンに変換する」というタスクが混ざっており責務が2つ発生してしまっています。こちらを別メソッドとして抽出することができます。
- 左側が新しくメソッドとして切り出したもの、右側が残ったコードになります。コードを別メソッドで切り出し、残ったコードは本来の責務1つのみとなります。こうすることで、可読性も高まり修正をする時も、このメソッドは一つの理由だけで修正されることになります。メソッドは小さくて独立したものになっていれば、機能追加・読みやすさの向上につながります。これらを抽出するポイントとしては、メソッドの事前処理や事後処理などの本質とは関係のない処理、いわゆるグルーコードを積極的に抽出することです。また抽出したメソッドが汎用性の高い場合は、utilsなどへ置いてプロジェクト内部で読み込めるようにしておくと便利です。
- 良い例がなく自作してみてすごく難しかったんですが、画像のようにobjの中にあるnameがあれば取ってくる、なければ空文字を返すという処理です。一旦obj.nameがあるか確認するメソッドを作って、その真偽値によって空文字を返すメソッドを作って、値があればobj.nameを返すというだけですが、やりすぎてしまうと逆に変わり辛く、修正も困難になってしまいます。
- 続いては「一度に1つの事を」です。一度に複数のことをするコードは理解しにくく、責務が複数あるとテストも書きづらくなってしまいます。大きな関数は責務を分けて小さく分割すべきです。では具体的な手順ですが、コードが行っているタスクを全て列挙して、それらをできるだけ異なる関数に分割していきます。この「タスク」という定義はケースバイケースになると思うので、適宜判断しましょう。一つの基準として関数の命名に悩むようであれば、「複数のことをしている関数だ」といえますので一つの基準として覚えておきましょう。
- こちらは例題として「賛成、upで+1」と「反対、downで-1」をユーザーが投票できる左側のメソッドがあったとします。左側のコードはスコアを更新するという1つのタスク以外にも「old_voteとnew_voteを数値にパースする」というタスクが含まれています。これらのタスクを別々に切り出したコードが右側になります。最小のタスクに切り出したことで可読性が増し、コードを「楽に理解できる」ようになったと言えます。
- 続いては「コードを言葉で説明する」です。コードの動作を説明する時に、自分よりも知識が少ない人でも「誰にでもわかるように」簡単な言葉で説明できないと本当に理解してコードを書いているとは言えません。それには自分の考えを凝縮して、最も大切な概念にすることが必要です。そして、普段からソースコードに触れているプログラマにとっては、コードそのものがプログラムの動作を説明する大切な手段になります。つまり、コードも「簡単な言葉」で書くべきです。この第三章ではコードをより明確にする手順を使っていきます。
- コードをより明確にする手順は以下の通りです。1〜〜〜。では次から具体例を見て行きましょう。
- では具体例ですが、左側はPHPのコードの一部で、ユーザにページを閲覧する権限があるかどうかを確認して、もし権限がなければ、権限がないことをユーザに知らせるページへ戻すというコードです。左側にはロジックが多くあり可読性が低くなっています。このコードを一旦誰にでもわかるような簡単な言葉に置き換えてからコードを書き直したのが右側になります。ロジックそのものも否定形がなくなったりネストが浅くなったり単純化されたため可読性も増しました。
- 次の例は、ユーザがページを訪問するとヒントがランダムに表示され残りは隠された状態だが、「その他ヒントをみる」をクリックすると、次のヒントが表示されるというjQueryコードです。同じく「誰にでもわかるように」一度コードの動作を簡単な言葉にしてみます。その説明を元に書き直したのが左側になります。コードは短くなり、数値を直接操作する必要もなくなり、人間がどのように考えるかを重視した読みやすいコードになりました。
- このように動作や設計/仕様をうまく言葉でできないのであれば何かを見落としているか、そもそも詳細が明確になっていないと言えます。また、「簡単な言葉で説明する」手法は、開発以外でも適用できて、例えばデバッグの際にパソコンの横にアヒルのおもちゃを置いて、そのおもちゃに向かって語りかけることで、問題を解決するとう「ラバーダッキング」技法というものが存在します。あと、リーダブルコードには先ほどの例よりももっと巨大なコードを改善する例があったのですが、こちらでは取り上げれるような大きさではなかったため、ぜひ書籍を読んでみて頂ければと思います。それと、これらロジックの整理ということでは、サンプルのように実際にやりたいことを先に言語化してみるのと、個人的にはテスト技法のデシジョンテーブルや直交表、状態遷移表のNスイッチカバレッジを活用すれば、ロジックを整理するのにはとても有効だと感じました。テスト技法については今回のLTでは省きます。
- 続いては「短いコードを書く」です。このタイトルだけだとワンライン=正義のような誤解を生みそうなので、そうではないことを先に申し上げておきます。リーダブルコードで一貫していることは「読みやすいコードが優れたコード」であるということです。ではここで言われている「短いコードを書く」とはなんなのか?ですが、リーダブルコードでは「最も読みやすいコードは、何も書かれていないコードである」と記述されています。これはつまり「YAGNIの原則」にあたり、「後で使うだろうという予測の元に作ったものは、実際には10%程度しか使われないので、それに費やした時間の90%は無駄になる」という原則です。そしてコードがないのであればバグが生まれることもありません。ただし、YAGNIの原則を実現させるにはクライアントの要求を正しく理解している必要があります。「何を実現させたいのか?何を解決させたいのか?」をしっかり把握することが「短いコードを書く」ことの第一歩になります。また、規模が大きくなるにつれて、未使用のコードが生まれてきてしまいますが、これはあえて言うまでもなく削除していきましょう。そして、ライブラリの活用も有効です。これに関しては自作していった方がブラックボックス化されなくて良い、という意見もありそうですが、ライブラリの機能を熟知して実際に活用するのは有効な手段であると記載されています。理由としては、成熟したライブラリのコードの裏側には、膨大な設計・デバッグ・修正・ドキュメント・最適化・テストが存在しており、現在まで生き延びてきたライブラリコードには大きな価値があるため、それを再利用すると時間とコード記述の節約になるためであると書かれています。よく使われる統計では、平均的なエンジニアが1日に書く出荷用のコードは10行である」という統計があり、このことを考えるとライブラリの再利用の意義がわかる気がします。
- では最後にまとめです。〜〜〜。今回可読性についてPart3までやらさせて頂きましたが、次回Part4で最終回になります。ご静聴有難うございました。