17 comments

[ 2.9 ms ] story [ 35.4 ms ] thread
Not only have you shed some light on how Om can be used with the Flux model, you also explained Flux better than most. This a good start, thanks.
I've been really wanting to get into using Om and Clojure, but have not been sure of where to start.
Maybe I'm not getting something, but all this Flux stuff reminds me a lot of DDD+CQRS (domain driven design w/ command query response segregation), to the point where it seems like it's the same concepts repackaged with different terminology.

This post in particular seems to be advocating the concept of having a single 'aggregate root' as opposed to independently loaded 'entities', and Flux sounds like it just advocates the use of an 'event bus' to send separate 'read'/'write' 'commands' to 'domain objects'... the main difference of course being that all this recently has been specifically with the browser in mind. Is that a reasonable assessment?

Totally reasonable.

Amongst people that I associate with that build complex web apps, there's been an ongoing debate on whether a centralized event dispatch (what Flux advocates) is preferable to decentralized event emitting components (what Backbone and web components advocate).

For most of my career, I've been a fan of decentralized event emitting components. However, with Om's persistent data structures and functional render loop, having all of your data in a single place is suddenly a lot more palatable. From there, I think the event bus approach flows naturally.

Or at least, that's what I'm thinking now :) I still haven't written something with complex enough tests and other external dependencies to have gotten bit by this yet.

+1, I wonder if all reasonable immutable architectures share the same design foundations. Another example is datomic which if you squint only a little bit, is basically the same thing as CQRS/ES in shrink wrap
I think there's an important difference between CQRS/ES and Datomic, namely that Datomic is actually "just" a persistent data structure (in both CS senses of the word).

In CQRS/ES you don't usually want to store the state as such, you just store all the logical events which lead to a certain state. While the Datomic approach is certainly valuable for certain scenarios if you want to query historical data, it's less so if you want to know why something looks the way it currently does (in terms of the domain).

(At least that's my understanding of Datomic, I may be mistaken.)

I think many haven't heard of or know the DDD+CQRS terminology.

I even suspect if Peter Hunt mentioned how they are doing DDD+CQRS for building applications, it might have been met with ridicule from audience.

It is kind of interesting, the field of software engineering is not that old, but there already probably multiple cycles of the same concept being rediscovered over and over again.

Another rather cliche one is callback based concurrency. There was a wave of "oh look at this new thing we discovered, you don't block and instead provide a function to be called later". And many older folks probably looked at each other and said "Wait, what year is it?"

Yeah, I think it's basically the same concepts but repackaged for web developers. You can tell from the names - "React", "Om" and "Flux" sound like the kind of things web developers might use, and "Domain-Driven Design" and "Command/Query Responsibility Segregation" sound like things that enterprise developers might use. Both sets of names are a way of marketing similar concepts to different audiences.
While Flux advocates for a totally new application architecture, it's one that still seems to fit the MVC architecture, especially when expressed using reactive concepts. I wrote a similar blog post to this one except using Elm as the reactive system[0], D3 for composable views[1], and MVC as the application architecture[2]. Once you have a reactive system and a declarative representation for your interface, applications get much easier to build. Decentralized state and event handling is secondary to those two concerns, and frankly of dubious value: once you start using lense-like things to help manage the distributed state, you're still going to run into issues where the lens isn't expressive enough to to handle certain operations (deleting an item from a list, for example), forcing you to either change your model so the lens is expressive enough, or dispatch events to a centralized location to handle the change. So the choice is either decentralize things and mangle your model, or keep things centralized.

[0]: http://elm-lang.org

[1]: https://github.com/seliopou/elm-d3

[2]: http://computationallyendowed.com/blog/2014/07/20/reactive-m...

Holy crap, talk about perfect timing.

I'm using CSP in my project with this project: https://github.com/ubolonton/js-csp, and I've been studying flux this week. Yesterday and today I've been writing a channel-based dispatcher, and digesting how to convert the flux concepts into a channel-based system.

Thanks for this post! I'm somewhat new to CSP so this sheds a whole lot of light on how to do it. I knew there must be a better way to do the dependencies, because right now I'm manually managing them. Using `merge` is brilliant.

Just tweeted this on Sunday: https://twitter.com/jlongster/status/496019503730679809 :)

Speaking of Flux, http://www.justgetflux.com "makes your computer screen look like the room you're in, all the time." One of the best things I've ever done for myself.
The first call to dispatch should probably have been

    (dispatch [:deleted-todo todo-id])
Though personally, I would prefer to define dispatch as

    (defn dispatch [tag & args]
      (put! dispatch-chan (apply vector tag args)))
instead and then change the second call to

    (dispatch :txs tx-data root-cursor)
(Also as a style thing, I'd call it dispatch! since it has side effects)

Good article though and describes something very similar to what I'm doing in my own Om project. I've abstracted the dispatching into om-tools mixins though, so you can do something like this:

    (dom/div
      {:on-click (.sender owner :click-event)}
      "Click Me")
And when the div is clicked, :click-event is dispatched (I also have the concept of component ids and if the component has an id, it is included in the event, so you can register for all events with a given tag, all events from a given component, or only events from a given component with a given tag).

So far, its working quite well.

EDIT: fixed typo in the code

Off-topic, but when did HN get code fragments? That's a really cool development.
Its had preformatted text for as long as I remember. Put four spaces at the start of each line to use it.
Huh, thanks. Somehow I'd either never noticed this or completely forgotten.