How to Modularize Big Files?

148 views
Skip to first unread message

Rex van der Spuy

unread,
Dec 2, 2016, 11:32:56 AM12/2/16
to Elm Discuss
Hi Everyone,

Over the past few months I've been follow the Best Practice recommendations in Elm World to not use nested Model/Update/View modules.
The general consensus seems to be just to keep one giant M/U/V engine running, and farm out specialized work to helper functions.
Cool, that make sense!
Updating child modules is a big chore anyway that I'm happy not to have to do.

But, the "small" application that I'm working at the moment has now grown to over 1000 lines of code.
I'm starting to have to hunt for things, do a lot of scrolling, and I'm forgetting how it's organized.
And I realized I have absolutely no idea at all how to modularize it into a sensible/understandable collection of smaller files.

Can anyone help?

Here's a code dump of what my main application code looks like so far:


(It's a kind of Eliza-like chat-bot - the code above won't run without some dependencies that I haven't included, but hopefully it illustrates my problem?)
Disclaimer: this is a work-in-progress and there is some redundant and, frankly, plain bad code I need to clean up -- so please ignore my messy work!!

But, can anyone recommend to me how I can organize this into a manageable series of smaller files?

The general way it's structured is:

- imports
- initial model
- update (including update helper functions)
- view (including css and elm-mdl components)
- subscriptions
- main app wiring


Thanks, Everyone!


Max Goldstein

unread,
Dec 2, 2016, 11:44:42 AM12/2/16
to Elm Discuss
I would want to move all of the view code to a new module, exposing only the view function itself. In order to do that, you'll have to move the definition of Model and Msg to a module imported by both Main and View. You can call this module Common. I think the initial model belongs next to its definition, in Common. I wish there was a way to keep Msg near update but View needs it too.

If you have many helper functions that called from update directly, those can live in Main. If you have many helpers that are only called from other helpers, try to find the small interface update needs, expose that, and hide the rest.

Matthew Griffith

unread,
Dec 2, 2016, 11:46:49 AM12/2/16
to Elm Discuss

Hello!

Here are a few things I'd think about.

First, (and this is kinda unrelated to organization) but I'd recommend using elm-format and having type signatures.


Some quick thoughts:

You could break your styles into their own file, either using elm-css, or raw elm styles.

You could break Model out into it's own file and take related model processing functions there.

Side note, you can combine all your animation subscriptions into one message.

Rex van der Spuy

unread,
Dec 2, 2016, 12:04:36 PM12/2/16
to Elm Discuss


On Friday, December 2, 2016 at 11:44:42 AM UTC-5, Max Goldstein wrote:
I would want to move all of the view code to a new module, exposing only the view function itself. In order to do that, you'll have to move the definition of Model and Msg to a module imported by both Main and View. You can call this module Common. I think the initial model belongs next to its definition, in Common. I wish there was a way to keep Msg near update but View needs it too.

If you have many helper functions that called from update directly, those can live in Main. If you have many helpers that are only called from other helpers, try to find the small interface update needs, expose that, and hide the rest.


Thanks so much, Max, that's extremely helpful and practical advice! :)
So your suggestion would give me a file structure that looks like this?

- common.elm: initial model and messages
- view.elm: all the view code
- main.elm: imports common, view. includes all the update code, subscriptions and app wiring

I also think of Msg as part of update, so I know what you mean about that separation seeming awkward.

Great, I'l try this!

Rex van der Spuy

unread,
Dec 2, 2016, 12:11:31 PM12/2/16
to Elm Discuss


On Friday, December 2, 2016 at 11:46:49 AM UTC-5, Matthew Griffith wrote

First, (and this is kinda unrelated to organization) but I'd recommend using elm-format and having type signatures.

... guilty as charged! :)
I actually could never get elm-format to integrate with Sublime Text despite many attempts - no idea why.
Type signatures... I'll try using them more often! (... the compiler scares me sometimes, so I usually just let it try and figure all the types out on its own.)
 


Side note, you can combine all your animation subscriptions into one message.

Oh, I think this is something I fundamentally don't understand about elm-style-animation.
Could you point me to reference on how to set that up?

Matthew Griffith

unread,
Dec 2, 2016, 1:29:12 PM12/2/16
to Elm Discuss

This file shows how multiple animations can be run through one Animate Msg:



You basically make your subscription like this:

Animation.subscription Animate
    [ model.annulus
    , model.sun
    , model.smallPlanet
    , model.largePlanet
    , model.mediumPlanet
    ]

And your Animate Msg in your update function would look like this:

Animate animMsg ->
    let
        annulus =
            Animation.update animMsg model.annulus

        sun =
            Animation.update animMsg model.sun

        smallPlanet =
            Animation.update animMsg model.smallPlanet

        mediumPlanet =
            Animation.update animMsg model.mediumPlanet

        largePlanet =
            Animation.update animMsg model.largePlanet

        global =
            Animation.update animMsg model.global
    in
        ( { model
            | annulus = annulus
            , sun = sun
            , smallPlanet = smallPlanet
            , mediumPlanet = mediumPlanet
            , largePlanet = largePlanet
            , global = global
          }
        , Cmd.none
        )


The only thing this buys you compared to breaking out every animation into a separate Msg, is that your update function may be a little shorter.  

So the way you're doing it is fine:)

Try compiling with '--warn', it'll tell you all the type signatures and you can copy paste :D  

Max Goldstein

unread,
Dec 2, 2016, 9:08:20 PM12/2/16
to Elm Discuss
Yes, that is exactly the file structure I had in mind. Let me know if you run into trouble.

If you extract another module, it should import Common and be imported by Main, just like View. Because of this 1-n-1 structure, I think of this as a diamond.

Reply all
Reply to author
Forward
0 new messages