Thingking about Meteor 2.0 šŸ¤”

Well, now comes the hard part. Actually making it happenā€¦

No, I donā€™t support killing DDP and Minimongo as these are core parts of what makes Meteor Meteor and provide functionality that many long term users (like me) rely on in our Webapps.

Providing the option to use/not use DDP and Minimongo or to programmatically turn them on and off is fine.

As for Fibers, I am not sure what the issue is. Promise.await() is easy to use and works perfectly when calling promise-enabled functions or those that use async/await

Ben Newman gave an excellent talk in 2015 to explain why Meteor should retain the use of Fibers.

Slides:

http://benjamn.github.io/goto2015-talk/#/

I sincerely ask - what has changed since Benā€™s talk that would make a complete migration to async/await worth doing?

Are there any issues with Fibers in Node.js 10?

6 Likes

I totally agree on the Minimongo and DDP part. Its for me one of Meteorā€™ biggest strengths. Not sure about Fibers though. Its on one hand confusing for developers coming from other platforms. On the other its a very convinient way of writing.

2 Likes

As I said before here, the concept Meteor means different thing to different people, so weā€™ve to keep the discussion in the perspective/context of how the tool is being used.

I agree, I use Minimongo and DDP myself but that was @sacha statement from here. And I think they didnā€™t mean to kill minimongo/DDP but to make it an optional package since those using GraphQL donā€™t really need the web sockets open which consume server memory and has slight initiation delay at the client, so making it optional, in my opinion, is a reasonable ask since theyā€™re using Meteor just as a backend for a GraphQL end point.

Iā€™m not sure either but folks who advocating for it are saying itā€™s a barrier to move Meteor to NPM, itā€™s holding some developers coming from the rest of the NodeJS ecosystem off guard, and they might also be barrier for contributing to Meteor core, those points have been echoed several times in this thread but I think that requirement could be flushed out more because, for me, it still sounds vague but maybe itā€™s my lack of experience with Meteor core. You can see @gaurav7 comment here when I questioned why Fiber is an issue. Also, Ben did highlight some of the issues that comes with using Fibers, especially catch 3 in his slides. I think in his last comment you can see that he favoured the tradeoff of simplifying Meteor usage (developers experience) on the expense of the effort it takes Meteor core contributors to learn and maintain Fiber (contributors experience).

1 Like

Well I think you started a good thread, I think itā€™s worth outlining and capturing the community needs/pain points/sentiments. But yeah execution is another story, Iā€™m seeing progress on the Vue guide, which I think is a real service to Meteor that the community is well positioned to independently help with.

4 Likes

@vlasky see my earlier comment highlighting the parts of Benā€™s presentation where he seems to acknowledge the points being echoed in this thread w.r.t Fibers.

Sure Fiber makes many things appear ā€œeasyā€, as long as it works. But itā€™s a nightmare when it does cause a problem, the likelihood of which increases as you scale and/or use more 3rd party libraries. So far, the ā€œease of useā€ argument perhaps rightly trumped over the cons, justifying the tradeoffs. But there was no alternative then. Now we have one, in the form of async/await, and the best part is that itā€™s a proper standard!

Not only would removing Fiber make Meteor more approachable to other Node.js app developers and authors of libraries & tools, but it would also save the few precious resources currently working on the framework (mainly Ben, as per github stats) from spending time on unproductive work (i.e. no new framework feature) that Fiber keeps demandingā€¦ just look at some of the current open issues to get an idea:

All this just to pretend that weā€™re writing synchronous code on a platform thatā€™s inherently asynchronous! Is that really worth all the trouble now that thereā€™s a good/better alternative?

As an example of the overhead it would eliminate: the whole meteor/promise package wonā€™t be needed if Fiber were to be removed! Note that Promise.await and Promise.async are not standard APIs.

7 Likes

Yes exactly this is why Iā€™m now supporting simpleDDP and am building my vue connectors for it.

It feels to me that the red line here is pluggability. It takes quite an effort just to understand Meteorā€™s internals. Making this easier and putting developers in control over what functionality they require is crucial. Thatā€™s one thing I love about Vue and Nuxt. The plugins

1 Like

Do you think Fibers can be removed in a backward compatible way (i.e legacy app code still works as is)? It sounds to me that removing Fiber from the Meteor core is going to be a major refactoring given the potential impact/testing required.

Iā€™ve personally never experienced an issue with underlying cause pertaining to Fiber usage and weā€™ve tons of third-party npm packages so I canā€™t relate to that statement, and being on this forum for sometime, I donā€™t see many issues pertaining to Fibers usage either. Also it seems coroutines are emulating multi-threading and multi-threading bugs are nightmare in general. However, there are some hard corner cases issues reported on Github pertaining to Fiber use such as this oneā€¦

Human mind is naturally sequential thus having Meteor backend synchronous by default is in an advantage and one less hurdles for newcomers before getting their todo list render on the screen.

Actually Iā€™ve the same question toward removing Fiber, is that really worth the trouble? If I understood Benā€™s talk correctly, coroutines (Fibers) is a more generic/flexible approach toward async code when compared to async/await and he demonstrated how async/await can be implemented using coroutines furthermore it does enhance the developers experience (in Java weā€™ve synchronized blocked, other languages (Kotlin for example) have co-routines as well as Benā€™s alluded too). There is a great talk from Kotlin authors explaining why coroutines are superior to async/await, they made very similar points to Ben, you can find it here. So my personal take on the refactoring of Meteor Fibers, that itā€™ll be a major undertaking (which I think an effort could be spend elsewhere) that doesnā€™t improve the developers experience (in fact it might degrade it) and I really donā€™t think itā€™s the main hurdle for contributing toward Meteor (I think itā€™s more marketing issue) so for me the refactoring is not justified, but again I keep an open mind, I think itā€™s debatable topic.

1 Like

@alawi, agreed.

Maybe we need to be public with a way to abstract it out for NodeJS developers thinking of using Meteor, via stubs for Promise. If I look at some of our method calls, we do use Fibers a lot for async calls (e.g. communicating with AWS, files etc.) so I can see why developers would currently have no choice but to interact with Fibers.

But refactoring Meteor to extract Fibers would be writing a whole new framework.

Sorry maybe a little off topic, but Iā€™m a bit confused on why using Fibers for async calls on the server? Iā€™m a bit puzzled why I didnā€™t have to interact with Fibers, I do make a lot of async calls to third party APIs/filesystem but I just use promises/async await or Meteor.wrapAsync, so when exactly do I need to use Fiber, am I missing something, why I havenā€™t experienced the ā€œFiber painā€ yet :sweat_smile:?

1 Like

When you make a call to a Meteor method, and that method depends on an async call (e.g. pushing a file on S3) how else would you do it?

We return a future.wait() in the Meteor method, and in the callback from S3 we return future.return(result) or future.throw(error)

How else would would you do it?

EDIT: Fixed text to replace fiber with future

I just checked Meteor.wrapAsync (which we donā€™t use ā€“ maybe we should change that). It takes care of that for you. It also does the Meteor.bindEnvironment for the callback.

Maybe this is the solution. Maybe Meteor.wrapAsync could be the starting point of using Promise (developers donā€™t care whatā€™s under the hood)

1 Like

Yes, I used Meteor.wrapAsync for the Stripe calls convert the async calls to sync and I wait for the results, the code block reads sequentially thus making it easy to reason about, thatā€™s why I said removing Fiber might actually degrade the developer experience. For file uploads, I push to S3 from the client. In both cases, I wasnā€™t even aware of Fiber when working on them!

By the way I highly recommend Rob Fallows article here, really helped me to wrap my head around Meteorā€™s async.

1 Like

Yeah very likely it would be a rewrite at least for the parts that are tightly coupled with fibers. Thatā€™s why I brought this up only in the context of a hypothetical Meteor 2.0 (which I wish doesnā€™t stay hypothetical for too long :slightly_smiling_face:).

The latest versions of AWS SDK have .promise() methods. So you could also do something like

async function upload() {
   const response = await s3.upload({}).promise()
}

or pretending synchronous code through implicit use of fibers:

function upload() {
   const response = Promise.await(s3.upload({}).promise());
}

So I must clarify in my push for removal of fibers, that itā€™s entirely possible to write async/await code in Meteor today. And with the non-standard helpers like Promise.await and Promise.async you are able to interact with external promise-based APIs.

// node_modules/external/index.js:
export function asyncCall(callback) {
  callback(err, result);
}

// non-Meteor Node.js
import { asyncCall } from 'external';
asyncCall((err, result) => {})

// Meteor Node.js
import { asyncCall } from 'external';
Meteor.wrapAsync(asyncCall, this)((err, result) => {})

Which one has a better Developer Experience? :slight_smile:

To be fair, DX is also a function of what youā€™re already used to. When Meteor was launched, Node.js was also fairly new, there was no (popular) Rails-eque fullstack web-framework, callback hell was one of the early criticisms of Node.js. So giving the appearance of synchronous code might have been a masterstroke then to attract developers from other platforms like PHP and Java.

But today, Node.js has arguably surpassed the popularity of the traditional platforms. Co-routines are not idiomatic to Node.js for whatever reason. So if Meteor wants to go back to ā€œmainstreamā€ and lower the barrier to entry, I believe it should eliminate aspects that are not familiar to Node.js developers trying out Meteor.

So the use of fibers not only enforces technical tradeoffs that are not worth anymore, I believe it has also made Meteor framework ā€œnot worth the extra learning curve at a fundamental levelā€, as modern alternatives keep coming up.

3 Likes

Iā€™m not familiar with Meteor internals, but prima facie I expect it to be quite a major work, almost a rewrite of all code thatā€™s coupled with fibers. Thatā€™s why I made the suggestion only in the context of Meteor 2.0.

Every API that hides the asynchronous execution would have to be changed to be Promise-based. So

const user = Meteor.users.findOne();

might become

(async () => {
  const user = await Meteor.users.findOne();
})(); // framework may support top level `await` but let's skip the nitty-gritties iin this discussion

or its equivalent:

Meteor.users.findOne().then(user => {})

Hopefully there would be a way to make the current fibers approach an opt-in, maybe via a package. Somebody familiar with how fibers are used internally might be able to tell how backward compatible that could be made. But if thatā€™s not feasible, it shouldnā€™t stop this evolution; then Meteor 2.0 could be a recommendation for new apps while current apps could stay with 1.x and gradually migrate if worth it for that individual project.

Well, ā€œmanyā€ might be subjective, but I think there are enough to warrant a revisit of the decision. More importantly itā€™s the nature of those issues. And perhaps even more importantly, any such problem is doomed to be specific to Meteor; the rest of the Node.js community is unlikely to find any incentive in fixing them. See the example I shared earlier.

Today, this problem can be considered ā€œsolvedā€ in Node.js because of async/await. Since Meteor is not a language, but rather a framework on Node.js, it would be better to defer to Javascript/Node.js standards where feasible ā€“ if we were to apply the principle of least astonishment here. A newcomer is more likely to read about Node.js first than Meteor.js, right?

Sure thatā€™s the decision to be made, and I hope the points Iā€™m putting forth would help with that. I have come to conclude that while adopting fibers was likely a good decision at the time, it has become a technical debt considering the current state of Node.js and its ecosystem, and of course also considering the current state of Meteor.js.

I donā€™t think he said coroutines is ā€œbetterā€ than async/await, just that with coroutines we wonā€™t need those separate keyword. But forward to today, we have those separate keywords as part of the language itself! And coroutines may never become a standard in JS (for good reasons).

Iā€™ve explained my take from his presentation earlier; pasted below is the part that addresses the specific points you raise here:

My point is not whether coroutines are ā€œbetterā€ as a concept. My simple submission is: is Meteor still compelled to live with the tradeoffs of using fibers? If Meteor were to be written from the ground up today, would one have still used fibers? I reckon that removing fibers would not only eliminate the technical debt whose interest has to be paid in the form of the kind of issues I listed earlier, but also help with the adoption and community contribution.

2 Likes

Yes, but I only had to use wrapAsync for third party API the rest of our code is all sync which is easier to read. So 95% of our code read sequentially (all the DB calls) thanks to Fiber and the 5% (even less in our case) when we call third party API we just wrap it in a function.

Well it depends, I came from Java and the sequential nature of Meteor appealed to me, I agree with the folks from Kotlin, I do think itā€™s the better and more natural way to handle async.

I understand you point/concern @gaurav7 that Meteor is diverging from how async is now being handled in a typical modern node backends and yes we might end up in some niche issues, issue (#9796) is the most interesting, which turned out to be V8 defect on how threads being managed. But I think given the history, available resources, and even tradeoffs (there are strong arguments for using coroutines to handle async), I personally think the effort/discussion for Meteor 2.0 should be focused somewhere else but anyway I think thatā€™s the core maintainers call, since theyā€™re impacted the most by this refactor, so I rest my case :slight_smile:

1 Like

Agreed. I think the biggest impact of removal of fibers would be to make the maintainersā€™ lives easier once the feat is accomplished; then they wonā€™t have to deal with all the overhead :smile:

1 Like

We should at least stop depending on Fibers when it comes to the new packages. Maybe over time we can refactor some of our most valuable packages to become async / await. For me it might be cool to discover just exactly how Minimongo works while adding a new feature hydration. :slight_smile: