Saturday, August 10, 2013

Evangelizing "MEAN STACK"


Any self-respecting "Brogrammer" like me knows how to program in Javascript. When startups try to test your skill set in "lingo" like: "Backend" (and by backend I mean...you an ass man, bro?) Your typically response is: "a whole bunch of stuff that isn't Javascript." 

Guess what: with MEAN STACKNot anymore dude. Yeah, you just went from alert('Hello World'); monkey to full-stack developer...HIGH FIVE.

For a good time, check out: Brosciencelife on Youtube

MEAN STACK, as conceptualized by Valeri Karpov in the blog post linked above, is not new technology, and it's not even based on any new components. It's just, in my opinion, an exciting layering of existing technologies that all run on JavascriptmongoDB, ExpressJS, AngularJS, and NodeJS. And let me tell you: this bad boy cuts through your projects like a hot knife through butterRighteous swell, bro.

Lets get down to it. I'd heard the hype: NodeJs is performant, non-blocking, and easy to learn. (See pretty much everyone at GluCon), and I'd also heard the jeers, Ted Dziuba, etc. (though 
I can't find any of their posts anymore, just mentions of them ... interesting)
var express = require('express'); var app = express();
var server = http.createServer(app).listen(app.get(3000), function() {
console.log('Express server listening on port ' + app.get('port'));
});

Boom!

I know it takes more than that ... but you get the idea. Nothing new there.

So I thought I'd try an example of an operation I hadn't seen a lot of floating around on the interwebz: Streaming new DB entries in realtime out to a page via WebSockets.

This is where it gets really interesting (at least it did for me) using MongoDB's streaming cursors, with capped data-collections. To create basically a one-stop message-queue real-time to web-socket buzzword orgy of awesomeness.

First define a schema in Mongoose, and add a tailable find:
var BidSchema = new Mongoose.Schema({
    price : { type : Number },
    amount : { type : Number } }, 
    { capped: { size: 5242880, max: 1000, autoIndexId: true }});

var Bid = db.model('bidSchema', BidSchema);

var bidStream = Bid.find().tailable().stream();

I ran into some issues at first when I tried this. 
MongoError: tailable cursor requested on non capped collection
BROTIP: THIS ONLY CAPPED COLLECTIONS CAN BE USED FOR STREAMING NEW RECORDS OUT OF MONGODB.

Next we setup a SocketIO to send our results out to the page as they are entered into the database:

var ioserver = require('socket.io').listen(server);
var clientsocket = null;

ioserver.sockets.on('connection', function(socket){
 clientsocket = socket;
 var timeout = null;
 
 bidStream.on('data', function (doc) { 
  clientsocket.emit('bid', doc);
 }).on('error', function (err) {
   console.log('error: '+err);
 }).on('close', function () {
   // the stream is closed
   system.debug('close');
 });
});


Next we setup our client-side, AngularJS Controller:
    script
      var socket = io.connect('http://localhost');

      function BidsController($scope, $http, $window){
        $scope.bids = [];

        $scope.save = function(bidForm){
          $http.post('/placebid', { bid : $scope.newBid }).success(function(response){
            console.log(response);
          });
        };

        $window.socket.on('bid', function (bid) {
          console.log(bid);
          $scope.$apply(function(){
            $scope.bids.push(bid);
          });
        });

      };
And our Jade Template display:

    body
    div(ng-controller="BidsController")
      h1 Enter a bid:
      form(name="bidForm", ng-submit="save(bidForm)")
        input.form-control(type="text", ng-model="newBid.price", name="price", placeholder="Enter a price.")
        input.form-control(type="text", ng-model="newBid.amount", name="amount", placeholder="Enter an amount.")
        input(type="submit")
      table(style="border:1px solid black;")
        tbody
          tr(ng-repeat="bid in bids")
            td(style="border:1px solid black;") {{bid.price}} 
            td(style="border:1px solid black;") ${{bid.amount}}

Bam. That was easy. Like I said...hot-knife through butter...!

Now your a full-stack developer, with plenty of time to go get stacked at the gym.

So get out there and get it brogrammer!

Source: Github here

PS. The whole "bro" thing was not a knock on the MEAN Stack - I've just been watching too much: Brosciencelife on youtube, that hitting the gym all week getting rock-swol for the Denver Triathlon. 

PSS. I'm still having trouble with the streaming cursor in mongoDB returning duplicates/triplicates of the same documents. I'll update if I figure it out, or someone comes along on stackoverflow.

2 comments: