utilities.js files that went on forever and had completely unrelated functionality, which I generally found to be very difficult to maintain. And this keen separation has been good - it's made life a lot easier.
This made it hard to approach another language with a different mindset. I knew that seasoned Elm developers advised against subdividing models and separating modules prematurely, but I thought "no I can't just keep everything together, that's going to be way too difficult to manage". So I diligently set about making sure that I had a series of nested state machines which each managed their own state, and a parent state machine that mapped all of the messages that came out of the application and called their
update functions correctly, and I was mostly happy. My views had to do
Html.map more than I'd like, because they were having to map
Z.Msg, and so on...) back to the parent state machine's message type, but it felt okay.
Then I came to adding a command to fetch some data from a REST endpoint. Things started to feel a little less "okay" here, because all of a sudden I had a command that was being called in the parent state machine's module when the application was initialised, and passing the result of it down two levels to call a child state's
update function. This smelled pretty bad, but, it worked: when the application started up, the data was fetched, processed, and passed to
Then I came to trying to re-fetch that data from a message that was passed by the state machine that actually used it. Things got very messy from here, and the way that I had organised my code in order to make my life easier ended up causing me major problems. I found it difficult to see a sensible path forward for this functionality, and I hadn't even really written all that much code!
Thanks to the ease of refactoring that comes with Elm, I figured I'd give this a try (even though it felt alien to me to do so, to be honest) - I made a new module that held all of my messages, and combined all of my previously separate
update functions into one, fixed up the changes I'd made to the application's model along the way - as I realised that the model had been laid out in order to facilitate my file structure - re-compiled, and re-ran the application.
All good so far, everything works as it did previously. So, now I need to actually make the change to allow for data to be fetched when the user requests it - not just on application load - and I think to myself "okay, where do I have to make this update in my new structure"...before instantly realising "oh, the one place where updates can happen".
It turns out, this isn't unmanageable at all - in fact, it's much easier to reason about this entire application now, and even easier than that to know where you need to make changes whenever you're adding a new feature. Maybe soon I'll think "okay
x needs to be managed in isolation", but at least I'll only be adding that extra complexity when it feels beneficial, rather than adding it because I think I'll probably need it to be that way. If I'd avoided this early subdivision, I'd have saved myself a lot of time trying to make something work in a way that it probably shouldn't, so learn from my mistakes: if tutorials, articles, and seasoned Elm developers tell you to leave splitting up your application until later, listen to them!