[Ruby] Ruby コーディングアンチパターン

WEB+DB PRESS Vol.86 の memo.

WEB+DB PRESS Vol.86
WEB+DB PRESS Vol.86

posted with amazlet at 16.07.11
結城 洋志 沖元 謙治 足永 拓郎 林 健太郎 大竹 智也 内田 誠悟 伊藤 直也 中山 裕司 hiroki.o 泉水 翔吾 佐藤 太一 高橋 俊幸 西尾 泰和 舘野 祐一 中島 聡 橋本 翔 はまちや2 竹原 麻植 泰輔
技術評論社
売り上げランキング: 218,454

コーディングアンチパターン

引数を囲む括弧を省略しない

# Bad
do_something foo, bar
# Good
do_something(foo, bar)
# Exception
require 'path/to/file'

条件節での代入を避ける

# Bad
if result = do_something
  p result
end
# Good
result = do_something
if result
  p result
end
# Case by case
if (result = do_something)
  p result
end

代入式と条件式を分けると冗長となる場合はこの限りで無い。

and, or, not を使わない

# Bad
result = (1 and 2)
fetch_something or raise 'Failed fetching!'
# Good
result = 1 && 2
fetch_something || raise('Failed fetching!')
fetch_something || (raise 'Failed fetching!')

クラス変数を使わない

クラス変数を使わず「クラスインスタンス変数」を利用する。

# Bad
class Foo
  def self.value=(value)
    @@value = value
  end
end
# Good
class Foo
  def self.value=(value)
    @value = value
  end
end

クラス変数はそれが定義されたクラスだけでなく、そのサブクラスとも共有される変数であるため。
スーパークラスとサブクラスで共有されるが、このような挙動がほしいケースはあまりない。

ensure 節に return を記述しない

例外発生時に例外がもみ消されてしまう。

test.rb
require 'fileutils'
# Bad
def process(should_success)
  puts 'Creating tmp directory'
  Dir.mkdir('tmp')
  raise 'error!' unless should_success
ensure
  puts 'Removing tmp directory'
  FileUtils.rm_rf('tmp')
  return 'succes'
end
# Good
def process(should_success)
  puts 'Creating tmp directory'
  Dir.mkdir('tmp')
  raise 'error!' unless should_success
  'success'
ensure
  puts 'Removing tmp directory'
  FileUtils.rm_rf('tmp')
end
return_value = process(ARGV.first == 'true')
puts "Return value: #{return_value.inspect}"

rescue 節を使って例外を補足し、その例外を投げないまま戻り値を返したい場合でも、ensure 節ではなく rescue 節の最後に戻り値を記述する。

未使用のローカル変数

アンチパターンではないが。
変数名を _ で始めることで「これは宣言したが未使用な変数である」ということを表明する慣習がある。

scores = {
  'foo' => 93,
  'bar' => 89,
  'baz' => 98
}
sorted_scores = scores.sort_by { |_name, score| score }

一貫性を保つためのスタイル

Enumerable モジュールのメソッドの別名

同じ動作で別名が付けられているもの。
プロジェクト内でどちらを利用するか決めておく。

  • map/collect
  • reduce/inject
  • find/detect
  • find_all/select

複数行の文字列の連結

文字列リテラルを連結するいくつかの選択肢。

# 行末に \ を使う
'foo' \
'bar'
# String#+ メソッド
'foo' +
'bar'
# String#<< メソッド
'foo' <<
'bar'

それぞれメリット・デメリットがあるが、どれを使っても良い。

複数行のメソッドチェインのドット位置

メソッド呼び出しの . をどう置くか。

# 改行前の行末に置く
string.downcase
  .gsub(' ', '_')
# 改行後の行頭に置く
string.downcase.
  gsub(' ', '_')

それぞれメリット・デメリットがあるが、プロジェクトメンバーの嗜好に合うものを使う。

まとめ

まとめ部分。
Ruby Style Guide と RuboCop について触れられている。

補足