ess you night nullsafe opeFollow Follow these rules:
Install CodeNarc, add Pricefx profile to the project and follow the suggested inspection problems, see Code Quality in IDEA.
⚠ Copy pasted the -pasting of code is forbidden; use functions to share functionality use functions.
All Groovy source code files (= “element” folders) should be auto-formatted by IDEA, see /wiki/spaces/LEARN/pages/2651979915 Source Code Auto Formatting .
Note: logic.json should be excluded ! It since it is formatted by Packaging Tool differently.Always use curly brackets for
if
,for
,while
, e.g.:Code Block if (isCondition) { return null }
Reformatting of big amount of old code should be done within a separate commit, otherwise it is almost impossible to validate the merge request.
Follow the Recommended Logic Structure. Try to keep all input elements in the beginning of the logic.
Use
out.SomeElementElementName
instead of (deprecated)api.getElement("SomeElementElementName")
.Use
input.SomeInputNameInputName
instead of (deprecated)api.input("SomeInputNameInputName")
.Avoid api.local, api.global where possible. Using them in functions is forbidden except for caching. For small amount of data, use a dedicated element – this will help you trace the logic more easily. Big data cause a slowdown in line item logics.
Use field names in filters or use
api.namedEntities()
if possible.Use real data type when declaring the variable instead of
def
. Mandatory use in functions – both parameters and the return type.Prevent api.isSyntaxCheck IssuesVariable names should be self-explanatory. This is especially valid for method parameters.
/wiki/spaces/KB/pages/784957624 by having the AbortSyntaxCheck AbortInputGeneration element in the logic.
Keep elements/functions small and simple. Shorter methods are always better than big ones. Try to break bigger element code / function code into smaller pieces.
Where to place functions?
1. In the element – if used only once.
2. In the Library element – if used twice or more, but only within the same logic.
3. In Groovy Library – if used between logics.Use Input Builders – mandatory for configurators and header logics, but recommended also for ordinary logics.
Use
@Field
constants (no use for fields, table names, configurator names in customer projects). Mandatory use for important values used in conditions or repeatedly used constant Strings or used in Accelerators.Use
api.findLookupTableValues("TableName")
instead ofapi.find("MLTVx", ...)
= you will get all rows and you will not have to make a condition forvalidAfter
.Use consistently one approach for adding items to a list, do not mix various approaches. It is recommended to use
List << value
rather thanList.add(value)
(unless you need nullsafe operator).Use the same approach for accessing a List item, do not mix various approaches. Use either
list[index]
orlist?.getAt(index)
. Not instead oflist.get(index)
.Use the same approach for accessing Map values, do not mix various approaches. It is recommended to use
Map.key
rather thanMap[key]
orMap.get(key)
unless there are spaces or special characters in 'key'.BigDecimal
should be the most commonly used data type for amount or percentage variables (never use floats for amounts or percentages). UseBigDecimal
constants (e.g.0.0
instead of0
) so you can rely it will be aBigDecimal
.If casting is needed, e.g.
?.toBigDecimal()
for amounts, do this at the first occurrence of the variable.Make sure the
.find()
is used properly, see List.find() Closure vs. Map.get().Utilize Groovy conditions for IF statements that check if a List is not empty and not null, String is not empty and not null or value is not 0 and not null. Instead:
Code Block List rows = ... if (rows != null && rows.size() > 0) { ... }
write simply:
Code Block List rows = ... if (rows) { ... }
Use closures (
collect
,collectEntries
,each
,eachWithIndex
findAll
,find
,eachWithIndex
,findAll
withIndex
,first
,last
,max
,min
,inject
,sort
, etc.) whenever applicable.
Note: For better performance, use thesortBy
parameter inapi.find()
rather than thesort()
closure.E.g. instead of for LOOP:
Code Block for (item in items) { ... }
use
Code Block items.each { item -> ... }
Instead of FOR loop:
Code Block def list for (item in items) { list.add(x) }
use collect:
Code Block items.collect { item -> x }
Instead of FOR loop:
Code Block def map for (item in items) { map.put(x, y) }
use collectEntries:
Code Block items.collectEntries { item -> [(x) : y ] }
Use "find" (resp. "query") prefix for names of functions that query Master Data tables (resp. Analytics Data Sources / Datamarts). Do not mix data querying and calculation in the functions.
Use the library element alias when calling multiple Groovy library functions in an element or function:
def CurrencyUtils = libs.MainLib.CurrencyUtils
Casting: instead of
def xxx = out.ElementName as BigDecimal
or?.toBigDecimal
in place of use, move the cast to thereturn
of theElementName
element.For performance reasons, avoid returning big data in an element. Remember: in Groovy, the expression on the last line is the value returned!
Initialize
Map
directly, do not use.put()
. E.g. instead ofCode Block def map = [:] map["key1"] = "value1" map["key2"] = "value2" map["key3"] = "value3"
or
Code Block def map = [:] map.put("key1", "value1") map.put("key2", "value2") map.put("key3", "value3")
directly use (and following follow auto-format):
Code Block def map = [ key1: "value1", key2: "value2", key3: "value3", ]
Analogically, initialize
List
directly, not use.add()
. E.g. instead ofCode Block def list = [] list << "value1" list << "value2" list << "value3"
or
Code Block def list = [] list.add("value1") list.add("value2") list.add("value3")
directly use (and following auto-format):
Code Block def list = [ "value1", "value2", "value3", ]
For assignments based on IF
Code Block def result if (condition) { result = x } else { result = y }
directly use:
Code Block def result = condition ? x : y
or for longer x, y expressions:
Code Block def result = condition ? x : y
Sort the Groovy library elements alphabetically by element name (BatchUtils, DatamartUtils, RoundingUtils)
The Groovy library functions should have a JavaDoc to provide information on how to use.
Split suuuupeeeeeerlooooong lines. If the function has many parameters, put a group of parameters on a separate line.
Dot not commit commented code and
api.trace
in GIT. Avoidapi.log
unless it is really needed for the PROD run. See Tracing & Logging .Resolve the TODOs before making a release or before GOLIVE.
Prefer
item in set
orlist?.contains(item)
overitem == option1 || item == option2 || item == option3
for conditionals