Rewatched Richard Feldman's talk on scaling Elm apps from Elm Europe 2017. You may have seen it. I was at the event but more has sunk in on repetition.
This is a superb talk about not breaking up your update, model and msg definitions when no reusability is required or intended. Breaking up code prematurely is a common tendency especially if you've come from the OO world.
For update especially, the idea is to avoid unnecessary separate mini-update functions that return model and cmd and have to be mapped back to the main update function.
Instead Feldman says to break out smaller functions from within update branches that have got too big. Give these functions the narrowest possible arguments and return the minimum required.
This makes debugging easier since you can see more rapidly what parts of the code are relevant by the type signatures, and your upgrade function is more scannable.
To avoid breaking up the messages definition and the model, the idea is to create functions that use extensible records - think polymorphism - 'focus on functions that take a subset of the model'. Again, what this does is keep the type signatures narrow and therefore more debuggable.
The legitimate time that you need to break out into a separate model, messages, update, view is for a reusable 'component' that has it's own state. Obviously if you are repeating use of a function then it may be necessary to have a separate copy of the state for each usage.
In this case html.map and cmd.map are your friends for merging the result back. You should also pass and return what you like, or the minimum, not just be sending msg, model and getting back model, cmd msg every time unnecessarily.
In summary Feldman's theme was to make things 'small enough to fit in our heads' but not introduce unnecessary complexity. Keep this goal in mind, and don't get caught up in thinking from other languages that may not be effective.