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

June 29, 2023
Tweet

More Decks by Henning Schwentner

Other Decks in Programming

Transcript

  1. Starring With vs
    Special Appearances by

    View Slide

  2. View Slide

  3. View Slide

  4. Kolleg:in gesucht
    (Deutschlandweit)

    View Slide

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

    View Slide

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

    View Slide

  7. View Slide

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

    View Slide

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

    View Slide

  10. View Slide

  11. @hschwentner
    So!ware != End in itself

    View Slide

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

    View Slide

  13. View Slide

  14. Software
    Domäne

    View Slide

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

    View Slide

  16. @hschwentner
    Programming is
    Model Building

    View Slide

  17. @hschwentner
    Rules of thumb:

    View Slide

  18. Objects from real world
    turn into
    objects in so!ware

    View Slide

  19. View Slide

  20. Actions from real world
    turn into
    operations in software

    View Slide

  21. View Slide

  22. =>
    Object-orientation

    View Slide

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

    View Slide

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

    View Slide

  25. View Slide

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

    View Slide

  27. Anders
    Hejlsberg
    Everything is
    an object

    View Slide

  28. Are those objects?

    View Slide

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

    View Slide

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

    View Slide

  31. @hschwentner
    Entity vs. Value

    View Slide

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

    View Slide

  33. Anders
    Hejlsberg
    Everything is
    an object
    …except
    structs

    View Slide

  34. Values from real world
    turn into
    values in software

    View Slide

  35. View Slide

  36. @hschwentner
    What is an object/entity?

    View Slide

  37. View Slide

  38. Identity

    View Slide

  39. View Slide

  40. View Slide

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

    View Slide

  42. Grafik: Pixabay

    View Slide

  43. Foto: Bernd Schwabe in Hannover/Wikipedia

    View Slide

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

    View Slide

  45. @hschwentner
    What is a value?

    View Slide

  46. Grafik: Public Domain/Pixabay

    View Slide

  47. Foto: A. Markiewicz

    View Slide

  48. View Slide

  49. @hschwentner

    View Slide

  50. @hschwentner
    Value:
    *No identity
    *immutable

    View Slide

  51. @hschwentner
    Example

    View Slide

  52. %
    &
    '

    View Slide

  53. View Slide

  54. '

    View Slide

  55. '
    '

    View Slide

  56. View Slide

  57. %
    &
    '

    View Slide

  58. '
    '
    &
    '
    &
    '

    View Slide

  59. View Slide

  60. Foto: Bibi Saint-Pol/Wikipedia

    View Slide

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

    View Slide

  62. View Slide

  63. View Slide

  64. View Slide

  65. View Slide

  66. View Slide

  67. Foto: Tiia Monto/Wikipedia

    View Slide

  68. View Slide

  69. View Slide

  70. View Slide

  71. View Slide

  72. View Slide

  73. View Slide

  74. @hschwentner
    Identity of an Object

    View Slide

  75. 3

    View Slide

  76. 3
    3

    View Slide

  77. 3

    View Slide

  78. @hschwentner
    Where does an object
    live actually?

    View Slide

  79. View Slide

  80. View Slide

  81. View Slide

  82. View Slide

  83. View Slide

  84. View Slide

  85. View Slide

  86. compile time

    View Slide

  87. View Slide

  88. run time

    View Slide

  89. @hschwentner
    Where does an object
    live actually?

    View Slide

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

    View Slide

  91. built-in value types
    primitive types
    simple types

    View Slide

  92. int
    boolean/bool
    double
    char

    View Slide

  93. @hschwentner
    Where does such a value
    live actually?

    View Slide

  94. 3

    View Slide

  95. 3
    3

    View Slide

  96. View Slide

  97. User-defined value types

    View Slide

  98. LocalDate/DateTime
    String

    View Slide

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

    View Slide

  100. @hschwentner
    Values in Java

    View Slide

  101. int
    boolean
    double
    char

    View Slide

  102. unsigned
    complex

    View Slide

  103. iban
    postcode
    amount

    View Slide

  104. Foto: Public Domain/Pixabay

    View Slide

  105. Grafik: Gemeinfrei/Wikipedia

    View Slide

  106. value-based class

    View Slide

  107. @hschwentner
    Only final
    fields

    View Slide

  108. @hschwentner
    No
    state-changing
    methods

    View Slide

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

    View Slide

  110. value-based class
    <= 13

    View Slide

  111. LocalDate
    String

    View Slide

  112. record
    >= 14

    View Slide

  113. value type
    >= ??

    View Slide

  114. @hschwentner
    Values in C#

    View Slide

  115. int
    bool
    double
    char

    View Slide

  116. struct
    <= 7.1

    View Slide

  117. @hschwentner
    Only readonly
    fields

    View Slide

  118. @hschwentner
    No
    state-changing
    methods

    View Slide

  119. readonly struct
    >= 7.2

    View Slide

  120. @hschwentner
    equals() !
    == "

    View Slide

  121. record
    <= 9

    View Slide

  122. @hschwentner
    Value equality

    View Slide

  123. @hschwentner
    equals() !
    == !

    View Slide

  124. @hschwentner
    Beware: Can be mutable

    View Slide

  125. @hschwentner
    On the heap

    View Slide

  126. record struct
    <= 10

    View Slide

  127. @hschwentner
    Beware: Is mutable

    View Slide

  128. readonly record struct
    <= 10
    !

    View Slide

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

    View Slide

  130. @hschwentner
    Objects/Entities in Java

    Example

    View Slide

  131. public class Account {
    }

    View Slide

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

    View Slide

  133. @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 Slide

  134. @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 Slide

  135. @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 Slide

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

    View Slide

  137. 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 Slide

  138. @hschwentner
    Values in Java

    Example

    View Slide

  139. public class Amount {
    }

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  144. @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 Slide

  145. @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 Slide

  146. @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 Slide

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

    View Slide

  148. @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 Slide

  149. @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 Slide

  150. @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 Slide

  151. @hschwentner
    Values in C#

    Example

    View Slide

  152. public class Amount
    {
    }

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  157. [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 Slide

  158. [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 Slide

  159. [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 Slide

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

    View Slide

  161. [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 Slide

  162. View Slide

  163. 3

    View Slide

  164. 3

    View Slide

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

    View Slide

  166. [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 Slide

  167. [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 Slide

  168. @hschwentner
    equals() !
    == "

    View Slide

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

    View Slide

  170. [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 Slide

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

    View Slide

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

    View Slide

  173. @hschwentner
    Values in Java

    Example continued

    View Slide

  174. But

    View Slide

  175. 3
    3

    View Slide

  176. @hschwentner
    equals() !
    == "

    View Slide

  177. View Slide

  178. 3

    View Slide

  179. by value

    View Slide

  180. by reference

    View Slide

  181. 3

    View Slide

  182. View Slide

  183. Memory*2

    View Slide

  184. 3

    View Slide

  185. 3

    View Slide

  186. View Slide

  187. View Slide

  188. int[]

    View Slide

  189. 3 5 10 5 0

    View Slide

  190. Object[]

    View Slide

  191. 3 5 10 5 0

    View Slide

  192. 3
    10 5
    0

    View Slide

  193. @hschwentner
    A
    Concrete
    Example

    View Slide

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

    View Slide

  195. @hschwentner
    Conclusion

    View Slide

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

    View Slide

  197. Bild: Gemeinfrei

    View Slide

  198. @hschwentner
    Further Reading

    View Slide

  199. project valhalla

    View Slide

  200. https://domainstorytelling.org

    View Slide

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

    View Slide

  202. View Slide

  203. View Slide

  204. View Slide

  205. View Slide

  206. 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 Slide

  207. View Slide

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

    View Slide