コード日進月歩

しんくうの技術的な小話、メモ、つれづれ、など

変数代入を複数回行うと何が良くないのか、どうするといいのか

変数の代入を複数回行う、すなわち変数の再代入をすることは何が辛いか、また変数の代入を1回にすると何が嬉しいかを書く。

今回の題材

例えばRubyで以下のようなメソッドがあるとする

def make_aisatsu_text(people_name: "Suzuki", is_san: false)
  text = is_san ? "さん" : ""
  text = people_name + text
  text = text + "、こんにちわ!" 
  return text
end

この記述を例に辛い部分は大きく以下の2つ

  • 変数の状態がメソッドの最初から最後まで変わり続けるので変更に弱い
  • (型付き言語だと発生しないが)途中の状態が削除されると読み取り難易度が増す

1つずつ簡単に説明していく

変数の状態がメソッドの最初から最後まで変わり続けるので変更に弱い

上記の例だと text という内容が行によって変わり続ける。 最後にreturnする内容をするのを text にしたいという意図はあるかもしれないが この方法は今後拡張したときに厳しくなる。

例えば * Satoさんへの挨拶の場合は、「久しぶり」という言葉を、そうでない人には「はじめまして」を挟む * 天気がいいかを調べる、 sunny? メソッドがtrueなら「天気がいいですね」という言葉を挟む という変更が加わるとすると以下のようになる

def make_aisatsu_text(people_name: "Suzuki", is_san: false)
  text = is_san ? "さん" : ""
  text = people_name + text
  if people_name == "Sato" 
    text = text + "、久しぶり"
  else
    text = text + "、はじめまして"
  end
  if sunny?
    text = text * "、天気がいいですね"
  end
  text = text + "、こんにちわ!" 
  return text
end

このようになるが、この時点でかなり読みづらくなっている(と私は思っている) さらに「こんにちわ!の位置は文の最初の方に…」などの変更が入ったら更にカオスになる。

途中の状態が削除されると読み取り難易度が増す

上に書いた仕様追加されたコードで更に「Tanakaさんの場合は名前を呼ぶ部分はいらなくなりました」といって削除を行うとする。 単純にやると以下のような事が起きる。

def make_aisatsu_text(people_name: "Suzuki", is_san: false)
  text = is_san ? "さん" : ""
  text = people_name + text
  if people_name == "Tanaka"
    text = ""
  end
  if people_name == "Sato" 
    text = text + "、久しぶり"
  else
    text = text + "、はじめまして"
  end
  if sunny?
    text = text * "、天気がいいですね"
  end
  text = text + "、こんにちわ!" 
  return text
end

textを "" してリセットするという処理を入れたが、増々読みにくくなった。

このように継ぎ足していく処理とまっさらにする処理が混在する状況になると「この行における text は何が入っているのか?」というのがよりわかりにくくなる。

改善例

シンプルに再代入をやめることだけでかなりスッキリさせることができる。

def make_aisatsu_text(people_name: "Suzuki", is_san: false)
  san_text = is_san ? "さん" : ""
  full_name_text = people_name + san_text
  return full_name_text + "、こんにちわ!"
end

盛々の仕様変更も耐えやすい

def make_aisatsu_text(people_name: "Suzuki", is_san: false)
  san_text = is_san ? "さん、" : ""
  full_name_text = people_name + san_text
  meet_text = people_name == "Sato" ? "久しぶり、" : "はじめまして、"
  weather_text = sunny? ? "天気がいいですね、" : ""

  main_text = meet_text + weather_text + "こんにちわ!"

  return main_text if people_name == "Sato"
  return full_name_text + main_text
end

参考リンク