Hey folks, I just want to say, it's really really really hard to reply to these posts which are both really long and really dense. It's better to answer in a terse, short format. This is a conversation - not a blog post. Longer comments and responses are usually better in a blog post, because it's quite hard to keep all the context in our heads for each mail on a mailing list.
Regarding how to structure code for large apps, I really recommend looking at the NRI elm-style-guide. https://github.com/noredink/elm-style-guide#nri The "reusable" parts are those prefixed by `Nri`. Here's an example of what some type signatures might look like: -- Button.elm view : msg -> Html msg view onClick = ... -- Emoji.elm type Emoji = Smile | SadFace view : Emoji -> Html msg view emoji = ... -- Leaderboard.elm type LeaderSettings field = { numberOfPlayers : Int, fields: List field } view : LeaderSettings field -> (field -> msg) -> Html msg view settings onFieldChange = ... I recommend trying out this approach, and see how you like it. It makes implementing things _so_ simple. I've tried every approach under the sun, and seen more codebases than I can count. This is the one that wins for me. If anyone tries this approach, but fails to get their head around how to refactor their code to work with it, or fails to see how it's simpler, hit me up on Slack (eeue56) or at elm-europe or https://osloelmday.no, and I will guarantee your code will walk away looking nicer than it did before. On Wed, Apr 19, 2017 at 8:50 PM, Mark Hamburg <[email protected]> wrote: > The monster model design is one aspect that leads to the ball of mud code. > Let's look at the source quote for the term big ball of mud: > > A Big Ball of Mud is a haphazardly structured, sprawling, sloppy, > duct-tape-and-baling-wire, spaghetti-code jungle. These systems show > unmistakable signs of unregulated growth, and repeated, expedient repair. > Information is shared promiscuously among distant elements of the system, > often to the point where nearly all the important information becomes global > or duplicated. The overall structure of the system may never have been well > defined. If it was, it may have eroded beyond recognition. Programmers with > a shred of architectural sensibility shun these quagmires. Only those who > are unconcerned about architecture, and, perhaps, are comfortable with the > inertia of the day-to-day chore of patching the holes in these failing > dikes, are content to work on such systems. > > — Brian Foote and Joseph Yoder, Big Ball of Mud. Fourth Conference on > Patterns Languages of Programs (PLoP '97/EuroPLoP '97) Monticello, Illinois, > September 1997 > > When everything starts out in one place with access to everything else, it's > natural to end up with everything talking to and depending on everything > else — or at least the dependencies are less likely to be well regulated > because there is no mechanism doing the regulation. Now, as conservative > politicians will love to tell you, regulations get in the way and we can be > more productive without them, so yes, this unregulated environment is > seemingly more productive. The type system will help in detecting out and > out errors in making changes but once things get intertwined, they become > less amenable to significant change. That's often fine for an agile > development model in which one focuses on small changes but I've seen agile > teams that could generate lots of small changes but when faced with needing > to do something big found themselves profoundly stuck. An approach which > basically seems to advocate building a monolithic, intertwined codebase and > if that gets to be too much, here are some techniques to break it down after > the fact will work to an extent but will be fighting to apply order to chaos > and almost all the time it will be easier for a developer trying to get a > task done to just add a little more chaos. > > As for your specific advice, it includes several useful points and I've > refactored code using those same techniques, but the distillation of the > don't use nested TEA argument when people have asked what to do instead has > tended to be "use functions" which as I've noted doesn't mean much in a > functional language. (I guess it means use functions rather than types but > since types are what allow us to make illegal states impossible, I don't > think it really comes down to just use functions either.) What TEA and > nested TEA provided was architectural guidance on how to structure things > for long term evolution. Saying, if your update function gets too big you > can handle individual cases with separate functions is I guess useful advice > but something that I would hope would be obvious to most people working in a > functional language. What sort of calling conventions work well? Which ones > don't work well and should be avoided? That's the sort of architectural > advice that can be put into practice early on and expect it to pay off later > when changes need to be made. For example, to buttress the non-component > view of the world, one could push on the fact that many views do not need to > own their own state but can simply be functions that render state provided > from somewhere else. One could phrase that as: "You have a view function but > ask yourself whether you really need a model and an update or whether those > are better handled somewhere else. If you do so, then you can take a big > pile of view code and move it somewhere else and not need to look at it when > trying to figure out what is going on in your model." > > As for C++ example I cited, there is nothing Elm is bringing to the table > that makes it superior to C++ in the case I described. C++ is fully > type-checked. Mutability v immutability was not a concern here. Of concern > was that question "which parts of this are visible to other code for the > benefit of code within the would be library and which parts are visible > because they are expected to be stable interfaces for other code". And the > fact it was a question arose exactly because the code base started as an > entity that only needed to serve itself and for which the refactorings were > all just adjustments within those bounds. The choices were expedient for > immediate development but detrimental to long-term reuse. > > Should one build everything to be reusable/replaceable? Almost certainly not > because doing so does come with overhead. But identifying likely break > points where code may need to be either reused or replaced and structure > those break points up front to enable that reduces the effort when you do > need it to be separate. And if you've got that separation, then you can > potentially frustrate Foote and Yoder by building balls of mud through > iterative development but they will be smaller balls of mud for which the > strengths and weaknesses of the code can be assessed separately. > > Mark > > On Wed, Apr 19, 2017 at 11:00 AM, Richard Feldman > <[email protected]> wrote: >>> >>> "just write one monster model" approach >> >> >> Mark, this is about the third time you've insinuated that my explanation >> of how to split things up somehow amounts to not splitting things up at all. >> Someone called you out on it, and then you switched insults from "ball of >> mud" to "monster model." If you genuinely want to have a discussion, it's >> important not to misrepresent the other side. >> >> It's also weird to me that you keep responding to my point of "this >> approach has worked really well for lots of Elm programmers, in practice, in >> real life, already" with "I bet that won't work well in practice, in real >> life, based on my experiences in other languages." We're past the point of >> theoretical predictions here. The experiment has already been done, and then >> replicated successfully many times. >> >> Your comment that "this approach didn't work for us in C++" seems >> particularly weird. I'd say there are "a few" differences between Elm and >> C++, refactoring experience included. ;) >> >> -- >> You received this message because you are subscribed to the Google Groups >> "Elm Discuss" group. >> To unsubscribe from this group and stop receiving emails from it, send an >> email to [email protected]. >> For more options, visit https://groups.google.com/d/optout. > > > -- > You received this message because you are subscribed to the Google Groups > "Elm Discuss" group. > To unsubscribe from this group and stop receiving emails from it, send an > email to [email protected]. > For more options, visit https://groups.google.com/d/optout. -- You received this message because you are subscribed to the Google Groups "Elm Discuss" group. To unsubscribe from this group and stop receiving emails from it, send an email to [email protected]. For more options, visit https://groups.google.com/d/optout.
