Scripting on the JVM
With the transition to a microservice architecture we are finding we need to create new services with an increasing frequency. The process behind getting a new microservice set up and ready for development is typically repetitive and fairly time consuming. So as with any such task automation seemed like a good idea. We already have a maven archetype in place to generate java projects however there are multiple other steps outside of the concern of maven that need to happen to get a microservice into an integration environment. For example a github repository is needed and all the generated code needs to be committed. Also we are using Ruby and Cucumber for BDD acceptance testing around our microservices, these need to be created and installed.
Given that this will be generating Java microservices for development, it is fair to assume that there will be a working JVM on the machine that will be creating these projects. Because of this Groovy seemed like a good choice of language for creating these microservices. At a later date it should also be possible to run the whole processes within a Docker container that is set up with all the required libraries and dependencies. That would allow the whole project generation to be done via a webUI similar to start.spring.io.
This was the first time I had worked with Groovy in a long time, my first exposure being some simple Groovy and Grails apps about 5 years ago. The language has advanced a long way in that time and has some very nice scripting features as well as a few drawbacks.
Groovy has a very nice way of running command line processes with some excellent
String objects and allowing them to be run as a
Will run the git init command in the myService directory this will run asynchronously
however if you need to wait for a process to finish then chain
to the execute command.
The output of running a command can easily be accessed by adding
.text to the
end of a
ProcessGroovyMethod object as returned by execute.
Similarly, the way that Groovy handles files is also nice, following some standard linux conventions. Everything is considered to be a file, however you can treat it as a directory.
Directories can be created with:
Files can be read or written to with:
It is also easy to iterate over every file in a directory and perform an action
based on it, by simply calling
listFiles.each() and providing a closure.
This provided the basics for the scripting with creating the project structure, creating files based off a common template, running the maven archetype to generate the java service and running git init and committing the created files.
One of the major things that I have found lacking with regards to groovy scripting is an easy way to perform REST operations, it would be nice to have a similar wrapping syntax to the command execution or the file access within the core libraries.
This can be overcome with some dependencies but that leads me onto the ugly aspect.
Dependency management, for a script.
If you want to use something more than the core libraries you will need a way to import and manage these dependencies. For example I am looking at using the HTTPBuilder module, this can be done with a standard dependency management tool, such as maven or gradle. This however feels rather heavy weight for a simple script and I was hoping for a nicer way to deal with this. I tried using grab which seems to be the default groovy package manager and looked like it had potential however it was not able to import the required libraries. From looking on the Internet, a lot of people have experienced this problem with grab. If I can get this issue resolved then it should be much cleaner, with dependencies being pulled in with:
Groovy has some good approaches to scripting, in particular the use of creating processes from strings and file handling. As a Java developer it is has provided me with a great deal of flexibility to create the project structure I need, while working in a language that is familiar to me. It has just caused some frustrations with trying to interface with external APIs in order to perform all of the steps needed to create the service.