hashie gemを使わない3つの理由

弊社ではSlack上で、pokemon-go板が出来たりカスタムリアクション
が大流行したりなどしていますが、Pokemon GOにいまいちピンときていない前田です。

hashieというrubyのgemがあります。
皆さんは使っていますでしょうか?
先日弊社のサーバーサイドチームでRubyのgemであるhashieを使用するかどうか、で議論がありました。
omniauth gem で使用していたりなど、スターも結構付いているgemですが、現在弊社では基本的には使用していません。
本日はその主な理由を3つ書きたいと思います。

hashieを使わない理由 1

使用しても可読性はそれほど上がらず、使用しない箇所が混在すると混乱のもとになる

発端は私が書いた、下記のようなコードでした。

# params = { maker_cd: 100, grade_cd: 200 }

# コントローラー
def index
  Car.by_params(Hashie::Mash.new(params))
end

# モデル
class Car < ActiveRecord::Base
  scope :by_params, lambda { |params|
    by_maker_cd(params.maker_cd)
    .by_grade_cd(params.grade_cd)
  }
end

以前、Hashie::Mashを使って実装した際、[]じゃなくて.の形で呼べるのはすごく便利だなぁと思って隙あらば良く使っていました。

しかし、他のHashie::Mashを使わない人がこのコードを見た時にクレームが出てしまいました。
scopeにHashie::Mashオブジェクトを渡さないといけないのはコントローラーでは分からないし、一部Hashie::Mashを使用して、Hashie::Mashを使用しない箇所があれば全体の統一感がでなくなるし、バグの温床になりやすい。

また、上記のコードは、

def index
  Car.by_params(params)
end

class Car < ActiveRecord::Base
  scope :by_params, lambda { |params|
    by_maker_cd(params[:maker_cd])
    .by_grade_cd(params[:grade_cd])
  }
end

と、普通はこのように書くと思いますが、Hashie::Mashを使った時と使わない時でコードが見やすくなったとかといえば、それほど多きな違いがあるわけではありません。
であれば使わないほうが万人向けのコードであり、Hashie::Mashが使われていたり使われていなかったり、といったことを意識しなくてもよいコードのほうが良いですよね。

hashieを使わない理由 2

数字がキーの場合はドットでアクセス出来ない

[1] pry(main)> m = Hashie::Mash.new(1 => 'one')
=> {"1"=>"one"}
[2] pry(main)> m.1
SyntaxError: unexpected tINTEGER, expecting '('
[3] pry(main)> m[1]
=> "one"

Hashは数字をキーに出来る。
Hashie::Mashでオブジェクトを生成しても、[]でアクセスできるが.でアクセス出来ない。
これでは通常のハッシュと変わりは無いのでHashie::Mashを使用する意味は無い。
ハッシュ形式で数字がキーということはあまり無いケースかもしれないが、こういう制限がある、というのは見落としやすいので、必要の無い箇所にまでHashie::Mashを使用したりしていると、気づかないうちにバグをコードに埋め込んでしまう可能性がある。

hashieを使わない理由 3

パラメータの型を強制する機能があるけど..

例えば下記のようなクラスを作って各パラメータの型を強制したい時がある。

class Person < Hashie::Mash
  include Hashie::Extensions::Coercion
  include Hashie::Extensions::MergeInitializer

  coerce_key :name, String
  coerce_key :age, Integer
end


[1] pry(main)> man = Person.new(name: 111, age: '25')
=> {"name"=>"111", "age"=>25}
[2] pry(main)> man.name
=> "111"
[3] pry(main)> man.age
=> 25

便利ですが、それってVirtusで出来るよね。

class Animal
  include Virtus.model

  attribute :kind, String
  attribute :age, Integer
end

[1] pry(main)> dog = Animal.new(kind: 123, age: '3')
=> #<Animal:0x00563a43c65da8 @age=3, @kind="123">
[2] pry(main)> dog.kind
=> "123"
[3] pry(main)> dog.age
=> 3

しかもこちらのほうがシンプル!


もっと深い機能を使えばHashie::Mashを使用したほうがいい場面があるかと思いますが、とりあえず弊社では当分使用するシーンは無さそうです。

このエントリーをはてなブックマークに追加