Slide 1

Slide 1 text

WORKING WITH MAYBE

Slide 2

Slide 2 text

There are only two certainties in life: death, and taxes.

Slide 3

Slide 3 text

UNCERTAINTY IN CODE

Slide 4

Slide 4 text

USER INPUT

Slide 5

Slide 5 text

OTHER SYSTEMS

Slide 6

Slide 6 text

INSIDE YOUR PROGRAM

Slide 7

Slide 7 text

No content

Slide 8

Slide 8 text

SOCIETY FOR THE PRESERVATION OF VOWEL NAMES

Slide 9

Slide 9 text

> All names lowercase > Vowel names prefixed with asterisk > Display unknown donors as "Anonymous"

Slide 10

Slide 10 text

No content

Slide 11

Slide 11 text

No content

Slide 12

Slide 12 text

JAVASCRIPT let displayName = function(user) { if (startsWithVowel(user.name)) { "*" + user.name.toLowerCase(); } else { user.name.toLowerCase(); } }

Slide 13

Slide 13 text

IS THIS SAFE?

Slide 14

Slide 14 text

¯\_(ϑ)_/¯

Slide 15

Slide 15 text

UNCERTAINTY let user1 = null; let user2 = { name: null }; displayName(user1); displayName(user2);

Slide 16

Slide 16 text

You can never trust anything

Slide 17

Slide 17 text

NULL EXCEPTIONS

Slide 18

Slide 18 text

TYPE SYSTEMS?

Slide 19

Slide 19 text

NULL IS VIRAL

Slide 20

Slide 20 text

Uncertainty begets uncertainty

Slide 21

Slide 21 text

NULL IS USED TO REPRESENT MANY DIFFERENT CONCEPTS

Slide 22

Slide 22 text

THE ELM APPROACH

Slide 23

Slide 23 text

"Trust no one" vs "Trust everyone"

Slide 24

Slide 24 text

UNCERTAINTY PROBLEMS 1. any value can be missing at any time

Slide 25

Slide 25 text

UNCERTAINTY PROBLEMS 1. any value can be missing at any time

Slide 26

Slide 26 text

UNCERTAINTY PROBLEMS 1. any value can be missing at any time 2. Maybe is viral

Slide 27

Slide 27 text

UNCERTAINTY PROBLEMS 1. any value can be missing at any time 2. Maybe is viral 3. Programmers abuse the concept

Slide 28

Slide 28 text

formatName : Maybe User -> Maybe String startsWithVowel : Maybe String -> Maybe Bool

Slide 29

Slide 29 text

type alias User = { name : Maybe String } formatName : Maybe User -> Maybe String formatName maybeUser = case maybesUser of Just user -> case startsWithVowel user.name of Just True -> case user.name of Just name -> Just <| "*" ++ String.toLower name Nothing -> Nothing -- should never happen Just False -> case user.name of Just name -> Just <| String.toLower name Nothing -> Nothing -- should never happen Nothing -> Just "Anonymous" startsWithVowel : Maybe String -> Maybe Bool startsWithVowel name = -- ...

Slide 30

Slide 30 text

!!!

Slide 31

Slide 31 text

ELIMINATE THE MAYBE

Slide 32

Slide 32 text

UNWRAPPING EARLY getNameOrDefault : Maybe User -> String getNameOrDefault optionalUser = case optionalUser of Just user -> user.name Nothing -> ""

Slide 33

Slide 33 text

"DEFAULT VALUES"

Slide 34

Slide 34 text

ANOTHER FORM OF OPTIONAL viewName : Maybe User -> Html a viewName optionalUser = case getNameOrDefault optionalUser of "" -> text "Anonymous" actualName -> text actualName

Slide 35

Slide 35 text

EXPLICIT OPTIONAL VALUE viewName : Maybe User -> Html a viewName optionalUser = case optionalUser of Nothing -> text "Anonymous" Just user -> text user.name

Slide 36

Slide 36 text

POLYMORPHISM Passing default values like "" into a chain of functions is a clever way of no-opp

Slide 37

Slide 37 text

No content

Slide 38

Slide 38 text

GUIDELINE 1 Separate code that checks for presence from code that calculates values.

Slide 39

Slide 39 text

No content

Slide 40

Slide 40 text

No content

Slide 41

Slide 41 text

CONFIDENT BUSINESS FUNCTION formatName : User -> String formatName user = user.name |> String.toLower |> prefixVowelName

Slide 42

Slide 42 text

HANDLE THE MAYBE Maybe.map formatName optionalUser |> Maybe.withDefault "Anonymous"

Slide 43

Slide 43 text

Business functions cannot take Maybe as an argument

Slide 44

Slide 44 text

2 MAYBES Uncertain user and uncertain donation amount

Slide 45

Slide 45 text

BUSINESS FUNCTION WITH NO MAYBES userWithDonation : User -> Int -> String userWithDonation user donation = (formatName user) ++ " - $" ++ toString donation

Slide 46

Slide 46 text

map2 Maybe.map2 userWithDonation optionalUser optionalDonation |> Maybe.withDefault "Anonymous"

Slide 47

Slide 47 text

Write confident business-logic functions and only deal with Maybe at the edges of your system (with the appropriate map function)

Slide 48

Slide 48 text

UNCERTAINTY FROM WITHIN

Slide 49

Slide 49 text

findByName : String -> List User -> Maybe User findByName name users = users |> List.filter (\user -> user.name == name) |> List.head

Slide 50

Slide 50 text

GUIDELINE 2 Business functions may return Maybe but may not accept Maybe as any of its arguments.

Slide 51

Slide 51 text

QUARANTINE

Slide 52

Slide 52 text

type alias Session = { searchTerm : Maybe String } session.searchTerm |> Maybe.andThen (\name -> findByName name users)

Slide 53

Slide 53 text

IS Maybe BAD?

Slide 54

Slide 54 text

TWO MEANINGS List.head [] -- Nothing List.head [Nothing, { name = "Arthur" }] -- Nothing

Slide 55

Slide 55 text

MODEL THE DIFFERENCE type Donor = Anonymous | Named String

Slide 56

Slide 56 text

GUIDELINE 0 Actively try to model your data structures to avoid Maybe

Slide 57

Slide 57 text

FORCING A SINGLE SHAPE

Slide 58

Slide 58 text

UNCERTAINTY FROM WITHIN type alias DonorWizard = { donor : Maybe Donor , donationAmount : Maybe Int }

Slide 59

Slide 59 text

IMPOSSIBLE STATES { donor = Nothing , donationAmount = Just 100000 }

Slide 60

Slide 60 text

UNION TYPES type DonorWizard = Step1 (Maybe Donor) | Step2 Donor (Maybe Int) | Complete Donor Int

Slide 61

Slide 61 text

No content

Slide 62

Slide 62 text

> Actively try to model your data structures to avoid Maybe > Separate code that checks for presence from code that calculates values. > Business functions may return Maybe but may not accept Maybe as any of its arguments.

Slide 63

Slide 63 text

JOËL QUENNEVILLE > Github - github.com/JoelQ > Slack - @joelq > Twitter - @joelquen Come talk to me, I have postcards!