Creative App Engine

Jacob MacDonald

jaccarmac@gmail.com

About me.

  • 18 years old.
  • Five years of programming experience.
  • One year of professional experience at Stickman Ventures.

I'm on the Internet!

App Engine is awesome.

Familiar runtimes.

  • Python/Java/PHP/Go.

Powerful libraries.

  • Python: PyPI.
  • Java: Maven Central/Clojars/Gradle
  • Go: Standard library/the Internet.
  • PHP: ?/App Engine's extensions.
  • Google's libraries.
from google.appengine.ext import ndb

class TestModel(ndb.Model):
    x = ndb.StringProperty(required=True)
    y = ndb.GeoPtProperty
    z = ndb.DateTimeProperty(auto_now_add=True)

TestModel(x="test").put()

TestModel.query(TestModel.x == "test")

Excellent scaling.

  • Nine classes.
  • Three instance types.
    • Automatic.
    • Manual.
    • Basic.
  • Free instance hours.
    • 28/8/8.

App Engine isn't perfect.

The Sandbox.

  • Limited file I. No O.
  • No native extensions.
  • Response time limits.

Python/Java/Go/PHP sucks.

  • Python is slow.
  • Java is complex.
  • Go is new.
  • PHP is PHP.

Locked to a platform.

  • Configuration won't transfer to other hosts (exception: Java…).
  • App Engine libraries only work on App Engine.

Java: Maven is unnecessary.

  • App Engine uses the JVM, which is fantastic.
  • You can use your favorite JVM language (Scala, Clojure, Python, Ruby).
  • WAR directories seem fancy, but they aren't.
    • Class files.
    • XML.

Google's way.

  1. Generate an archetype.
    mvn archetype:generate
    com.google.appengine.archetypes:skeleton-archetype
    1
    com.jaccarmac.neumont-dlc
    example
    0-1-0
    
    Y
    
  2. Edit example/example-ear/src/main/application/META-INF/appengine-application.xml.
    <application>example</application>
    
  3. Edit example/pom.xml.
    <appengine.target.version>1.9.6</appengine.target.version>
    
  4. Compile everything.
    mvn clean install
    
  5. Write Java servlets.

Jacob's way.

  1. Generate a Compojure project.
    lein new compojure example
    
  2. WAR it up.
    lein ring uberwar
    
  3. Unzip the WAR.
  4. Write your own example/appengine-web.xml.
    <appengine-web-app xlmns="http://appengine.google.com/ns/1.0">
      <application>example</application>
      <version>0-1-0</version>
      <threadsafe>true</threadsafe>
    </appengine-web-app>
    
  5. Copy it into example/war/WEB-INF.
  6. Deploy or test.
    dev_appserver.sh war
    
    appcfg.sh update war
    

Your way.

  1. Make class files.
  2. Put them in a WAR.
  3. Write some XML.
  4. Deploy.
  5. Profit?

Go: Not quite Node.

  • Go is relatively fast.
  • Go runs the first time (!).
  • Go is still young.

Naive Node.

// Use Go as a Javascript VM for App Engine.
package notnode

import (
        "fmt"
        "github.com/robertkrimen/otto"
        "io/ioutil"
        "net/http"
)

func init() {
        http.HandleFunc("/", handleRequestFromJs("/"))
        http.HandleFunc("/easter", handleRequestFromJs("/easter"))
}

func handleRequestFromJs(path string) func(http.ResponseWriter, *http.Request){
        return func(w http.ResponseWriter, r *http.Request) {
                vm := otto.New()
                vm.Set("requestPath", path)
                vm.Set("printToWeb", func(call otto.FunctionCall) otto.Value {
                        fmt.Fprint(w, call.Argument(0).String())
                        return otto.Value{}
                })
                program, err := ioutil.ReadFile("main.js")
                if err != nil {
                        panic(err)
                }
                vm.Run(string(program))
        }
}

My simple handler.

if (requestPath === "/easter") {
    printToWeb("You found my secret!");
} else {
    printToWeb("Hello, otto world!");
}

Python: Write fast, run slow.

  • Access great libraries.
  • Write fast.
  • Run slow.

Our goal.

Get from this:

import webapp2

class MainPage(webapp2.RequestHandler):
    def get(self):
        self.response.headers['Content-Type'] = 'text/plain'
        self.response.write('Hello, world!')

app = webapp2.WSGIApplication([('/', MainPage)], debug=True)

To this:

import flask
app = flask.Flask(__name__)

@app.route('/')
def helloworld():
    return('Hello, world!')

Or, for Lisp lovers:

(import flask)
(setv app (flask.Flask __name__))

(with-decorator (app.route "/")
  (defn hy-world []
    "Hy, world!"))

Flask and Virtualenv.

What you want to do:

virtualenv venv -p python2.7
source venv/bin/activate
pip install Flask
dev_appserver.py .

What you have to do:

(import sys)
(import os.path)
(sys.path.append (os.path.join (os.path.dirname __file__)
                               "venv/lib/python2.7/site-packages"))
hy2py main.hy > main.py

Thanks much!

Now get out there and hack some stuff.