DEV Community

loading...

Discussion on: Organizing MVU Projects

Collapse
tysonmn profile image
Tyson Williams

Great post. Thanks for sharing all of these detailed thoughts. I make similar decisions with an MVU application, so it is thought provoking to see the choices made by others.

However I saw some opportunities for improvement. First it seemed like a mix of concerns to have update potentially creating a side effect function. Secondly it left update less testable than it could be. You can test the model easily, but it is quite invasive to test whether the correct side effects were requested. The ideal would be for Cmd to be just data representing the side effect and its necessary arguments.

I called the type Effect. [...] I call the function for this perform.

I like your names.

In Elmish.WPF, we call this the Command Message (CmdMsg) pattern. I don't know where that idea originated. It was part of the project before I became a co-maintiner.

In basic examples, I call the type CmdMsg and the function bindCmd. In my large application at work, I found the short type names like Model, Msg, and CmdMsg confusing because the tooltips don't include the namespace/module containing that type. As such, I now include the domain terms in the type names. For example, one group of types could be named BlogPost (without the suffix Model), BlogPostMsg, and BlogPostCmdMsg.

[...] Msg, InitArgs, and Model all have the same basic tree structure, but with different types as leaf nodes. To avoid conflicts, I must name them slightly differently.

There is another way to avoid naming conflicts. Instead of

type Msg =
  | HomeMsg of Home.Msg
  | CourseSearchMsg of Course.Search.Msg
  | CourseDetailMsg of Course.Detail.Msg

type InitArgs =
  | HomeInit of Home.InitArgs
  | CourseSearchInit of Course.Search.InitArgs
  | CourseDetailInit of Course.Detail.InitArgs
Enter fullscreen mode Exit fullscreen mode

you can do

[<RequiredQualifiedAccess>]
type Msg =
  | Home of Home.Msg
  | CourseSearch of Course.Search.Msg
  | CourseDetail of Course.Detail.Msg

[<RequiredQualifiedAccess>]
type InitArgs =
  | Home of Home.InitArgs
  | CourseSearch of Course.Search.InitArgs
  | CourseDetail of Course.Detail.InitArgs
Enter fullscreen mode Exit fullscreen mode
Collapse
kspeakman profile image
Kasey Speakman Author

Thanks for the great comment!

RequireQualifiedAccess is another good option I did not think about. Thanks for mentioning it.

I am still evaluating the last option which would eliminate the duplicate tree structures altogether.

The first time I thought of the Effect pattern was in 2018. We were starting a new project and moving away from Elm. I wanted to designate a place for side effects so init/update could remain pure. But I'm sure I was not the first with the idea. And I'm glad to not be the only one finding it useful.

Best wishes!