- it made us think early on in the project, what will be required to run the application in production (e.g. operating system, software, ports, certificates, etc.). This gave us sufficient time to react to unexpected obstacles;
- by automating the deployment process early, we reduced the number of times we had to do this activity manually later on;
- seeing the application work in a production-like environment was encouraging feedback that we would be able to release to production whenever our client required;
- deploying the application while it was still very simple allowed us to focus on the deployment process without getting distracted by problems caused by the application.
Ditching the Container
When we first tried to deploy the application, it was not much more than a Hello World web application. We decided to use Jetty as a web server, since we had used it many times on projects before - both standalone and embedded. Whenever we used Jetty in the past, however, we would normally build a WAR file or a WAR-like directory structure, write a web deployment descriptor and finally deploy or load the artefact into Jetty.
Having spent a bit of time working on a Ruby on Rails application recently, the deployment process used in the past seemed cumbersome and complicated - even more so given the simplicity of the application at hand. That's when we realised that what we cared most about is the application itself and to a much lesser extent the container. In fact, we didn't care about the container at all. All we cared about was that our application would be able to serve incoming requests. At some point, we started to think of the application more of as a self-contained program, which just happened to expose some of its functionality via HTTP. The diagram below illustrates this mind-shift.
The biggest change was the mind-shift. It took some time to get used to the idea that the application is no longer "contained" in something else, but that it can be "self-contained". But there were also a number of other practical consequences that this change entailed:
- simplified development process. It was very easy and fast for developers to run the application in the same way as it would run in production;
- simplified testing. It was very easy to start and stop the application for automated functional tests;
- simplified packaging and deployment process (e.g. no web.xml, no war file, no prescribed directory structure, etc.);
- simplified application start (i.e. simply execute a Java program);
- started using standard DI mechanisms to wire up Jetty as a dependency and injected it where needed.*
* Strictly speaking, you don't need to ditch the container to do this but we felt that the mind-shift we had gone through enabled us to see the potential for doing this.
Making this architectural change simplified our development and deployment process. It also simplified the way we thought about the application. The only price we paid was loosing the ability to deploy the application to different web server without making changes. Fortunately, this price was purely hypothetical because we had absolutely no need nor desire to use a different web server in production. On the positive side, we were now hiding the fact that we were relying on Java Servlets to realise our web functionality. In fact, seeing what some of the other communities are building (e.g. Sinatra, Node.js, etc.), I'd be tempted to try to write a web application that doesn't use Servlets at all. Part of it for fun, part of it to overcome some of the limitations inherent with the Servlet model.