PickMeUp Meteor Demo
I built this demo app to evaluate Meteor. You can skip to the Review Notes below.
Background
In a previous job I built something very similar to Meteor using Python & CouchDB. I wanted to evaluate Meteor with something beyond a simple chat application, to see how easy it would be to cover some of the real-world use cases I hit before. Meteor is full-stack, although you can swap out some of the parts as wrappers become available.
Application Use Case
After work my wife picks me up from the bus stop. I wanted an app to track where I was and notify her a few minutes before I reach the stop. She should have a webapp that alerts her when I arrive, and I should be able to send my location from either my laptop, tablet or smartphone.
Try the Demo
Meteor hosts meteor apps for free, so PickMeUp is on pickmeup.meteor.com and pickmeup.meteor.com/bus.
PickMeUp two pages--a bus rider view is required, and the pickup view is optional. Open both.
Someone needs to share their location on the bus rider view, so if you don't see a map after a few seconds, tell you browser to allow your coordinates. If you already see a map, don't share your location.
The destination is hard-coded to Magnolia Bakery in New York City, not my real bus stop.
The maps have markers for current location and destination, and the buttons outside the map control zoom. These are separate for each view.
The "send alert" and "send alert now" buttons manually toggle a simple alert notice. This is synced between views.
Approach
I used Bootstrap 3 to get easy mobile-first design, through the meteor-bootstrap-3 plugin. (I had tried a plugin with Bootstrap 3 less, but when it didn't immediately work, I used the other.)
Iron Router handles the multiple webapp views as different pages.
I used raw HTML5 geolocation, and will package that as a Meteor plugin.
I used Google Maps API v3 to drive a map live. It's too custom to package in its current form, but it's a good example of how to avoid Google Maps having 0 height, flickering when Meteor re-renders, the map showing all gray and a few other gotchas that make integration annoying.
Review Notes
I found that Meteor is stable, has an active community, and great tool chain support. I was able to complete the vast majority of this project, from scratch, over a weekend. It uses things you probably already know, or all well documented, like Handlebars, Underscore, jQuery and mongoDB. You get javascript on both the server and client side, so your front-end developers can contribute to the back-end, or at least read the code. Making packages is easy with Atmosphere, which has helped get some some useful 3rd party tools integrated (like Bootstrapbs3). It's reactive first, which means you don't need to seek out javascript developers who have already been through the pain of building real webapps, and not just session machines that push templates from Java or PHP. Webapps are reactive, and there's some learning curve in terms of structuring things. Meteor helps with that A LOT, and for that it's worth learning, even if you're firmly planted in a Python/Django shop.
Coming up to speed
New javascript/node programmers should be able to come up to speed quickly. Organization is open and light, which is a trade-off. Today, it means you don't need Meteor experts. Longer term it means every project will have a different organization, which will burn time bringing new people on board, or (re)documenting your architecture.
To minimize this, it's a good idea to package pieces of your app as real packages, even if you don't share them openly. This will help impose some natural organization as your app grows. Isolated tests become easier too.
Invisible Magic
The heart of Meteor is a systematic mapping of mongoDB collections to handlebars, using invisible magic. I'm never a fan of invisible magic in platforms, but it has strong benefits in getting started quickly. Meteor exposes things like Handlebars perfectly, but completely hides things like SockJS. That's normally fine. But use jQuery in a Template you'll see that there are "wrong" things and "right" things to do that aren’t obvious. It appears much of this will get addressed by release 1, but some is inherent in the design.
Data Models
Reactive systems need to finely segment data to make targeted updates at the clients. Meteor is no exception. For instance, a Session
object is given to make reactive data NOT synced between clients. It's not really good for Session stuff that isn't reactive, so don't do that--you'll inadvertently trigger updates elsewhere. If you aren't careful to specify simple enough data to use Session.equals()
, you'll trigger many reactive updates. For instance, the docs point out that if you consistently use
Session.get("key") === value
you will trigger a reactive update on every Template function that uses that pattern when any Session key updates. Instead use
Session.equals("key", value)
which will only update Template functions that share the same key.
This isn't extensible in the following case (where Geolocation is used instead of Session):
var location = Geolocation.findOne();
if( location !== undefined && 'alert' in location ) {
return location.alert;
}
return false;
So making individual atomic keys is better, which ultimately means using flat data architectures. This is generally true for reactive programming, and not expensive with almost any NoSQL backend. But most examples of Meteor over use Session because it's convenient. So those parts won't necessarily scale or work well together. And packages are free to pollute the Session name space.
The solution is fine-grain control over the rendering, which requires some handlebars black magic (like #isolate, #constant). A declarative method for stating dependencies would require overhead and initial learning, but would go a long way to avoiding the slow expertise you need to develop when tripping over the best-practices you don't know yet.
Service-Oriented Architecture
SOA for webapps over websockets is a topic unto itself. As a full-stack tool, Meteor will require some code to map 3rd party APIs to reactive sources. It was easy enough to use Google Maps V3 API, and you can use Meteor.http() for other RESTful calls. With the support behind Meteor, I expect many packages will be wrapped in a useful way. For now, the full benefit is only seen by fork-lifting the results of RESTful calls into a Collection. This is a level of indirection, requires some server-side code that will become boilerplate (unless you call from the client and overload Session), and yields a light performance hit.
You wouldn't really use Meteor to create an SOA API, it’s not for that.
Testing
As a rapid prototype, I didn't use Test Driven Development. My philosophy on that is: learn by doing, build by testing. This was a learning exercise. But to build a product I'm a big advocate of TDD. To package the geolocation stuff, I'd start with the test cases and rebuild it robustly.
There are a few Meteor test tools. The most promising looks like Laika, which uses PhantomJS for client manipulation. You can use Mocha and all your favorite node tools, but Laika duplicates a lot of the magic Meteor runs for you, so you don’t just get a ton of undeclared variable errors.
Why I didn't use CoffeeScript
Simply put, there are more Javascript programmers than CoffeeScript programmers. I like hiring and working with programmers who read the code they're using, so it's more helpful to write in language more people can read. I don't have a strong opinion of which is "best"--there will be both, and Meteor works with both.
Conclusion
For now, learning Meteor is great to see how reactive programming of webapps works in the real world. It’s also good for small projects. It’s new, but the odds of it getting to production quality look very good, so it’s worth getting some skills together now.