コードがスパゲッティになるのを避けるには…
よく「コードがスパゲッティになってる」と言ったりします。麺が複雑に絡み合って、ほどけない状態ですね。ここで「麺」に例えられているものは、何なのでしょうか?
真っ先に思い浮かぶのは、「コードの実行の流れ」です。
でも、GOTO文しか無かった時代ならともかく、現代のプログラミング言語なら、コードの流れを追うのに苦労することは少ないかな?
コールバック、非同期処理、Promise、スレッド、golangのgoroutine、Clojureのcore.asyncなどは、そもそも生まれつき難解なので、スパゲッティの理由には当たりません。
では、麺の正体は何か?
答えは「変数のスコープ」だと思います。スコープとは、その変数を読み書きできる範囲のことです。
デバッグのためにプログラムを解読しているとしましょう。if
文があり、変数a
の値に応じて分岐しています。この変数に値をセットしている場所を遡って探しますよね。スコープが広い変数なら、すごく離れた場所で値が書き換えられているかもしれません。
スコープが広いということは、麺が長〜い、ということです。絡みやすいんですね。その一端をつまんだとき、もう片方の端がとんでもないところに飛び出てしまうんです。特に、グローバル変数やクラスのインスタンス変数は、関数間をまたげる飛び道具なので注意が必要です。
スコープと似て非なるものに、「変数の寿命」があります。
寿命が長い変数は、(たとえスコープが狭くても)やはり長い麺になる危険があります。例えば、クラス変数やC言語でstatic
が付いた変数は、寿命が長いです。Webアプリで良く使う「セッション」も、(厳密には変数ではないけど)情報を長生きさせる便利なテクニックです。しかし寿命が長いだけに、「適切なタイミングで値を無効化する」というひと手間が必要だったりします。
さて、もうお分かりですね。コードがスパゲッティになるのを避けるには、どうすれば良いか?
麺を短くしましょう。
関数の引数やローカル変数はスコープが狭いです(寿命も短い)。でも、もちろん、その関数自体が長いと意味がありません。関数は、一息で読めるくらいの長さにしましょう。