トップ «前の日記(2019-02-27) 最新 次の日記(2019-03-10)» 編集

日々の破片

著作一覧

2019-03-03

_ リファクタリング: HashからStruct

時期

元のプログラムでJSONなどの外部データから得られたHashをそのまま利用していたら、そのデータが複数のモジュール間を行き来するようになった。

モティベーション

Hashキーのリテラルが複数モジュールで記述されるためスペルミスがあってもわかりにくい。外部データで値としてnilが含まれることを前提している場合、キー名の書き間違いによるnilなのか、値がnilなのかの区別ができないためである。キー名の書き間違いはプログラムエラーとして検出したい。

解決方法:HashからStructへ変える

Structは、属性名をキーとした[]記法もできるため、仮に修正漏れがある、あるいはモジュール修正の時期によってStructへの記述変更したモジュールとHash記法のままのモジュールの混在が可能。

data = JSON.parse(responseText)
if data['result'] == 'OK'
  other_module.received(data)
  ...
end
 
class OtherModule
  def received(data)
    if data['foo'] == 'bar'
      ...
ResponseData = Struct.new(:result, :foo...)
...
data = JSON.parse(responseText).inject(ResponseData.new) {|s, (k, v)| s[k] = v; s}
if data.result == 'OK'
  othermodule.received(data)
  ...
...
  def received(data)
    if data['foo'] == 'bar'   # 後刻、他の修正と共に、data.fooに修正する
...

ボヘミアンスタイルでJSONを利用している場合

# 未知のプロパティは無視する
data = JSON.parse(responseText).inject(ResponseData.new) do |s, (k, v)| 
  if s.respond_to?(k.to_sym)
    s[k] = v
  end
  s
end

代替

リテラルの代わりに定数を利用する

module ResponseKeys
  RESULT = 'result'.freeze
  ...
end
...
if data[ResponseKeys::RESULT] == 'OK'

定数を使う場合のStructに対する
pros: 特にない。
cons: 冗長。

2019/3/6 追記: とみたさんにStructのコンストラクタ呼出し時にkeyword_initを使うと勝手に属性が設定されるからより簡潔と教わった。ありがとうございます。


2003|06|07|08|09|10|11|12|
2004|01|02|03|04|05|06|07|08|09|10|11|12|
2005|01|02|03|04|05|06|07|08|09|10|11|12|
2006|01|02|03|04|05|06|07|08|09|10|11|12|
2007|01|02|03|04|05|06|07|08|09|10|11|12|
2008|01|02|03|04|05|06|07|08|09|10|11|12|
2009|01|02|03|04|05|06|07|08|09|10|11|12|
2010|01|02|03|04|05|06|07|08|09|10|11|12|
2011|01|02|03|04|05|06|07|08|09|10|11|12|
2012|01|02|03|04|05|06|07|08|09|10|11|12|
2013|01|02|03|04|05|06|07|08|09|10|11|12|
2014|01|02|03|04|05|06|07|08|09|10|11|12|
2015|01|02|03|04|05|06|07|08|09|10|11|12|
2016|01|02|03|04|05|06|07|08|09|10|11|12|
2017|01|02|03|04|05|06|07|08|09|10|11|12|
2018|01|02|03|04|05|06|07|08|09|10|11|12|
2019|01|02|03|04|05|06|07|08|09|10|11|12|
2020|01|02|03|04|05|06|07|08|09|10|11|12|
2021|01|02|03|04|05|06|07|08|09|10|11|12|
2022|01|02|03|04|05|06|07|08|09|10|11|12|
2023|01|02|03|04|05|06|07|08|09|10|11|12|
2024|01|02|03|

ジェズイットを見習え