Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

CRITICAL: Copy pasting the code is not allowed, functions should be used for the shared functionality

...

All code reflects the auto-format, see Unified Code Style and How to Auto Format;

...

Follow these rules:

  • Install CodeNarc, add Pricefx profile to the project and follow the suggested inspection problems, see Code Quality in IDEA.

  • ⚠ Copy-pasting of code is forbidden; use functions to share functionality.

  • All Groovy source files (= “element” folders) should be auto-formatted by IDEA, see Source Code Auto Formatting .
    Note: logic.json should be excluded 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.

...

  • ElementName instead of (deprecated) api.getElement("

...

  • ElementName").

  • Use input.

...

  • InputName instead of (deprecated) api.input("

...

  • InputName").

  • 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

...

  • .

  • Variable names should be self-explanatory. This is especially valid for method parameters.

  • /wiki/spaces/KB/pages/784957624 by having the 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 Buildersmandatory 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 of api.find("MLTVx", ...) = you will get all rows and you will not have to make a condition for validAfter.

  • Use consistently one approach for adding

...

  • items to

...

  • a list, do not mix

...

  • various approaches.

...

  • It is recommended to use List << value

...

  • rather than List.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]

...

  • or list?.getAt(index) instead of list.get(index).

  • Use the same approach for accessing Map values, do not mix various approaches.

...

  • It is recommended to use Map.key

...

  • rather than Map[key] or Map.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). Use BigDecimal constants (e.g. 0.0 instead of 0) so you can rely

...

  • it will be a BigDecimal.

  • 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, findAll, find, eachWithIndex, withIndex, first, last, max, min,

...

  • sort, etc.) whenever applicable.
    Note:

...

  • For better performance, use the sortBy parameter in api.find()

...

  • rather than the sort() 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 the return of the ElementName 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 of

    Code 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 follow auto-format):

    Code Block
    def map = [
      key1: "value1",
      key2: "value2",
      key3: "value3",
    ]
  • Analogically, initialize List directly, not use .add(). E.g. instead of

    Code 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. Avoid api.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 or list?.contains(item) over item == option1 || item == option2 || item == option3 for conditionals