Ch.9~10(変数と読みやすさ&無関係の下位問題を抽出する)|『リーダブルコード』読解メモ #5

f:id:lib-arts:20191013194556p:plain

コーディングにあたっての指針を示しておければということで、『リーダブルコード』を課題本に設定しまとめています。(基本的に本を片手にご確認いただく前提なので、細かいところの記述は省略すると思います。勝手に解釈した上での要約なので、万が一解釈違いは生じていたとしたらご容赦ください。)

O'Reilly Japan - リーダブルコード

#1ではCh.1の『理解しやすいコード』とCh.2の『名前に情報を詰め込む』について、#2ではCh.3の『誤解されない名前』とCh.4の『美しさ』について、#3ではCh.5の『コメントすべきことを知る』とCh.6の『コメントは正確で簡潔に』について、#4ではCh.7の『制御フローを読みやすくする』とCh.8の『巨大な式を分割する』についてまとめました。

Ch.1~2(理解しやすいコード&名前に情報を詰め込む)|『リーダブルコード』読解メモ #1 - lib-arts’s diary

Ch.3~4(誤解されない名前&美しさ)|『リーダブルコード』読解メモ #2 - lib-arts’s diary

Ch.5~6(コメントすべきことを知る&コメントは正確で簡潔に)|『リーダブルコード』読解メモ #3 - lib-arts’s diary

Ch.7~8(制御フローを読みやすくする&巨大な式を分割する)|『リーダブルコード』読解メモ #4 - lib-arts’s diary

#5では引き続いて、Ch.9の『変数と読みやすさ』とCh.10の『無関係の下位問題を抽出する』についてまとめていきます。
以下目次になります。
1. Ch.9_変数と読みやすさ
2. Ch.10_無関係の下位問題を抽出する
3. まとめ

 

1. Ch.9_変数と読みやすさ(簡単な要約)
Ch.9では変数を適当に使うとプログラミングが理解しにくくなるという話をする。具体的には以下の3つの問題に取り組む。

(1) 変数が多いと変数を追跡するのが難しくなる。
(2) 変数のスコープが大きいとスコープを把握する時間が長くなる。
(3) 変数が頻繁に変更されると現在の値を把握するのが難しくなる。

以下、それぞれの問題への対処についてまとめていく。

(1) 変数を削除する
Ch.8の「巨大な式を分割する」では「説明変数」や「要約変数」を使ってコードを読みやすくした。読みやすくなった理由としては変数が巨大な式を分割して説明文のようになったからである。ここではコードが読みやすくならない変数の削除について取り扱う。可読性を向上させない変数を削除することでコードは簡潔で理解しやすいものになる。以下具体的にまとめる。

・役に立たない一時変数
-> 複雑な式を分解しておらず、明確になっておらず、一度しか使わず重複コードの削除にならない一時変数に着目すると良い。

・中間結果を削除する
-> 関数から早く返すようにすることでコードを簡潔にすることができるケースは早く返した方が良い。

・制御フロー変数を削除する
-> 制御フロー変数はうまく実装すれば回避できるので極力用いない方が良い。

(2) 変数のスコープを縮める
グローバル変数は避ける」というアドバイスのように、変数がどこでどのように使われるか難しい状況は避けた方が良い。「名前空間を汚染する(ローカル変数と衝突する可能性がある)」ことがあり、ローカル変数を使っているつもりでグローバル変数を修正したり、グローバル変数を使っているつもりでローカル変数を修正してしまう可能性があるので注意が必要である。
そのため、変数のことが見えるコード行数をできるだけ減らすことが重要である。

(3) 変数は一度だけ書き込む
ここまで述べたように変数が多くなるとコードが理解しにくくなるが、さらに理解しにくいこととして、変数が絶えず変更され続けることがある。これによって、値を追跡する難易度が格段に上がってしまう。この問題を避けるに当たって、「変数は一度だけ書き込む」というのを意識すると良い。
この手法は使えない時もあるが、変数の変更箇所はできるだけ少なくするように気をつけるべきである。

 

2. Ch.10_無関係の下位問題を抽出する(簡単な要約)
エンジニアリングとは、大きな問題を小さな問題に分割して、それぞれの解決策を組み立てることに他ならない。この原則をコードにあてはめれば堅牢で読みやすいコードになる。
Ch.10のアドバイスは無関係の下位問題を積極的に見つけて抽出することである。下記を考えておくと良い。

(1) 関数やコードブロックを見て「このコードの高レベルの目標は何か?」と自問する。
(2) コードの各行に対して「高レベルの目標に直接的に効果があるのか?あるいは、無関係の下位問題を解決しているのか?」と自問する
(3) 無関係の下位問題を解決しているコードが相当量あれば、それらを抽出して別の関数にする。

上記の技法は簡単に使えるのにコードを大幅に改善できる。使いこなすにあたってのコツは無関係の下位問題を積極的に探し出すことである。下記にこの技法を適用した例をいくつか紹介していく。

・findClosestLocation()
-> コードの高レベルの目標が「与えられた地点から最も近い場所を見つけること」にある際に、「2つの地点(緯度経度)の球面距離を算出する」といううのは新しい関数に切り出すことができる。こうすることで難しそうな計算に心を奪われることなく、高レベルの目標に集中できる。また、個別に関数で切り出すことで個別にテストができ、かつ個別に再利用が可能であり、そういった点でもメリットが大きい。

・純粋なユーティリティコード
-> 文字列の操作、ハッシュテーブルの使用、ファイルの読み書きなどのプログラムの核となる基本的なタスクに対する「基本的なユーティリティ」は、プログラミング言語の組み込みライブラリとして実装されていることが多い。が、時折ないこともあるので、この言語(ライブラリ)にこういった機能があれば良いのにという機能については関数を自分で書くという心構えでいると良いケースが多い。

・汎用コードをたくさん作る
-> 汎用コードは素晴らしく、理由としてはプロジェクトから完全に切り離されており再利用が可能だからである。こういう実装は、簡単に共有できるように特別なディレクトリ(ex. utils/)を用意して管理しておくと良い。また、この際にトップダウン(先に高レベルのモジュールや関数を設計してからそれらをサポートする低レベルの関数を実装していく方式)を用いるかかボトムアップ(先に全ての下位問題を解決してからそれらを利用する高レベルのコンポーネントを実装していく方式)を用いるかという視点も持っておくと良い。

・既存のインターフェースを簡潔にする
-> 利用している実装のインターフェースが綺麗でなくても、自分で「ラップ」関数を作ることができるのでこの点は意識しておくと良い。そのため、「理想とは程遠いインタフェースには妥協する必要はない」と考えておくと良い。


3. まとめ
#5ではCh.9の『変数と読みやすさ』とCh.10の『無関係の下位問題を抽出する』について取り扱いました。下位問題の抽出やトップダウンボトムアップの記述が思考の整理として有意義に感じました。
#6ではCh.11の『一度に1つのことを』とCh.12の『コードに思いを込める』についてまとめていきます。