I’m breaking up with Groovy

Well, not really.

While this might work we didn’t really implement the map constructor the way we should have, such as protecting against unknown values etc.

But move on at this point and get to a core issue.

You see, Groovy doesn’t really have a concept of final.

For that matter, it doesn’t really have the concept of private either.

Most of the time you can freely modify final fields, and access internal private members.

Go ahead, try it!This is a very Python way of doing things.

But we (Java devs) like control.

We like safety and encapsulation.

And when it come to immutable objects, we need it!Sure you can, correctly do immutable objects in groovy:@Immutableclass SimpleBean { int value1 String value2}Simple enough.

It even, somehow, enforces the final nature and private variables.

Hazah!Only not.

What if I want a custom constructor?Sorry, you can’t provide a constructor for Immutable objects.

Ok, what about default values?Nope, can’t do that either.

What about non-null enforcement?Nope.

Basically, if you want any of that you need to create a builder for your immutable object and hope and pray someone doesn’t call that public constructor that is just sitting around, waiting for them.

Photo by David Bartus from PexelsJava ModulesGroovy relies heavily on reflection internally.

So much so that for a awhile after Java modules were released Groovy just won’t work.

Even with reflection you can’t access stuff you shouldn’t anymore.

To be fair, this broke lots of other libraries, slf4j, CORBA, Spring, Jenkins, etc.

Anything that relied on a global classpath with unfettered access broke.

Now this was something I was actually used to, and welcomed, since it brought me back to my OSGi days of multiple classpaths.

But I hadn’t expected Groovy to be so broken out of the gates.

Truthy-nessYou love it or you hate it.

At first I loved it:List items;if (items) { .

}But lets dig into this.

What is actually happening in the if clause.

Groovy will try to convert items in a conditional clause to true.

Its not always the same and not always apparent.

In this case, if items is non null and non empty then the clause is true.

Fairly benign.

Lets try something else:BigDecimal v1 = 0.

00BigDecimal v2 = 0.

000v1 == v2Is the equals true or false here?.So first off, if you didn’t know as Java devs, ‘==’ in groovy is not an equivalence check.

Nor, as many docs would tell you, is it a shortcut to ‘equals’.

No, groovy is sneaky.

If it can it will try a ‘compareTo’ first then it will fall back on ‘equals’.

So the statement above v1 does NOT equals v2 since the precision is different.

But since groovy uses compareTo the ‘==’ will evaluate to true.

Now you could argue that 0.

00 is equal to 0.

000 back in some cases we want to know if the precision is also different.

Which kind of gets to my point.

It’s not obvious what Groovy is doing sometimes until it breaks in weird ways at runtime.

by Pixabay from PexelsCompilation Toolinggroovyc is fine, as much as gcc is fine and javac is fine.

Meaning its not fine …at all.

I have struggled repeatedly with using Maven to compile groovy.

Now, to be fair, this isn’t really groovy’s fault but more so Maven’s.

There are lots of ways to do it.

Groovy Ant Task (Deprecated) If you need Groovy 1.

8 this is the only game in townGMaven (Deprecated)GMaven PlusGroovy Eclipse Maven PluginGMaven Plus doesn’t integrate into the normal maven compiler, and while it claims to support joint compilation (compiling groovy and java at same time) I found that it didn’t always work.

Especially when there was some circular dependency between Java and Groovy.

Groovy Eclipse isn’t much better.

It is very difficult to configure.

You need to ensure you have the right version of the compiler and batch libraries for the version of groovy you are intending to use.

It does a good job with joint compilation.

But doesn’t do groovy docs, or groovy execution.

Gradle does seem to handle groovy a bit better than Maven does.

Other ToolingAs a secondary language Groovy gets secondary tooling.

Checkstyle doesn’t work.

Codenarc is kinda okay, Sonar sort of supports it.

IDE’s mostly work correctly with it.

Eclipse is terrible, Intellij works fairly well.

Noticing a trend?Falling Behind JavaBeing a language built on top of another language you will by definition always be lagging behind in features (java modules).

Or if you try and innovate and move ahead you run the risk of feature conflict (closures and lambda).

Both of these are common in Groovy as highlighted above.

Version CompatibilityGroovy does good things here and some not so good things here.

I can commend them that I can take a piece of groovy code compiled for groovy 1.

8 and still run it in 2.

5 Great job!But why do things break between minor version changes?.Why do you change behavior?.Why do you lie?!?If you use Groovy, then Groovy release notes are almost required reading.

This is a common theme in Groovy.

They change stuff.

And they change stuff in ways that I would consider to be major changes but they don’t reflect that in their version numbers.

For example, from Groovy 2.

4 to 2.

5 they changed their CLI tooling.

On the surface this doesn’t seem like a big deal, and all the code still compiled.

But we had several tools that went from named command line arguments needing a long name with two dashes–name <value>To needing a single ‘-’.

-name <value>This broke lots of our automated tooling and took forever for us to figure out.

by Pixabay from PexelsOther weird shitDid you know that Groovy prior to 2.

4 inserted a field into every class that was the timestamp of compilation?.I didn’t, until I did API analysis checks on our libraries and found every version of our classes was binary incompatible with previous releases.

Or that old versions of Groovy didn’t support calling a super method if you overrided it in a subclass.

Or that groovy doesn’t support many now standard Java syntax like:default methods in interfaces (coming Groovy 3)Java Try with resources block (coming Groovy 3)Method references (coming Groovy 3)Nested code blocks (coming Groovy 3)This kind of this has become a meme at work.

“Oh yeah that … #groovy”Photo by rawpixel.

com from PexelsBLOATWith every release of Groovy they add lots of stuff.

At first this seems awesome.

All these new ways to do something.

But Groovy tries to be everything to everyone.

It adds lots of baggage to the language.

While the syntax may be shorter, the syntax is also more complex and always changing.

There is something to be said for keeping a language feature set small.

Don’t have lots of ways to do something.

Instead have a few ways to do it right.

Take Go for example.

It is by no means incredibly feature rich.

Quite the opposite.

But you can learn the syntax for it in an afternoon.

Besides syntax bloat there is library bloat as well.

As library developers we need to be conscious of the dependencies we burden our consumers with.

Dependencies are not free.

Increased size in deployed applicationsIncreased risk of dependency collisions (Not in OSGi :P)Now groovy has done different things in the past to solve these problems.

By shadding their dependencies they eliminate the classpath collision problem but doubled code size.

So they went back to reusing OSS libraries, but that reintroduced collisions.

by Pixabay from PexelsThe breakupSo here we stand.

One time Java dev, ran off with Groovy.

The new hot thing.

Now I want Java back.

Java 8 adds lots of great stuff, like streams which eliminate the need for Groovy closures.

But how do I get lots of the code simplifing things I liked about groovy.

LombokLombok is a javac extension.

It inserts code at compilation time.

The code it inserts has ZERO dependencies on other libraries.

The code is fast and follows good programming practices.

Best of all it makes reading Java very simple.

Yes, you read that right JAVA!.You write .

java files and can write ANY java code in the class files you are using Lombok on.

Mutable Bean (Get/Set/Equals/HashCode/ToString)import lombok.

Data;@Datapublic class SimpleBean { int value1; String value2;}Immutable Bean:import lombok.

Value;@Valuepublic class SimpleBean { int value1; String value2;}Immutable bean with builder pattern, default values, and non null enforcement:@Value@Builderpublic class SimpleBean { @Builder.

Default int value1=25; @NonNull String value2;}Where do I got from here.

WellI still write Groovy,I write Java with LombokFor me the one thing Groovy has hands down better than Java right now isn’t even really groovy.

by Pixabay from Pexels (CC0)SpockWe all write tests.

But Junit tests are annoying to write because we are stuck with the language features of Java.

Spock is an awesome testing framework that uses the language features of Groovy for good not evil.

I can write human readable tests quickly.

I can mock, stub, spy, inject all quickly and easilly.

I get great informative error messages when tests fail.

class SimpleBeanSpec extends Specification { def "test simpleBean"() { given: SimpleBean bean = new SimpleBean() when: bean.

value1 = 25 then: bean.

value1==25 }}Basically, if you aren’t writing your tests in Spock, you really should.

Since I only use Spock for tests then all the groovy dependencies and many of the other problem I run into with groovy simply go away.

I miss…I still miss many things of Groovy.

I miss the:Ease of creating lists and mapsString interpolationNull dereferenceBut I find I don’t miss them enough to warrant the continued struggles.

I know Groovy 3 promises to fix many of the issues I brought up.

But it also does a lot of the same things I don’t like.

Groovy continues to introduce even more syntax.

And Groovy is making other big changes, like changing the parser.

Most of all they are still lagging behind Java.

Maybe someday, I’ll go back to Groovy as an old friend, or Java will finally add just the few things I feel it lacks.

Or maybe, just maybe, something else might come along…Kotlin anyone?.

. More details

Leave a Reply