Upgrade to Pro — share decks privately, control downloads, hide ads and more …

2022 - 默默會 - 重新學習 MVC 的 Model

蒼時弦や
November 01, 2022

2022 - 默默會 - 重新學習 MVC 的 Model

大多數人軟體工程師都學過 MVC 框架,然而 Model 到底是什麼,只是單純對應資料的物件嗎?讓我們從 Domain-Driven Design 的理論基礎之一「模型」來討論 MVC 框架的 Model 是什麼,以及我們該如何使用它。

蒼時弦や

November 01, 2022
Tweet

More Decks by 蒼時弦や

Other Decks in Programming

Transcript

  1. Rails Developer Foundation ver.Open
    Learn Model Again

    View Slide

  2. CONSULTANT × SPEAKER
    蒼時弦也
    YouTube Coding Live Blog https://blog.aotoki.me Discord Discuss about Ruby
    Introduce About Me

    View Slide

  3. Coding Happier About Me
    Senior 60% +10%
    Junior 18% +3%
    Junior 18% +3%
    Avg - 37%
    VS
    Senior 60% +3%
    Junior 18% +15%
    Junior 18% +15%
    Avg - 43%

    View Slide

  4. What we talk about Overview
    What is Model
    What is Model
    How to Modeling
    Case Study

    View Slide

  5. What we talk about Overview
    What is Model
    How to Modeling
    How to Modeling
    Case Study

    View Slide

  6. What we talk about Overview
    What is Model
    How to Modeling
    Case Study
    Case Study

    View Slide

  7. What is Model The Model
    What is Model
    Anyone have can sharing about it?

    View Slide

  8. What is Model The Model
    Float
    100.0
    String
    TWD
    VS Money
    TWD $100.0

    View Slide

  9. What is Model The Model
    Information
    A model is an informative representation of an object, person or system.

    View Slide

  10. What is Model The Model
    Float
    100.0
    String
    TWD
    VS Money
    TWD $100.0
    Which one can “Pay”
    Pay

    View Slide

  11. How to Modeling Modeling
    Modeling
    How to "modeling"

    View Slide

  12. Value Object Modeling
    Data
    Amount=100.0
    +
    Data
    Currency=TWD
    Value
    Composite Value
    Money=TWD,100.0

    View Slide

  13. Value Object Modeling
    class Money

    attr_reader :currency, :amount


    def initialize(currency, amount)

    @currency = currency

    @amount = amount

    end

    end

    View Slide

  14. Entity Modeling
    Value
    ID=1
    +
    Value
    Money
    Entity
    Composite Entity
    ID=1, Balance=Money

    View Slide

  15. Entity Modeling
    class Wallet

    attr_reader :id, :balance


    def initialize(id, balance)

    @id = id

    @balance = balance

    end

    end

    View Slide

  16. Method Modeling
    Entity
    ID=1, Balance=Money
    Deposit(Money) Entity
    ID=1, Balance=Money

    View Slide

  17. Entity Modeling
    class Wallet

    attr_reader :id, :balance


    def initialize(id, balance)

    @id = id

    @balance = balance

    end


    end
    sig { params(amount: Money).returns(Money) }

    def deposit(amount)

    @balance += amount

    end

    View Slide

  18. The Payment App Case Study
    The Payment App
    The usage of “Model” in the real-world

    View Slide

  19. Analytics Case Study
    Customer
    Pay
    Command
    Transfer to Merchant
    System
    Paid
    Event
    Failed
    Event

    View Slide

  20. Analytics Case Study
    Customer
    Pay
    Command
    Transfer to Merchant
    System
    Paid
    Event
    Failed
    Event
    Given threre have a customer “Aotoki”
    And I logged as “Aotoki”

    View Slide

  21. Analytics Case Study
    Customer
    Pay
    Command
    Transfer to Merchant
    System
    Paid
    Event
    Failed
    Event
    When I pay for the merchant “FamilyMart”

    View Slide

  22. Analytics Case Study
    Customer
    Pay
    Command
    Transfer to Merchant
    System
    Paid
    Event
    Failed
    Event
    Then I can see “Pay for FaimlyMart successful”

    View Slide

  23. Analytics Case Study
    Customer
    Pay
    Command
    Transfer to Merchant
    System
    Paid
    Event
    Failed
    Event
    Then I can see “Pay for FaimlyMart failed”

    View Slide

  24. Specs Case Study
    Feature:
    Scenario:
    Given
    And
    And
    When
    Then
    Payment

    Pay to the merchant

    there have a custoemr
    there have a merchant
    I logged as
    I pay for the merchant
    I can see
    “Aotoki”

    “FamilyMart”

    “Aotoki”

    “FamilyMart”

    “Pay for FamilyMart successful”

    View Slide

  25. Specs Case Study
    RSpec.describe do

    describe
    subject
    before do

    end


    it is_expected to have_text
    end

    end
    , type: :request
    do

    { post payment_path, }


    customer = create(:customer, )

    sign_in customer


    create(:merchant, )

    { . ( ) }

    ‘Payment’
    ‘POST /payment’
    merchant_id: ‘fmart’, amount: 100
    name: ‘Aotoki’, balance: 100
    id: ‘fmart’
    ‘Pay for FamilyMart successful’

    View Slide

  26. Specs Case Study
    RSpec.describe do

    describe
    subject
    it is_expected to have_text
    end

    end
    , type: :request
    do

    { post payment_path, }


    { . ( ) }

    ‘Payment’
    ‘POST /payment’
    merchant_id: ‘fmart’, amount: 100
    ‘Pay for FamilyMart successful’

    View Slide

  27. Example Code Case Study
    def create

    render text: ‘Pay for FamilyMart successful’

    end

    View Slide

  28. Example Code Case Study
    class Merchant

    include ActiveModel::Model

    include ActiveModel::Attributes


    attribute :name, :string


    alias_attribute :to_s, :name

    end

    View Slide

  29. Example Code Case Study
    def create

    render text:
    end
    merchant = Merchant.new(name: ‘FamilyMart’)


    “Pay for #{merchant} successful”

    View Slide

  30. Example Code Case Study
    class Customer

    include ActiveModel::Model

    include ActiveModel::Attributes


    attribute :name, :string

    attribute :balance, :integer



    def withdraw(amount)

    raise ArgumentError, ‘insufficient balance’ if amount > self.balance


    self.balance -= amount

    end

    end

    View Slide

  31. Example Code Case Study
    class Merchant

    include ActiveModel::Model

    include ActiveModel::Attributes


    attribute :name, :string

    alias_attribute :to_s, :name


    end
    attribute :balance, :integer


    def deposit(amount)

    self.balance += amount

    end

    View Slide

  32. Example Code Case Study
    def create

    merchant = Merchant.new(name: ‘FamilyMart’)

    render text: “Pay for #{merchant} successful”

    end
    customer = Customer.new(name: ‘Aotoki’, balance: 100)


    payment_amount = params.require(:amount)


    customer.withdraw(payment_amount)

    merchant.deposit(payment_amount)


    View Slide

  33. Example Code Case Study
    class Merchant
    def deposit(amount)

    self.balance += amount

    end

    end
    < ApplicationRecord

    View Slide

  34. Example Code Case Study
    class Customer
    def withdraw(amount)

    raise ArgumentError, ‘insufficient balance’ if amount > self.balance


    self.balance -= amount

    end

    end
    < ApplicationRecord

    View Slide

  35. Example Code Case Study
    def create

    payment_amount = params.require(:amount)


    merchant.deposit(payment_amount)


    render text: “Pay for #{merchant} successful”

    end
    merchant = Merchant.find_by!(id: params[:merchant_id])


    current_customer.withdraw(payment_amount)

    ActiveRecord::Base.transaction do

    merchant.save!

    current_customer.save!

    end


    View Slide

  36. Example Code Case Study
    def create

    merchant = Merchant.find_by!(id: params[:merchant_id])


    payment_amount = params.require(:amount)


    current_customer.withdraw(payment_amount)

    merchant.deposit(payment_amount)


    ActiveRecord::Base.transaction do

    merchant.save!

    current_customer.save!

    end


    render text: “Pay for #{merchant} successful”

    end
    rescue ActiveRecord::RecordInvalid

    render text: “Pay for #{merchant} failed”

    View Slide

  37. Example Code Case Study
    class Money

    include ActiveModel::Model

    include ActiveModel::Attributes


    attribute :value, :integer


    def +(other)

    Money.new(value: self.value + other.value)

    end


    def -(other)

    raise ArgumentError, ‘Money cannot be negative’ if other.value > self.value


    Money.new(value: self.value - other.value)

    end

    end

    View Slide

  38. Example Code Case Study
    class Merchant < ApplicationRecord

    def deposit(amount)

    self.balance += amount

    end

    end
    composed_of :balance,

    class_name: ‘Money’,

    mapping: %[balance value]


    View Slide

  39. Example Code Case Study
    class Customer < ApplicationRecord

    def withdraw(amount)

    self.balance -= amount

    end

    end
    composed_of :balance,

    class_name: ‘Money’,

    mapping: %[balance value]


    View Slide

  40. Example Code Case Study
    def create

    merchant = Merchant.find_by(id: params[:merchant_id])


    current_customer.withdraw(payment_amount)

    merchant.deposit(payment_amount)


    ActiveRecord::Base.transaction do

    merchant.save!

    current_customer.save!

    end


    render text: “Pay for #{merchant} successful”

    rescue ActiveRecord::RecordInvalid

    render text: “Pay for #{merchant} failed”

    end
    payment_amount = Money.new(value: params.require(:amount))


    View Slide

  41. Example Code Case Study
    def create

    merchant = Merchant.new(name: ‘FamilyMart’)


    ActiveRecord::Base.transaction do

    merchant.save!

    current_customer.save!

    end


    render text: “Pay for #{merchant} successful”

    rescue ActiveRecord::RecordInvalid

    render text: “Pay for #{merchant} failed”

    end
    context = BuyingContext.new


    input = PaymentInput.new(params)

    context.pay(to: merchant, from: current_customer, amount: input.amount)


    View Slide

  42. Survey Feedback
    Survey https://www.surveycake.com/s/lbmn9

    View Slide