My background is mostly in JavaScript, and when building JavaScript applications, I like to have them separated pretty heavily. This came about after seeing one too many 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 X.Msg
(and Y.Msg
, and 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 update
correctly.
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!
Undoing my own mess
When I felt like I was fighting against the tool, I decided to ask the community on the Elm Slack workspace, and someone there suggested that I wouldn't have this problem if my message types were all aligned; which of course, they only weren't because I'd approached this as if it were a JavaScript application.
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!
Top comments (3)
Ditto! I've tried various approaches -- am now about 80% through a rewrite of an app I worked for a year. Just four files now, and the going is really smooth.
as someone who recently started looking into/learning elm, this was an awesome read, thanks for the post!
Thanks! I hope you're enjoying your foray into Elm as much as I am. I've just watched this talk from Elm-Europe 2017 which I'd advise watching as well for better detail around how to expand your Elm codebase more organically: youtube.com/watch?v=XpDsk374LDE