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

Value and Record Types

Value and Record Types

Slides from my talk “Better Domain Models with Value and Record Types.”

Henning Schwentner

September 12, 2023
Tweet

More Decks by Henning Schwentner

Other Decks in Programming

Transcript

  1. Starring With vs
    Special Appearances by

    View full-size slide

  2. Java
    old!
    C# ABAP
    PHP
    Python

    View full-size slide

  3. Kolleg:in gesucht
    (Deutschlandweit)

    View full-size slide

  4. Buy it on Amazon.com:
    https://hschwentner.io

    View full-size slide

  5. Photo: Henning Schwentner
    Let me
    tell you a
    story

    View full-size slide

  6. @hschwentner
    Example: A Banking Domain
    bank
    account
    customer
    teller
    computer
    transaction

    View full-size slide

  7. to deposit
    to withdraw
    bank account
    money amount
    IBAN
    to pay interest

    View full-size slide

  8. @hschwentner
    Example: A Banking Domain
    computer
    Banking
    3000

    View full-size slide

  9. @hschwentner
    Software != End in itself

    View full-size slide

  10. @hschwentner
    !
    ! "
    Software is build
    Tech people
    business people
    #
    "
    for
    for by

    View full-size slide

  11. Software
    Domain

    View full-size slide

  12. Foto: Rosie the Riveter/Wikimedia/CC-PD-Mark

    View full-size slide

  13. @hschwentner
    Programming is
    Model Building

    View full-size slide

  14. @hschwentner
    Rules of thumb:

    View full-size slide

  15. Objects from real world
    turn into
    objects in software

    View full-size slide

  16. Actions from real world
    turn into
    operations in software

    View full-size slide

  17. =>
    Object-orientation

    View full-size slide

  18. Object-Oriented Programming
    Ole-Johan
    Dahl
    Photo: Stein Krogdahl, University of Oslo
    Kristen
    Nygaard
    Photo: Jorge Stolfi/Wikipedia
    !

    View full-size slide

  19. Photo: P. Campbell/Wikipedia
    Alan Kay
    Everything is
    an object
    "

    View full-size slide

  20. Foto: P. Campbell/Wikipedia
    James
    Gosling
    Everything is
    an object
    #

    View full-size slide

  21. Anders
    Hejlsberg
    Everything is
    an object

    View full-size slide

  22. Are those objects?

    View full-size slide

  23. @hschwentner
    In the real world
    not
    everything is an object

    View full-size slide

  24. @hschwentner
    Domain-Driven Design
    Eric
    Evans
    "
    Entity
    Value Object
    Aggregate
    Service
    Factory
    Repository

    View full-size slide

  25. @hschwentner
    Entity vs. Value

    View full-size slide

  26. Foto: P. Campbell/Wikipedia
    James
    Gosling
    Everything is
    an object
    int
    short
    long
    byte
    char
    float
    double
    boolean
    … except:

    View full-size slide

  27. Anders
    Hejlsberg
    Everything is
    an object
    …except
    structs

    View full-size slide

  28. Values from real world
    turn into
    values in software

    View full-size slide

  29. @hschwentner
    What is an
    object/entity?

    View full-size slide

  30. Foto: Th.omas G.Graf/Wikipedia
    oto: H. Schwentner

    View full-size slide

  31. Grafik: Pixabay

    View full-size slide

  32. Foto: Bernd Schwabe in Hannover/Wikipedia

    View full-size slide

  33. @hschwentner
    Object:
    *Identity
    *Lifecycle
    *(mutable) state

    View full-size slide

  34. @hschwentner
    What is a value?

    View full-size slide

  35. Grafik: Public Domain/Pixabay

    View full-size slide

  36. Foto: A. Markiewicz

    View full-size slide

  37. @hschwentner

    View full-size slide

  38. @hschwentner
    Value:
    *No identity
    *immutable

    View full-size slide

  39. @hschwentner
    Example

    View full-size slide

  40. Foto: Bibi Saint-Pol/Wikipedia

    View full-size slide

  41. @hschwentner
    Objects in Languages
    like Java or C#

    View full-size slide

  42. Foto: Tiia Monto/Wikipedia

    View full-size slide

  43. @hschwentner
    Identity of an Object

    View full-size slide

  44. @hschwentner
    Values in Languages
    like Java or C#

    View full-size slide

  45. built-in value types
    primitive types
    simple types

    View full-size slide

  46. int
    boolean/bool
    double
    char

    View full-size slide

  47. User-defined value types

    View full-size slide

  48. LocalDate/DateTime
    String

    View full-size slide

  49. object types that behave like
    value types
    value-based class
    (class with)
    value equality

    View full-size slide

  50. @hschwentner
    Values in Java

    View full-size slide

  51. int
    boolean
    double
    char

    View full-size slide

  52. unsigned
    complex

    View full-size slide

  53. iban
    postcode
    amount

    View full-size slide

  54. Foto: Public Domain/Pixabay

    View full-size slide

  55. Grafik: Gemeinfrei/Wikipedia

    View full-size slide

  56. value-based class

    View full-size slide

  57. @hschwentner
    Only final
    fields

    View full-size slide

  58. @hschwentner
    No
    state-changing
    methods

    View full-size slide

  59. @hschwentner
    equals()
    does not depend on
    identity

    View full-size slide

  60. value-based class
    <= 13

    View full-size slide

  61. LocalDate
    String

    View full-size slide

  62. record:
    all fields final
    field-based equal()
    [and hashCode()]
    getters for all fields
    >= 16

    View full-size slide

  63. value type
    >= ??

    View full-size slide

  64. @hschwentner
    Values in C#

    View full-size slide

  65. int
    bool
    double
    char

    View full-size slide

  66. struct
    <= 7.1

    View full-size slide

  67. @hschwentner
    Only readonly
    fields

    View full-size slide

  68. @hschwentner
    No
    state-changing
    methods

    View full-size slide

  69. readonly struct
    >= 7.2

    View full-size slide

  70. @hschwentner
    equals() !
    == "

    View full-size slide

  71. @hschwentner
    Value equality

    View full-size slide

  72. @hschwentner
    equals() !
    == !

    View full-size slide

  73. @hschwentner
    Beware: Can be mutable

    View full-size slide

  74. @hschwentner
    On the heap

    View full-size slide

  75. record struct
    <= 10

    View full-size slide

  76. @hschwentner
    Beware: Is mutable

    View full-size slide

  77. readonly record struct
    <= 10
    !

    View full-size slide

  78. @hschwentner
    Why aren’t int and
    string enough?

    View full-size slide

  79. @hschwentner
    Objects/Entities in Java

    Example

    View full-size slide

  80. public class Account {
    }

    View full-size slide

  81. import org.jmolecules.ddd.annotation.Entity;
    @Entity
    public class Account {
    }

    View full-size slide

  82. @Entity
    public class Account {
    private int _balance;
    public int getBalance() {
    return _balance;
    }
    public void setBalance(int balance) {
    _balance = balance;
    }
    }

    Bad: The account
    balance can be set
    to any value

    View full-size slide

  83. @Entity
    public class Account {
    private int _balance;
    public int balance() {
    return _balance;
    }
    public void deposit(int amount) {
    _balance += amount;
    }
    public void withdraw(int amount) {
    _balance -= amount;
    }
    Better: Operations
    with domain-
    specific behavior
    and names

    View full-size slide

  84. @Entity
    public class Account {
    private int _balance;
    public int balance() {
    return _balance;
    }
    public void deposit(int amount) {
    _balance += amount;
    }
    public void withdraw(int amount) {
    if (amount > balance()) {
    throw new IllegalArgumentException("Amount too big");
    Even better:
    Preconditions can
    be checked

    View full-size slide

  85. @Entity
    public class Account {
    // ...
    public void withdraw(int amount) {
    assert amount <= balance();
    _balance -= amount;
    }
    } Assertion using
    keyword assert

    View full-size slide

  86. GREAT, BUT…
    @Entity
    public class Account {
    // ...
    public void withdraw(int amount) {
    assert amount <= balance();
    _balance -= amount;
    }
    } Can I withdraw a
    negative amount?
    In EUR or GBP
    or…?

    View full-size slide

  87. @hschwentner
    Values in Java

    Example

    View full-size slide

  88. public class Amount {
    }

    View full-size slide

  89. import org.jmolecules.ddd.annotation.ValueObject;
    @ValueObject
    public class Amount {
    }

    View full-size slide

  90. @ValueObject
    public class Amount {
    private int _amount;
    private Currency _currency;
    }

    View full-size slide

  91. @ValueObject
    public class Amount {
    private final int _amount;
    private final Currency _currency;
    }

    View full-size slide

  92. @ValueObject
    public class Amount {
    private final int _amount;
    private final Currency _currency;
    public Amount(int amount, Currency currency) {
    _amount = amount;
    _currency = currency;
    }
    }

    View full-size slide

  93. @ValueObject
    public class Amount {
    private final int _amount;
    private final Currency _currency;
    private Amount(int amount, Currency currency) {
    _amount = amount;
    _currency = currency;
    }
    public static Amount of(int amount, Currency currency) {
    return new Amount(amount, currency);
    }
    }

    View full-size slide

  94. @ValueObject
    public class Amount {
    private final int _amount;
    private final Currency _currency;
    public Amount(int amount, Currency currency) {
    _amount = amount;
    _currency = currency;
    }
    @Override
    public boolean equals(Object other) {
    return _amount == ((Amount) other)._amount
    && _currency.equals(((Amount) other)._currency);
    }

    View full-size slide

  95. @ValueObject
    public class Amount {
    private final int _amount;
    private final Currency _currency;
    public Amount(int amount, Currency currency) {
    _amount = amount;
    _currency = currency;
    }
    @Override
    public boolean equals(Object other) {
    return _amount == ((Amount) other)._amount
    && _currency.equals(((Amount) other)._currency);
    }

    View full-size slide

  96. @ValueObject
    public record Amount(int amount, Currency currency) {}

    View full-size slide

  97. @ValueObject
    public class Amount {
    private final int _amount;
    private final Currency _currency;
    public Amount(int amount, Currency currency) {
    _amount = amount;
    _currency = currency;
    }
    public Amount add(Amount otherAmount) {
    return Amount.of(_amount + otherAmount._amount, _currency);
    }
    }
    Der neue Typ hat
    richtiges fachliches
    Verhalten

    View full-size slide

  98. @ValueObject
    public class Amount {
    private final int _amount;
    private final Currency _currency;
    public Amount(int amount, Currency currency) {
    _amount = amount;
    _currency = currency;
    }
    public Amount add(Amount otherAmount) {
    assert hasSameCurrency(otherAmount);
    return Amount.of(_amount + otherAmount._amount, _currency);
    }
    … und Verträge, die
    vor falschen
    Währungen
    schützen

    View full-size slide

  99. @ValueObject
    public record Amount(int amount, Currency currency) {
    public Amount add(Amount otherAmount) {
    assert hasSameCurrency(otherAmount);
    return new Amount(amount + otherAmount.amount(), currency);
    }
    public boolean hasSameCurrency(Amount otherAmount) {
    return otherAmount.currency() == currency;
    }
    }

    View full-size slide

  100. @hschwentner
    Values in C#

    Example

    View full-size slide

  101. public class Amount
    {
    }

    View full-size slide

  102. using NMolecules.DDD;
    [ValueObject]
    public class Amount
    {
    }

    View full-size slide

  103. [ValueObject]
    public class Amount
    {
    private readonly int _amount;
    private readonly Currency _currency;
    }

    View full-size slide

  104. [ValueObject]
    public class Amount
    {
    private int _amount;
    private Currency _currency;
    }

    View full-size slide

  105. [ValueObject]
    public class Amount
    {
    private readonly int _amount;
    private readonly Currency _currency;
    public Amount(int amount, Currency currency)
    {
    _amount = amount;
    _currency = currency;
    }
    }

    View full-size slide

  106. [ValueObject]
    public class Amount
    {
    private readonly int _amount;
    private readonly Currency _currency;
    // ...
    public override bool Equals(object other)
    {
    return other is Amount
    && _amount == ((Amount) other)._amount
    && _currency.Equals(((Amount) other)._currency);
    }
    }

    View full-size slide

  107. [ValueObject]
    public class Amount
    {
    private readonly int _amount;
    private readonly Currency _currency;
    // ...
    public override bool Equals(object other)
    => other is Amount
    && _amount == ((Amount) other)._amount
    && _currency.Equals(((Amount) other)._currency);
    }

    View full-size slide

  108. [ValueObject]
    public class Amount
    {
    private readonly int _amount;
    private readonly Currency _currency;
    // ...
    public override bool Equals(object other)
    => other is Amount
    && _amount == ((Amount) other)._amount
    && _currency.Equals(((Amount) other)._currency);
    // GetHashCode()
    }

    View full-size slide

  109. [ValueObject]
    public class Amount
    {
    private readonly int _amount;
    private readonly Currency _currency;
    // ...
    public static bool operator ==(Amount a, Amount b) => a.Equals(b);
    }

    View full-size slide

  110. [ValueObject]
    public class Amount
    {
    private readonly int _amount;
    private readonly Currency _currency;
    // ...
    public static bool operator ==(Amount a, SignDate b) => a.Equals(b);
    public static bool operator !=(Amount a, SignDate b) => !a.Equals(b);
    }

    View full-size slide

  111. [ValueObject]
    public struct Amount
    {
    private readonly int _amount;
    private readonly Currency _currency;
    public Amount(int amount, Currency currency)
    {
    _amount = amount;
    _currency = currency;
    }
    }

    View full-size slide

  112. [ValueObject]
    public struct Amount
    {
    private readonly int _amount;
    private readonly Currency _currency;
    public Amount(int amount, Currency currency)
    {
    _amount = amount;
    _currency = currency;
    }
    // Equals() does not have to be overridden
    }

    View full-size slide

  113. [ValueObject]
    public struct Amount
    {
    private readonly int _amount;
    private readonly Currency _currency;
    public Amount(int amount, Currency currency)
    {
    _amount = amount;
    _currency = currency;
    }
    // but the operators have to be overridden
    }

    View full-size slide

  114. @hschwentner
    equals() !
    == "

    View full-size slide

  115. [ValueObject]
    public record Amount(int amount, Currency currency);

    View full-size slide

  116. [ValueObject]
    public record Amount(int amount, Currency currency);
    // automatically readonly
    // Equals(), GetHashCode(), ToString(), operators
    // do not have to be overloaded and work as expected

    View full-size slide

  117. [ValueObject]
    public record struct Amount(int amount, Currency currency);

    View full-size slide

  118. [ValueObject]
    public readonly record struct Amount(int amount, Currency currency);

    View full-size slide

  119. @hschwentner
    Values in Java

    Example continued

    View full-size slide

  120. @hschwentner
    equals() !
    == "

    View full-size slide

  121. by reference

    View full-size slide

  122. @hschwentner
    A
    Concrete
    Example

    View full-size slide

  123. @hschwentner
    LeasingNinja
    https://leasingninja.io

    View full-size slide

  124. @hschwentner
    Conclusion

    View full-size slide

  125. @hschwentner
    Key take aways:
    *value/object are different
    *only records yet
    * value types are still to come
    (*domain model and
    performance)

    View full-size slide

  126. Bild: Gemeinfrei

    View full-size slide

  127. @hschwentner
    Further Reading

    View full-size slide

  128. project valhalla

    View full-size slide

  129. https://domainstorytelling.org

    View full-size slide

  130. Workshop
    Domain-Driven Design concrete
    wps.de/ddd

    View full-size slide

  131. Bibliography
    Beck, Kent et al. Manifesto for Agile Software Development. 2001.
    Evans, Eric. Domain-Driven Design: Tackling Complexity in the Heart of Software. Boston: Addison-Wesley, 2004.
    Hofer, Stefan and Henning Schwentner. Domain Storytelling: a Collaborative, Visual, and Agile Way to Develop Domain-
    Driven Software. Boston: Addison-Wesley, 2022.

    View full-size slide

  132. Henning Schwentner
    ⌂ https://hschwentner.io
    @hschwentner
    [email protected]
    Kolleg:in gesucht
    (Deutschlandweit)

    View full-size slide