When I worked in C# at PartsTrader I started to see the similarities between what Domain Driven Design is looking for and what Functional Programming does. Or rather what FP has to do to be able to be useful in the real world.
So I'm talking about separating out pure functions from side effects. In DDD the idea is to circumscribe business logic, keeping all the IO and external interfaces outside the circle.
The difference is that in Elm this split is mandatory. In DDD and object oriented languages it's a voluntary design decision with some serious book reading available to convince you that you are doing the right thing lol.
However, it still comes back to immutability. Functional programming gives you this off the bat. In non-functional languages it is still a great idea, but you have to choose to do it. The benefits are that your code is easier to debug as what goes in and comes out remains constant at every level.
In Elm the entire code is immutable - think of it as one big function that is called as needed. Anything side-effecty will be done by the runtime and then the function called again.
This has some interesting benefits. If you want to see what your programme is doing, just look at the big 'update' function that is at the bottom of this tree and anything it delegates it to. With the strict typing on top of that, if you make any changes that disrupt things you find out very quickly on compile, and the error messages just 'know' so much about what you are doing.
Which is not to disparage .Net's Visual Studio when using C#. It 'knows' a hell of a lot before you even get to compile thanks to the work that has gone into it over the years from some very smart people.
In non-functional languages it is also good practice to pass in any values that may change randomly so that you still have unit-testable functions - dependency injection. In Elm, functions that call side effects don't return things back into the code and so don't impact the return value. They go off to the runtime, which then returns values through the message update channel as if some magic fairy generated them.
I am working on an old JS code base that I've largely converted to ES6. While I've brought in Webpack, I've shied away from introducing any of the new frameworks like React and Angular - both of which I have used before. I use a bit of native JSX as a short cut for templating forms and menus, but that's another story.
With ordinary JS you can still take a strategy of making things as immutable as possible. Again it means segregating out anything that is a side effect until your functions become pure.
In my case I'd like to start to reorganise the codebase so that, well, it looks more like an Elm structure with a tree of update logic updating a model and a set of view functions that simply reflect the changes in the model - all as pure as possible. I'm still working through how best to do that in combination with the heavy use of Mapbox and Leaflet in the app.
I believe that immutability and segregation of side effects is one of the core goals worth striving for in software design. If it can't be achieved immediately it should at least be regarded as the preferred direction.
I am confident that by taking this approach something easier to read, maintain and add to will come of it.