-
Notifications
You must be signed in to change notification settings - Fork 739
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
thoughts on modularity, real re-use, app-wide coordination #66
Comments
As you have seen with |
Hi, i'm trying to build websites using elm. |
Expect more discussion. |
Here's the beginning of advice on this kind of stuff: http://guide.elm-lang.org/reuse/ We will have more resources coming in the next few months, but that is the gist. If you are thinking about components, if you are thinking about parents and children and communication, something has already gone wrong. Also, this community uses forums like elm-discuss and the Elm slack for discussions like this. Issues are for tracking concrete problems and work, not for discussions. |
Hi Elm community,
This is not an issue, just a discussion I would like to have on building modular, well-defined applications under the elm architecture. I will try to keep it brief, which will require a lot of hand-waving.
The most important pieces of any application architecture I have implemented always seem to turn out the same:
These three pieces enormously impact the refactor-ability of the codebase, the velocity of developers in that codebase, and the lifespan/maintainability of the entire application.
Modularity / Re-use
Ideally an entire application is built from the bottom up from small, loosely coupled, reusable components. If these components can be completely unaware of their place in an application, and only serve a small, defined purpose with a minimal api surface, you are on the right track to a highly maintainable and refactor-able code base.
Clear and predictable communication
If each component is modular, you can build up a tree hierarchy of components where communication between depths or leaves or branches happens only across a small interface at defined intersections. No matter the form of communication - be it a flux architecture, a messaging bus, or pub/sub, this "bounded" communication also keeps you on the right track to a highly maintainable and refactor-able code base.
The ability to coordinate context switches
Most apps have major contextual chunks that form concrete or logical boundaries in which to partition your components. Sometimes this is as simple as main navigation tabs, and sometimes it is more nuanced (consider following a deep link to a different part of your application). If your architecture does not offer a way to reliably and conveniently swap between these contexts, you are going to end up with a lot of fragile code that has to be hand-held through state re-hydration, serialization, branching within contexts, and all sorts of other tedious and error-prone bandaids.
Where does elm fit in?
I have been fooling around with the elm architecture for a little bit, and have tried to familiarize myself with its strengths and weaknesses. It seems relatively similar to the redux pattern (immutable, explicit top->bottom action flow, predictability) with perhaps the major difference being that truly reusable components are much simpler.
Modularity
Using
Signals
andforwardTo
, parents provide their reusable children the information necessary to "just work" so that children can be completely unaware of the rest of the application. There are plenty of (mostly) clear examples where this can be extended to allow lists of lists of entirely dynamic reusable components (the "Model with a context" example is still pretty unclear to me).One issue I bumped into almost immediately using this pattern is a similar but slightly more advanced use case: when a parent does not merely want to forward its child's actions, but is interested in a subset of those actions.
For example, consider a simple chat interface with a
MessageBox
, aPost
, and aChat
component to hold everything together. What I want to be able to do is pipeInputChanged
into theMessageBox
without needing to know the details, but whenMessageSent
appears, capture some details about that action inside of the parent. A rough sketch would be something like...This won't compile. I can think of a few other ways to achieve the same end, but none of them are a good idea because they either burden the reusable component with unnecessary requirements or end up with circular and difficult-to-trace "on update do another update" patterns.
I feel like if a cleaner general pattern can be reached (and it might be simple and I'm just missing it), then truly reusable components are actually possible in elm.
Communication
This is pretty inherit in elm. Everything is explicit, and the communication lines are well drawn down a component hierarchy. The biggest challenge I believe will be maintaining a small API surface across components. Sometimes the temptation is strong to update on actions that probably aren't any of your component's business. This eventually carves out an application where changing one action name, or removing a single component can break everything in that hierarchy subtree.
"Update H" needs to be piped from a -> c -> h. In a naive implementation, changing the action to "Update h" requires also changing a and c. I think elm avoids this through the use of a generic "On some child action just pipe the message through and update the model".
Context
I have no idea how elm might handle something like this. I believe the excellent work done over at redux-saga handles context switching in one of the most elegant ways I have seen. Because redux, like the elm architecture, is basically an event-sourced architecture, the concept of sagas "just works". When
SOME_TRANSITIONING_EVENT
arrives, you can utilize the api of components to predictably transition the application step by step.The problem with sagas, though, is they are by-nature imperative and not functional. It would be great to hear some thoughts on how the elm architecture handles this case.
The text was updated successfully, but these errors were encountered: