SlideShare ist ein Scribd-Unternehmen logo
1 von 136
Downloaden Sie, um offline zu lesen
Domain Modeling
Made Functional
(DevTernity 2022)
@ScottWlaschin
fsharpforfunandprofit.com
Functional programming:
what is it good for?
• Mathematical things only
Functional programming:
what is it good for?
• Mathematical things only
• Interactive & collaborative domain modeling
• Representing a domain model accurately
Functional
Programming
Domain
Driven
Design
Part I
The importance of design
Input Output
Process
The software development process
Input Output
Process
The software development process
Input Output
Process
Garbage in Garbage out
The software development process
Input Output
Process
(reduce) Garbage in (reduced) Garbage out
The software development process
• Borrow from Agile and DDD
• Agile contribution:
– Rapid feedback during design
• DDD contribution:
– Stakeholders have a shared mental model
– …which is also represented in the code
How can we do design right?
Can you really make code
represent the domain?
What non-developers think source code looks like
and some C developers!
module CardGame =
type Suit = Club | Diamond | Spade | Heart
type Rank =Two |Three | Four | Five | Six | Seven | Eight
| Nine |Ten | Jack | Queen | King
type Card = Suit * Rank
type Hand = Card list
type Deck = Card list
type Player = { Name:string; Hand:Hand }
type Game = { Deck:Deck; Players: Player list }
type Deal = Deck –› (Deck * Card)
type PickupCard = (Hand * Card) –› Hand
Shared
language What DDD source code should look like
module CardGame =
type Suit = Club | Diamond | Spade | Heart
type Rank =Two |Three | Four | Five | Six | Seven | Eight
| Nine |Ten | Jack | Queen | King
type Card = Suit * Rank
type Hand = Card list
type Deck = Card list
type Player = { Name:string; Hand:Hand }
type Game = { Deck:Deck; Players: Player list }
type Deal = Deck –› (Deck * Card)
type PickupCard = (Hand * Card) –› Hand
* means a pair. Choose one from each type
list type is built in
Deal
(original)
Deck
(remaining)
Deck
(on table)
Card
Modeling an action with a function
type Deal = Deck -> (Deck * Card)
Input Output
Pickup Card
(updated)
Hand
(original)
Hand
(on table)
Card
Modeling an action with a function
type PickupCard = (Hand * Card) –> Hand
Input Output
module CardGame =
type Suit = Club | Diamond | Spade | Heart
type Rank =Two |Three | Four | Five | Six | Seven | Eight
| Nine |Ten | Jack | Queen | King
type Card = Suit * Rank
type Hand = Card list
type Deck = Card list
type Player = { Name:string; Hand:Hand }
type Game = { Deck:Deck; Players: Player list }
type Deal = Deck –› (Deck * Card)
type PickupCard = (Hand * Card) –› Hand
module CardGame =
type Suit = Club | Diamond | Spade | Heart
type Rank =Two |Three | Four | Five | Six | Seven | Eight
| Nine |Ten | Jack | Queen | King
type Card = Suit * Rank
type Hand = Card list
type Deck = Card list
type Player = { Name:string; Hand:Hand }
type Game = { Deck:Deck; Players: Player list }
type Deal = Deck –› (Deck * Card)
type PickupCard = (Hand * Card) –› Hand
module CardGame =
type Suit = Club | Diamond | Spade | Heart
type Rank =Two |Three | Four | Five | Six | Seven | Eight
| Nine |Ten | Jack | Queen | King
type Card = Suit * Rank
type Hand = Card list
type Deck = Card list
type Player = { Name:string; Hand:Hand }
type Game = { Deck:Deck; Players: Player list }
type Deal = Deck –› (Deck * Card)
type PickupCard = (Hand * Card) –› Hand
Can non-programmers provide
useful feedback?
Rapid feedback during
the design stage
Building a shared mental model is an
interactive process
...
type Deck = Card list
type Deal = Deck –› (Deck * Card)
...
type Deck = Card list
type Deal = ShuffledDeck –› (ShuffledDeck * Card)
...
type Deck = Card list
type Deal = ShuffledDeck –› (ShuffledDeck * Card)
type ShuffledDeck = Card list
...
type Deck = Card list
type Deal = ShuffledDeck –› (ShuffledDeck * Card)
type ShuffledDeck = Card list
type Shuffle = Deck –› ShuffledDeck
...
type Deck = Card list
type Deal = ShuffledDeck –› (ShuffledDeck * Card)
type ShuffledDeck = Card list
type Shuffle = Deck –› ShuffledDeck
Final version of the domain
module CardGame =
type Suit = Club | Diamond | Spade | Heart
type Rank = Two |Three | Four | Five | Six | Seven | Eight | ...
type Card = Suit * Rank
type Hand = Card list
type Deck = Card list
type Player = { Name:string; Hand:Hand }
type Game = { Deck:Deck; Players: Player list }
type Deal = ShuffledDeck –› (ShuffledDeck * Card)
type ShuffledDeck = Card list
type Shuffle = Deck –› ShuffledDeck
type PickupCard = (Hand * Card) –› Hand
module CardGame =
type Suit = Club | Diamond | Spade | Heart
type Rank = Two |Three | Four | Five | Six | Seven | Eight | ...
type Card = Suit * Rank
type Hand = Card list
type Deck = Card list
type Player = { Name:string; Hand:Hand }
type Game = { Deck:Deck; Players: Player list }
type Deal = ShuffledDeck –› (ShuffledDeck * Card)
type ShuffledDeck = Card list
type Shuffle = Deck –› ShuffledDeck
type PickupCard = (Hand * Card) –› Hand
In the real world
Suit
Rank
Card
Hand
Deck
Player
Deal
In the code
Suit
Rank
Card
Hand
Deck
Player
Deal
In the real world
Suit
Rank
Card
Hand
Deck
Player
Deal
In the code
Suit
Rank
Card
Hand
Deck
Player
Deal
ShuffledDeck
Shuffle
ShuffledDeck
Shuffle

In the real world
Suit
Rank
Card
Hand
Deck
Player
Deal
In the code
Suit
Rank
Card
Hand
Deck
Player
Deal
PlayerController
DeckBase
AbstractCardProxyFactoryBean

module CardGame =
type Suit = Club | Diamond | Spade | Heart
type Rank = Two |Three | Four | Five | Six | Seven | Eight | ...
type Card = Suit * Rank
type Hand = Card list
type Deck = Card list
type Player = { Name:string; Hand:Hand }
type Game = { Deck:Deck; Players: Player list }
type Deal = ShuffledDeck –› (ShuffledDeck * Card)
type ShuffledDeck = Card list
type Shuffle = Deck –› ShuffledDeck
type PickupCard = (Hand * Card) –› Hand
module CardGame =
type Suit = Club | Diamond | Spade | Heart
type Rank = Two |Three | Four | Five | Six | Seven | Eight | ...
type Card = Suit * Rank
type Hand = Card list
type Deck = Card list
type Player = { Name:string; Hand:Hand }
type Game = { Deck:Deck; Players: Player list }
type Deal = ShuffledDeck –› (ShuffledDeck * Card)
type ShuffledDeck = Card list
type Shuffle = Deck –› ShuffledDeck
type PickupCard = (Hand * Card) –› Hand
Again: The process of building the
shared mental model is critical!
Collaboration!
Key DDD principle:
Communicate the design
in the code
A domain modeling challenge!
type Contact = {
FirstName: string
MiddleInitial: string
LastName: string
EmailAddress: string
IsEmailVerified: bool
} // true if ownership of
// email address is confirmed
type Contact = {
FirstName: string
MiddleInitial: string
LastName: string
EmailAddress: string
IsEmailVerified: bool
}
Prologue: which values are optional?
type Contact = {
FirstName: string
MiddleInitial: string
LastName: string
EmailAddress: string
IsEmailVerified: bool
}
Prologue: what are the constraints?
type Contact = {
FirstName: string
MiddleInitial: string
LastName: string
EmailAddress: string
IsEmailVerified: bool
}
Prologue: domain logic?
Prologue: F# can help
type Contact = {
FirstName: string
MiddleInitial: string
LastName: string
EmailAddress: string
IsEmailVerified: bool
}
Prologue: F# can help
type Contact = {
FirstName: string
MiddleInitial: string
LastName: string
EmailAddress: string
IsEmailVerified: bool
}
Part II
Understanding FP type systems
FP principle:
Composition everywhere
Composition = Make big things from small things
Algebraic type system
New types are built from smaller types by:
Composing with “AND”
Composing with “OR”
All languages have this.
Example: pairs, tuples, records
FruitSalad = One each of and and
Compose with “AND”
type FruitSalad = {
Apple: AppleVariety
Banana: BananaVariety
Cherry: CherryVariety
}
Snack = or or
Compose with “OR”
type Snack =
| Apple of AppleVariety
| Banana of BananaVariety
| Cherry of CherryVariety
A real world example
of composing types
Some requirements:
We accept three forms of payment:
Cash, PayPal, or Card.
For Cash we don't need any extra information
For PayPal we need a email address
For Cards we need a card type and card number
interface IPaymentMethod
{..}
class Cash() : IPaymentMethod
{..}
class PayPal(string emailAddress): IPaymentMethod
{..}
class Card(string cardType, string cardNo) : IPaymentMethod
{..}
In OO design you would probably implement it as an
interface and a set of subclasses, like this:
type EmailAddress = string
type CardNumber = string
In FP you would probably implement by
composing types, like this:
type EmailAddress = ...
type CardNumber = …
type CardType = Visa | Mastercard
type CreditCardInfo = {
CardType : CardType
CardNumber : CardNumber
}
type EmailAddress = ...
type CardNumber = ...
type CardType = ...
type CreditCardInfo = ...
type PaymentMethod =
| Cash
| PayPal of EmailAddress
| Card of CreditCardInfo
type EmailAddress = ...
type CardNumber = ...
type CardType = ...
type CreditCardInfo = ...
type PaymentMethod =
| Cash
| PayPal of EmailAddress
| Card of CreditCardInfo
type EmailAddress = ...
type CardNumber = ...
type CardType = ...
type CreditCardInfo = ...
type PaymentMethod =
| Cash
| PayPal of EmailAddress
| Card of CreditCardInfo
type PaymentAmount = decimal
type Currency = EUR | USD
type EmailAddress = ...
type CardNumber = ...
type CardType = ...
type CreditCardInfo = ...
type PaymentMethod =
| Cash
| PayPal of EmailAddress
| Card of CreditCardInfo
type PaymentAmount = decimal
type Currency = EUR | USD
type Payment = {
Amount : PaymentAmount
Currency : Currency
Method : PaymentMethod }
type EmailAddress = ...
type CardNumber = ...
type CardType = ...
type CreditCardInfo = ...
type PaymentMethod =
| Cash
| PayPal of EmailAddress
| Card of CreditCardInfo
type PaymentAmount = decimal
type Currency = EUR | USD
type Payment = {
Amount : PaymentAmount
Currency : Currency
Method : PaymentMethod }
Part III
Domain modeling
with composable types
type Contact = {
FirstName: string
MiddleInitial: string
LastName: string
EmailAddress: string
IsEmailVerified: bool
} // true if ownership of
// email address is confirmed
This looks suspiciously like
database-driven design...
type Contact = {
Name: PersonalName
Email: EmailContactInfo }
"A contact has a name AND email info"
"Like this?..."
type Contact = {
Name: PersonalName
Email: EmailContactInfo }
"A contact has a name AND email info"
We have two new concepts already!
type PersonalName = {
FirstName: string
MiddleInitial: string
LastName: string
}
"What's a personal name?"
type PersonalName = {
FirstName: string
MiddleInitial: string
LastName: string
}
required
required
optional
"What's required or optional?"
Modeling
optional values
Null is not the same as “optional”
Length
string –› int
“a”
“b”
“c”
1
2
3
“a”
“b”
“c”
null
Null is not the same as “optional”
Length
string –› int
“a”
“b”
“c”
null
1
2
3
Null is not allowed
Length
string –› int
“a”
“b”
“c”
null
1
2
3
X
A better way for optional values
+
=
“a”
“b”
“c”
“a”
“b”
“c”
missing
or
Tag with “Nothing”
type OptionalString =
| SomeString of string
| Nothing
type OptionalInt =
| SomeInt of int
| Nothing
type OptionalString =
| SomeString of string
| Nothing
type OptionalBool =
| SomeBool of bool
| Nothing
Defining optional types
type Option<'T> =
| Some of 'T
| None
type Option<'T> =
| Some of 'T
| None
type PersonalName = {
FirstName: string
MiddleInitial: Option<string>
LastName: string
}
type PersonalName = {
FirstName: string
MiddleInitial: string option
LastName: string
}
Modeling simple values and
constrained values
Modeling simple values
• Avoid "Primitive Obsession"
• Simple values should not be modelled with
primitive types like "int" or "string" or "float"
"Does 'float' have
something to do
with water?"
Modeling constrained values
• It's rare to have an unconstrained int or string:
– An EmailAddress must not be empty,
it must match a pattern
– A PhoneNumber must not be empty,
it must match a pattern
– A CustomerId must be a positive integer
Is an EmailAddress just a string? No!
Is a CustomerId just a int? No!
type EmailAddress = EmailAddress of string
Use wrapper types to keep domain concepts
distinct from their representation
type CustomerId = CustomerId of int
type String50 = String50 of string
type EmailAddress = EmailAddress of string
type PhoneNumber = PhoneNumber of string
type CustomerId = CustomerId of int
type OrderId = OrderId of int
Two benefits:
- Clearer domain modelling
- Can't mix them up accidentally
Implementing constructors
for constrained types
let createEmailAddress (s:string) =
if s.Contains("@")
then (EmailAddress s)
else ?
createEmailAddress:
string –› EmailAddress
let createEmailAddress (s:string) =
if s.Contains("@")
then Some (EmailAddress s)
else None
createEmailAddress:
string –› EmailAddress option
type String50 = String50 of string
let createString50 (s:string) =
if s.Length <= 50
then Some (String50 s)
else None
createString50 :
string –› String50 option
+
– 999999
Qty: Add To Cart
type OrderLineQty = OrderLineQty of int
let createOrderLineQty qty =
if qty > 0 && qty <= 99
then Some (OrderLineQty qty)
else None
createOrderLineQty:
int –› OrderLineQty option
The "Contact" challenge,
after first refactor
type Contact = {
FirstName: string
MiddleInitial: string
LastName: string
EmailAddress: string
IsEmailVerified: bool
}
type Contact = {
FirstName: string
MiddleInitial: string option
LastName: string
EmailAddress: string
IsEmailVerified: bool
}
Use option type for
potentially missing values
type Contact = {
FirstName: String50
MiddleInitial: String1 option
LastName: String50
EmailAddress: EmailAddress
IsEmailVerified: bool
}
Use wrapper types
instead of primitives
type PersonalName = {
FirstName : String50
MiddleInitial : String1 option
LastName : String50 }
type EmailContactInfo = {
EmailAddress : EmailAddress
IsEmailVerified : bool }
Also acts as "consistency boundaries"
2 different
domain concepts
Replacing flags with choices
What about this?
type EmailContactInfo = {
EmailAddress : EmailAddress
IsEmailVerified : bool }
• Rule 1: If the email is changed, the verified flag
must be reset to false.
• Rule 2: The verified flag can only be set by a
special verification service
type EmailContactInfo = {
EmailAddress : EmailAddress
IsEmailVerified : bool }
Listen closely to what the domain expert says...
type EmailContactInfo =
| Unverified of EmailAddress
| Verified of ???
So model it as a choice
"An email address is either
Verified OR Unverified"
"Email contact info is either Verified OR Unverified"
type EmailContactInfo =
| Unverified of EmailAddress
| Verified of ???
"Email contact info is either Verified OR Unverified"
type EmailContactInfo =
| Unverified of EmailAddress
| Verified of ???
type VerifiedEmail = VerifiedEmail of EmailAddress
"there is no problem that can’t be
solved by wrapping it in another type"
Q: Is a verified email different from an unverified email?
Are there different business rules?
A: Yes, it must not be
mixed up with unverified.
"Email contact info is either Verified OR Unverified"
type EmailContactInfo =
| Unverified of EmailAddress
| Verified of VerifiedEmail
type VerificationService =
(EmailAddress * VerificationHash) –› VerifiedEmail option
So model it as a function
Q: Where do we get
Verified emails from?
A: A special
verification process
type VerifiedEmail =
VerifiedEmail of EmailAddress
type EmailContactInfo =
| Unverified of EmailAddress
| Verified of VerifiedEmail
type VerificationService =
(EmailAddress * VerificationHash) –› VerifiedEmail option
Q: Are the business rules clear now?
type VerifiedEmail =
VerifiedEmail of EmailAddress
type EmailContactInfo =
| Unverified of EmailAddress
| Verified of VerifiedEmail
type VerificationService =
(EmailAddress * VerificationHash) –› VerifiedEmail option
Q: Are the business rules clear now?
type VerifiedEmail =
VerifiedEmail of EmailAddress
type EmailContactInfo =
| Unverified of EmailAddress
| Verified of VerifiedEmail
type VerificationService =
(EmailAddress * VerificationHash) –› VerifiedEmail option
Q: Are the business rules clear now?
type VerifiedEmail =
VerifiedEmail of EmailAddress
type EmailContactInfo =
| Unverified of EmailAddress
| Verified of VerifiedEmail
type VerificationService =
(EmailAddress * VerificationHash) –› VerifiedEmail option
Those business rules are automatically enforced by the design!
The "Contact" challenge,
completed
type EmailAddress = ...
type VerifiedEmail =
VerifiedEmail of EmailAddress
type EmailContactInfo =
| Unverified of EmailAddress
| Verified of VerifiedEmail
type PersonalName = {
FirstName: String50
MiddleInitial: String1 opt
LastName: String50 }
type Contact = {
Name: PersonalName
Email: EmailContactInfo }
type EmailAddress = ...
type VerifiedEmail =
VerifiedEmail of EmailAddress
type EmailContactInfo =
| Unverified of EmailAddress
| Verified of VerifiedEmail
type PersonalName = {
FirstName: String50
MiddleInitial: String1 opt
LastName: String50 }
type Contact = {
Name: PersonalName
Email: EmailContactInfo }
type PersonalName = {
FirstName: String50
MiddleInitial: String1 opt
LastName: String50 }
type Contact = {
Name: PersonalName
Email: EmailContactInfo }
type EmailAddress = ...
type VerifiedEmail =
VerifiedEmail of EmailAddress
type EmailContactInfo =
| Unverified of EmailAddress
| Verified of VerifiedEmail
type PersonalName = {
FirstName: String50
MiddleInitial: String1 opt
LastName: String50 }
type Contact = {
Name: PersonalName
Email: EmailContactInfo }
type EmailAddress = ...
type VerifiedEmail =
VerifiedEmail of EmailAddress
type EmailContactInfo =
| Unverified of EmailAddress
| Verified of VerifiedEmail
type PersonalName = {
FirstName: String50
MiddleInitial: String1 opt
LastName: String50 }
type Contact = {
Name: PersonalName
Email: EmailContactInfo }
type EmailAddress = ...
type VerifiedEmail =
VerifiedEmail of EmailAddress
type EmailContactInfo =
| Unverified of EmailAddress
| Verified of VerifiedEmail
type PersonalName = {
FirstName: String50
MiddleInitial: String1 opt
LastName: String50 }
type Contact = {
Name: PersonalName
Email: EmailContactInfo }
type EmailAddress = ...
type VerifiedEmail =
VerifiedEmail of EmailAddress
type EmailContactInfo =
| Unverified of EmailAddress
| Verified of VerifiedEmail
type PersonalName = {
FirstName: String50
MiddleInitial: String1 opt
LastName: String50 }
type Contact = {
Name: PersonalName
Email: EmailContactInfo }
type EmailAddress = ...
type VerifiedEmail =
VerifiedEmail of EmailAddress
type EmailContactInfo =
| Unverified of EmailAddress
| Verified of VerifiedEmail
Refactoring towards
deeper insight
type SendPasswordReset =
EmailAddress -> ...
If emailAddress.IsVerified then
send password
else
error "this should never happen"
Business rule: Only send password resets to verified emails
"this should never happen" 
type VerifiedEmail = ...
type SendPasswordReset =
VerifiedEmail -> ...
Business rule: Only send password resets to verified emails
Part IV
Encoding business rules with types
"Make illegal states unrepresentable!"
–Yaron Minsky
type Contact = {
Name: Name
Email: EmailContactInfo
Address: PostalContactInfo
}
type Contact = {
Name: Name
Email: EmailContactInfo
Address: PostalContactInfo
}
New rule:
“A contact must have an email or a postal address”
type Contact = {
Name: Name
Email: EmailContactInfo option
Address: PostalContactInfo option
}
New rule:
“A contact must have an email or a postal address”
Let’s make illegal states
unrepresentable!
“A contact must have an email or a postal address”
implies:
• email address only, or
• postal address only, or
• both email address and postal address
type ContactInfo =
| EmailOnly of EmailContactInfo
| AddrOnly of PostalContactInfo
| EmailAndAddr of EmailContactInfo * PostalContactInfo
type Contact = {
Name: Name
ContactInfo : ContactInfo }
“A contact must have an email or a postal address”
Composable types are almost as awesome as this
Collaboration is two-way.
It's OK to push back
“A contact must have an email or a postal address”
“A contact must have at least one way of being contacted”
“A contact must have at least one way of being contacted”
type Contact = {
Name: Name
PrimaryContactInfo: ContactInfo
SecondaryContactInfo: ContactInfo option }
type ContactInfo =
| Email of EmailContactInfo
| Addr of PostalContactInfo
type ContactInfo =
| Email of EmailContactInfo
| Addr of PostalContactInfo
| Facebook of FacebookInfo
| SMS of PhoneNumber
|Twitter of TwitterId
| Skype of SkypeId
Summary
• Represent the shared mental model in code
– The developers should become domain experts too
– Design collaboratively to build the shared mental
model
• Designs will evolve
– Embrace change. This is not Big Design Up Front
– Refactor towards deeper insight
– Static types give you confidence to make changes
Summary
• Use the power of a composable type system
– Choices rather than inheritance
– Options instead of null
– Avoid primitive types
– Model constraints with new types
– Make illegal states unrepresentable
Slides and video at fsharpforfunandprofit.com/ddd
Thanks!

Weitere ähnliche Inhalte

Was ist angesagt?

オブジェクト指向エクササイズのススメ
オブジェクト指向エクササイズのススメオブジェクト指向エクササイズのススメ
オブジェクト指向エクササイズのススメ
Yoji Kanno
 
ドメインロジックの実装方法とドメイン駆動設計
ドメインロジックの実装方法とドメイン駆動設計ドメインロジックの実装方法とドメイン駆動設計
ドメインロジックの実装方法とドメイン駆動設計
Tadayoshi Sato
 
オブジェクト指向の設計と実装の学び方のコツ
オブジェクト指向の設計と実装の学び方のコツオブジェクト指向の設計と実装の学び方のコツ
オブジェクト指向の設計と実装の学び方のコツ
増田 亨
 

Was ist angesagt? (20)

オブジェクト指向エクササイズのススメ
オブジェクト指向エクササイズのススメオブジェクト指向エクササイズのススメ
オブジェクト指向エクササイズのススメ
 
ドメインロジックの実装方法とドメイン駆動設計
ドメインロジックの実装方法とドメイン駆動設計ドメインロジックの実装方法とドメイン駆動設計
ドメインロジックの実装方法とドメイン駆動設計
 
Where狙いのキー、order by狙いのキー
Where狙いのキー、order by狙いのキーWhere狙いのキー、order by狙いのキー
Where狙いのキー、order by狙いのキー
 
イミュータブルデータモデルの極意
イミュータブルデータモデルの極意イミュータブルデータモデルの極意
イミュータブルデータモデルの極意
 
オブジェクト指向の設計と実装の学び方のコツ
オブジェクト指向の設計と実装の学び方のコツオブジェクト指向の設計と実装の学び方のコツ
オブジェクト指向の設計と実装の学び方のコツ
 
"Simple Made Easy" Made Easy
"Simple Made Easy" Made Easy"Simple Made Easy" Made Easy
"Simple Made Easy" Made Easy
 
ちいさなオブジェクトでドメインモデルを組み立てる
ちいさなオブジェクトでドメインモデルを組み立てるちいさなオブジェクトでドメインモデルを組み立てる
ちいさなオブジェクトでドメインモデルを組み立てる
 
ヤフー社内でやってるMySQLチューニングセミナー大公開
ヤフー社内でやってるMySQLチューニングセミナー大公開ヤフー社内でやってるMySQLチューニングセミナー大公開
ヤフー社内でやってるMySQLチューニングセミナー大公開
 
思考停止しないアーキテクチャ設計 ➖ JJUG CCC 2018 Fall
思考停止しないアーキテクチャ設計 ➖ JJUG CCC 2018 Fall思考停止しないアーキテクチャ設計 ➖ JJUG CCC 2018 Fall
思考停止しないアーキテクチャ設計 ➖ JJUG CCC 2018 Fall
 
ソフトウェア設計における 意思決定とそのレビューの秘訣
ソフトウェア設計における 意思決定とそのレビューの秘訣ソフトウェア設計における 意思決定とそのレビューの秘訣
ソフトウェア設計における 意思決定とそのレビューの秘訣
 
SQLアンチパターン - ナイーブツリー
SQLアンチパターン - ナイーブツリーSQLアンチパターン - ナイーブツリー
SQLアンチパターン - ナイーブツリー
 
DDD x CQRS 更新系と参照系で異なるORMを併用して上手くいった話
DDD x CQRS   更新系と参照系で異なるORMを併用して上手くいった話DDD x CQRS   更新系と参照系で異なるORMを併用して上手くいった話
DDD x CQRS 更新系と参照系で異なるORMを併用して上手くいった話
 
Cognitive Complexity でコードの複雑さを定量的に計測しよう
Cognitive Complexity でコードの複雑さを定量的に計測しようCognitive Complexity でコードの複雑さを定量的に計測しよう
Cognitive Complexity でコードの複雑さを定量的に計測しよう
 
イミュータブルデータモデル(入門編)
イミュータブルデータモデル(入門編)イミュータブルデータモデル(入門編)
イミュータブルデータモデル(入門編)
 
世界一わかりやすいClean Architecture
世界一わかりやすいClean Architecture世界一わかりやすいClean Architecture
世界一わかりやすいClean Architecture
 
PostgreSQLアンチパターン
PostgreSQLアンチパターンPostgreSQLアンチパターン
PostgreSQLアンチパターン
 
Laravelでfacadeを使わない開発
Laravelでfacadeを使わない開発Laravelでfacadeを使わない開発
Laravelでfacadeを使わない開発
 
ドメイン駆動設計 失敗したことと成功したこと
ドメイン駆動設計 失敗したことと成功したことドメイン駆動設計 失敗したことと成功したこと
ドメイン駆動設計 失敗したことと成功したこと
 
なぜデータモデリングが重要なのか?
なぜデータモデリングが重要なのか?なぜデータモデリングが重要なのか?
なぜデータモデリングが重要なのか?
 
データ履歴管理のためのテンポラルデータモデルとReladomoの紹介 #jjug_ccc #ccc_g3
データ履歴管理のためのテンポラルデータモデルとReladomoの紹介 #jjug_ccc #ccc_g3 データ履歴管理のためのテンポラルデータモデルとReladomoの紹介 #jjug_ccc #ccc_g3
データ履歴管理のためのテンポラルデータモデルとReladomoの紹介 #jjug_ccc #ccc_g3
 

Ähnlich wie Domain Modeling Made Functional (DevTernity 2022)

FaceUp card game In this assignment we will implement a made.pdf
FaceUp card game In this assignment we will implement a made.pdfFaceUp card game In this assignment we will implement a made.pdf
FaceUp card game In this assignment we will implement a made.pdf
abifancystore
 
This is the final code which meets your requirement.Than youCard.j.pdf
This is the final code which meets your requirement.Than youCard.j.pdfThis is the final code which meets your requirement.Than youCard.j.pdf
This is the final code which meets your requirement.Than youCard.j.pdf
aplolomedicalstoremr
 
BlackJackBlackjack.c Blackjack.c Defines the entry point .docx
BlackJackBlackjack.c Blackjack.c  Defines the entry point .docxBlackJackBlackjack.c Blackjack.c  Defines the entry point .docx
BlackJackBlackjack.c Blackjack.c Defines the entry point .docx
AASTHA76
 
project 6cards.pyimport randomclass Card( object ).docx
project 6cards.pyimport randomclass Card( object ).docxproject 6cards.pyimport randomclass Card( object ).docx
project 6cards.pyimport randomclass Card( object ).docx
briancrawford30935
 

Ähnlich wie Domain Modeling Made Functional (DevTernity 2022) (10)

Domain Modeling with FP (DDD Europe 2020)
Domain Modeling with FP (DDD Europe 2020)Domain Modeling with FP (DDD Europe 2020)
Domain Modeling with FP (DDD Europe 2020)
 
Domain Modeling Made Functional (KanDDDinsky 2019)
Domain Modeling Made Functional (KanDDDinsky 2019)Domain Modeling Made Functional (KanDDDinsky 2019)
Domain Modeling Made Functional (KanDDDinsky 2019)
 
FaceUp card game In this assignment we will implement a made.pdf
FaceUp card game In this assignment we will implement a made.pdfFaceUp card game In this assignment we will implement a made.pdf
FaceUp card game In this assignment we will implement a made.pdf
 
This is the final code which meets your requirement.Than youCard.j.pdf
This is the final code which meets your requirement.Than youCard.j.pdfThis is the final code which meets your requirement.Than youCard.j.pdf
This is the final code which meets your requirement.Than youCard.j.pdf
 
BlackJackBlackjack.c Blackjack.c Defines the entry point .docx
BlackJackBlackjack.c Blackjack.c  Defines the entry point .docxBlackJackBlackjack.c Blackjack.c  Defines the entry point .docx
BlackJackBlackjack.c Blackjack.c Defines the entry point .docx
 
Domain typing in Ruby
Domain typing in RubyDomain typing in Ruby
Domain typing in Ruby
 
project 6cards.pyimport randomclass Card( object ).docx
project 6cards.pyimport randomclass Card( object ).docxproject 6cards.pyimport randomclass Card( object ).docx
project 6cards.pyimport randomclass Card( object ).docx
 
Intellectual playing cards - Not for everyone
Intellectual playing cards - Not for everyoneIntellectual playing cards - Not for everyone
Intellectual playing cards - Not for everyone
 
Domain Driven Design with the F# type System -- NDC London 2013
Domain Driven Design with the F# type System -- NDC London 2013Domain Driven Design with the F# type System -- NDC London 2013
Domain Driven Design with the F# type System -- NDC London 2013
 
Blackjack Coded in MATLAB
Blackjack Coded in MATLABBlackjack Coded in MATLAB
Blackjack Coded in MATLAB
 

Mehr von Scott Wlaschin

Mehr von Scott Wlaschin (20)

Pipeline oriented programming
Pipeline oriented programmingPipeline oriented programming
Pipeline oriented programming
 
The Power of Composition (NDC Oslo 2020)
The Power of Composition (NDC Oslo 2020)The Power of Composition (NDC Oslo 2020)
The Power of Composition (NDC Oslo 2020)
 
Building confidence in concurrent code with a model checker: TLA+ for program...
Building confidence in concurrent code with a model checker: TLA+ for program...Building confidence in concurrent code with a model checker: TLA+ for program...
Building confidence in concurrent code with a model checker: TLA+ for program...
 
The lazy programmer's guide to writing thousands of tests
The lazy programmer's guide to writing thousands of testsThe lazy programmer's guide to writing thousands of tests
The lazy programmer's guide to writing thousands of tests
 
The Functional Programmer's Toolkit (NDC London 2019)
The Functional Programmer's Toolkit (NDC London 2019)The Functional Programmer's Toolkit (NDC London 2019)
The Functional Programmer's Toolkit (NDC London 2019)
 
The Power Of Composition (DotNext 2019)
The Power Of Composition (DotNext 2019)The Power Of Composition (DotNext 2019)
The Power Of Composition (DotNext 2019)
 
The Functional Programming Toolkit (NDC Oslo 2019)
The Functional Programming Toolkit (NDC Oslo 2019)The Functional Programming Toolkit (NDC Oslo 2019)
The Functional Programming Toolkit (NDC Oslo 2019)
 
Four Languages From Forty Years Ago (NewCrafts 2019)
Four Languages From Forty Years Ago (NewCrafts 2019)Four Languages From Forty Years Ago (NewCrafts 2019)
Four Languages From Forty Years Ago (NewCrafts 2019)
 
Functional Design Patterns (DevTernity 2018)
Functional Design Patterns (DevTernity 2018)Functional Design Patterns (DevTernity 2018)
Functional Design Patterns (DevTernity 2018)
 
Four Languages From Forty Years Ago
Four Languages From Forty Years AgoFour Languages From Forty Years Ago
Four Languages From Forty Years Ago
 
The Power of Composition
The Power of CompositionThe Power of Composition
The Power of Composition
 
F# for C# Programmers
F# for C# ProgrammersF# for C# Programmers
F# for C# Programmers
 
Designing with capabilities (DDD-EU 2017)
Designing with capabilities (DDD-EU 2017)Designing with capabilities (DDD-EU 2017)
Designing with capabilities (DDD-EU 2017)
 
Thirteen ways of looking at a turtle
Thirteen ways of looking at a turtleThirteen ways of looking at a turtle
Thirteen ways of looking at a turtle
 
Designing with Capabilities
Designing with CapabilitiesDesigning with Capabilities
Designing with Capabilities
 
Dr Frankenfunctor and the Monadster
Dr Frankenfunctor and the MonadsterDr Frankenfunctor and the Monadster
Dr Frankenfunctor and the Monadster
 
Enterprise Tic-Tac-Toe
Enterprise Tic-Tac-ToeEnterprise Tic-Tac-Toe
Enterprise Tic-Tac-Toe
 
An introduction to property based testing
An introduction to property based testingAn introduction to property based testing
An introduction to property based testing
 
Functional Programming Patterns (NDC London 2014)
Functional Programming Patterns (NDC London 2014)Functional Programming Patterns (NDC London 2014)
Functional Programming Patterns (NDC London 2014)
 
Functional Programming Patterns (BuildStuff '14)
Functional Programming Patterns (BuildStuff '14)Functional Programming Patterns (BuildStuff '14)
Functional Programming Patterns (BuildStuff '14)
 

Kürzlich hochgeladen

CHEAP Call Girls in Pushp Vihar (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICE
CHEAP Call Girls in Pushp Vihar (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICECHEAP Call Girls in Pushp Vihar (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICE
CHEAP Call Girls in Pushp Vihar (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICE
9953056974 Low Rate Call Girls In Saket, Delhi NCR
 
CALL ON ➥8923113531 🔝Call Girls Kakori Lucknow best sexual service Online ☂️
CALL ON ➥8923113531 🔝Call Girls Kakori Lucknow best sexual service Online  ☂️CALL ON ➥8923113531 🔝Call Girls Kakori Lucknow best sexual service Online  ☂️
CALL ON ➥8923113531 🔝Call Girls Kakori Lucknow best sexual service Online ☂️
anilsa9823
 
CALL ON ➥8923113531 🔝Call Girls Badshah Nagar Lucknow best Female service
CALL ON ➥8923113531 🔝Call Girls Badshah Nagar Lucknow best Female serviceCALL ON ➥8923113531 🔝Call Girls Badshah Nagar Lucknow best Female service
CALL ON ➥8923113531 🔝Call Girls Badshah Nagar Lucknow best Female service
anilsa9823
 
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
Health
 

Kürzlich hochgeladen (20)

Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...
Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...
Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...
 
CHEAP Call Girls in Pushp Vihar (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICE
CHEAP Call Girls in Pushp Vihar (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICECHEAP Call Girls in Pushp Vihar (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICE
CHEAP Call Girls in Pushp Vihar (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICE
 
Microsoft AI Transformation Partner Playbook.pdf
Microsoft AI Transformation Partner Playbook.pdfMicrosoft AI Transformation Partner Playbook.pdf
Microsoft AI Transformation Partner Playbook.pdf
 
Hand gesture recognition PROJECT PPT.pptx
Hand gesture recognition PROJECT PPT.pptxHand gesture recognition PROJECT PPT.pptx
Hand gesture recognition PROJECT PPT.pptx
 
Learn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdf
Learn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdfLearn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdf
Learn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdf
 
The Ultimate Test Automation Guide_ Best Practices and Tips.pdf
The Ultimate Test Automation Guide_ Best Practices and Tips.pdfThe Ultimate Test Automation Guide_ Best Practices and Tips.pdf
The Ultimate Test Automation Guide_ Best Practices and Tips.pdf
 
W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...
W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...
W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...
 
CALL ON ➥8923113531 🔝Call Girls Kakori Lucknow best sexual service Online ☂️
CALL ON ➥8923113531 🔝Call Girls Kakori Lucknow best sexual service Online  ☂️CALL ON ➥8923113531 🔝Call Girls Kakori Lucknow best sexual service Online  ☂️
CALL ON ➥8923113531 🔝Call Girls Kakori Lucknow best sexual service Online ☂️
 
5 Signs You Need a Fashion PLM Software.pdf
5 Signs You Need a Fashion PLM Software.pdf5 Signs You Need a Fashion PLM Software.pdf
5 Signs You Need a Fashion PLM Software.pdf
 
CALL ON ➥8923113531 🔝Call Girls Badshah Nagar Lucknow best Female service
CALL ON ➥8923113531 🔝Call Girls Badshah Nagar Lucknow best Female serviceCALL ON ➥8923113531 🔝Call Girls Badshah Nagar Lucknow best Female service
CALL ON ➥8923113531 🔝Call Girls Badshah Nagar Lucknow best Female service
 
How To Troubleshoot Collaboration Apps for the Modern Connected Worker
How To Troubleshoot Collaboration Apps for the Modern Connected WorkerHow To Troubleshoot Collaboration Apps for the Modern Connected Worker
How To Troubleshoot Collaboration Apps for the Modern Connected Worker
 
Vip Call Girls Noida ➡️ Delhi ➡️ 9999965857 No Advance 24HRS Live
Vip Call Girls Noida ➡️ Delhi ➡️ 9999965857 No Advance 24HRS LiveVip Call Girls Noida ➡️ Delhi ➡️ 9999965857 No Advance 24HRS Live
Vip Call Girls Noida ➡️ Delhi ➡️ 9999965857 No Advance 24HRS Live
 
Reassessing the Bedrock of Clinical Function Models: An Examination of Large ...
Reassessing the Bedrock of Clinical Function Models: An Examination of Large ...Reassessing the Bedrock of Clinical Function Models: An Examination of Large ...
Reassessing the Bedrock of Clinical Function Models: An Examination of Large ...
 
Short Story: Unveiling the Reasoning Abilities of Large Language Models by Ke...
Short Story: Unveiling the Reasoning Abilities of Large Language Models by Ke...Short Story: Unveiling the Reasoning Abilities of Large Language Models by Ke...
Short Story: Unveiling the Reasoning Abilities of Large Language Models by Ke...
 
Try MyIntelliAccount Cloud Accounting Software As A Service Solution Risk Fre...
Try MyIntelliAccount Cloud Accounting Software As A Service Solution Risk Fre...Try MyIntelliAccount Cloud Accounting Software As A Service Solution Risk Fre...
Try MyIntelliAccount Cloud Accounting Software As A Service Solution Risk Fre...
 
Unveiling the Tech Salsa of LAMs with Janus in Real-Time Applications
Unveiling the Tech Salsa of LAMs with Janus in Real-Time ApplicationsUnveiling the Tech Salsa of LAMs with Janus in Real-Time Applications
Unveiling the Tech Salsa of LAMs with Janus in Real-Time Applications
 
SyndBuddy AI 2k Review 2024: Revolutionizing Content Syndication with AI
SyndBuddy AI 2k Review 2024: Revolutionizing Content Syndication with AISyndBuddy AI 2k Review 2024: Revolutionizing Content Syndication with AI
SyndBuddy AI 2k Review 2024: Revolutionizing Content Syndication with AI
 
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
 
How To Use Server-Side Rendering with Nuxt.js
How To Use Server-Side Rendering with Nuxt.jsHow To Use Server-Side Rendering with Nuxt.js
How To Use Server-Side Rendering with Nuxt.js
 
Unlocking the Future of AI Agents with Large Language Models
Unlocking the Future of AI Agents with Large Language ModelsUnlocking the Future of AI Agents with Large Language Models
Unlocking the Future of AI Agents with Large Language Models
 

Domain Modeling Made Functional (DevTernity 2022)

  • 1. Domain Modeling Made Functional (DevTernity 2022) @ScottWlaschin fsharpforfunandprofit.com
  • 2. Functional programming: what is it good for? • Mathematical things only
  • 3. Functional programming: what is it good for? • Mathematical things only • Interactive & collaborative domain modeling • Representing a domain model accurately
  • 6. Input Output Process The software development process
  • 7. Input Output Process The software development process
  • 8. Input Output Process Garbage in Garbage out The software development process
  • 9. Input Output Process (reduce) Garbage in (reduced) Garbage out The software development process
  • 10. • Borrow from Agile and DDD • Agile contribution: – Rapid feedback during design • DDD contribution: – Stakeholders have a shared mental model – …which is also represented in the code How can we do design right?
  • 11.
  • 12.
  • 13.
  • 14. Can you really make code represent the domain?
  • 15. What non-developers think source code looks like and some C developers!
  • 16. module CardGame = type Suit = Club | Diamond | Spade | Heart type Rank =Two |Three | Four | Five | Six | Seven | Eight | Nine |Ten | Jack | Queen | King type Card = Suit * Rank type Hand = Card list type Deck = Card list type Player = { Name:string; Hand:Hand } type Game = { Deck:Deck; Players: Player list } type Deal = Deck –› (Deck * Card) type PickupCard = (Hand * Card) –› Hand Shared language What DDD source code should look like
  • 17. module CardGame = type Suit = Club | Diamond | Spade | Heart type Rank =Two |Three | Four | Five | Six | Seven | Eight | Nine |Ten | Jack | Queen | King type Card = Suit * Rank type Hand = Card list type Deck = Card list type Player = { Name:string; Hand:Hand } type Game = { Deck:Deck; Players: Player list } type Deal = Deck –› (Deck * Card) type PickupCard = (Hand * Card) –› Hand * means a pair. Choose one from each type list type is built in
  • 18. Deal (original) Deck (remaining) Deck (on table) Card Modeling an action with a function type Deal = Deck -> (Deck * Card) Input Output
  • 19. Pickup Card (updated) Hand (original) Hand (on table) Card Modeling an action with a function type PickupCard = (Hand * Card) –> Hand Input Output
  • 20. module CardGame = type Suit = Club | Diamond | Spade | Heart type Rank =Two |Three | Four | Five | Six | Seven | Eight | Nine |Ten | Jack | Queen | King type Card = Suit * Rank type Hand = Card list type Deck = Card list type Player = { Name:string; Hand:Hand } type Game = { Deck:Deck; Players: Player list } type Deal = Deck –› (Deck * Card) type PickupCard = (Hand * Card) –› Hand
  • 21. module CardGame = type Suit = Club | Diamond | Spade | Heart type Rank =Two |Three | Four | Five | Six | Seven | Eight | Nine |Ten | Jack | Queen | King type Card = Suit * Rank type Hand = Card list type Deck = Card list type Player = { Name:string; Hand:Hand } type Game = { Deck:Deck; Players: Player list } type Deal = Deck –› (Deck * Card) type PickupCard = (Hand * Card) –› Hand
  • 22. module CardGame = type Suit = Club | Diamond | Spade | Heart type Rank =Two |Three | Four | Five | Six | Seven | Eight | Nine |Ten | Jack | Queen | King type Card = Suit * Rank type Hand = Card list type Deck = Card list type Player = { Name:string; Hand:Hand } type Game = { Deck:Deck; Players: Player list } type Deal = Deck –› (Deck * Card) type PickupCard = (Hand * Card) –› Hand Can non-programmers provide useful feedback?
  • 24. Building a shared mental model is an interactive process
  • 25. ... type Deck = Card list type Deal = Deck –› (Deck * Card)
  • 26. ... type Deck = Card list type Deal = ShuffledDeck –› (ShuffledDeck * Card)
  • 27. ... type Deck = Card list type Deal = ShuffledDeck –› (ShuffledDeck * Card) type ShuffledDeck = Card list
  • 28. ... type Deck = Card list type Deal = ShuffledDeck –› (ShuffledDeck * Card) type ShuffledDeck = Card list type Shuffle = Deck –› ShuffledDeck
  • 29. ... type Deck = Card list type Deal = ShuffledDeck –› (ShuffledDeck * Card) type ShuffledDeck = Card list type Shuffle = Deck –› ShuffledDeck
  • 30. Final version of the domain
  • 31. module CardGame = type Suit = Club | Diamond | Spade | Heart type Rank = Two |Three | Four | Five | Six | Seven | Eight | ... type Card = Suit * Rank type Hand = Card list type Deck = Card list type Player = { Name:string; Hand:Hand } type Game = { Deck:Deck; Players: Player list } type Deal = ShuffledDeck –› (ShuffledDeck * Card) type ShuffledDeck = Card list type Shuffle = Deck –› ShuffledDeck type PickupCard = (Hand * Card) –› Hand
  • 32. module CardGame = type Suit = Club | Diamond | Spade | Heart type Rank = Two |Three | Four | Five | Six | Seven | Eight | ... type Card = Suit * Rank type Hand = Card list type Deck = Card list type Player = { Name:string; Hand:Hand } type Game = { Deck:Deck; Players: Player list } type Deal = ShuffledDeck –› (ShuffledDeck * Card) type ShuffledDeck = Card list type Shuffle = Deck –› ShuffledDeck type PickupCard = (Hand * Card) –› Hand
  • 33. In the real world Suit Rank Card Hand Deck Player Deal In the code Suit Rank Card Hand Deck Player Deal
  • 34. In the real world Suit Rank Card Hand Deck Player Deal In the code Suit Rank Card Hand Deck Player Deal ShuffledDeck Shuffle ShuffledDeck Shuffle 
  • 35. In the real world Suit Rank Card Hand Deck Player Deal In the code Suit Rank Card Hand Deck Player Deal PlayerController DeckBase AbstractCardProxyFactoryBean 
  • 36. module CardGame = type Suit = Club | Diamond | Spade | Heart type Rank = Two |Three | Four | Five | Six | Seven | Eight | ... type Card = Suit * Rank type Hand = Card list type Deck = Card list type Player = { Name:string; Hand:Hand } type Game = { Deck:Deck; Players: Player list } type Deal = ShuffledDeck –› (ShuffledDeck * Card) type ShuffledDeck = Card list type Shuffle = Deck –› ShuffledDeck type PickupCard = (Hand * Card) –› Hand
  • 37. module CardGame = type Suit = Club | Diamond | Spade | Heart type Rank = Two |Three | Four | Five | Six | Seven | Eight | ... type Card = Suit * Rank type Hand = Card list type Deck = Card list type Player = { Name:string; Hand:Hand } type Game = { Deck:Deck; Players: Player list } type Deal = ShuffledDeck –› (ShuffledDeck * Card) type ShuffledDeck = Card list type Shuffle = Deck –› ShuffledDeck type PickupCard = (Hand * Card) –› Hand
  • 38. Again: The process of building the shared mental model is critical! Collaboration!
  • 39. Key DDD principle: Communicate the design in the code
  • 40. A domain modeling challenge!
  • 41. type Contact = { FirstName: string MiddleInitial: string LastName: string EmailAddress: string IsEmailVerified: bool } // true if ownership of // email address is confirmed
  • 42. type Contact = { FirstName: string MiddleInitial: string LastName: string EmailAddress: string IsEmailVerified: bool } Prologue: which values are optional?
  • 43. type Contact = { FirstName: string MiddleInitial: string LastName: string EmailAddress: string IsEmailVerified: bool } Prologue: what are the constraints?
  • 44. type Contact = { FirstName: string MiddleInitial: string LastName: string EmailAddress: string IsEmailVerified: bool } Prologue: domain logic?
  • 45. Prologue: F# can help type Contact = { FirstName: string MiddleInitial: string LastName: string EmailAddress: string IsEmailVerified: bool }
  • 46. Prologue: F# can help type Contact = { FirstName: string MiddleInitial: string LastName: string EmailAddress: string IsEmailVerified: bool }
  • 47. Part II Understanding FP type systems
  • 49.
  • 50. Composition = Make big things from small things
  • 52. New types are built from smaller types by: Composing with “AND” Composing with “OR”
  • 53. All languages have this. Example: pairs, tuples, records FruitSalad = One each of and and Compose with “AND” type FruitSalad = { Apple: AppleVariety Banana: BananaVariety Cherry: CherryVariety }
  • 54. Snack = or or Compose with “OR” type Snack = | Apple of AppleVariety | Banana of BananaVariety | Cherry of CherryVariety
  • 55. A real world example of composing types
  • 56. Some requirements: We accept three forms of payment: Cash, PayPal, or Card. For Cash we don't need any extra information For PayPal we need a email address For Cards we need a card type and card number
  • 57. interface IPaymentMethod {..} class Cash() : IPaymentMethod {..} class PayPal(string emailAddress): IPaymentMethod {..} class Card(string cardType, string cardNo) : IPaymentMethod {..} In OO design you would probably implement it as an interface and a set of subclasses, like this:
  • 58. type EmailAddress = string type CardNumber = string In FP you would probably implement by composing types, like this:
  • 59. type EmailAddress = ... type CardNumber = … type CardType = Visa | Mastercard type CreditCardInfo = { CardType : CardType CardNumber : CardNumber }
  • 60. type EmailAddress = ... type CardNumber = ... type CardType = ... type CreditCardInfo = ... type PaymentMethod = | Cash | PayPal of EmailAddress | Card of CreditCardInfo
  • 61. type EmailAddress = ... type CardNumber = ... type CardType = ... type CreditCardInfo = ... type PaymentMethod = | Cash | PayPal of EmailAddress | Card of CreditCardInfo
  • 62. type EmailAddress = ... type CardNumber = ... type CardType = ... type CreditCardInfo = ... type PaymentMethod = | Cash | PayPal of EmailAddress | Card of CreditCardInfo type PaymentAmount = decimal type Currency = EUR | USD
  • 63. type EmailAddress = ... type CardNumber = ... type CardType = ... type CreditCardInfo = ... type PaymentMethod = | Cash | PayPal of EmailAddress | Card of CreditCardInfo type PaymentAmount = decimal type Currency = EUR | USD type Payment = { Amount : PaymentAmount Currency : Currency Method : PaymentMethod }
  • 64. type EmailAddress = ... type CardNumber = ... type CardType = ... type CreditCardInfo = ... type PaymentMethod = | Cash | PayPal of EmailAddress | Card of CreditCardInfo type PaymentAmount = decimal type Currency = EUR | USD type Payment = { Amount : PaymentAmount Currency : Currency Method : PaymentMethod }
  • 65. Part III Domain modeling with composable types
  • 66. type Contact = { FirstName: string MiddleInitial: string LastName: string EmailAddress: string IsEmailVerified: bool } // true if ownership of // email address is confirmed This looks suspiciously like database-driven design...
  • 67. type Contact = { Name: PersonalName Email: EmailContactInfo } "A contact has a name AND email info" "Like this?..."
  • 68. type Contact = { Name: PersonalName Email: EmailContactInfo } "A contact has a name AND email info" We have two new concepts already!
  • 69. type PersonalName = { FirstName: string MiddleInitial: string LastName: string } "What's a personal name?"
  • 70. type PersonalName = { FirstName: string MiddleInitial: string LastName: string } required required optional "What's required or optional?"
  • 72. Null is not the same as “optional” Length string –› int “a” “b” “c” 1 2 3 “a” “b” “c” null
  • 73. Null is not the same as “optional” Length string –› int “a” “b” “c” null 1 2 3
  • 74. Null is not allowed Length string –› int “a” “b” “c” null 1 2 3 X
  • 75. A better way for optional values + = “a” “b” “c” “a” “b” “c” missing or Tag with “Nothing” type OptionalString = | SomeString of string | Nothing
  • 76. type OptionalInt = | SomeInt of int | Nothing type OptionalString = | SomeString of string | Nothing type OptionalBool = | SomeBool of bool | Nothing Defining optional types
  • 77. type Option<'T> = | Some of 'T | None
  • 78. type Option<'T> = | Some of 'T | None
  • 79. type PersonalName = { FirstName: string MiddleInitial: Option<string> LastName: string }
  • 80. type PersonalName = { FirstName: string MiddleInitial: string option LastName: string }
  • 81. Modeling simple values and constrained values
  • 82. Modeling simple values • Avoid "Primitive Obsession" • Simple values should not be modelled with primitive types like "int" or "string" or "float" "Does 'float' have something to do with water?"
  • 83. Modeling constrained values • It's rare to have an unconstrained int or string: – An EmailAddress must not be empty, it must match a pattern – A PhoneNumber must not be empty, it must match a pattern – A CustomerId must be a positive integer
  • 84. Is an EmailAddress just a string? No! Is a CustomerId just a int? No!
  • 85. type EmailAddress = EmailAddress of string Use wrapper types to keep domain concepts distinct from their representation type CustomerId = CustomerId of int type String50 = String50 of string
  • 86. type EmailAddress = EmailAddress of string type PhoneNumber = PhoneNumber of string type CustomerId = CustomerId of int type OrderId = OrderId of int Two benefits: - Clearer domain modelling - Can't mix them up accidentally
  • 88. let createEmailAddress (s:string) = if s.Contains("@") then (EmailAddress s) else ? createEmailAddress: string –› EmailAddress
  • 89. let createEmailAddress (s:string) = if s.Contains("@") then Some (EmailAddress s) else None createEmailAddress: string –› EmailAddress option
  • 90. type String50 = String50 of string let createString50 (s:string) = if s.Length <= 50 then Some (String50 s) else None createString50 : string –› String50 option
  • 92. type OrderLineQty = OrderLineQty of int let createOrderLineQty qty = if qty > 0 && qty <= 99 then Some (OrderLineQty qty) else None createOrderLineQty: int –› OrderLineQty option
  • 94. type Contact = { FirstName: string MiddleInitial: string LastName: string EmailAddress: string IsEmailVerified: bool }
  • 95. type Contact = { FirstName: string MiddleInitial: string option LastName: string EmailAddress: string IsEmailVerified: bool } Use option type for potentially missing values
  • 96. type Contact = { FirstName: String50 MiddleInitial: String1 option LastName: String50 EmailAddress: EmailAddress IsEmailVerified: bool } Use wrapper types instead of primitives
  • 97. type PersonalName = { FirstName : String50 MiddleInitial : String1 option LastName : String50 } type EmailContactInfo = { EmailAddress : EmailAddress IsEmailVerified : bool } Also acts as "consistency boundaries" 2 different domain concepts
  • 99. What about this? type EmailContactInfo = { EmailAddress : EmailAddress IsEmailVerified : bool }
  • 100. • Rule 1: If the email is changed, the verified flag must be reset to false. • Rule 2: The verified flag can only be set by a special verification service type EmailContactInfo = { EmailAddress : EmailAddress IsEmailVerified : bool }
  • 101. Listen closely to what the domain expert says... type EmailContactInfo = | Unverified of EmailAddress | Verified of ??? So model it as a choice "An email address is either Verified OR Unverified"
  • 102. "Email contact info is either Verified OR Unverified" type EmailContactInfo = | Unverified of EmailAddress | Verified of ???
  • 103. "Email contact info is either Verified OR Unverified" type EmailContactInfo = | Unverified of EmailAddress | Verified of ???
  • 104. type VerifiedEmail = VerifiedEmail of EmailAddress "there is no problem that can’t be solved by wrapping it in another type" Q: Is a verified email different from an unverified email? Are there different business rules? A: Yes, it must not be mixed up with unverified.
  • 105. "Email contact info is either Verified OR Unverified" type EmailContactInfo = | Unverified of EmailAddress | Verified of VerifiedEmail
  • 106. type VerificationService = (EmailAddress * VerificationHash) –› VerifiedEmail option So model it as a function Q: Where do we get Verified emails from? A: A special verification process
  • 107. type VerifiedEmail = VerifiedEmail of EmailAddress type EmailContactInfo = | Unverified of EmailAddress | Verified of VerifiedEmail type VerificationService = (EmailAddress * VerificationHash) –› VerifiedEmail option Q: Are the business rules clear now?
  • 108. type VerifiedEmail = VerifiedEmail of EmailAddress type EmailContactInfo = | Unverified of EmailAddress | Verified of VerifiedEmail type VerificationService = (EmailAddress * VerificationHash) –› VerifiedEmail option Q: Are the business rules clear now?
  • 109. type VerifiedEmail = VerifiedEmail of EmailAddress type EmailContactInfo = | Unverified of EmailAddress | Verified of VerifiedEmail type VerificationService = (EmailAddress * VerificationHash) –› VerifiedEmail option Q: Are the business rules clear now?
  • 110. type VerifiedEmail = VerifiedEmail of EmailAddress type EmailContactInfo = | Unverified of EmailAddress | Verified of VerifiedEmail type VerificationService = (EmailAddress * VerificationHash) –› VerifiedEmail option Those business rules are automatically enforced by the design!
  • 112. type EmailAddress = ... type VerifiedEmail = VerifiedEmail of EmailAddress type EmailContactInfo = | Unverified of EmailAddress | Verified of VerifiedEmail type PersonalName = { FirstName: String50 MiddleInitial: String1 opt LastName: String50 } type Contact = { Name: PersonalName Email: EmailContactInfo }
  • 113. type EmailAddress = ... type VerifiedEmail = VerifiedEmail of EmailAddress type EmailContactInfo = | Unverified of EmailAddress | Verified of VerifiedEmail type PersonalName = { FirstName: String50 MiddleInitial: String1 opt LastName: String50 } type Contact = { Name: PersonalName Email: EmailContactInfo }
  • 114. type PersonalName = { FirstName: String50 MiddleInitial: String1 opt LastName: String50 } type Contact = { Name: PersonalName Email: EmailContactInfo } type EmailAddress = ... type VerifiedEmail = VerifiedEmail of EmailAddress type EmailContactInfo = | Unverified of EmailAddress | Verified of VerifiedEmail
  • 115. type PersonalName = { FirstName: String50 MiddleInitial: String1 opt LastName: String50 } type Contact = { Name: PersonalName Email: EmailContactInfo } type EmailAddress = ... type VerifiedEmail = VerifiedEmail of EmailAddress type EmailContactInfo = | Unverified of EmailAddress | Verified of VerifiedEmail
  • 116. type PersonalName = { FirstName: String50 MiddleInitial: String1 opt LastName: String50 } type Contact = { Name: PersonalName Email: EmailContactInfo } type EmailAddress = ... type VerifiedEmail = VerifiedEmail of EmailAddress type EmailContactInfo = | Unverified of EmailAddress | Verified of VerifiedEmail
  • 117. type PersonalName = { FirstName: String50 MiddleInitial: String1 opt LastName: String50 } type Contact = { Name: PersonalName Email: EmailContactInfo } type EmailAddress = ... type VerifiedEmail = VerifiedEmail of EmailAddress type EmailContactInfo = | Unverified of EmailAddress | Verified of VerifiedEmail
  • 118. type PersonalName = { FirstName: String50 MiddleInitial: String1 opt LastName: String50 } type Contact = { Name: PersonalName Email: EmailContactInfo } type EmailAddress = ... type VerifiedEmail = VerifiedEmail of EmailAddress type EmailContactInfo = | Unverified of EmailAddress | Verified of VerifiedEmail
  • 120. type SendPasswordReset = EmailAddress -> ... If emailAddress.IsVerified then send password else error "this should never happen" Business rule: Only send password resets to verified emails "this should never happen" 
  • 121. type VerifiedEmail = ... type SendPasswordReset = VerifiedEmail -> ... Business rule: Only send password resets to verified emails
  • 122. Part IV Encoding business rules with types "Make illegal states unrepresentable!" –Yaron Minsky
  • 123. type Contact = { Name: Name Email: EmailContactInfo Address: PostalContactInfo }
  • 124. type Contact = { Name: Name Email: EmailContactInfo Address: PostalContactInfo } New rule: “A contact must have an email or a postal address”
  • 125. type Contact = { Name: Name Email: EmailContactInfo option Address: PostalContactInfo option } New rule: “A contact must have an email or a postal address”
  • 126. Let’s make illegal states unrepresentable!
  • 127. “A contact must have an email or a postal address” implies: • email address only, or • postal address only, or • both email address and postal address
  • 128. type ContactInfo = | EmailOnly of EmailContactInfo | AddrOnly of PostalContactInfo | EmailAndAddr of EmailContactInfo * PostalContactInfo type Contact = { Name: Name ContactInfo : ContactInfo } “A contact must have an email or a postal address”
  • 129. Composable types are almost as awesome as this
  • 130. Collaboration is two-way. It's OK to push back
  • 131. “A contact must have an email or a postal address” “A contact must have at least one way of being contacted”
  • 132. “A contact must have at least one way of being contacted” type Contact = { Name: Name PrimaryContactInfo: ContactInfo SecondaryContactInfo: ContactInfo option } type ContactInfo = | Email of EmailContactInfo | Addr of PostalContactInfo
  • 133. type ContactInfo = | Email of EmailContactInfo | Addr of PostalContactInfo | Facebook of FacebookInfo | SMS of PhoneNumber |Twitter of TwitterId | Skype of SkypeId
  • 134. Summary • Represent the shared mental model in code – The developers should become domain experts too – Design collaboratively to build the shared mental model • Designs will evolve – Embrace change. This is not Big Design Up Front – Refactor towards deeper insight – Static types give you confidence to make changes
  • 135. Summary • Use the power of a composable type system – Choices rather than inheritance – Options instead of null – Avoid primitive types – Model constraints with new types – Make illegal states unrepresentable
  • 136. Slides and video at fsharpforfunandprofit.com/ddd Thanks!