The builder pattern

When we need to pass many arguments to a function we might have something like

module Button exposing (..)

type alias Args =
    { isEnabled : Bool
    , label : String
    , hexColor : String
    , ...

btn: Args -> Html msg

In the caller module:

import Button

Button.btn { isEnabled = True, label = "Click me", ....}

The problem with this is that each time we add an argument to Args we need to change every single place where we call this function.


With builder pattern we build the arguments with the minimum necessary information, then modify the arguments if we need to.

module Button exposing (..)

newArgs: String -> Args
newArgs label =
    { isEnabled = True
    , label = label
    , hexColor: "#ABC"
    , ...

withIsEnabled : Bool -> Args -> Args
withIsEnabled isEnabled args =
    { args | isEnabled = isEnabled }

btn: Args -> Html msg

This modules exposes a function to create the initial arguments and a series of function to modify the arguments (commonly using with as prefix).

Then the caller module uses this:

import Button

aButton =
    Button.newArgs "Click me"
        |> Button.withIsEnabled False
        |> Button.withHexColor "#123"
        |> Button.btn

The advantage of this is that adding new arguments to Args doesn't require us to change every caller.

As test factories

This pattern is also very useful for tests. Similar to test factories in many languages. For example if we were testing a User, we could start with a basic user and then use the builder pattern to modify attributes for different tests.