Structuring Real-Life Applications
The Internet is full of smart peanut-size examples of how to solve X with "FRP" and Bacon.js. But how to organize a real-world size application? That's been asked once in a while and indeed I have an answer up in my sleeve. Don't take though that I'm saying this is the The Definitive Answer. I'm sure your own way is as good or better. Tell me about it!
I think there are some principles that you should apply to the design of any application though, like Single Reponsibility Principle and Separation of Concerns. Given that, your application should consist of components that are fairly independent of each others implementation details. I'd also like the components to communicate using some explicit signals instead of shared mutable state (nudge nudge Angular). For this purpose, I find the Bacon.js EventStreams
and Properties
quite handy.
So if a component needs to act when a triggering event occurs, why not give it an EventStream
representing that event in its constructor. The EventStream
is an abstraction for the event source, so the implementation of your component is does not depend on where the event originates from, meaning you can use a WebSocket message as well as a mouse click as the actual event source. Similarly, if you component needs to display or act on the state of something, why not give it a Property
in its constructor.
When it comes to the outputs of a component, those can exposed as EventStreams
and Properties
in the component's public interface. In some cases it also makes sense to publish a Bus
to allow plugging in event sources after component creation.
For example, a ShoppingCart model component might look like this.
Internally, the ShoppingCart contents are composed from an initial status and addBus
and removeBus
streams using Bacon.update
.
The external interface of this component exposes the addBus
and removeBus
buses where you can plug external streams for adding and removing items. It also exposes the current contents of the cart as a Property
.
Now you may define a view component that shows cart contents, using your favorite DOM manipulation technology, like virtual-dom:
And a component that can be used for adding stuff to your cart:
And you can plug these guys together as follows.
So there you go!