Application servers are dead. At least, that seems to be the message being pushed by most evangelists and even a few enterprise software providers. In their place will rise self-contained microservices, running much the same kind of technology, but now deployed in containers or stand alone applications.
I really like the idea of microservices. They force you to communicate via well-defined interfaces, provide a small surface area for updates and testing, and look really good on a resume. Unfortunately, without a PaaS, I just don’t see how self-contained, self-hosting microservices would actually work in practice.
The problem is GitFlow. I’m sure most of you practice some version of it or have at least heard about it. But for those not familiar with GitFlow, the basic premise is that developers implement, test, and validate new features in a branch and merge their changes into mainline once stakeholders are happy.
In the diagram above, every dot potentially represents a deployed application. As you can see, GitFlow encourages a lot of separation, which in turn results in a lot of development versions of applications that need to be deployed somewhere for stakeholders and automated testing tools to sign off before moving to production.
For those still clinging to their application servers, testing and validating new features is a simple case of uploading your WAR with a unique context path, testing in isolation, and deleting the WAR when code is merged or abandoned. This whole branch lifecycle is well catered for via the various CLI tools and management consoles that have been baked into app servers for decades, while integration with app servers is just a plugin away for most build servers.
Which is not to say that deploying a WAR per feature hasn’t had its challenges. Anyone who has been down this road will undoubtedly have run into PermGen memory errors as they pushed the limits of a memory model that wasn’t designed for the continuous loading and unloading of applications. But some scheduled reboots and a move to Java 8 and its metaspace implementation provides a reasonable workaround for most teams.
Once your app server is tuned though, it will happily support developers working with GitFlow. I’ve seen modest hardware running app servers like WildFly hosting 200+ WAR files as developers move even trivial application changes out into branches (and then forget to clean them up when they are done, but that is a different story).
These same modest servers would quickly crumble under the weight of 200+ Spring Boot or WildFly Swarm UberJars, and 200 is a conservative number since, by their nature, microservices encourage an ever larger number of individual applications. Then multiply that number by the number of environments applications are pushed through as they are tested. When you start looking at these numbers, you realize that:
Microservices * GitFlow = A whole lot of deployments.
But I’m getting ahead of myself here, because I’m not even sure how you would go about managing the lifecycle of feature branch UberJars on a simple Linux box. How do I manage the ports? What commands do I run to deploy, start, stop, and un-deploy UberJars? How do I query the server to find running applications and expose them to testers and other stakeholders?
The reality is that no one has time to be hand holding deployments in a continuous integration and delivery environment. App servers give you a refined and battle-tested solution for managing the lifecycle of the kind of short-lived applications that GitFlow encourages, and any move to microservices will have to provide this same level management. Without it, developers will waste far too much time manually deploying their applications, and businesses will waste far too money on resources to host feature branches that everyone has forgotten about.