Perlで生でrand関数をごちゃごちゃ使うコードはもう嫌だ
2011-12-25
Hachioji.pm#12で発表したネタです。Data::WeightedRoundRobin使ったら、rand使うようなコードが、いい感じにすっきり見やすくかけましたよーという話です。
嫌なコードの概要
要件
「以下のような感じで、実行する処理をランダムで変更してよ!」って要件がたまにありますね。
- 3割の確率でhogeを実行
- 3割の確率でmogeを実行
- 2割の確率でfooを実行
- 1割の確率でbarを実行
- 1割の確率でjarを実行
ファクトリーメソッドパターン的な実装ですね。
ごにょごにょするとこんな感じの実装に
my $rand = rand();
my $method;
if($rand < 0.3){
$method = 'hoge';#3割
}elsif($rand >= 0.3 && $rand < 0.6){
$method = 'moge';#3割
}elsif($rand >= 0.6 && $rand < 0.8){
$method = 'foo';#2割
}elsif($rand >= 0.8 && $rand < 0.9){
$method = 'bar';#1割
}elsif($rand >= 0.9){
$method = 'jar';#1割
}
my $value = $method($args);
嫌なところ
- なんかぱっとみわかりづらいから、割合をコメントで書く
- なんかrandとかカッコ悪い
- なんか条件の比較文でミスってそう
とにかく、プログラムッチクというとなにかとランダムという要件が多いし、こんなコードばかりグチャグチャ書くのはもういやですね。
解決方法の発見
私は自宅でHokkaido.pm#06のUstを見ていたときのことです、そのとき、Data::WeightedRoundRobinなるモジュールが紹介されていたのでした!!!
いわく、
「重み付けされた値をベストエフォートな感じでラウンドロビンしてくれるモジュール」
というのを、Hachioji.pm#12に行く電車の中で思い出したのです。
「あれ?なんかこれ使えば、あのださいコードかっこ良くなるんじゃない?」というように。
Data::WeightedRoundRobinを使った解決コード
use Data::WeightedRoundRobin;
my $wrr = Data::WeightedRoundRobin->new([
{ value => 'hoge', weight => 30 },
{ value => 'moge', weight => 30 },
{ value => 'foo', weight => 20 },
{ value => 'bar', weight => 10 },
{ value => 'jar', weight => 10 },
]);
my $method = $wrr->next;
my $value = $method($args);
今回のケースに合わせてよりシンプルにしたコード
use Data::WeightedRoundRobin;
my $method = Data::WeightedRoundRobin->new([
{ value => 'hoge', weight => 30 },
{ value => 'moge', weight => 30 },
{ value => 'foo', weight => 20 },
{ value => 'bar', weight => 10 },
{ value => 'jar', weight => 10 },
])->next;
my $value = $method($args);
感想
Data::WeightedRoundRobin使うと、マジでみやすいですねー。
- コメントいらない
- ifのわけわからない条件文でバグることない
- 行数少ない
という感じで、今後も使っていきます!