Saturday, October 10, 2015

The 12 Factor App

I Just read the 12 Factor App, a set of best practices for deploying web apps and services. So far, most of what they say makes sense and reflects what we have been doing. A few points differ however, from our current practices. I won't say I disagree on these points, but I do need to think them over.

The areas that seem different from how we have been working are listed below:

#3 Environment Variables for All Config
Under "#3 Config", they recommend using environment variables for all configuration (no config files). They explicitly recommend against what we have been doing: creating separate config files for each runtime environment (dev, stage, prod). I'll have to think this over.

#7 Export services via port binding
Under #7 Port Binding", they recommend a mechanism completely contrary to most java web app deployments: they recommend each web app to have a main method. And that main method, in turn, launches the app server (in-process). Another way to phrase this is that the app server (or http server) is embedded as part of the web app. This way, you can launch your app from the command line. Your app (internally) starts the app server (as part of the same process) and starts accepting requests on port 8080, for example. 

This way of doing things is common for nodejs and python apps. But it is not common for java apps. I have never seen it used for Tomcat apps. You do occasionally see a java app that is both web app and app server all rolled into one. And it is almost always using jetty (not tomcat) under the covers. We usually call this "embedded jetty". Here is how you do it in Jetty:

public class HelloWorld extends AbstractHandler {

    @Override
    public void handle(String target, Request baseRequest, 
          HttpServletRequest req, HttpServletResponse res) 
          throws IOException, ServletException {
        response.setContentType("text/html; charset=utf-8");
        response.setStatus(HttpServletResponse.SC_OK);
        response.getWriter().println("<h1>Hello World</h1>");
        baseRequest.setHandled(true);
    }

    public static void main(String[] args) throws Exception {
        Server server = new Server(8080);
        server.setHandler(new HelloWorld());
        server.start();
        server.join();
    }

}

Then you just run this app from the command line. This is both your web app and your app server. No need to run the app server as a separate process. 

This "12 Factor" recommendation sounds like a good idea for shops that are deploying all of their apps in, say, docker, and want to treat java apps the same as nodejs apps or ruby apps. But if you have ever used something like Google App Engine, which is freakishly easy and elegant (and totally the opposite of this recommendation) you may want to re-thinks "12 Factor #7".