インスタントラーメン袋に書いてあるレシピを見てみよう。

(1) お湯550mlとフレークを入れてお湯を沸かす。
(2) 粉末スープと麺を入れて、さらに4分間茹でる。

3番はおすすめの食べ方なので、これを除けば2段階だと言える。 ところで、実際にラーメンを調理する自分の姿を想像してみると、これよりはるかに多くの段階が隠れている。

(1) 鍋を取り出す。
(2) 鍋に水550mlとフレークを入れる。
(3) 水と材料の入った鍋を加熱する。
(4) 水が沸騰するのを待つ。
(5) 水が沸騰し始めたら、麺と粉末スープを入れる。
(6) さらに4分間茹でる。
(7) 火を消す。
(8) ボウルに盛り付ける。

これより詳しく説明することもできる。よく考えてみると「鍋を加熱する」にもいくつかの段階が省略されている。装備によっても違うので分岐が必要だ。

(1) インダクションの場合は、電源を入れて、ボタンを押して、温度を上げる。
(2) ガスレンジの場合は、ガスバルブを開けてダイヤルを回して点火する。
(3) ポータブルバーナーの場合は、燃料ボトルを入れ、ロックして、点火する。

しかし、どんなラーメンレシピにも上記のような内容が含まれていない。なぜならこれくらいの詳細は読者が既に知っていると見なすか、実はラーメンメーカーが気にする必要がないからだ。あまりにも当たり前のことだと思うかもしれないが、このようなコードは一般的である。 関数名で表現されたものよりもたくさんの仕事をしたり、過度に詳細な実装部がさらされたりする。 通常この場合は、if文やfor文が多く、冗長なコードになっている。

例えば、fetchRecentArticlesという関数が現れたと想像してみみよう。この関数が実行する作業は次のようになると予想できる。

(1) 保存された記事を適度に読み込む。
(2) 最近X日以内に生成されたものを選んだ後に結果を返す。

ところで、関数の内容を見てみると、関数内でローカルキャッシュを確認し、キャッシュがなければサーバーAPIを呼び出してデータを取得してパーシングし、リポジトリからデータを読み込むためのキー値を定義し、switch文で記事の種類によって異なるフィルタリングロジックを生成している場合はどうか。 実際の中核部分は冗長なコードの中に埋もれてしまう。コードを修正しようとしてもどこを見るべきか、探すのに時間がかかってしまう。ラーメンを作るのに必要なお湯を沸騰させるということだけ知れば良いのに、火をどのようにつけるのかまで説明しているわけだ。

「なぜ磁石は互いに押し出すのか」という記者の質問にリチャード・ファインマンが答えをした映像でも同様の意味を見つけることができる。同じ質問でも質問者が誰か(物理学専攻者、一般人、宇宙人など)によって、または質問者が何を知りたいかによって説明は千差万別になる。「それは元々そうだよ」のように一言の答えになることもでき、説明が限りなく次々と詳細に説明することもできる。YouTube Video

自分が作成したコードが適切な水準のロジックだけを見えるようにしているかを考えてみよう。関数の役割に合った作業だけしているのか、それともありとあらゆる細部のロジックを冗長に並べているのではないかを確認し、手を加えなければならない。ところが「適切な水準」というのは正解がない。コードが属しているクラスやモジュールによって異なる。コードの読み手/書き手の能力によっても変わることがある。誰にとっては簡潔なコードは、誰にとっては理解しにくいコードかもしれない。コードをリファクタリングしてみると、基準が変わることもある。全ては流動的である。正確に当てはめられる基準はないが、読者の立場から自分のコードを一度でももっと読んでみて、関数を短くする練習をして、仲間同士でコードレビューをすることで適切な水準に合わせていくことができる。

オブジェクトは1つの責任を持つという単一責任の原則を守ることは決して容易ではないが、最初は関数単位から始めよう。関数を簡潔にできるようになったら、次にクラスレベルでも適用してみる。単一責任の原則は、全てのパターンやアーキテクチャの始まりである。つまり、単一責任の原則を守らなければ、どのようなパターンを使っても、どのようなアーキテクチャを導入しても時間が流れるほど結局、スパゲッティコードになる可能性が高い。言語文法も、コードをより簡潔に表現するための手段として勉強をすれば、道を失わない。関数を短くし、クラスを小さくする練習をたくさんしよう。

https://ja.wikipedia.org/wiki/%E5%8D%98%E4%B8%80%E8%B2%AC%E4%BB%BB%E3%81%AE%E5%8E%9F%E5%89%87

一緒に読めば良い記事

Swiftで振り返るオブジェクト指向プログラミング:避けるべきコーディング習慣