概要
原著者の許諾を得て翻訳・公開いたします。
- 英語記事: Extract conditionals into well-named methods - Andy Croll
- 原文公開日: 2018/01/21
- 著者: Andy Croll
Ruby: 条件を切り出していい感じのメソッド名を付けよう(翻訳)
シンプル(かつ効果の高い)リファクタリング手法のひとつといえば、メソッドへの切り出しがあります。切り出したメソッドに名前を付ける手法は、コードの背後に潜むアイデアを示すうえで有用なツールです。
次のようには書かないこと
条件にステートメントをごちゃごちゃ書く。
class BrightonCoffeeShop
def initialize(name)
@name = name
end
def good?
if @name == 'Starbucks' || @name == 'Costa' ||
@name == "Barry's Caff"
false
elsif @name == 'Coffee@33' || @name == 'Small Batch'
true
else
false
end
end
end
この実装が、name
が不明な場合にfalse
を返すことはもう見え見えです。あなたがこの喫茶店で満足にくつろげるようにする唯一の方法は、わけのわからないルールを排除することです。
次のように書くこと
「メソッドの切り出し」リファクタリング手法を用いて、ロジックをprivate
メソッドに移動し、コードのコンセプトを的確に表すメソッド名を付ける。
class BrightonCoffeeShop
def initialize(name)
@name = name
end
def good?
clean? && local? && excellent_coffee?
end
private
def clean?
!filthy?
end
def excellent_coffee?
['Coffee@33', 'Small Batch'].include?(@name)
end
def filthy?
@name == "Barry's Caff"
end
def local?
!national_chain?
end
def national_chain?
['Starbucks', 'Costa'].include?(@name)
end
end
そうすべき理由
メソッドを切り出して定義することで、メソッドに名前を付けます。上の#good?
メソッドは、よい喫茶店かどうかを判断するための基準を示します。この新しいprivateメソッドは、クラスのドキュメントとしても機能します。
修正前のコードでは、「よい」喫茶店と「よくない」喫茶店のリストしかなく、このリストがどのように形成されたのかという知識も示されていませんでした。
このクラスに対する初歩的なリファクタリングとして、GOOD
とBAD
という配列にそれぞれよい名前と悪い名前のリストを詰め込み、喫茶店のname
をそれでチェックするという方法もないわけではありません。しかしその方法では、その喫茶店がよい理由も悪い理由も見えなくなってしまうでしょう。しかもその理由こそが、このコードで最も重要な部分なのです。
修正後のコードでは、#clean?
(清潔)や#local?
(地元)といったポジティブな評価基準だけではなく、#filthy?
(不潔)や#national_chain?
(全国チェーン)といったネガティブな評価基準についても切り出しました。このおかげで、#good?
メソッドのネガティブバージョンをprivateメソッドに用意しなくても済みます。少々やりすぎに思える部分かもしれませんが、このクラスでは満足の行く喫茶店に対する肯定的な評価の方を強く重視しているのですから、これによって有用なコンテキストが付け加えられます。
リファクタリングの手法が何であれ、リファクタリング前には最初の実装をカバーするよいテストをしっかり書いて、機能がうっかり変わらないようにしておきましょう。
そうするべきでない理由があるとすれば
上よりももっとシンプルな例であれば、このリファクタリングを行うまでもないかもしれません。しかしそれでもドキュメント作成の有用な手法でもあり、条件のロジックを明確化できます。
上よりもさらに複雑な場合(喫茶店に対して良否以外にも多くの要件を課すなど)は、個別の喫茶店をサブクラス化する形でリファクタリングするとよいかもしれません。
はてブより
Ruby: 条件を切り出していい感じのメソッド名を付けよう(翻訳)
- [Ruby]
- [リファクタリング]
この前後輩が長いifの条件を改行したいんだけど……って聞いてきたので、先頭揃えるのがよく見る気がするけど匂ってるのでメソッドに切り出そうって話した。結局ifをネストしてた。