iT邦幫忙

2021 iThome 鐵人賽

DAY 19
0

Use Case

  • 定義對外唯一的 method call
  • 利用 dry-monads 的特性處理預期及非預期錯誤
  • use case 內利用 steps 拆解每一個步驟,讓程式碼易讀
  • 利用 dry-initializer 讓依賴的元件可被替換,進而使程式碼易測試
require 'dry/monads/all'
require 'wisper'
require 'dry/initializer'

module Boxenn
  class UseCase
    extend Dry::Initializer
    include Wisper::Publisher
    include Dry::Monads
    include Dry::Monads::Do

    def call(*args)
      Success(yield(steps(*args)))
    rescue Dry::Monads::Do::Halt
      raise
    rescue StandardError => e
      Failure.new([e], trace: e.backtrace.first)
    end

    protected

    def steps
      raise NotImplementedError
    end
  end
end

舉個例子

這邊用建立訂單當作例子,假設建立訂單需要驗證訂單及發送行銷信給客戶。

class CreateOrder < Boxenn::UseCase
	option :repo, default: -> { OrderRepository.new }
	option :marketing_client, default: -> { Marketing::Client.new }

	def steps(params:)
		order = build_order(params)
		yield valid_order(order) # 因為回傳是 Dry::Monads::Result 所以需要 yield
		create_order(order)
		send_marketing_email(order.serial_number)
	end

	private

	def build_order(params)
	  OrderEntity.new(params)
	end

	def valid_order(order)
		# 假設 order entity 有個 method valid? 會回傳 Bool 告知是否合法
		return Success() if order.valid?
		
		Failure('Invalid Order')
	end

	def create_order(order)
		repo.save(order)
	end

	def send_marketing_email(serial_number)
		marketing_client.send_purchase_email(order_serial_number: serial_number)
		Success() # 最後一個 call 的 method 需要回傳 Dry::Monads::Result
	end
end
use_case = CreateOrder.new
use_case.call(params: params) # => Success()

下一篇將說明 domain 間的依賴關係,以及 pub-sub pattern 的使用。


上一篇
[DAY18] Use Case 設計概念
下一篇
[DAY20] Domain 間的依賴關係
系列文
在 Ruby on Rails 中導入 Domain-Driven Design 是不是搞錯了什麼?30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言