A neat diagram comparing Meteor, Flux, and Relay

This is a diagram on one of the whiteboards in the Meteor office that I came up with while doing the research for the initial React integration. I’d like to emphasize that this isn’t a plan, just an artifact of investigating the ecosystem back in April:

This is something I’m posting to encourage a discussion that started on the thread about the new method wrapper package:

I think this sounds very right to me. I think Methods in Meteor are so similar to Flux actions, and I think it makes sense to expand on that similarity in the new future. Let’s look at the differences:

Differences between Meteor Methods and Flux actions

  1. You currently can’t use Methods to manage your client-side stores, only Minimongo.
  2. Methods are written in an imperative fashion where you call mutators on your stores; in some Flux architectures you would instead have stores listen for an action fired from the dispatcher
  3. Methods travel from the client to the server automatically; I don’t think there’s a standard for how this is supposed to work in a Flux architecture since Flux only really addresses the client.

Similarly, there’s a nice isomorphism between Meteor pub/sub and GraphQL. Both systems involve fetching data from the server, and a global client-side cache for optimistic UI and a simpler programming model.

Differences between Meteor DDP+Minimongo and GraphQL+Relay

  1. In Meteor you separately subscribe to data and then fetch it from Minimongo; in Relay this is just one step where you declaratively specify what data you want.
  2. GraphQL has a language for specifying what fields and joins you want from the client; in DDP you need to pipe that through publication arguments.
  3. Relay doesn’t have a reliable realtime data pushing system; on the other hand Meteor’s is deeply coupled with MongoDB.

What do you guys think?

One thing I’m interested in particular is, what does Redux bring to the table here? I’ve heard a lot of people in the Flux community are super pumped about it. What would Meteor look like if Methods and Redux actions were merged into one?

30 Likes

Looking at this photo there’s one obvious question coming to mind… who broke the doors?

24 Likes

I don’t have the data to back this up, but whenever I read between flux/redux I have this strange feeling redux is to flux what reactivedict (perhaps even minimongo) is to reactivevar.

2 Likes

I think the big plus of redux is the event sourcing/actions model.
With my app, the biggest problem has been to reconcilliate (reduce) three sources of data :

  • data from the database
  • new data that’s currently created/modified on the client, but not yet commited to the db (session data)
  • data not yet commited but persisted during hot code push (client side storage data).

Hot code push is a great idea but one of the area of meteor that made me pull my hairs the most, since it’s really hard to do it right with current model.
I guess this could be easier with an event sourcing model ala Redux.
However the binding and wiring part of redux is not that elegant, imho.

1 Like

This conversation is great! I think Meteor could benefit from more architecture and could possibley make it easier than Redux.

I’m also going to use Redux in my examples because there are a lot of flavors of flux. Most all agree (even FB devs) that Redux is flux done right. Anyhow…

I’ve been using Redux, and Alt in production every day for the last several months in React Native and Meteor and i’ve mostly used it without getMeteorData so I feel like I can chip in a bit.

Using Redux (and Flux) not only makes it easier to share transient state with React components but it makes it very easy to keep track of where the data is in your app. I was pleasantly surprised at how much easier it was to debug and find problems in my React Native app than my Meteor (Blaze) app.

This boils down to the fact that data moves in a consistent way and you can just ‘follow the money’ until you track down the bug. However, in Meteor apps client data is scattered everywhere… minimongo, Session, and hopefully in template vars (my older apps didn’t have them yet). Probably more importantly this data could be changed from a lot of different places.

Debugging in a Redux environment usually consists of going to the UI, placing a debugger in render to view the props, placing a debugger in the action creator functions that the view is following and sometimes a debugger with the store that the action creator touches (one debugger can pause for all actions in Redux too).

This makes debugging really really simple. If you boil it down, convention and constraints make it easy to debug.

Differences between Meteor Methods and Flux actions

I’ve heard this comparison a bit before but honestly I think they’re orthogonal. Meteor methods closely map to AJAX calls that a server API accepts and authorizes, or an RPC call. They’re just making AJAX more simple.

This part is pedantic but a flux ‘action’ is just the object literal with data, eg… {type: 'CREATE_THING', color: 'red'} . The action creator is an optional abstraction that takes the data concern out of the view and is just a function. I presume you meant action creator.

Using redux as an example you can create an ‘action’ in your view without an action creator and pass it to dispatch like this:

dispatch({type: 'CREATE_THING', color: 'red'})

but having this in the view layer is messy and hard to test. Boiling it down, an action creator is just a plain old function that returns an object (metadata) that dispatch will consume:

function createThing() {
  return {type: 'CREATE_THING', color: 'red'};
}

and later in the UI:

// same result as previous dispatch example
dispatch(createThing())

It can also produce side effects (like dispatching more actions) and do other logic to prepare this payload (like taking a userId as a param and gathering profile info) but the main purpose of the action creator is to take logic out of the view layer to make views as dumb as possible (making it almost a ‘view controller’ if anything).

Typically I will call a Meteor method in place of an AJAX call inside the action creator. For example, sending an email to a user because the did some action in the UI.


Using Redux to store database data can be tricky in Meteor because the single Redux store (or flux stores) directly overlaps with Minimongo. Both are clientside caches that allow you to access and query data later. However, Minimongo allows you to use Mongo syntax to query data while the single Redux store has to be queried with traditional JS methods (map, filter, reduce, etc...).

Both allow optimistic UI, with Redux you insert and when the server responds you overwrite the data, it’s only updated if the server copy changes. Minimongo does this but automatically.

This package helps you take incoming data from subscriptions and dispatches them to Redux. However, you’ll have two copies of data in Minimongo so that can be expensive. It also ensure they’re both in sync. https://github.com/AdamBrodzinski/meteor-flux-helpers

10 Likes

Is that only question you got ? :slight_smile:

1 Like

I agree with these points. In Meteor, data is everywhere. I think Tracker is the one reason for that. Where we depend on invalidating autoruns for many places. There is no single place where can start to debug.

But, Meteor’s style make it easy to build an app very quickly specially with Blaze.

@sashko This is what I think about the architecture. I think client side app architecture hugely depends on the UI framework we use.

  • React has Relay/Flux(Redux)
  • Angular has 2 ways data binding and fully opinionated stack
  • Blaze got Tracker

I think it’s pretty good idea to integrate Meteor’s data stack to these architecture instead of building something new.

I think it’s not a good idea to put Tracker in the React world. This is not because of a technical reason, but we couldn’t use best practices and components/plugins used along with those architectures.

We could build a solid app architecture with Meteor may be with integrating React directly. But the problem is, once it became mature, there will be much better stuff and it’ll be outdated.

But if we go with the app architectures establish in each UI frameworks, is a matter of integrating into that.

So, now we need to think of what’s the minimal set of components, layers Meteor should have.

14 Likes

Me. And that door must weigh 100 pounds.

15 Likes

Now, you see, that’s the kind of community involvement we want to see. Answer all the open questions however tough they may be :smile:

9 Likes

For anyone that needs to become more familiar with Redux there’s a free video series done by the author of react-redux (not to be confused with redux itself). It’s up to date and I found it great.

7 Likes

Wait. So I no nothing of Flux, Relay (the FB stack). @serkandurusoy, do you see us Meteor devs needing to learn one or both of these in order to use React with Meteor? We can’t or shouldn’t use Methods? Will we eventually need to learn Flux or Relay in order to get the most out of React, even on Meteor?

Flux is just a pattern to share data between React components. Without Meteor something like this is essential to pass data around.

With Meteor you don’t have to follow the flux pattern because the reactive data sources allow us to update the UI without any kind of event wiring. Sticking data into a Session variable and rendering with getMeteorData will work.

Learning about flux will allow you to further understand how the React ecosystem thinks about data flow but is not required.

4 Likes

I want to add a bit about this.

With Meteor, app architecture is solely to us how we model and design it. It’s vary from the project to project.

So, it’s sometimes harder for a new comer to join with the project. If we follow a pattern like FLUX (via redux), it’s easy for someone new to join with the project.

I think Meteor Guide is good way to show some pattern on building Meteor apps. +1 on that.

10 Likes

+1

I recently had to onboard some developers and it was really fast for devs to hop in and get working if they already knew React and Redux. They just had to learn about how Meteor handles data and they were off to the races.

1 Like

@aadams as always, @SkinnyGeek1010 and @arunoda are spot on.

That’s just a pattern and you don’t have to learn it while you can definitely benefit from it.

Also there is a nice blog post back from august which is a good read on this subject.

1 Like

Just thought I’d add an image corrected for keystone distortion.

23 Likes

I have been trying to figure out for a while the best way to do extensible apps with Meteor for the next version of Worona. I will share my experiences with Flux and Meteor in case they are of some use here.

Sometimes I read about how Meteor and Flux relate to each other on posts or threads. I don’t think there is a direct resemblance. Meteor is a platform and Flux is an architecture.

I think there is a lot of confusion because people try to use other JS Flux implementations (created without Meteor in mind) in Meteor instead of just applying the principles of the architecture.

In my opinion, Flux just brings these principles to the table:

  • Total decoupling of the View layer using the Dispatcher for events and a single object tree State for data (this is from Redux).
  • One way data flow (easier debugging).
  • No chained actions (easier debugging).
  • Easier structure and code organisation.

I think each of those principles are good for a Meteor app because by default, Meteor comes without rules.

The View layer decoupling is very important. Designers should be able to write the UI with no/minimum javascript use.

Dispatcher is important as well. Its event pattern allows to easily extend the app when something happens.

No chained actions is very useful as well because it forces you to think easier ways to solve the same problem.

One way data flow makes reasoning about your app flow much easier.

What I mean by easier structure and code organisation is that when using Flux, you know that views can only dispatch, stores contain logic and modify data, they are structured by domain, state is a single object tree, and so on. So you don’t have to think where to put (or find!) stuff, you just write code. This code organisation is another thing Meteor doesn’t have.


At first, I tried to make Flux work with a port of the Facebook’s dispatcher. It was great, but if found the Flux’ “Action-driven” architecture collides with Meteor’s “Data-driven” mentality. I tried to solve it but:

  • When I tried using only Flux actions to change the state of my app, the reactive data sources where left behind.
  • When I tried to send a Flux action each time Meteor was changing some data, Meteor reactivity lost its magic and I ended up with a lot of not useful boilerplate code.

So that approach wasn’t working. Besides I wanted to introduce a single object tree for the whole state of the app in a kind of a Redux style.

I am a huge fan of Tracker. Reactive code is way easier to write and maintain. So it didn’t make sense to not use reactivity for the single object tree. I wrote a package called ReactiveState and it is working really well. People is using it even for other non-Flux apps.

Then, I went back and forth with Flux until I figured out a way to make both worlds (Flux’ Action-driven and Meteor’s Data-driven) work together. The solution was to make Flux actions reactive, but still have a non-reactive phase at the beginning and at the end of each dispatch.

The result is the MeteorFlux framework. I consider it still in development but so far it is working really well. GitHub - luisherranz/meteorflux: Flux architecture for Meteor


The Dispatcher starts the one-way-data-flow and it looks like this:

<a href="#" dispatch="CHECK_WP_API">Try again</a>

or in javascript:

Template.ApiChecker.events({
  'click .change-url'(event, template) {
    let url = template.find('input[name=url]');
    Dispatch('APP_CHANGED', { url });
  }
});

That’s it. Views aren’t allowed to do anything else.

After the dispatch, you can write two types of callbacks:

  • Normal (non-reactive) Store callbacks:
Register(() => {
  switch (Action.type()) {
    case 'NEW_APP_CREATED':
      Meteor.call('addNewApp', data);
      break;
    case 'APP_CHANGED':
      let id = State.get('app.id');
      Meteor.call('changeApp', id, data);
      break;
  }
});
// or async actions as well:
Register(() => {
  if (Action.is('LOGOUT')) {
    Meteor.logout( function(error) {
      if (!error) {
        Dispatch('LOGOUT_SUCCEED').then('SHOW_LOGIN');
      } else {
        Dispatch('LOGOUT_FAILED', { error });
      }
    });
  }
});
  • And then use reactive State modifications (called reducers in Redux):
// dependent on Flux actions...
State.modify('apiChecker.error', (state = false) => {
  switch (Action.type()) {
    case 'API_CHECK_FAILED':
      return true;
    case 'CHECK_API':
    case 'API_CHECK_SUCCEED':
      return false;
    default:
      return state;
  }
});

// or dependent on Meteor reactive sources...
State.modify('apps.items', (state = []) => {
  return Apps.find({}, { sort: { modifiedAt: -1 } });
});

let handle = Meteor.subscribe('apps');
State.modify('apps.isReady', (state = false) => {
  return (!!handle && handle.ready());
});

State.modify('app', (state = {}) => {
  let appId = State.get('app.id');
  return Apps.findOne(appId);
});

Finally use State to render the View. It is available everywhere, designers don’t need helpers.

<div class="ui grey header">
  Welcome {{profile.firstName}}!
</div>

<button class="ui button" dispatch="OPEN_NEW_APP_FORM">
  Add another app!
</button>

<div class="ui subheader">
  Choose an app:
</div>

{{#if apps.isReady}}
  <div class="ui cards">
    {{#each apps.items}}
       <button class="header" dispatch="SHOW_APP" data-id={{_id}}>
         {{name}}
       </button>
       <div class="meta">
         <strong>Url:</strong> {{url}}
       </div>
       <div class="meta">
          <strong>Modified:</strong> {{moFromNow modifiedAt}}
       </div>
    {{/each}}
   </div>
{{else}}
  Apps are loading, please wait!
{{/if}}

The log of the app is easy to follow and looks like this:

What the user did here was to enter its email and password on a login form. He didn’t have account yet, so we created a new one for him and showed him a special form called “Create your first app” asking for his name as well. When he submitted the form, the profile was changed, a new app was created and he is sitting now in the screen which shows him his list of apps.


This combination of Tracker and Flux is working really well so far. Logic is easy to write, strong against bugs (thanks to Tracker) easy to reason about and easy to extend (thanks to Flux).

The view layer is also easier to write and any designer can jump in. They only need a list of actions they can dispatch and the available tree of State. They shouldn’t care if data is coming from an external API, Minimongo, a javascript variable… whatever.

I don’t have easier examples to show at the moment other than the product we are building:

It is still in the first steps but if you are interested, you can get an idea. We are using “everything-is-a-package” as well. You can take a look at the action.js and state.js files of the dashboard packages to see more code examples.

14 Likes

I like where this is going, really good thoughts here & I hope it continues!

Redux is nice because when implemented properly, every single state change flows through the store, regardless of whether it’s a local change or persisted change. Data can’t come from or go to the server without going through redux. Minimongo achieves this, but is tightly coupled to…well, a lot of stuff. It also doesn’t care about state on the client.

Regarding client-only state, I can tell when a form is dirty, a url param has changed, a socket was interrupted, an auth token refreshed, or a css animation is happening all by looking at the “single source of truth”. This is really powerful because I can pass any subset of these truths to a component as a prop, which gives me fine-grained reactivity.

You can even use redux as a client-side cache to replace minimongo with a fully optimistic UI: https://github.com/mattkrick/meatier/blob/master/src/universal/redux/middleware/optimisticMiddleware.js#L28

Meteor 1.3 moving towards NPM is a great step #1, this would be an amazing step #3 (step #2 being a move to node 4 ;))

1 Like

Redux allows your UI to be a pure function. This comes with lots of benefits. For me, personally, the two biggest benefits are abstraction and time travel. You can record flows and save them for later. You can bundle up the entire user state and action sequences and send it to your server whenever theres a runtime exception. You can also generate tests for your application just by using it and recording the state-action sequences. Its really a pattern more than a framework. I’ve been reading about the Elm Architecture a bunch lately and its really opened my eyes to how user interfaces should be built.

4 Likes

I agree that redux is great with its abstraction and developer tools. Something we really missed in Blaze. But it’s just one way to build a modern app. People are hating on state mutation because it is indeed hard to manage…but to say its how you SHOULD build something is a little strong don’t you think Chet?

Meteor on the client has a DB which most frameworks do not. The concept of stores in other frameworks are objects or arrays. Then they have to have event emitters or fake callbacks to update things to keep stores in sync with actions that just happened. That’s why rehydration is a huge thing in Flux Architectures. The thing that these patterns lack is Tracker. Plain and simple, reactivity on the client is what brings Meteor, Minimongo at the forefront of a flux pattern.

You have stores (either client side local collections, minimongo bound collections, reactive vars, dicts, session) w/e

You then dispatch actions, which today meteor apps are over doing it in the view layer with Meteor.methods, but if they sent these actions via a dispatcher/or some action layer, then you could have some separation of concerns there

Actions cause state change, and the stores are aware immediately. No need for extra callbacks, or store subscribes. Tracker glues this together for us.

Elm though is indeed far out, and if I had a lack of client side reactivity in tracker I’d jump on the Redux/Elm bandwagon.

3 Likes