Hacker News new | ask | show | jobs
by murbard2 4046 days ago
I'm actually looking into meteor at the moment, and the financial backing is a big plus, as it gives me some guarantee that the project will keep being maintained for the foreseeable future.

It is indeed a breeze to prototype applications with it, but I am a little bit concerned about the costs of getting an actual production ready site with it.

For intance, when is it ever OK to let your client write directly in the database, even for their own data? If you're going to pass their calls through a deny and allow call, why not just expose RPCs to the client that will handle any writing?

It seems that a lot of the light versality you have at prototyping time is lost whenever you have to get it production ready. There is definitely some value in light prototypes, but it looks like a real pain to go from prototype to production.

Likewise, I'm confused about how to get around the limitations of mongodb. Say you run a store with a finite inventory, how do you handle concurrent purchases? How about a website to enroll into classes? How about a webforum which can have exactly 5 administrators?

4 comments

> For intance, when is it ever OK to let your client write directly in the database, even for their own data? If you're going to pass their calls through a deny and allow call, why not just expose RPCs to the client that will handle any writing?

Good question. A pattern I like to use for this in Meteor is to rely solely on their Method calls which allow you to restrict any database ops to the server side. The trick is that you lock down all client-side writing from the get go so you're not trying to guess whether you set your rules properly. Here's an example of that pattern: https://gist.github.com/themeteorchef/194a803f8a28840f475f.

Re: concurrent purchases in your store example, you can actually strip reactivity from certain database queries. So, on the front-end you can prevent state shifting out from under users. To control data on the server, you could have a method that checks whether or not the inventory has been depleted before allowing certain operations (e.g. routing to a new page, manipulating the database, etc). Definitely possible to do this without going bonkers.

Does that answer what you're looking for?

Yes, thanks, sort of! The pattern you use is basically the one I would naturally do, but it doesn't feel "meteoritic"... the client side manipulation of the db really seems centric to the magic of it.

Regarding the concurrent store, forget event about the client. You need to check whether or not the inventory has been depleted and then update the inventory, and create the client's invoice. That means blocking calls, double staged commits, and a whole lot of nasty things that have nothing to do with reactivity and everything to do with integrity.

> but it doesn't feel "meteoritic"... the client side manipulation of the db really seems centric to the magic of it.

In the prototyping sense, yes. I've been working with Meteor for about two years and the pattern I shared above still feels magical when you realize what it's doing in just a few minutes of work. The client-side writes are still okay. The big problem is remembering to specify the correct allow/deny rules.

The pattern above is a sort of brute force approach to saying "I'm an idiot, I'll forget to set rules, let's make this a non-issue." Of note, I recall some chatter about dropping allow/deny rules altogether in the future, so there's likely a better solution on the horizon.

> You need to check whether or not the inventory has been depleted and then update the inventory, and create the client's invoice.

This isn't as big of a problem as it's being made out to be. Really just a few lines of code, e.g.:

```

// Fetch just makes this an array instead of a Mongo cursor.

// The fields part just strips the returned object(s) back

// with only those fields + the _id of the object.

var inventoryAvailable = Inventory.find({product: productName}, {fields: {"available": 1}}).fetch();

if ( inventoryAvailable.available > 1 ) { // Call some purchase function. } else { // Throw an error back to the client. }

```

Re: the concern around race conditions between customers, Meteor could actually have a leg up on this. Because you have reactivity, if say there was only 1 of an item left, if one customer completed the purchase before another, you could throw up an overlay on the slower customers screen saying "uh oh, the last one of these just got snatched up...get on the waiting list?"

A lot of ways to skin this cat :)

Here's step 10 of the tutorial, which demonstrates how you can write custom RPCs to handle writing data in Meteor: https://www.meteor.com/try/10

You don't have to use the client-side insert/update/remove syntax if you don't want to. Unless you add an 'allow' call to let some of them through, they will all be automatically rejected by the server.

(I work at Meteor)

Thank you, I know that you can do that. My concern is more of a soft question: in practice, in production, isn't that what you always end up doing anyway? And if that's the case, how much of meteor's coolness is lost in the process? If I'm going to be writing rpcs for all writes, why not just use some websocket library?
Meteor's RPCs support automatic optimistic UI updates, where the same code can be used to update the client side data store and the server side database, resulting in the perception of zero latency between server and client.

Building that functionality out yourself from scratch could be difficult, since all of the components of Meteor work together to make that experience possible.

> For intance, when is it ever OK to let your client write directly in the database, even for their own data? If you're going to pass their calls through a deny and allow call, why not just expose RPCs to the client that will handle any writing?

If you have a client-side mirror of your server-side database whose changes are monitored by the templating engine, you can execute what Meteor calls "latency compensation", where changes users make are instantly reflected in the UI and synced to the server in the background. This is a central feature of Meteor. More here: https://www.meteor.com/full-stack-db-drivers and in this Youtube video: https://www.youtube.com/watch?v=tqLbodVH3dw

> It seems that a lot of the light versality you have at prototyping time is lost whenever you have to get it production ready. There is definitely some value in light prototypes, but it looks like a real pain to go from prototype to production.

It's actually very easy to go from prototype to production; you just remove some convenience packages (autopublish and insecure), set up your security rules, do some basic performance tuning (eg. don't publish entire documents if you only need 3 fields, which is a standard practice for any app) and that's about it. Of course the definition of "production" varies per project, but after shipping over 20 Meteor apps since 2012 these are the most common things I tend to do.

> Likewise, I'm confused about how to get around the limitations of mongodb. Say you run a store with a finite inventory, how do you handle concurrent purchases? How about a website to enroll into classes? How about a webforum which can have exactly 5 administrators?

You can express most of these in code. Yes, in relational databases you can express constraints in the database. But then you're having a NoSQL vs SQL debate, which is sort of out of scope of this discussion.

Sure you remove the autopublish package, but then your app stops working. You need to explicitely publish what you want published, you need to explicitely check and validate every input from the client... and that's fine, but then what exactly have you gained from using meteor over, say, socket.io or autobahn? Fast prototyping, yes, you've definitely gained that, but have you gained anything else? I'm genuinely asking, not making a rhetorical point.

Since meteor integrates very tightly with mongodb, a nosql database, I don't see how the limitations of nosql are out of the scope of the discussion? I also don't know what you mean by "you express most of these in code". The problem isn't writing a piece of code that expresses that constraint... the problem is doing so without introducing a race condition!

To answer your first question, there are a number of attractive advantages to using Meteor over say socket.io or autobahn on top of Node. One major one would be a consistent API for accessing your data on the Client and Server. I would argue that using Javascript on both backend and frontend with Node boosts a developer's productivity by reducing language/context switching. In the same vein accessing data using the Mongo query api on both backend and front end with Meteor's MiniMongo improves development. Also Meteor comes with built-in latency compensation when using either RPCs (with stubs on the client) or Minimongo operations. Latency compensation is a non-trivial problem which would need to be implemented by the developer when using something like socket.io. You also gain access to a growing list of great packages that implement things like user accounts which you would otherwise need to write yourself or wire together from various projects.

As for your second question. There are certainty use cases where MongoDB isn't appropriate, and support for other databases is on Meteor's roadmap. For now there are some community created packages for interfacing directly with SQL databases in place of MongoDB, but there are a number of issues with them. You could also pipe data in and out of an SQL database inside RPCs, however the data would not be updated in 'real-time' to clients. I anticipate SQL databases will get some good support options in time.

> I also don't know what you mean by "you express most of these in code". The problem isn't writing a piece of code that expresses that constraint... the problem is doing so without introducing a race condition!

I agree, and this also exposes a weakness of javascript as a backend language. If you use Java/Scala, you have multithreading support and can sync the threads + concurrently verify that an item isn't being purchased more than X times. Which makes this problem solvable even with a NoSQL database. Javascript is single threaded though, which makes this problem a lot harder and I don't know how you'd solve it without an RDBMS with transactional support.

> If you use Java/Scala, you have multithreading support and can sync the threads + concurrently verify that an item isn't being purchased more than X times.

That does cause you to have a hard limit of one application server for the app, which can be a pretty big deal...

No, you could have multiple servers talking to each other via something like ZooKeeper. But individually, each node/server would use multithreading to keep track of its state.
I guess, but that's some monumental hackery to overcome something that works perfectly fine in an RDBMS :-)
Do yourself a favor and set aside a weekend to go through this book: https://www.discovermeteor.com/

All of your questions are answered there.

As an onlooker that's discouraging. Can you give one-line answers to the points above?
Other users have answered these pretty well by now, I'd just like to add to the discussion of this question: >Likewise, I'm confused about how to get around the limitations of mongodb. Say you run a store with a finite inventory, how do you handle concurrent purchases? How about a website to enroll into classes? How about a webforum which can have exactly 5 administrators? A quick&easy for me has been to just set up a separate REST API to handle critical data like payments and just have a two-server app. Doesn't really add to development time vs a unified server. Meteor doesn't preclude SQL use, it just doesn't support reactive SQL off the shelf like it does Mongo.
Cant tell if this is sarcasm or not :P
No, genuine comment. Those are reasonable questions, and the answer "spend a weekend reading a book" isn't great.
It's not cheap and I can't even find a table of content for it. I've also read excerpts that dealt with autopublish etc, and they didn't really address the point I'm making.

Is there a benefit to using meteor beyond the fast prototyping? I'm not saying that's not potentially a huge benefit, but once you're done with your prototype, I still feel like you have to rewrite the whole thing.

Removing autopublish and writing methods is not the same thing as rewriting the whole thing. But if you want to skip autopublish, you can do so from the beginning. As mentioned elsewhere the ability to perform a database action initially on the client allows for latency compensation, which is a significant user benefit beyond fast prototyping.
The table of contents is right there on the homepage. And you can read the first four chapters for free here: http://book.discovermeteor.com