F# Bolero how to set the code apart to make the project structure clear?

126 Views Asked by At

I'm new to F# and Bolero. and after initialize the project as the docs shows, I find that sample application demonstrates 3 types of web applications but main codes is in one file called Main.fs .

here is part codes:

type Message =
    | SetPage of Page
    | Increment
    | Decrement
    | SetCounter of int
    | GetBooks
    | GotBooks of Book[]
    | SetUsername of string
    | SetPassword of string
    | GetSignedInAs
    | RecvSignedInAs of option<string>
    | SendSignIn
    | RecvSignIn of option<string>
    | SendSignOut
    | RecvSignOut
    | Error of exn
    | ClearError

let update remote message model =
    let onSignIn = function
        | Some _ -> Cmd.ofMsg GetBooks
        | None -> Cmd.none
    match message with
    | SetPage page ->
        { model with page = page }, Cmd.none

    | Increment ->
        { model with counter = model.counter + 1 }, Cmd.none
    | Decrement ->
        { model with counter = model.counter - 1 }, Cmd.none
    | SetCounter value ->
        { model with counter = value }, Cmd.none

    | GetBooks ->
        let cmd = Cmd.OfAsync.either remote.getBooks () GotBooks Error
        { model with books = None }, cmd
    | GotBooks books ->
        { model with books = Some books }, Cmd.none

    | SetUsername s ->
        { model with username = s }, Cmd.none
    | SetPassword s ->
        { model with password = s }, Cmd.none
    | GetSignedInAs ->
        model, Cmd.OfAuthorized.either remote.getUsername () RecvSignedInAs Error
    | RecvSignedInAs username ->
        { model with signedInAs = username }, onSignIn username
    | SendSignIn ->
        model, Cmd.OfAsync.either remote.signIn (model.username, model.password) RecvSignIn Error
    | RecvSignIn username ->
        { model with signedInAs = username; signInFailed = Option.isNone username }, onSignIn username
    | SendSignOut ->
        model, Cmd.OfAsync.either remote.signOut () (fun () -> RecvSignOut) Error
    | RecvSignOut ->
        { model with signedInAs = None; signInFailed = false }, Cmd.none

    | Error RemoteUnauthorizedException ->
        { model with error = Some "You have been logged out."; signedInAs = None }, Cmd.none
    | Error exn ->
        { model with error = Some exn.Message }, Cmd.none
    | ClearError ->
        { model with error = None }, Cmd.none


As you can see, the code is too long to manage. if I add more functionality I can barely imagine what the file will be like.

so how can I split the code into different files ?

1

There are 1 best solutions below

3
On

The most basic thing you could do is to split your Message type into multiple separate types and have one corresponding to different aspects of the logic. For example:

type CounterMessage = 
    | Increment
    | Decrement
    | SetCounter of int

type BooksMessage = 
    | GetBooks
    | GotBooks of Book[]

type Message =
    | SetPage of Page
    | CounterMessage of CounterMessage
    | BooksMessage of BooksMessage

Then you can similarly split your update function - and move each of the message-specific functions to a separate file:

let updateCounter remote message model = 
    match message with
    | Increment ->
        { model with counter = model.counter + 1 }, Cmd.none
    | Decrement ->
        { model with counter = model.counter - 1 }, Cmd.none
    | SetCounter value ->
        { model with counter = value }, Cmd.none

let update remote message model =
    match message with
    | SetPage page ->
        { model with page = page }, Cmd.none
    | CounterMessage msg ->
        updateCounter remote message model
    // (...)

This is something using just basic F# langauge mechanisms. Perhaps Bolero has some more sophisticated methods for structuring projects, but this is simple option will always work. The disadvantage is that you need to handle the "forwarding" of the messages yourself (and this is something that a more sophisticated option may alleviate) - but I think that for a moderately sized project, it is not such a bad things (and it helps making things explicit and clear).