Which artifacts do you want when you build a system?

Filed under: Automation, Continuous integration, — Tags: Gradle, Jenkins, Maven, TeamCity, deb, rpm — Thomas Sundberg — 2015-02-16

A Continuous Integration, CI, server builds a system every time a change has been detected in the version control system. This is a very common practice and something good. We are able to catch many silly mistakes early. The question is, what should the CI server build? Which artifact should the build produce?

The answer obviously depends. It depends on how you plan to use the artifacts later. If you build a Java system it is very easy to say that the artifacts should be a jar, a war or an ear file. This seems to be very natural for most Java developers.

Simple to build but useless deliverables

Who can do anything useful with a jar? Actually nobody. Not unless you make it executable, anyway. This is not very common. It is possible, and often desirable, to bundle everything needed into a jar that you later can invoke with java -jar my-project.jar

The same goes for a war or an ear. A war file could bundle its own servlet container. An example of a project that uses this technique is Jenkins. Jenkins is distributed as a war file that can be deployed into a servlet container. Jenkins can be also started standalone and use its embedded Jetty, which is a Servlet engine and HTTP server. This means that you can start Jenkins with java -jar jenkins.war

Problems could arise with more complicated systems that should run as a service on a host. A standalone, executable jar is not possible to start as a service on any operating system I know of. You will at least need a shell script on Linux to be able to start it from /etc/init.d This makes it more complicated to install.

If your target environment is Windows, then you need black magic or lots of money to be able to run the application as a service. This makes Windows system very impractical so lets not consider them for running any serious services. I know, I have worked as a CM for two years with a large web shop that is hosted in Windows. Believe me, it is complicated.

Useful deliverables

A good deliverable from the build is something that can be installed natively. An example could be an rpm package that can be installed on a Linux system. An rpm includes whatever is needed. In the case of an executable jar, at least the jar and a script so it can be started as a service.

If you have access to an rpm package, can you include more stuff and therefore simplify the installation? The answer is most certainly yes. An rpm is just a set of files that includes a way to install and uninstall them. Suppose that you are building a service that is supposed to run on top of a JBoss or Wildfly. What should the rpm package contain to make the installation simple?

I think you should bundle both your application, an ear file and possible some start and stop scripts, as well as the application server. This means that you can install it on any system that has a JVM installed.

This will make the installation simple for any system administrator. It will also make the installation simple on all test systems you want to install it on, before it is installed into production.

Better deliverables

Why stop with bundling the application and the application server? You could also bundle the JVM. This would mean that you, the developer, have full control over the runtime environment. The application is built using a well known application server and it is executed on a well know Java version.

The installation will now be trivial for the system administrators. There is no need to install a JVM on the Linux installation that should host the service. And then install the application.

All you actually need is a Linux distribution that can handle the rpm you are about to install and install it.

Simplified upgrading

This also has the benefit that whenever you want to upgrade a component, say the JBoss version, all you have to do is bundle your application with the new version. The combination will now be developed and tested as a whole and you should not find any funny things in production due to different application server versions. The same goes for the JVM. If you bundle the JVM, the risk of finding production problems due to a different version is small. You have developed and tested the entire application with the same JVM version.

The next logical step here is to build a container or an image for a virtual server as the artefact from the CI build. This is perhaps even better compared to building an easy-to-deploy package. Not all of my customers' operations departments are able to cope with that, so I haven't even tried to push the idea yet. But it is a tempting idea to provide something that simplifies the life even further for the operations guys that tend to be the receivers of the applications I help organizations to build.

Conclusion

Delivering artifacts from a Java project that isn't a jar, war or ear file is definitely more complicated. The most common build system, Maven and Gradle, produces jar files out of the box. But the process can easily be automated. It will simplify the rest of the handling of the application. Therefore, I think you should deliver installable packages instead of pure Java artifacts. You know your target environment. You know if you will install something on a Windows box and therefore use Chocolatey, you know if it is an rpm or deb package that is needed. If you don't, build all three and make them available.

The operations guys are your friends and they deserve to be treated well. Give them what they are used to and need. Not what you are able to build easily. If you are deploying the system, make sure you simplify that part of your job as much as possible. Don't settle for what the build system can build for you easily.

Acknowledgements

I would like to thank Malin Ekholm, Adrian Bolboaca and Alexandru Bolboaca for proofreading.

Resources



(less...)

Pages

About
Events
Why

Categories

Agile
Automation
BDD
Clean code
Continuous delivery
Continuous deployment
Continuous integration
Cucumber
Culture
Design
DevOps
Executable specification
Git
Gradle
Guice
J2EE
JUnit
Java
Javascript
Kubernetes
Linux
Load testing
Maven
Mockito
New developers
Pair programming
PicoContainer
Presentation
Programming
Public speaking
Quality
React
Recruiting
Requirements
Scala
Selenium
Software craftsmanship
Software development
Spring
TDD
Teaching
Technical debt
Test automation
Tools
Web
Windows
eXtreme Programming

Authors

Thomas Sundberg
Adrian Bolboaca

Archives

Meta

rss RSS