Velocity code style update

Hello,

Here are some topics which I think should be added to the Velocity coding style, in order to tighten it up (some rules below seem to be used, but with no formal documentation):

1. Comments

1.1. Comments should start with an uppercase letter and end with a dot. Example:

## This macro loops through all users in a wiki.

1.2. Use multiple single-line comments instead of one multi-line comment. Example:

#*
For example don't use this when you have a
multi-line comment.
It could break easily if you delete one character.
*#
  
##
## Use this instead
##
## Maybe also include the spacing above (title with 1 new line before
## and after, followed by description) as a comment format.
## Maybe add something about when/how to split the text on new lines
## (try to keep the lines under 120 characters, subject and verb on the
## same line, etc.).
## If rule 1.1. is approved, add any exceptions to the dot ending rule. 
## (like the title above, or potentially this parenthesis line)

1.3. Quoting issues encountered while developing by id+title or link, so they can be tracked easily. Example:

## This is a workaround for
## XWIKI-12345 : Comments not rendering when in edit mode

## Remove when `github.com/libs/other-library/issues/1234` is fixed.
  • Could add a list of regexes to use when searching for issues (like XWIKI-(\d+)).
  • Could use a more distinctive format, so one can apply a simple regex to find issues from multiple sources (maybe [{|ISSUE:Title|}]).

1.4. Add a Javadoc-like description for larger velocity scripts, so the intent and purpose of the page/code is made clear. (same format as 1.2.)

1.5. Should we have a rule about trailing/space-alligned comments (as in the example below at 2.2.)?

2. Code

2.1. Assignments should be space delimited (so not #set ($a='1234'), but #set ($a = '1234')).

  • This is already visible in the examples but it might not hurt to say explicitly.

2.2. Only use the ${variable} form where necessary for the code to compile. Example:

#set (${a} = ${b}) ## Don't do this
#set ($a = $b)     ## when this does the same thing.

2.3. If an assignment contains function/macro calls, add a space between the arguments and the outer parenthesis.

#set ($discard = $like.this($var.toString()) )
  • This could also be applied to other instructions, such as foreach and if.

2.4. All macros and velocity directives should have a space between the name and the parentheses. Example:

#set ($debugLevel = 1)
#if ($debugLevel > 0)
  #foreach ($user in $users)
    #myDisplayMacro ($user)
  #end
#end
  • Note: this seems to disable syntax highlighting for macros, as any construct of type #word() is highlighted as a macro (even if it doesn’t exist), while #word () is not (even if it does exist).

2.5. Separate velocity code into definitions and actual code. Example:

{{velocity output="false"}}
#macro (sayHi $username)
  Hi ${username|'stranger'}!
#end
{{/velocity}}{{velocity}}
#set ($users = ['A', 'B', 'C'])
#foreach ($user in $users)
  #sayHi ($user)
#end
{{/velocity}}

3. Other

3.1. Adding links to any relevant documentation and resources:

3.2. Maybe split some style rules into a separate ā€˜meta style’ page, which could include some common rules between languages. Example:

  • using camelCase for variable names
  • max line length (mentioned clearly only in XML code style)
  • comments
  • issue quoting

3.3. Add other information about writing velocity in XWiki as a new section (or a new page). This way all information about the language is closer together. (This could apply to the rest of the languages aswell). Example:

  • Best practices
  • Snippet library (maybe a selection of the most common pitfalls/problems)
  • Tutorials
  • Copyright headers
  • Other things in the Development Practices page

Conclusion

I’d love to hear your feedback, or if you have any other ideas!

1 Like

+1, as long the comment is a phrase (i.e. has a subject and a verb, like in your example); the dot at the end doesn’t make sense otherwise, e.g. if the comment serves as a section title

+1, same as in Java or JavaScript, multiline comments should be used only to document functions or methods, which corresponds conceptually to macros in Velocity:

#**
 * Serializes the given data as JSON and writes the result on the HTTP response, setting the proper content type and
 * length.
 *
 * @param $data the data to be written as JSON on the HTTP response
 *#
#macro (jsonResponse $data)
  #rawResponse($jsontool.serialize($data), 'application/json')
#end

I think it’s important to include the issue title besides the issue id, for cases when the issue tracker is down or simply decommissioned.

Yes, but the format is not multiple single line comments but a single multiline comment, as in the example I gave.

No. We shouldn’t use trailing comments IMO (the comment should be on a separate line, before the commented line of code).

+1

[quote=ā€œKebabRonin, post:1, topic:15757ā€]
2.2. Only use the ${variable} form where necessary for the code to compile.

+1

I haven’t done this, and I haven’t seen others doing it in the XWiki codebase, so -1 on my side.

+1 for Velocity directives, -1 for macro calls. It’s the same in Java, we do for ( and functionCall()

This could be listed as a best practice, but not as a rule to enforce. Note that you don’t have to do:

{{/velocity}}{{velocity}}

if the first Velocity macro has output=false (and you shouldn’t do it because it makes the code harder to read).

Thanks,
Marius

1 Like

This pattern normally doesn’t have the effect you intend. This pattern makes those Velocity macros inline, which means that they will be wrapped inside a paragraph. Outputting anything but inline content from a such a Velocity macro makes the output invalid. Therefore, Velocity macros need to have a blank line before and after them unless their content is really inline.

Apart from that comment, I agree with @mflorea.

+0, I’m not sure being consistent about this would improve much the quality.

+1 I don’t think the reason It could break easily if you delete one character. is enough, but we already do it in practice, and it would be a minimal effort to implement and maintain consistency on this.

+0 Workarounds are sometimes spread in between multiple files and multiple code blocks in the same file (sometimes even inserted into a line…) I don’t think this works perfectly for such cases.

What is a larger velocity script? I’d be okay with making this for any Xwiki standard velocity script. We should make this rule definition as objective as possible.

+1 We already fix PRs code style for this even though it wasn’t in our doc :slight_smile:

+1 , From experience it’s already what I do. A lot of times I’ll try without and realize there’s an escaping issue, then add it to address the escaping issue.

-0, it’s not the standard we used so far. I don’t see the benefit over no space, and in order to apply this rule we’d need to fix probably thousands of assignements that do not follow this.

I agree with the idea but not the implementation. Having a newline between both is enough IMO, in addition to the fact the we cannot have macro definition both before and after actual code (and actual code both before and after macro defs). The wording actual code is subjective. I think it’d be better to give a descriptive name instead, something like generative code. How should we handle places where you need to define a macro in the context of your code? E.g. xwiki-platform/xwiki-platform-core/xwiki-platform-web/xwiki-platform-web-templates/src/main/resources/templates/importinline.vm at 3630b941b16afde79728dbfa0f1e560c3db127e1 Ā· xwiki/xwiki-platform Ā· GitHub

+1

We use kebab-case for CSS/HTML classes/ids :slight_smile: .
There’s no max line length for .vm as far as I know.
Comments syntax can change in between languages.

All in all, there seems to be a lot more differences than things in common. Assuming we do maintain them, I think it’s a better idea to keep separate code styles for each language, even if some rules are very similar. This also makes it easier for new contributors to follow them (they don’t need to read through a huge file almost filled with rules that will barely if ever apply to the language they want to contribute in).
-1 from me on this one.

Best practices → Do we have some specifically for velocity? So far we only have code style
Snippet library (maybe a selection of the most common pitfalls/problems) → A link to https://snippets.xwiki.org/xwiki/bin/view/Main/WebHome with the velocity tag ON would be more reusable and extendable.
Copyright headers + Other things in the Development Practices page → This info is already on another page, we shouldn’t duplicate it but link it.
Tutorials → Do we have any besides https://www.xwiki.org/xwiki/bin/view/Documentation/DevGuide/Scripting/XWikiVelocityTraining/ ?

IMO most of this info could be grouped as links with 3.1 :slight_smile:

We could make a page under https://www.xwiki.org/xwiki/bin/view/Documentation/DevGuide/FrontendResources/ to list all these resources about using velocity (not sure about the position…).


Thanks for your proposal! I didn’t realize we missed so much codestyle on the velocity side ^^`

Lucas C.

1 Like

I agree with the idea but not the implementation. Having a newline between both is enough IMO, in addition to the fact the we cannot have macro definition both before and after actual code (and actual code both before and after macro defs). The wording actual code is subjective. I think it’d be better to give a descriptive name instead, something like generative code. How should we handle places where you need to define a macro in the context of your code? E.g. xwiki-platform/xwiki-platform-core/xwiki-platform-web/xwiki-platform-web-templates/src/main/resources/templates/importinline.vm at 3630b941b16afde79728dbfa0f1e560c3db127e1 Ā· xwiki/xwiki-platform Ā· GitHub

Afaik all velocity variables are considered globals, so you can reference them inside of macros. Worst case scenario, more parameters could be added to the macro.

So would adding a new line fix the issue, like this?

{{/velocity}}

{{velocity}}

TLDR. Global variables is a Velocity Templating Language quirk that works against projects of the size of XWiki, we should not use it.

I would rather not rely on the global scope too much, and set the value at the same time as I use the macro if that’s anything local. There’s no mecanism to prevent collision. If I use the same variable name as another unrelated template, this could create difficult to understand bugs…

E.g. I define macro1 in template1.vm. macro1 uses the variable errorMessage
I define macro2 in template2.vm. macro2 uses the variable errorMessage
Then I use macro1 and macro2 inside of template3.vm
Situation 1: I defined the variables outside of the macro. Only the latest definition will be used for both macros. This makes it so that somehow macro1 doesn’t use the right errorMessage value.
Situation 2: I defined the variables inside of the macros. They are recomputed at each macro use. This makes it so that both macro use the value they’d expect.


Since we don’t have any tool in velocity templating to prevent this situation, I think that in this case it’s way safer to mix computation and generation inside of macros.
If we want to separate them, we need to find a solution to avoid this situation.


About adding parameters to the macro. Those velocity macros are not API (we don’t have any frontend API), but some of them are often used for customizations and I think we’d do a lot of users wrong by breaking their use of the macro. This means we should keep a working version of the macro with minimal parameters. I doubt this’d be an easy refactoring in all cases.

Thanks,
Lucas

1 Like

There’s no documented limit, but I’ve always used the same as for Java, which is 120 characters. I don’t see why we would use something else, and we definitely need a limit :slight_smile: .

1 Like

+1 with Marius’ first answer.

1 Like

This was voted in [xwiki-devs] [proposal] Change the maximum line width in the codestyle to 128 characters

It was not explicitly mentioned that it was only for java code and we’ve used 120 characters for all code files (including non-code files like README and more), since there’s no reason to have a different limit.

1 Like

It’d definitely be useful to write it down somewhere then :+1:
When looking at files like macros.vm it doesn’t seem like it was enforced properly in VTL at least.
Personally, I tried to follow it. However sometimes VTL can be tricky with the way it handles white spaces and having everything on one line made it easier to implement. I probably did break this unwritten rule myself in some of my contributions.

I think we did try to enforce it but macros.vm (and all other files). It’s just that currently we don’t fail the build when it’s over 120 chars and sometimes it’s hard to cut a line to be less than 120 chars and since the build doesn’t fail, we sometimes leave it be…

We should probably enforce it in the build (unless there are cases where we think it’s not possibe to be less than 120 chars).

2 Likes

Some note that we also need to the produced HTML to be as clean as possible so this could be reason too. We’ll need to decide if we want the produced HTML to be as readable as possible (with extra space/NL) or the most compact possible (with space/NL removed).

Example:

#macro(skype $id)
<a href="skype:${id}?call"><img width="182" height="44" src="http://mystatus.skype.com/bigclassic/${id}" style="border: none;"></a>
#end

(more than 120 chars)

vs

#macro(skype $id)
<a href="skype:${id}?call">
<img width="182" height="44" src="http://mystatus.skype.com/bigclassic/${id}" style="border: none;">
</a>
#end

(less than 120 chars)

BTW we need to move that skype macro to some legacy macros.vm (I vaguely remember something, need to find it again. I might be hallucinating it too ;))…

In general, I agree with @mflorea . Some extra feedback below:

Yes, we already discussed it in the past that we needed to not rely on some external tool to understand the code (in case the external tool is broken/down/removed - This happens regularly non-xwiki URLs we use as comments). Ie the comment must be self explanatory. It’s ok to link to some external URL for precise details.

-1 from me.

+1 to use commas between parameters when calling a macro rather than spaces, as we do in java or javascript.

-1 from me to use #myDisplayMacro ($user)
+1 to use #myDisplayMacro($user) as we do in java/javascript

If you mean macro definitions in their own velocity rendering macro (ie have separate velocity rendering macros), then +0 or -1. I’d like to see more examples, as I’m inclined to think that there can be cases where we don’t want this.

I don’t understand what’s being proposed here. Why add links to Apache Velocity Engine VTL Reference for example? I’d be -1 for this. Why would we add links to the java spec in java code?

Why add links to https://www.xwiki.org/xwiki/bin/view/ScriptingDocumentation too? I’d like to see examples of what you mean.

Need some more precise proposals about this. Max line length is agreed already.

Also need more precise proposals.

Thanks!

1 Like

I wonder if it wasn’t done inside https://dev.xwiki.org/xwiki/bin/view/Community/CodeStyle/JavaCodeStyle/#HConfiguringyourIDEtousetheXWikicodestyle

These IDE configs are supposed to represent our precise code styles and so far we haven’t detailed each config separately. Note that I could ,ot find a reference to 120 chars in the IntelliJ IDEA config which is weird. It’s in the Eclipse one though.

We need to clarify this and we may need to extract all the rules into rules written in plain English (that’s a lot of work as there are around 50 rules+ defined). Note that checkstyle is only able to check a few of them.

When I view the XWiki IntelliJ config in my IDE, I do see the 120 chars:

It’s maybe defined outside of the Code Style in IDEA.

It’s actually defined for all languages:

Not sure why I don’t see it in the xml file for IDEA.

Seems like all we have in xwiki-platform-legacy-web right now are the Silk icons.


From what I can see, the 120 character code line length is the default for Intellij Idea Java.

This might be even one of the reasons why you agreed specifically on 120chars back then :slight_smile:

EDIT: Screenshots from unrelated users I can see online confirm that this is the default line length

Still, since it’s set (see my screenshot above), it should find its way in the code style export (xml file). But maybe you’re right (it would be a pretty poor engineering practice though, if they change that default one day, it’d fail everyone). If that’s the case it means we do define it as 120 chars for all files already and it’s ā€œdocumentedā€ (with the proviso mentioned above to possibly make it clearer).

Maybe not necessarily in two velocity macros, as that seems to be prone to causing issues. It could be relaxed to ā€œdefine velocimacros in the first part of the velocity file/xwiki macro, then continue with the codeā€. The intent was only to group definitions to improve code structure, while avoiding side-effects with the output="false" tag.

You’re right. I was rather thinking of a Quickstart-style page for velocity, where all resources about scripting in velocity would be easily accessible. Since the code style should be among the first things to read when contributing, I thought it would be a good place to put the links. (similar to CSS Tools)

Part of the reason I proposed this is because I didn’t find the Scripting API while reading the documentation for the first time, but it might have been just a me problem.

I looked through all the Code Styles. Here is a rundown, with some new proposals:

3.2.1. Indent 2 spaces

  • Present in: Velocity, XML, XAR, CSS (recommendation, not rule)
  • Exceptions: Java with 4 space indent

3.2.2. Max line length

  • Present in: Java (not stated explicitly, only part of checkstyle.xml), XML, CSS (comments only), JS (ESLint config buried in Development Practices)

3.2.3. camelCase for variable names

  • Present in: Java (stated explicitly), JS (ESLint config in Development Practices), Velocity (not stated explicitly, only inferred from the example)
  • Exceptions: CSS (kebab-case)

3.2.4. Comment format (content should be Sentence case and end with dot, regardless of language syntax for comments)

  • Present in: Java (not stated explicitly, only part of checkstyle.xml), CSS (just examples, maybe state it outright?)
  • Maybe also concerning the use of single/multi line comments? (general guide, regardless of syntax)
    • Each language might have different formats, as Lucas said (Java - multi-line javadoc, velocity seems mostly multiple one-line comments)

3.2.5. Quoting issues as id + title, so as not to depend on external tracking tools

3.2.6. [New] Language en_US for variable names and comments

3.2.7. [New] Trailing Whitespace prohibited (except for javadoc comments)

3.2.8. [New] Use double quotes " for strings when possible (as opposed to single quotes ' or backticks ` )

  • Exception would be velocity, where single quotes are preferred, to not force parsing
  • Present in: Java (language spec), XAR (not stated explicitly, but enforced by mvn xar:format)

3.2.9. [New] Space separated assignment operator or equivalent (like : in CSS or JS objects)

  • a = b, not a=b
  • Exception could be CSS (color: red)
  • Could maybe be extended to all operators? (Example: a + 2 * b instead of a+2*b)

This is related to my answer to 3.1. above, to have one stop for all things relating to developing with velocity in XWiki. Including the points in 3.1., the links could be:

3.3.1. Velocity documentation

3.3.2. XWiki Scripting API Reference

3.3.3. Snippets (filter on velocity, as @CharpentierLucas said)

  • Should contain solutions to common problems (like the snippets for checking XObjects or JS in the Best Practices page, or the snippet I posted here for returning values from macros)

3.3.4. Copyright Header (same as Development Practices)

3.3.5. Best practices

  • Seems like the Best Practices page contains some Velocity Best Practices
    • Linked there is this related to velocity, but it seems outdated/not implemented (?)
  • Additionally, the single vs double quotes for performance optimisation in the current Velocity Code Style could be considered a best practice

3.3.6. Tutorials

Question for the Use code in wiki pages for presentation only rule in Best Practices:

Wouldn’t the MVC rule mentioned exclude most applications of velocity for scripting?

Like a LiveTable querying the data in velocity (using xwql) and displaying it in the same script

I don’t think this is always respected, as I saw multiple scripts querying the database or saving documents. (Who is the Controller?)