Groovify CUBA - An overview of Groovy
Developing an application in CUBA is mostly about productivity. It has other advantages, but productivity is probably one of the most important reasons. To ramp up productivity on all stages of CUBA app development, we can invite Groovy to the party.
In this first of two blog posts i will give you an overview about Groovy, so you get a understanding that this might be valuable for you. Why? Because in my opinion the productivity advantage of CUBA falls apart when turn from generating the UI or creating the domain model to the part of programming where you actually want to implement business logic. In this case you are back at the POJO model either in your controller logic or in the services that are just Spring beans.
Coming to CUBA from a Groovy background and haven’t developed in Java for quite some time, it feels a little bit clumsy to go back. This is why i think it’s probably worth thinking about raising the productivity gain (in the business logic side of things) just a little bit by getting the different benefits of the Groovy language onto our CUBA application.
The elevator pitch for Groovy
Ok, for an elevator pitch, the easiest thing is to come up with is syntax. We as programmers all love to care about syntax, so there you go. A customer class in Java (~100 LOC):
The equivalent in Groovy (~15 LOC):
That’s it. It has the same functionality.
Just in case you think i’m kidding: The Unit test in this in this article proves that both variants are semantically equivalent.
Groovy basically has a significant better signal to noice ratio. I’m not sure if you noticed it, but there is a little bit of signal in this class. It’s the method calculateTurnover
, which is basically the “business logic” if you will. In the Java class it’s very hard to find, because it’s just not visible.
The differences of Groovy
When comparing both examples, these are some of the things that are different:
- removed imports, because of more default imports in Groovy
- removed semicolons where not needed
- changed default visibility scope:
private
for fields andpublic
for methods, because that’s the defacto default in Java - removed Getters and Setters, will be generated by the compiler in the default case
- removed constructors and added a map based constructor as well as a default one
- removed
toString
,equals
andhashCode
because of the AST-Transformation Annotation
We could even reduce it further with @Canonical
instead of @ToString
and @EqualsAndHashCode
.
A running example of this you’ll find here (which is a very good playground to start with btw.)
Groovy shines with Maps and Lists
Since bashing about Java Getters and Setters is not my main purpose here, let’s have a look at some more interessting stuff like the implementation of calculateTurnover
.
Groovy has some very cool features regarding the Collections API. In the official docs you’ll find a good overview of the features (2. Working with collections). I’ll guide you through a few of them.
Starting with the *
Operator. The attribute orders is a collection. When doing a *.
on a collection, it will execute the method call after the .
for each items in the collection. In this case getAmount()
on every item in the orders list will be called. The result of this is a List with the results of each entry. If you are familiar with functional programming, the Map operation would be something similar (the exact equivalent of it is the collect
method in Groovy).
Then, since orders*.amount
returns a list, we can call the operation sum
on it, which will act according to it’s name. The elvis operator ?:
will either return the expression on the left if it’s not null
, otherwise it will return the right side.
If this is to scary to you, another alternative implementation would be something like:
This example is a little closer to what we saw in the Java class. each
is a method on a List, that takes a closure (a function) as a parameter. On each element in the list the function will be executed and it
will be the corresponding list item. Same story as Java 8 Lambdas.
There are two additional things that are worth mentioning. First, as i said, the each method has one argument: a closure. In Groovy, often times it is not required to use parentheses at all. In this case, it is equivalent to orders.each({ sum += it.amount })
(see the docs - “5. Omitting parentheses” for more details). Second, return
is an optional keyword. If it’s not in place, Groovy will use the last expression of the method as the return value.
Since the headline talks about List and Maps, let’s have a short look at this first class language construct of Groovy. Here we have a few examples on how Groovy handles Maps:
The map constructor gives you a cartesian product on the possible constructors. Using a map as the parameter list in general (not just in the constructor) can be a very good idea, because it drastically increases the readability of the code compared to parameter lists where the third and the firth parameter is a boolean, and nobody is able to know what that actually indicates. It literally gives you named parameters like in C# or Javascript (when passing a JSON object to a function).
More differences that differtiates Groovy from Java can be found in the Groovy style guide.
By the way, ==
is not a reference comparison like in Java. Instead the equals
method of the objects are called, because like before:
Syntax is just Syntax - there are more things
Although this syntactic sugar compared to Java is neat, there are other things to keep in mind before switching your whole project from one language to another. Since this discussion would clearly go beyond this blog post, i’ll just go over them and give you some resources to dig down further.
Performance is one of these issues. In the beginning, before invokedynamic was build into the JVM, creating performant dynamic languages on the JVM was pretty hard. Nowadays Groovy gives the user choices about speed with @CompileStatic
. More information you’ll find at this InfoQ article from 2012 as well as this SE Radio podcast with Cédric Champeau. But whenever thinking about performance, keep in mind the two rules of software optimization.
Next up, we have dynamic-, static-, strong- and duck-typing. All of these attributes are correct for Groovy. You basically can def
all the things if you want to. The runtime will figure out the rest on your behalf. This is potentially not the best thing to do, so Groovy gives you choices. When you want to use types and have that checked by the compiler there are options like @TypeChecked
or @CompileStatic
. Have a look at this article optional typing in groovy for a few insights.
Aditionally there is a Metaobject Protocol (MOP), which lets you do runtime meta programming and since Groovy is compiled, you can do compile time metaprogramming with AST-Transformations. An example of runtime meta programming is the following example from a Grails (a Groovy based Web framework) Domain class:
findByTeaserLike
is a method that does not exist at compile time. It is a method that is evaluated at runtime and build and execute a SQL Query that queries for a post entry where the column teaser is like %my teaser%. A good insight on this feature (which is based on methodMissing
) you’ll find in the article Groovy Goodness: Create Dynamic Methods.
Based on this meta programming feature comes another one: domain specific languages. You can create languages that look like this:
To create a DSL in Groovy really is a breeze. This is perhaps not directly relevant for the developers (although it could be), doing this right can give your process a dramatic additional performance boost and include other people be part of the process as well. Have a look at the book domain specific languages from Martin Fowler for further reading.
Grooovy can make a difference
To wrap this up, i think you get a good feeling about the differences that Groovy can make. The syntactic sugar together with more options open up possibilities for the users of this language.
As i already wrote last time, software developers paychecks are the driving cost factors in most IT efforts. This is especially true for software development. Any opportunity to get better in this regard will increase the overall outcome. CUBA has helped us with different things to go down this road pretty far. To use Groovy in this scenario is just another one of these steps that focuses on the business part of things.
If you want to take a deeper look into Groovy (and i hope i could encourage you to do so), there a very good book about Groovy, called Programming Groovy 2 form Venkat Subramaniam which goes much deeper in the described topics.
In the second part of this two part blog posts, i will go trough the actual integration. We’ll have a look on how to enable Groovy in the CUBA app and take look at some other integration possibilities as well.