Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.
Prologue: how many things are wrong?

type Contact = {

FirstName: string
MiddleInitial: string
LastName: string
EmailAddr...
Prologue: which values are optional?

type Contact = {
FirstName: string
MiddleInitial: string
LastName: string
EmailAddre...
Prologue: what are the constraints?

type Contact = {
FirstName: string
MiddleInitial: string
LastName: string
EmailAddres...
Prologue: what groups are atomic?
type Contact = {

FirstName: string
MiddleInitial: string
LastName: string
EmailAddress:...
Prologue: domain logic?
type Contact = {

FirstName: string
MiddleInitial: string
LastName: string
EmailAddress: string
Is...
Prologue: F# can help
type Contact = {
FirstName: string
MiddleInitial: string
LastName: string
EmailAddress: string
IsEma...
Domain Driven Design
with the F# type system
Scott Wlaschin
@ScottWlaschin
fsharpforfunandprofit.com /ddd
What is DDD?

What is F#?

What is DDD and F#?

“F# is a mature, open
source, cross-platform,
functional-first programming...
What I’m going talk about:

• Functional programming for real
world applications
• F# vs. C# for domain driven design
• Un...
Functional programming
for real world applications
Functional programming is...
... good for mathematical and scientific tasks
... good for complicated algorithms
... really...
Functional programming is good for...

Boring
Line Of Business
Applications
(BLOBAs)
Must haves for BLOBA development...
• Express requirements clearly
• Rapid development cycle
• High quality deliverables
•...
F# vs. C#
for Domain Driven Design
Values vs. Entities
Values vs. Entities

Photo credit: http://www.flickr.com/photos/anacooke/
Values vs. Entities

Photo credit: http://www.flickr.com/photos/anacooke/
Values vs. Entities

Examples of Values:
• Personal name
• Email address
• Postal address
• Product code
uneaten apple

Ex...
How do you implement a Value object?

Equality based on comparing all properties
PersonalName:
FirstName = "Alice"
LastNam...
Value object definition in C#
class PersonalName
{
public PersonalName(string firstName, string lastName)
{
this.FirstName...
Value object definition in C# (extra code for equality)
class PersonalName
{
// all the code from above, plus...
public ov...
Value object definition in F#
type PersonalName = {FirstName:string; LastName:string}
Value object definition in F# (extra code for equality)

This page intentionally left blank
How do you implement an Entity object?

Equality based on some sort of id
Person:
Equal Person:
Id = 1
Id = 1
Name = "Alic...
Entity object definition in C# (part 1)
class Person
{
public Person(int id, PersonalName name)
{
this.Id = id;
this.Name ...
Entity object definition in C# (part 2)
class Person
{
// all the code from above, plus...
public override int GetHashCode...
Entity object definition in F# with equality override
[<CustomEquality; NoComparison>]
type Person = {Id:int; Name:Persona...
Entity object definition in F# with no equality allowed
[<CustomEquality; NoComparison>]
[<NoEquality; NoComparison>]
type...
Entity immutability
[<NoEquality; NoComparison>]
type Person = { ... ... ... }

let tryCreatePerson name =
// validate on ...
Entity object definition in F# with mutability
[<NoEquality; NoComparison>]
type Person = {Id:int; mutable Name:PersonalNa...
Reviewing the C# code so far...

: IValue

class PersonalName
{
public PersonalName(string firstName, string lastName)
{
t...
Reviewing the C# code so far...

: IValue

class PersonalName
{
public PersonalName(string firstName, string lastName)
{
t...
Reviewing the F# code so far...

[<StructuralEquality;NoComparison>]
type PersonalName = {
FirstName : string;
LastName : ...
Comparing C# vs. F#

C#

Value objects?
Entity objects?
Value objects by default?
Immutable objects by default?
Can you te...
F# for Domain Driven Design
Communicating a domain model
Communication is hard...

U-N-I-O-N-I-Z-E
Communication in DDD: “Bounded Context”

Supermarket
Marketing
Sales
Business
Customer
unionize
Product
Spam

Email System...
Communication in DDD: “Ubiquitous Language”

Warehouse
Chemistry
Sales
IonProduct MoleculeTransfer Depot Tracking
Product ...
module CardGame =
type Suit = Club | Diamond | Spade | Heart

Ubiquitous language

type Rank = Two | Three | Four | Five |...
module CardGame =
type Suit = Club | Diamond | Spade | Heart

Ubiquitous language

type Rank = Two | Three | Four | Five |...
module CardGame =
type Suit = Club | Diamond | Spade | Heart
type Rank = Two | Three | Four | Five | Six | Seven | Eight
|...
module CardGame =
type Suit = Club | Diamond | Spade | Heart
type Rank = Two | Three | Four | Five | Six | Seven | Eight
|...
Understanding the F# type system
An introduction to “algebraic” types
Understanding the F# type system
An introduction to “composable” types
Composable types
Creating new types in F#

New types in F# are constructed by combining
other types using two basic operations:
type typeW ...
Creating new types in F#

1
2
3
4

(aAddOne
function)
int –› int

2
3
4
5
Representing pairs

(1,2)
(2,3)
(3,4)
(4,5)

AddPair
? –› int

3
5
7
9
Representing pairs

(1,2)
(2,3)
(3,4)
(4,5)

=

1
2
3
4

×

2
3
4
5
Representing pairs

(true, false)
(true, true)
(false, false)
(false, true)

=

true
false

×

true
false
Representing pairs

pair of ints
written int * int
pair of bools
written bool * bool
Using tuples for data

Alice, Jan 12th
Bob, Feb 2nd
Carol, Mar 3rd

=

Set of
people

×

Set of
dates
Using tuples for data

Alice, Jan 12th
Bob, Feb 2nd
Carol, Mar 3rd

=

Set of
people

×

Set of
dates

type Birthday = Per...
Representing a choice

Temp F

or
Temp C

IsFever
? –› bool

true
false
Representing a choice

Temp F

or
Temp C

98˚ F
99˚ F
100˚ F
101˚ F

= +
37.0˚ C
37.5˚ C
38.0˚ C
38.5˚ C
Representing a choice

Temp F

or
Temp C

98˚ F
99˚ F
100˚ F
101˚ F

= +
37.0˚ C
37.5˚ C
38.0˚ C
38.5˚ C

type Temp =
| F ...
Using choices for data

type PaymentMethod =
| Cash
| Cheque of int
| Card of CardType * CardNumber
Working with a choice type
type PaymentMethod =
| Cash
| Cheque of int
| Card of CardType * CardNumber
let printPayment me...
What are types for in F#?

An annotation to a value for type checking
type AddOne: int –› int

Domain modelling tool
type ...
TYPE ALL THE THINGS
Designing with types
What can we do with this type system?
Required vs. Optional

type PersonalName =
{
FirstName: string;
MiddleInitial: string;
LastName: string;
}

required
optio...
Null is not the same as “optional”

“a”
“b”
“c”
null

Length
string –› int

1
2
3
Spock, set
phasers to null!

That is illogical,
Captain
Null is not the same as “optional”

“a”
“b”
“c”
null

Length
string –› int

1
2
3
Null is not allowed in F#

“a”
“b”
“c”
null
X

Length
string –› int

1
2
3
A better way for optional values

“a”
“b”
“c”
or

“a”
“b”
“c”

= +

type OptionalString =
| SomeString of string
| Nothing...
Defining optional types
type OptionalString =
| SomeString of string
| Nothing
type OptionalInt =
| SomeInt of int
| Nothi...
The built-in “Option” type

type Option<'T> =
| Some of 'T
| None
type PersonalName =
{
FirstName: string
MiddleInitial: s...
The built-in “Option” type

type Option<'T> =
| Some of 'T
| None
type PersonalName =
{
FirstName: string
MiddleInitial: O...
The built-in “Option” type

type Option<'T> =
| Some of 'T
| None
type PersonalName =
{
FirstName: string
MiddleInitial: s...
Single choice types

type Something =
| ChoiceA of A
type Email =
| Email of string
type CustomerId =
| CustomerId of int
Wrapping primitive types

Is an EmailAddress just a string?
Is a CustomerId just a int?
Use single choice types to keep th...
Creating the EmailAddress type

let createEmailAddress (s:string) =
if Regex.IsMatch(s,@"^S+@S+.S+$")
then (EmailAddress s...
Creating the EmailAddress type

let createEmailAddress (s:string) =
if Regex.IsMatch(s,@"^S+@S+.S+$")
then Some (EmailAddr...
Constrained strings

type String50 = String50 of string

let createString50 (s:string) =
if s.Length <= 50
then Some (Stri...
Constrained numbers

Qty: – 999999 +

Add To Cart
Constrained numbers

type OrderLineQty = OrderLineQty of int

let createOrderLineQty qty =
if qty >0 && qty <= 99
then Som...
The challenge, revisited

type Contact = {

FirstName: string
MiddleInitial: string
LastName: string
EmailAddress: string
...
The challenge, revisited

type Contact = {

FirstName: string
MiddleInitial: string option
LastName: string
EmailAddress: ...
The challenge, revisited

type Contact = {

FirstName: String50
MiddleInitial: String1 option
LastName: String50
EmailAddr...
The challenge, revisited
type PersonalName = {
FirstName: String50
MiddleInitial: String1 option
LastName: String50 }

typ...
Encoding domain logic

type EmailContactInfo = {
EmailAddress: EmailAddress
IsEmailVerified: bool }
Rule 1: If the email i...
Encoding domain logic

type VerifiedEmail = VerifiedEmail of EmailAddress
type VerificationService =
(EmailAddress * Verif...
The challenge, completed
type EmailAddress = ...
type VerifiedEmail =
VerifiedEmail of EmailAddress

type PersonalName = {...
Making illegal states unrepresentable

New rule:
“A contact must have an email or a postal address”

type Contact = {
Name...
Making illegal states unrepresentable

New rule:
“A contact must have an email or a postal address”

type Contact = {
Name...
Making illegal states unrepresentable

“A contact must have an email or a postal address”
implies:
• email address only, o...
Making illegal states unrepresentable

“A contact must have an email or a postal address”
type ContactInfo =
| EmailOnly o...
Making illegal states unrepresentable

“A contact must have an email or a postal address”
BEFORE: Email and address separa...
Making illegal states unrepresentable

“A contact must have an email or a postal address”
Making illegal states unrepresentable
“A contact must have at leastemail or of postalcontacted”
“A contact must have an on...
Stuff I haven’t had time to cover:
• Services
• States and transitions
• CQRS
• The functional approach to use cases
• Dom...
F# is low risk

Enterprise
development

Mobile
development

F# on over
2 billion devices

F# is the safe choice for functi...
Thank you!

fsharpforfunandprofit.com/ddd
fsharp.org/testimonials
tryfsharp.org
try F# in your web browser!

@ScottWlaschi...
Domain Driven Design with the F# type System -- NDC London 2013
Domain Driven Design with the F# type System -- NDC London 2013
Domain Driven Design with the F# type System -- NDC London 2013
Domain Driven Design with the F# type System -- NDC London 2013
Domain Driven Design with the F# type System -- NDC London 2013
Domain Driven Design with the F# type System -- NDC London 2013
Domain Driven Design with the F# type System -- NDC London 2013
Upcoming SlideShare
Loading in …5
×

Domain Driven Design with the F# type System -- NDC London 2013

21,577 views

Published on

(Video of these slides here http://fsharpforfunandprofit.com/ddd)

Statically typed functional programming languages like F# encourage a very different way of thinking about types. The type system is your friend, not an annoyance, and can be used in many ways that might not be familiar to OO programmers.

Types can be used to represent the domain in a fine-grained, self documenting way. And in many cases, types can even be used to encode business rules so that you literally cannot create incorrect code. You can then use the static type checking almost as an instant unit test — making sure that your code is correct at compile time.

In this talk, we'll look at some of the ways you can use types as part of a domain driven design process, with some simple real world examples in F#. No jargon, no maths, and no prior F# experience necessary.

Code, links to video, etc., at http://fsharpforfunandprofit.com/ddd

For more on DDD and F# see:

http://fsharpforfunandprofit.com/ddd/
http://tomasp.net/blog/type-first-development.aspx/
http://gorodinski.com/blog/2013/02/17/domain-driven-design-with-fsharp-and-eventstore/

Published in: Technology
  • Nice !! Download 100 % Free Ebooks, PPts, Study Notes, Novels, etc @ https://www.ThesisScientist.com
       Reply 
    Are you sure you want to  Yes  No
    Your message goes here
  • @Paul Jurczak Slide 98 has same subtypes and defines one as primary. Slide 94 has different subtypes but doesn't define one as primary. Trying to do both is possible (tuples inside a sum type), but at some point the code gets more ugly than it's worth and you hit diminishing returns! In real life it's not often that requirements are so strict anyway.
       Reply 
    Are you sure you want to  Yes  No
    Your message goes here
  • @Paul Jurczak Slide 98 has same subtypes and defines one as primary. Slide 94 has different subtypes but doesn't define one as primary. Trying to do both is possible (tuples inside a sum type), but at some point the code gets more ugly than it's worth and you hit diminishing returns! In real life it's not often that requirements are so strict anyway.
       Reply 
    Are you sure you want to  Yes  No
    Your message goes here
  • I've just seen the NDC 2014 version of this presentation and I have a comment about Contact type from page 98. It allows for PrimaryContactInfo and SecondaryContactInfo to be equal, which is not what you intended, right? Is there a way to define Contact requiring PrimaryContactInfo and SecondaryContactInfo to be of different subtypes?
       Reply 
    Are you sure you want to  Yes  No
    Your message goes here
  • @robertwlaschin Hi Robert - great to meet a real namesake!

    Glad you liked the slides -- if you want more on F#, try my blog at fsharpforfunandprofit.com.

    Thanks!
       Reply 
    Are you sure you want to  Yes  No
    Your message goes here

Domain Driven Design with the F# type System -- NDC London 2013

  1. 1. Prologue: how many things are wrong? type Contact = { FirstName: string MiddleInitial: string LastName: string EmailAddress: string IsEmailVerified: bool // true if ownership of } // email address is confirmed Domain Driven Design with the F# type system
  2. 2. Prologue: which values are optional? type Contact = { FirstName: string MiddleInitial: string LastName: string EmailAddress: string IsEmailVerified: bool }
  3. 3. Prologue: what are the constraints? type Contact = { FirstName: string MiddleInitial: string LastName: string EmailAddress: string IsEmailVerified: bool }
  4. 4. Prologue: what groups are atomic? type Contact = { FirstName: string MiddleInitial: string LastName: string EmailAddress: string IsEmailVerified: bool }
  5. 5. Prologue: domain logic? type Contact = { FirstName: string MiddleInitial: string LastName: string EmailAddress: string IsEmailVerified: bool }
  6. 6. Prologue: F# can help type Contact = { FirstName: string MiddleInitial: string LastName: string EmailAddress: string IsEmailVerified: bool }
  7. 7. Domain Driven Design with the F# type system Scott Wlaschin @ScottWlaschin fsharpforfunandprofit.com /ddd
  8. 8. What is DDD? What is F#? What is DDD and F#? “F# is a mature, open source, cross-platform, functional-first programming language which empowers users and organizations to tackle complex computing problems with simple, maintainable and robust code.” — fsharp.org
  9. 9. What I’m going talk about: • Functional programming for real world applications • F# vs. C# for domain driven design • Understanding the F# type system • Designing with types
  10. 10. Functional programming for real world applications
  11. 11. Functional programming is... ... good for mathematical and scientific tasks ... good for complicated algorithms ... really good for parallel processing ... but you need a PhD in computer science 
  12. 12. Functional programming is good for... Boring Line Of Business Applications (BLOBAs)
  13. 13. Must haves for BLOBA development... • Express requirements clearly • Rapid development cycle • High quality deliverables • Fun
  14. 14. F# vs. C# for Domain Driven Design Values vs. Entities
  15. 15. Values vs. Entities Photo credit: http://www.flickr.com/photos/anacooke/
  16. 16. Values vs. Entities Photo credit: http://www.flickr.com/photos/anacooke/
  17. 17. Values vs. Entities Examples of Values: • Personal name • Email address • Postal address • Product code uneaten apple Examples of Entities: • Customer • Order • Product half eaten apple
  18. 18. How do you implement a Value object? Equality based on comparing all properties PersonalName: FirstName = "Alice" LastName = "Adams" PersonalName: FirstName = "Alice" Equal LastName = "Adams"  Therefore must be immutable
  19. 19. Value object definition in C# class PersonalName { public PersonalName(string firstName, string lastName) { this.FirstName = firstName; this.LastName = lastName; } public string FirstName { get; private set; } public string LastName { get; private set; } }
  20. 20. Value object definition in C# (extra code for equality) class PersonalName { // all the code from above, plus... public override int GetHashCode() { return this.FirstName.GetHashCode() + this.LastName.GetHashCode(); } public override bool Equals(object other) { return Equals(other as PersonalName); } public bool Equals(PersonalName other) { if ((object) other == null) { return false; } return FirstName == other.FirstName && LastName == other.LastName; }
  21. 21. Value object definition in F# type PersonalName = {FirstName:string; LastName:string}
  22. 22. Value object definition in F# (extra code for equality) This page intentionally left blank
  23. 23. How do you implement an Entity object? Equality based on some sort of id Person: Equal Person: Id = 1 Id = 1 Name = "Alice Adams" X Name = "Bilbo Baggins"  Generally has mutable content
  24. 24. Entity object definition in C# (part 1) class Person { public Person(int id, PersonalName name) { this.Id = id; this.Name = name; } public int Id { get; private set; } public PersonalName Name { get; set; } }
  25. 25. Entity object definition in C# (part 2) class Person { // all the code from above, plus... public override int GetHashCode() { return this.Id.GetHashCode(); } public override bool Equals(object other) { return Equals(other as Person); } public bool Equals(Person other) { if ((object) other == null) { return false; } return Id == other.Id; } }
  26. 26. Entity object definition in F# with equality override [<CustomEquality; NoComparison>] type Person = {Id:int; Name:PersonalName} with override this.GetHashCode() = hash this.Id override this.Equals(other) = match other with | :? Person as p -> (this.Id = p.Id) | _ -> false
  27. 27. Entity object definition in F# with no equality allowed [<CustomEquality; NoComparison>] [<NoEquality; NoComparison>] type Person = {Id:int; Name:PersonalName}
  28. 28. Entity immutability [<NoEquality; NoComparison>] type Person = { ... ... ... } let tryCreatePerson name = // validate on construction // if input is valid return something // if input is not valid return error  
  29. 29. Entity object definition in F# with mutability [<NoEquality; NoComparison>] type Person = {Id:int; mutable Name:PersonalName}
  30. 30. Reviewing the C# code so far... : IValue class PersonalName { public PersonalName(string firstName, string lastName) { this.FirstName = firstName; this.LastName = lastName; } : IEntity class Person { public Person(int id, PersonalName name) { this.Id = id; this.Name = name; } public string FirstName { get; private set; } public string LastName { get; private set; } public int Id { get; private set; } public PersonalName Name { get; set; } public override int GetHashCode() { return this.FirstName.GetHashCode() + this.LastName.GetHashCode(); } public override int GetHashCode() { return this.Id.GetHashCode(); } public override bool Equals(object other) { return Equals(other as Person); } public override bool Equals(object other) { return Equals(other as PersonalName); } public bool Equals(PersonalName other) { if ((object) other == null) { return false; } return FirstName == other.FirstName && LastName == other.LastName; } } public bool Equals(Person other) { if ((object) other == null) { return false; } return Id == other.Id; } }
  31. 31. Reviewing the C# code so far... : IValue class PersonalName { public PersonalName(string firstName, string lastName) { this.FirstName = firstName; this.LastName = lastName; } : IEntity class Person { public Person(int id, PersonalName name) { this.Id = id; this.Name = name; } public string FirstName { get; private set; } public string LastName { get; private set; } public int Id { get; private set; } public PersonalName Name { get; set; } public override int GetHashCode() { return this.FirstName.GetHashCode() + this.LastName.GetHashCode(); } public override int GetHashCode() { return this.Id.GetHashCode(); } public override bool Equals(object other) { return Equals(other as Person); } public override bool Equals(object other) { return Equals(other as PersonalName); } public bool Equals(PersonalName other) { if ((object) other == null) { return false; } return FirstName == other.FirstName && LastName == other.LastName; } } public bool Equals(Person other) { if ((object) other == null) { return false; } return Id == other.Id; } }
  32. 32. Reviewing the F# code so far... [<StructuralEquality;NoComparison>] type PersonalName = { FirstName : string; LastName : string } [<NoEquality; NoComparison>] type Person = { Id : int; Name : PersonalName }
  33. 33. Comparing C# vs. F# C# Value objects? Entity objects? Value objects by default? Immutable objects by default? Can you tell Value objects from Entities at a glance? Understandable by non-programmer? F# Non-trivial Non-trivial No No No Easy Easy Yes Yes Yes No Yes
  34. 34. F# for Domain Driven Design Communicating a domain model
  35. 35. Communication is hard... U-N-I-O-N-I-Z-E
  36. 36. Communication in DDD: “Bounded Context” Supermarket Marketing Sales Business Customer unionize Product Spam Email System Warehouse Finance Chemistry Customer un-ionize Product Spam
  37. 37. Communication in DDD: “Ubiquitous Language” Warehouse Chemistry Sales IonProduct MoleculeTransfer Depot Tracking Product Stock Atom Promotion Customer Tracking Polymer Compound Bond
  38. 38. module CardGame = type Suit = Club | Diamond | Spade | Heart Ubiquitous language type Rank = Two | Three | Four | Five | Six | Seven | Eight | Nine | Ten | Jack | Queen | King | Ace 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
  39. 39. module CardGame = type Suit = Club | Diamond | Spade | Heart Ubiquitous language type Rank = Two | Three | Four | Five | Six | Seven | Eight | Nine | Ten | Jack | Queen | King | Ace type Card = Suit * Rank type Hand = Card list type Deck = Card list '*' means a pair. Choose one from each type list type is built in type Player = {Name:string; Hand:Hand} type Game = {Deck:Deck; Players: Player list} type Deal = Deck –› (Deck * Card) type PickupCard = (Hand * Card) –› Hand
  40. 40. module CardGame = type Suit = Club | Diamond | Spade | Heart type Rank = Two | Three | Four | Five | Six | Seven | Eight | Nine | Ten | Jack | Queen | King | Ace 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
  41. 41. module CardGame = type Suit = Club | Diamond | Spade | Heart type Rank = Two | Three | Four | Five | Six | Seven | Eight | Nine | Ten | Jack | Queen | King | Ace 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
  42. 42. Understanding the F# type system An introduction to “algebraic” types
  43. 43. Understanding the F# type system An introduction to “composable” types
  44. 44. Composable types
  45. 45. Creating new types in F# New types in F# are constructed by combining other types using two basic operations: type typeW = typeX "times" typeY type typeZ = typeX "plus" typeY
  46. 46. Creating new types in F# 1 2 3 4 (aAddOne function) int –› int 2 3 4 5
  47. 47. Representing pairs (1,2) (2,3) (3,4) (4,5) AddPair ? –› int 3 5 7 9
  48. 48. Representing pairs (1,2) (2,3) (3,4) (4,5) = 1 2 3 4 × 2 3 4 5
  49. 49. Representing pairs (true, false) (true, true) (false, false) (false, true) = true false × true false
  50. 50. Representing pairs pair of ints written int * int pair of bools written bool * bool
  51. 51. Using tuples for data Alice, Jan 12th Bob, Feb 2nd Carol, Mar 3rd = Set of people × Set of dates
  52. 52. Using tuples for data Alice, Jan 12th Bob, Feb 2nd Carol, Mar 3rd = Set of people × Set of dates type Birthday = Person * Date
  53. 53. Representing a choice Temp F or Temp C IsFever ? –› bool true false
  54. 54. Representing a choice Temp F or Temp C 98˚ F 99˚ F 100˚ F 101˚ F = + 37.0˚ C 37.5˚ C 38.0˚ C 38.5˚ C
  55. 55. Representing a choice Temp F or Temp C 98˚ F 99˚ F 100˚ F 101˚ F = + 37.0˚ C 37.5˚ C 38.0˚ C 38.5˚ C type Temp = | F of int | C of float Tag these with “C”
  56. 56. Using choices for data type PaymentMethod = | Cash | Cheque of int | Card of CardType * CardNumber
  57. 57. Working with a choice type type PaymentMethod = | Cash | Cheque of int | Card of CardType * CardNumber let printPayment method = match method with | Cash –› printfn “Paid in cash" | Cheque checkNo –› printfn “Paid by cheque: %i" checkNo | Card (cardType,cardNo) –› printfn “Paid with %A %A" cardType cardNo
  58. 58. What are types for in F#? An annotation to a value for type checking type AddOne: int –› int Domain modelling tool type Deal = Deck –› (Deck * Card)
  59. 59. TYPE ALL THE THINGS
  60. 60. Designing with types What can we do with this type system?
  61. 61. Required vs. Optional type PersonalName = { FirstName: string; MiddleInitial: string; LastName: string; } required optional required
  62. 62. Null is not the same as “optional” “a” “b” “c” null Length string –› int 1 2 3
  63. 63. Spock, set phasers to null! That is illogical, Captain
  64. 64. Null is not the same as “optional” “a” “b” “c” null Length string –› int 1 2 3
  65. 65. Null is not allowed in F# “a” “b” “c” null X Length string –› int 1 2 3
  66. 66. A better way for optional values “a” “b” “c” or “a” “b” “c” = + type OptionalString = | SomeString of string | Nothing missing Tag with “Nothing”
  67. 67. Defining optional types type OptionalString = | SomeString of string | Nothing type OptionalInt = | SomeInt of int | Nothing type OptionalBool = | SomeBool of bool | Nothing
  68. 68. The built-in “Option” type type Option<'T> = | Some of 'T | None type PersonalName = { FirstName: string MiddleInitial: string LastName: string }
  69. 69. The built-in “Option” type type Option<'T> = | Some of 'T | None type PersonalName = { FirstName: string MiddleInitial: Option<string> LastName: string }
  70. 70. The built-in “Option” type type Option<'T> = | Some of 'T | None type PersonalName = { FirstName: string MiddleInitial: string option LastName: string }
  71. 71. Single choice types type Something = | ChoiceA of A type Email = | Email of string type CustomerId = | CustomerId of int
  72. 72. Wrapping primitive types Is an EmailAddress just a string? Is a CustomerId just a int? Use single choice types to keep them distinct type EmailAddress = EmailAddress of string type PhoneNumber = PhoneNumber of string type CustomerId = CustomerId of int type OrderId = OrderId of int
  73. 73. Creating the EmailAddress type let createEmailAddress (s:string) = if Regex.IsMatch(s,@"^S+@S+.S+$") then (EmailAddress s) else ? createEmailAddress: string –› EmailAddress
  74. 74. Creating the EmailAddress type let createEmailAddress (s:string) = if Regex.IsMatch(s,@"^S+@S+.S+$") then Some (EmailAddress s) (EmailAddress s) else None ? createEmailAddress: string –› EmailAddress option
  75. 75. Constrained strings type String50 = String50 of string let createString50 (s:string) = if s.Length <= 50 then Some (String50 s) else None createString50 : string –› String50 option
  76. 76. Constrained numbers Qty: – 999999 + Add To Cart
  77. 77. Constrained numbers type OrderLineQty = OrderLineQty of int let createOrderLineQty qty = if qty >0 && qty <= 99 then Some (OrderLineQty qty) else None createOrderLineQty: int –› OrderLineQty option
  78. 78. The challenge, revisited type Contact = { FirstName: string MiddleInitial: string LastName: string EmailAddress: string IsEmailVerified: bool }
  79. 79. The challenge, revisited type Contact = { FirstName: string MiddleInitial: string option LastName: string EmailAddress: string IsEmailVerified: bool }
  80. 80. The challenge, revisited type Contact = { FirstName: String50 MiddleInitial: String1 option LastName: String50 EmailAddress: EmailAddress IsEmailVerified: bool }
  81. 81. The challenge, revisited type PersonalName = { FirstName: String50 MiddleInitial: String1 option LastName: String50 } type Contact = { Name: PersonalName Email: EmailContactInfo } type EmailContactInfo = { EmailAddress: EmailAddress IsEmailVerified: bool }
  82. 82. Encoding domain logic 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
  83. 83. Encoding domain logic type VerifiedEmail = VerifiedEmail of EmailAddress type VerificationService = (EmailAddress * VerificationHash) –› VerifiedEmail option type EmailContactInfo = | Unverified of EmailAddress | Verified of VerifiedEmail
  84. 84. The challenge, completed type EmailAddress = ... type VerifiedEmail = VerifiedEmail of EmailAddress type PersonalName = { FirstName: String50 MiddleInitial: String1 option LastName: String50 } type EmailContactInfo = | Unverified of EmailAddress | Verified of VerifiedEmail type Contact = { Name: PersonalName Email: EmailContactInfo }
  85. 85. Making illegal states unrepresentable New rule: “A contact must have an email or a postal address” type Contact = { Name: Name Email: EmailContactInfo Address: PostalContactInfo }
  86. 86. Making illegal states unrepresentable New rule: “A contact must have an email or a postal address” type Contact = { Name: Name Email: EmailContactInfo option Address: PostalContactInfo option }
  87. 87. Making 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
  88. 88. Making illegal states unrepresentable “A contact must have an email or a postal address” type ContactInfo = | EmailOnly of EmailContactInfo | AddrOnly of PostalContactInfo | EmailAndAddr of EmailContactInfo * PostalContactInfo type Contact = { Name: Name ContactInfo : ContactInfo }
  89. 89. Making illegal states unrepresentable “A contact must have an email or a postal address” BEFORE: Email and address separate type Contact = { Name: Name Email: EmailContactInfo Address: PostalContactInfo } AFTER: Email and address merged into one type type Contact = { Name: Name ContactInfo : ContactInfo } type ContactInfo = | EmailOnly of EmailContactInfo | AddrOnly of PostalContactInfo | EmailAndAddr of EmailContactInfo * PostalContactInfo
  90. 90. Making illegal states unrepresentable “A contact must have an email or a postal address”
  91. 91. Making illegal states unrepresentable “A contact must have at leastemail or of postalcontacted” “A contact must have an one way a being address” type ContactInfo = | Email of EmailContactInfo | Addr of PostalContactInfo type Contact = { Name: Name PrimaryContactInfo: ContactInfo SecondaryContactInfo: ContactInfo option }
  92. 92. Stuff I haven’t had time to cover: • Services • States and transitions • CQRS • The functional approach to use cases • Domain events • Error handling • And much more...
  93. 93. F# is low risk Enterprise development Mobile development F# on over 2 billion devices F# is the safe choice for functional-first development credit: @7sharp9 @MattDrivenDev
  94. 94. Thank you! fsharpforfunandprofit.com/ddd fsharp.org/testimonials tryfsharp.org try F# in your web browser! @ScottWlaschin #fsharp on Twitter

×