moai's blog

ソフトウェア開発にまつわる内容を記載します。

振る舞いを切り出して共通化するときの指針

なにこれ

振る舞いを切り出して共通化する時、どのようなケースの場合は共通化すればいいんだろうかと悩んできました。 なんとなくこうすれば良いのではと思っていることがあるので書いてみたものです。

背景

完全に同じmethodだけど、2クラスぐらいなら抽象化しないままそのまま取り扱ったほうが別クラスなので別に扱ったほうが後々の変更に便利そう。 なので、別に切り出すほどではないような少し似ているくらいなら放置しようかという気持ちになっている。 しかし、同じものは何回も書きたくないのでDRYの法則は守りたい。 そうやってモヤモヤしていたものを最近はこういう指針でやっていこうと思ったので、書いておくことにした。

こういう方針でやればいいんじゃないか?

これを満たすときには共通化すればいいと思う。

  • 記述している振る舞いが本質的に同じものである。
  • 3つ以上同じ処理を書くことが容易に想像がつく。

記述しているものが本質的に同じもの

これは高確率で抽象化しても良いと思う。例えば、本と野菜にどちらも消費税込みの小売価格を計算するメソッドが有ったら、 抽象化して、親クラスを作るなりすればいいと思う。

class Book

  def price
    100
  end

  def retail_price
    self.price * 1.08
  end

end

class Vegetable

  def price
    100
  end

  def retail_price
    self.price * 1.08
  end

end

でも、たまたま振る舞いは同じだけど、本質的には違うものは抽象化したらアカンと思う。 例えば、小売価格を計算するBookと信託手数料を計算するInvestmentTrustクラスは同じ* 1.08するのかもしれない。 だけど、こいつらは抽象化したらあかん。 下で言うと、retail_price と trust_commisionをまとめるようなものです。

class Book

  def price
    100
  end

  def retail_price
    self.price * 1.08
  end

end

class InvestmentTrust

  def price
    100
  end

  def trust_commission
    self.price * 1.08
  end

end

3つ以上同じ処理を書くことが容易に想像がつく

3つ以上同じ処理を書くことが容易に想像がつく場合も抽象化しても良いと思う。 逆に言うと2つくらいなら放置しておく。 2つくらいなら時期がきたら誰かが抽象化してくれると思うし、2つくらいなら複雑性も上がらないと思うから。

下の例で、かつ物を一般向けに販売するシステムなんかを作っていた場合、その小売価格を計算することなんてたくさんあるだろうから すぐに親クラスを作って抽象化すればいいと思う。

class Book

  def price
    100
  end

  def retail_price
    self.price * 1.08
  end

end

class Vegetable

  def price
    100
  end

  def retail_price
    self.price * 1.08
  end

end

でも、上の例でも、かつ物を卸のシステムを作っていて、でも特別に本と野菜だけは特別に小売する場合なら 少し待ってもいいと思う。 時期がきたら特別扱いしなくても良くなると思う。 Rubyなんかで作っている場合は変更も容易だし、気がついたときに変更すればいいと思います。

ただ、異論も認めます。