Learning about docker this weekend… it always is hard to find resources for people who understand the concepts of VMs and containers and need to dive into something just a little bit complicated. I had been through lots of intro tutorials, when docker first arrived on the scene, and was seeking to set up a hosted dev instance for existing open source project which already had a docker set up.

Here’s an outline of the key concepts:

  • docker-machine: commands to create and manage VMs, whether locally or on a remote server
  • docker: commands to talk to your active VM that is already set up with docker-machine
  • docker-compose: a way to create and manage multiple containers on a docker-machine

As happens, I see parallels between human spoken language and new technical terms, which makes sense since these are things made by and for humans. The folks who made Docker invented a kind of language for us to talk to their software.

I felt like I was learning to read in a new language, like pig-latin, where words have a prefix of docker, like some kind of honorific

They use docker- to speak to VMs locally or remotely, and docker (without a dash) is an intimate form of communication with your active VM

Writing notes here, so I remember when I pick this up again. If there are Docker experts reading this, I’d be interested to know if I got this right and if there are other patterns or naming conventions that might help fast-track my learning of this new dialect for deploying apps in this land of containers and virtual machines.

Also, if a kind and generous soul wants to help an open source project, I’ve written up my work-in-progress steps for setting up OpenOpps-platform dev instance and would appreciate any advice, and of course, would welcome a pull request.

Serverless development just got easier — today’s release of Cloud Firestore with event triggers for Cloud Functions combine to offer significant developer velocity from idea to production to scale.

I’ve worked on dozens of mobile and web apps and have always been dismayed by the amount of boilerplate code needed to shuffle data between client and server and implement small amounts of logic on the server-side. Serverless APIs + serverless compute reduce the amount of code needed to write an app, increasing velocity throughout the development cycle. Less code means fewer bugs.

Cloud Firestore + Cloud Functions with direct-from-mobile access enabled by Firebase Auth and Firebase Rules combine to deliver something very new in this space. Unhosted Web apps are also enabled by Web SDKs.

It is not a coincidence that I’ve worked on all of these technologies since joining Google last year. My first coding project at Google was developing the initial version of the Firestore UI in the Firebase Console. I then stepped into an engineering management role, leading the engineering teams that work on server-side code where Firebase enables access to Google Cloud.

Cloud Firestore

  • Realtime sync across Web and mobile clients: This is not just about realtime apps. Building user interfaces is substantially easier: using reactive patterns and progressively filling in details allows apps to be ready for user interaction faster.
  • Scales with the size of the result set: Simple apps are simple. For complex apps, you still need to be thoughtful about modeling your data, and the reward is that anything that works for you and your co-workers will scale to everyone on the planet using your app. From my perspective, this is the most significant and exciting property of the Cloud Firestore.
  • iOS, Android and Web SDKs

Cloud Functions

  • Events for create, write, update, and delete (learn how)
  • Write and deploy JavaScript functions that do exactly and only what you need
  • You can also use TypeScript (JS SDKs include typings)

All the Firebase things

  • Free tier and when you exceed that, you only pay for what you use.
  • Zero to planet scale: no sharding your database, no calculating how many servers you need, focus on how your app works.
  • Secure data access with Firebase Rules: simple, yet powerful declarative syntax to specify what data can be accessed by client code. For example, some data may be read-only access for social sharing or public parts of an app, user data might be only written by that user, and some other data may be only written by server-code.
  • Firebase Auth: all the social logins, email/password, phone or you can write code for custom auth
  • Lots more Firebase things

All this combines to allow developers to focus on building an app, writing new code that offers unique value. It’s been a while since I’ve been actually excited about new technology that has immediate and practical use cases. I’m so excited to be able to use this tech in the open for my side projects, and can’t wait to see the serious new apps…..

SailsJS is a NodeJS MVC framework that we use for the OpenOpps Platform. Sails has some basic testing docs, but it doesn’t explain how to set up the framework nicely where the database is dropped in between tests. I find myself always re-figuring out these patterns when I write experimental apps.

With an in-memory database, this bootstrap.test.js will drop the database between tests:

var sails = require('sails');

before(function(done) {
  sails.lift({
    // test config
    environment: 'test',
    port: 9999,   // so we can run the app and tests at the same time
    hostName: 'localhost:9999',
    connections: {
      testDB: {
        adapter: 'sails-memory'
      }
    },
    models: {
      connection: 'testDB'
    },
  }, function(err, server) {
    if (err) return done(err);
    done(err, sails);
  });
});

after(function(done) {
  sails.lower(done);
});

beforeEach(function(done) {
  // Drops database between each test.  This works because we use
  // the memory database
  sails.once('hook:orm:reloaded', done);
  sails.emit('hook:orm:reload');
});

When I need to use postgres, Waterline doesn’t expose SQL truncate which would be much faster, instead this bootstrap.test.js will destroy all the models:

var async = require('async');
var sails = require('sails');

before(function(done) {
  sails.lift({
    // test config
    environment: 'test',
    port: 9999,   // so we can run the app and tests at the same time
    hostName: 'localhost:9999',
    models: {
      connection: 'postgresql'
    },
  }, function(err, server) {
    if (err) return done(err);
    done(err, sails);
  });
});

afterEach(function(done) {
  destroyFuncs = [];
  for (modelName in sails.models) {
    destroyFuncs.push(function(callback) {
      sails.models[modelName].destroy({})
      .exec(function(err) {
        callback(null, err)
      });
    })
  }
  async.parallel(destroyFuncs, function(err, results) {
    done(err);
  })
});

after(function(done) {
  sails.lower(done);
})