スコープを狭くしよう、というコラムです。
変数には1度だけ書き込むほうがいい
かのリーダブルコードに以下のような記述がある
本章では「生きている」変数が多いとコードが理解しにくくなることを説明した。でももっと理解し難いのは、変数が絶えず変更され続けることだ。値を追跡する難易度が格段に上がってしまう。
この問題と戦うために、ちょっと変わったものを提案したい。それは、変数は一度だけ書き込むというものだ。
- リーダブルコード 9.3 変数は一度だけ書き込む より
変数というのは可変の数値ではあるが、なるべく変更されるのは少なくあってほしい。理由をあげるとすれば…
- 変数が書き換わることがあればその書き換わる前後で差分を比較する必要がある
- 値が変わらなければ、意図違いで使うことは減る。
という部分である。ここらへんは詳しくはリーダブルコードを読んでください。。
この「変数は1度だけ書き込むことが望ましい」ということを踏まえて「オブジェクトはできるだけ不変とする」という話をしたい。
オブジェクトはできるだけ生成後に変わる部分を少なく
たとえば下記のようなクラスがあったとする。
class Human
attr_accessor :first_name, :last_name, :age
def output_profile_text
"Hello! My name is #{first_name} #{last_name}, #{age} old."
end
end
これをオブジェクト化して使おうとすると以下のようになると思います。
taro = Human.new
taro.first_name = "Taro"
taro.last_name = "Suzuki"
taro.age = "20"
p taro.output_profile_text
このようになった場合に、 taro
オブジェクトは生成後に必要な値をセットしないと output_profile_text
が正しく書き出せない。
taro = Human.new
taro.first_name = "Taro"
taro.last_name = "Suzuki"
p taro.output_profile_text
また名前のようなものは、一度設定したら変わることはないので、外から変更可能というのも別に必要性がない。
taro = Human.new
taro.first_name = "Taro"
taro.last_name = "Suzuki"
taro.last_name = "Sato"
このように
- 最初から使うことが約束されている
- 途中から書き換えることが無い
というような情報はインスタンスが作られる時点でセットしてあげるようにしたほうが、変な書き換えを心配しなくていいし、見るべきスコープを狭くすることができる。ここの考え方は最初の変数の話と似た部分となる。
class Human
def initialize(first_name:, last_name:, age:)
@first_name = first_name
@last_name = last_name
@age = age
end
def output_profile_text
"Hello! My name is #{@first_name} #{@last_name}, #{@age} old."
end
end
taro = Human.new(first_name: "Taro", last_name: "Suzuki", age: 20)
p taro.output_profile_text
このようにして書き換えてあげれば途中で書き換える使われ方も減るはずだし、スコープも狭くなるので見通しは遠くなるはずです。
参考リンク