Groovy coding conventions
At work we are using Groovy language to write the Cucumber acceptance tests. Groovy turns out to be very nice language with flat learning curve for Java developer. There are many interesting features in the language, but I believe some of them have to be used with caution.
As we work more with Groovy and learn more of its features we found there are many ways of doing the same thing. It is useful, because it makes code more expressive, but it can also be an issue when there are multiple developers working on the same code base. This problem most probably exists in every programming language and it can be partially solved by agreeing on the coding conventions. Unfortunately there is no established code convention for Groovy yet as there are for other languages like Java.
In this post I list some features of the Groovy language and try to choose a convention to use. Of course this is not the only correct approach. This is more a try to orginise the conventions and keep it for future reference.
This post format is:
Feature/Property name
Description of the feature/property (facts only no personal opinion)
Chosen convention with description (chosen by personal opinion)
Semicolons
Description
Semicolons at the end of the line are optional in Groovy.
Convention
No semicolons when only one statement in the line.
Types
Description
Groovy allows to not specify types of:
- values returned from method
- parameters of the method
- local variables
- class field
When using “def” in Groovy, the actual type holder is “Object”. In method definition we can omit both parameters’ types and “def” to make the parameter the type of “Object”.
It is easier to work with the code when all types are specified because the IDE can then suggest possible methods and fields of the obejcts.
Convention
Values returned from the method
Always specify the type of the value returned from the method or use “void” when no value is returned.
Parameters of the method
Always specify the types of the method’s parameters.
Local variable
Specify the type of the local variables when it makes it more readable (eg. in methods longer than 10 lines). If the type of the local variable is obvious it can be declared with “def” keyword. In simple cases IDE can figure out what is the type of the object.
Class field
Always specify the type class’ fields.
Return keyword in the methods
Description
“Return” keyword is optional in Groovy. Methods will return the value returned by the last run expression in the method. Unfortunatelly it is not always clear which one is the “last run expression in the method”. It can lead to confusion especially when returned value type for the method is not specified. Method can then return some value when we expect it to not return anything.
Convention
Always use “return” keyword in the method which is expected to return some value.
Access modifiers
Description
In Groovy all class fields are by default private and all methods are by default public. Because of that there is no need to add “public” in keyword for the methods and “private” keyword for the fields.
For all private fields Groovy creates basic getters and setters in the runtime so there is no need to do it manually. It is still possible to create getter or setter manually if we want to some specific logic for it.
Convention
Methods
Do not specify methods as “public”. Leave it without access modifier instead.
Fields
Do not specify fields as “private”. Leave it without access modifier instead.
Do not create simple getters and setters for fields. Groovy creates them in the runtime.
Class objects
Description
Classes are first-class citizens in Groovy. There is no need to use “.class” suffix. It is perfectly fine to specify just a class name.
Convention
Do not use “.class” suffix when you need Class object. Instead just write the name of the class.
Fields access
Description
In Groovy there is a shortcut notation to access and set fields of the class. Instead of using getters and setters it is possible to use field-like access notation:
`
resourceGroup.getResourcePrototype().getName() == SERVER_TYPE_NAME
resourceGroup.resourcePrototype.name == SERVER_TYPE_NAME
resourcePrototype.setName(“something”)
resourcePrototype.name = “something”
`
When using field-like notation setters and getters are invoked under the hood. So in case there will be more sophisticated than basic setter created in future for the field it will be still invoked with field-like access.
Convention
Always use field-like notation instead of setters and getters (e.g. customer.id = 3
instead of customer.setId(3)
) the effect is always the same – calling the setter (created or auto-generated).
Default method’s parameters
Description
It is possible in Groovy to specify default values of the paramters in the method.
<br /> void createNewCustomer(int id, String name, int status = 1) {...}<br /> ...<br /> createNewCustomer(123, "customerName")<br />
In the above example “createNewCustomer” method has optional third parameter. If it is not specified the value of the parameter is “1”.
Convention
Instead of overloading methods and invoking one from another use default parameter feature.
E.g.
void createNewCustomer(int id, String name, int status = 1) {...}
instead of
<br /> void createNewCustomer(int id, String name, int status) {...}<br /> void createNewCustomer(int id, String name) {<br /> createNewCustomer(id, name, 1)<br /> }<br />
Equals and ==
Description
In Groovy “==” operator is the same as “.equals(..)” method in Java. If it is required to check if the reference to the object is the same (like with “==” in Java) you have to use object.is(..)
method.
Convention
For checking if objects are equal use “==” operator instead of object.equals(..)
method.
String and GString
Description
In Groovy it is possible to use parameters in the GString instead of concatenating Strings to put some parameters in it.
E.g. "this string needs variable: ${variable}"
instead of "this string needs a variable: " + variable
Every string which is created using quotes is a GString objects which accepts a variable in the form with dollar sign. Braces are optional when there is only a simple variable, but they are required when there is some operation (like getter invocation) needed.
To create String object specify the object in the single quote. Using it when there is no variables in the string has positive impact on performance.
'This is String object'
Because semicolons are optional in Groovy, to create multiline String or GString triple single quote or triple quotes have to be used.
`
def gstring = „””This is multiline
GString object in Groovy”””
def string = ”’This is multiline
String object in Groovy”’;
`
Convention
Use quotes (GString) whenever there is need to inject some parameter into the string.
When there is a constant or a string without any parameters use single quote to create String object.
Collections
Description
Groovy has simplified syntax to create lists and maps. To create a list you have to put objects in the sqare brackets.
def listOfStrings = ["abc", "def", "ghi"]
To create map you have to specify key and values separeted by the colon.
def mapOfStringToString = [firstKey: "1value", secondKey: "2value"]
Groovy assume that key in the Map is “String” by default. To insert a variable or object as a key wrap it with the brackets “()”.
<br /> def keyForTheMap = 'firstKey'<br /> def mapOfStringToString = [(keyForTheMap): "1value", secondKey: "2value"]<br />
Groovy has also its own syntax to add elements to maps and lists.
`
def map = [first : “foo”]
map « [second: “bar”]
def list = [1,2,3,4]
list « 5
`
To check if collection contains the element it is possible to use „in” parameter. E.g. 4 in list
instead of list.contains(4)
.
Groovy adds the functionality called “Lambda expressions” or “Closures”. These are especially useful when working on the collections. Instead of iterating through the collection you can use one of the available methods accepting function as a parameter (each{}, find{}, findAll{}, every{}, collect{}, inject{}).
Convention
Use native Groovy collection syntax to create Maps and Lists instead of creating it with new ArrayList() / new HashMap()
.
Use Java native methods (add(..) and put(..)) to add elements to lists and maps.
Use Java syntax with collection.contains(element)
method to check if element is part of the collection.
Prefer to use Groovy collections closures (each{}, find{}, findAll{}, every{}, collect{}, inject{}) over looping when this makes code more readable (probably in most cases)
Groovy Truth
Description
In Groovy all objects can be ‘coerced’ to a boolean value: everything that’s null, void or empty evaluates to false, and if not, evaluates to true.
This means if (name != null && name.length > 0) {}
is the same as if (name) {}
Convention
Always use full condition to check if object is non-empty. E.g. write if (name != null && name.length > 0) {}
instead of if (name) {}
. Result of testing just the name
(which is String) is not obvious.
Alternativly you can use safe dereference operator to ommit checking null value e.g. if (name?.length > 0) {}
Groovy safe dereference and Elvis operators
Description
Groovy supports the variant of the “.” operator to safely navigate an object graph.
E.g. instead of: if (customer != null) { name = customer.name } else { name = null }
you can write def name = customer?.name
.
Groovy adds “Elvis” operator to set value of ease the use of ternary operator in some common cases. So instead of writing def result = name != null ? name : "Unknown"
it is possible to write def result = name ?: "Unknown"
.
Convention
Use safe deference operator “?.” to get property of the object which can be a null instead of testing if it is null with if condition (e.g. “order?.customer?.address”).
Use Elvis operator to set default value for variables (e.g. def result = name ?: "Unknown"
instead of def result = name != null ? name : "Unknown"
).
References:
When writing this posts I was using this two articles as a reference:
1 http://groovy.codehaus.org/Groovy+style+and+language+feature+guidelines+for+Java+developers