DRY原則-二重化の過ち
DRY原則
(Don't Repeat Yourself = 繰り返しを避けること)
システム内の二重化を最小限に抑えることを目的としている
DRY原則を破るということは、同じ知識を2箇所以上に記述すること。
この場合、片方を変更するのであれば、もう片方も変更しなければいけなくなる。
開発自体の理解とメンテナンスを容易にする唯一の方法は、DRY原則に従うこと。
「すべての知識はシステム内において単一、かつ明確な、そして信頼できる表現になっていなければならない」
既にあるものを簡単に見つけ出して再利用できるようにし、同じものを何度も作成しないような環境を構築すること
重複しているクエリを修正する
最後の条件だけ違うパターン
共通コード.rb
transaction_arel = Transaction.arel_table
credit_arel = Credit.arel_table
shop_arel = Shop.arel_table
shop_association_arel = ShopAssociation.arel_table
# 条件
condition_shop = ... # ここ
credit = Credit
.joins(:transaction)
.where(credit_arel[:member_id].eq(nil))
.where(condition_shop)
修正前.rb
if sample?
condition_shop = Shop
.joins(:shop_associations)
.where(shop_arel[:identifier].eq(SAMPLE_IDENTIFIER))
.where(shop_association_arel[:shop_id].eq(transaction_arel[:shop_id]))
.exists
else
condition_shop = Shop
.joins(:shop_associations)
.where(shop_arel[:identifier].eq(SAMPLE_IDENTIFIER))
.where(shop_association_arel[:shop_id].eq(transaction_arel[:shop_id]))
.exists.not
end
修正案1.rb
shop = Shop
.joins(:shop_associations)
.where(shop_arel[:identifier].eq(UNIQLOPAY_IDENTIFIER))
.where(shop_association_arel[:shop_id].eq(transaction_arel[:shop_id]))
condition_shop = sample? ? shop.exists : shop.exists.not
修正案2.rb
condition_shop = Shop
.joins(:shop_associations)
.where(shop_arel[:identifier].eq(UNIQLOPAY_IDENTIFIER))
.where(shop_association_arel[:shop_id].eq(transaction_arel[:shop_id]))
.exists
condition_shop = condition_shop.not unless sample?
Shopモデルに対するクエリの定義が重複せず、コードが簡潔になる。
途中の条件が違うパターン
修正前.rb
if sample?
contracts = contract_arel
.project(contract_arel[column_name], contract_arel[:start_date].maximum.as('start_date'))
.group(contract_arel[column_name])
.as('contracts')
else
contracts = contract_arel
.project(contract_arel[column_name], contract_arel[:start_date].maximum.as('start_date'))
.where(contract_arel[:start_date].lteq(target_date))
.group(contract_arel[column_name])
.as('contracts')
end
修正後.rb
contracts = contract_arel.project(contract_arel[column_name], contract_arel[:start_date].maximum.as('start_date'))
contracts = contracts.where(contract_arel[:start_date].lteq(target_date)) unless sample?
contracts = contracts.group(contract_arel[column_name]).as('contracts')
- クエリの定義が重複していない。
- 条件結果の結果に応じてクエリの一部を条件付きで追加している。