Vagrant for a Java project: should you compile in the VM or on the host?
Here’s the question: When using Vagrant for a Java project (or any compiled language project for that matter), should you compile in the VM or on the host? Also, would you want your IDE and all your development tools to be run from inside the VM as well, or on the host?
It seems to be not very well defined exactly how a Java IDE and the compile/deploy process work with a Vagrant VM. Generally my impression is that code is edited on the host, and run on the VM, which works great for non-compiled languages. Other answers on Stackoverflow have implied that Vagrant is less useful for compiled languages because of the extra compile step, but I still want to see what can be done.
Some things I’ve thought through already:
Why compile on the VM
- if compiling on host, java is one more piece of software to install
- if compiling on host, the java version on host must be manually kept up to date with that on the VM
- the corresponding java version on the host might be unavailable (say, on a Mac)
Why have IDE on the VM
- tighter integration between environment and IDE, can use shortcuts to run the application
- can connect debugger for java applications without remote debugging (one step run/debug)
Why compile on the host
- faster compile times
- want to keep the VM as close to what production looks like as possible
Why have IDE on the host
- it’s the vagrant convention to edit code on the host and run it on the VM
- better UI performance (X forwarding and VNC are slow)
What are your thoughts: should I run my IDE from inside the VM or the host? Should I compile from inside the VM or the host?
After much thought and experimentation, I've decided on where to use Vagrant and how it integrates with the Java development workflow.
For JavaEE / deployed applications, configuring a web server and a database server are definitely things that have "enough" complexity to warrant the use of Vagrant. With two servers and the myriad ways to configure them, it's easy for configuration to get out of sync from one developer to another, bringing about the "works on my machine" syndrome. For this kind of software, it would work best to edit and compile the code on the host, and deploy to a Vagrant VM that mimics your production environment. The deployment folder for the web server could even be symlinked to a compile target on the host, removing the need to manually redeploy. So Vagrant could be an important part of your development lifecycle, but the cycle time for code/compile/deploy from the host and run on the VM with Java would be longer than the cycle time for code on the host and run on the VM that we see with PHP/Ruby/Node/etc.
For standalone Java applications (like libraries or desktop applications) the story changes a bit. In this case it makes the most sense to edit, compile, and run on the host machine, eschewing the use of Vagrant altogether. If you're using one of the big Java IDE's (Eclipse, Netbeans, IntelliJ...), you already have Java installed on the machine. At that point there is very little advantage compared to the overhead of using Vagrant, and only serves to put an extra layer of complexity in your development process. This is because by the time you are able to edit Java with an IDE you are able to run everything on the host anyway. One issue is that the version of Java required for the project may not match the version running the IDE on the host. In general (hopefully) this is not too much of a problem; as of this writing JDK6 is end-of-lifed and JDK8 is not yet released (guess where that leaves us). But if you did need to run multiple versions, you should be able to set JAVA_HOME on the host as needed. Though this does introduce extra complexity, it is less complexity than maintaining a Vagrant runtime just to work with projects using different versions of Java.
The interesting question is what to do with containerless web applications. Should the web server (in this case internal to the application) be run inside the VM as we did for the external web server? Or run on the host as we did for the standalone application? For containerless web applications, there is no external web server to worry about, but there is still likely a database. In this situation we can take a hybrid approach. Running a containerless web app is essentially the same as running a standalone application, so it would be effective to compile and run your code on the host machine. But with a database involved there is still enough complexity and configuration there that it makes sense to have the database server be on its own Vagrant VM.
Hopefully this gives Java developers who are interested in Vagrant some context about how to use it.
I was interested to this topic during the last year :)
My solution is to have a vagrant machine configurable with flags. For example one of this flag enable the desktop gui because some developer prefer to code on the host machine while others prefer to have a much more integrated environment with the desktop and the IDE in it.
To face the desktop slowness you should install a very useful vagrant plugin (yeah... vagrant has plugins that greatly improve the development environment) in this way: vagrant plugin install vagrant-vbguest This plugin will install virtual box guest addition on every guest to make it usable while using the virtualbox interface. Then to enable the gui edit the Vagrantfile in this way:
config.vm.provider "virtualbox" do |vb| vb.gui = true end
Instead to speed-up the shared folder performances I suggest to use rsync: config.vm.synced_folder "./git", "/home/vagrant/git", type: "rsync", rsync__exclude: ".git/" In this way the source code is edited on the host and then rsync-ed to the guest.