計算結果をインスタンス変数に入れて使い回すようなコードをちょいちょい見かけるけど、なるべくそういう事をしたくないなと思っている理由などを書く。
コードサンプル
こんなん。
class User attr_reader :age # ...その他のコード def set_age @age = (# 誕生日と現在日時で年齢を計算) end # ...その他のコード end
インターフェースがわかりにくい
これはインターフェース設計の問題だと思うけど、
上記のUserオブジェクトで年齢データを取得したい時、
user = User.find(10) age = user.age
とやっても正しい年齢が取得できない。
正しい使い方は
user = User.find(10) user.set_age age = user.age
こんな使い方は外からはわからない。
内部からでも使い方がわかりにくい
上記は「外から使い方がよくわからない」という話だけど、内部から見ても使い方がわかりにくい。
内部で年齢を扱うロジックを書こうとした時、@ageを使っていいのかどうかパッと見よくわからない。
@ageは変数なのでどこで何を入れられているのか調べないと使えるのかどうかよくわからない。
今回の場合、先にset_ageを呼ばないといけないことに気が付かないといけない。
データの整合性を考慮しないといけない
これが一番大きい問題だと思っている。
例えば、user.set_ageを実行した後にちょうど誕生日を迎えた場合、user.ageは本当の年齢を返さなくなってしまう。(本当の年齢は+1歳されたので)
変数に計算結果を入れるということは、冗長にデータを持つということなのでデータの整合性に気を配らないと行けない。
無計画に変数にデータを保持させていくと、この部分がつらくなってくる。 (※すぐ捨てるローカル変数は好きにして良いと思う)
毎回計算させたらいいのではないか?
変数に入れるのは無駄に何度も計算コストを払いたくない、という意志からきているのではないかと予想するが、インメモリデータで計算できるならコストは無視できる場合が多いのではないかと思ってる。
class User def age return (# 誕生日と現在日時で年齢を計算) end end
実装した結果「どうしても時間がかかってしまう」という場合にのみ、キャッシュを検討する。
この時、データ整合性に気を配って、かつできるだけキャッシュデータのスコープを絞るようにするのがいいと思っている。