Hello everybody and welcome to the third installment of the Coding Guidelines franchise. Until now we have been moving slowly, but steadily, through the plot and we will soon be in the grand finale.
As promised in the last post we will be zooming today inside the Flow services to see the correct usage of the Flow building blocks.
Branch step guidelines
Branch on variable or expression
The BRANCH step is used to conditionally execute a child step based on the value of one or more variables in the pipeline.
There are 2 ways the BRANCH step is used:
- by specifying a Switch variable and branching on that variable (in this case, Evaluate Labels = false)
- by not specifying a Switch variable, but providing the children of the BRANCH step with labels that can be evaluated (in this case, Evaluate Labels = true)
You can see an example of both possibilities below:
Make sure that if you are using the second version you have Evaluate Labels = true. You will get an error otherwise.
Branching on a variable should be preferred (as it is faster) over branching on expression.
Branching can be used also with regular expressions, so if you put a regular expression in a label, it will match any string fitting the criteria specified by the regular expression.
However, I do not like to use overly complex regular expressions in this case. They tend to make the code harder to read.
Also to be on the safe side regarding the readability I like to comment the regex branch with an explanation of what the regex actually does/means.
Important Note: If you branch on an expression, you cannot branch on null or empty values. This means that you cannot have children of the BRANCH step with the label empty or $null.
Branch on the /./ regular expression
When developers want to check the existence of a pipeline variable, the common way to do it is to create a BRANCH step with the children labels $null and $default.
This structure can be replaced with one BRANCH on the /./ regex, which achieves the same result.
The advantage of using this approach is that the code will be smaller and there will be one less label to evaluate/check.
The disadvantage is that it will be harder to read, as probably not everybody will know the meaning of the /./ regex.
The way to go can be decided based on the context and what is more important to you when writing a particular service.
I find that this situation is very similar to the one where you have to choose between the ternary if-operator and the classical if-else structure in classical Java development.
Branch on the hidden constant
Sincerely now, it took me a while to come with this name. The Hidden Constant. It’s like the title of a decent spy movie.
Unlike espionage, however, the reality is usually simpler and more ordinary.
This rule is about not having a BRANCH label that always evaluates to true (or false for that matter).
You would think this is a no-brainer and it should be. However, if it appears in this post it means that I saw it somewhere.
Time-activated sleeper code
You might think that it is cool to have a BRANCH that checks a current date against a date in the future and toggles between different pieces of code based on the result. IT IS NOT.
This is not the way to make your code more self-evolving. There are several problems that can arise from this situation. The following two just came off the top of my mind:
- the deployment might be postponed to another date
- you might have timezone related issues
And if you manage to avoid these problems you will still end up with a piece of dead code that will never be executed.
Branch step must have child nodes
If a BRANCH step has no child nodes it should be deleted. Obviously.
Branch step default child
At the moment I am writing this I am torn. I have problems to recommend the correct approach here. So, I would say that the correct approach is case based.
If you plan, for example, to set a variable in the BRANCH step, knowing that the variable will be used throughout the entire flow service (or more), it is better to have also a default step for the BRANCH so that you cover all your basis.
If you find yourself writing a default step for a BRANCH and have no idea what to put there, you are better off deleting it.
Map step guidelines
Each MAP step should be commented. Doing this improves code readability and maintainability.
The developer that reads the code needs to have an idea of what a MAP step does without drilling into it.
But be aware: just like the code, the comments have to be maintained as well. So, if you change the mappings from a MAP step in a meaningful way make sure that the comment reflects the new status quo.
Map steps must have mapped fields
Well, duh. An empty MAP step would have no reason for existence.
Bring MAP steps together
I find it very frustrating to look at some Flow code that has 5 or more subsequent MAP steps (some without comments, by the way) and each step is mapping just 1 or 2 fields.
It really gives the impression of sloppiness.
You should find the correct balance between the number of MAP steps and the number of mappings per MAP step.
Do not get me wrong, I am not saying you should have just one MAP step where you map everything.
Depending on the case, this might be even impossible. And if it is possible it looks like a hard to read mess.
The rules I use are the following:
- if you are mapping a large document structure, use 1 MAP step for a maximum of 2 substructures
- map in one step all the fields that logically belong together
- use multiple steps if a MAP step has to prepare field(s) for another MAP step
Use Indices when mapping arrays
If you want to clearly specify which element of the array should be mapped use the Indices property.
Use Copy Condition with caution
I am not saying you should not use the Copy condition property, but you should know it comes at the cost of readability and visibility.
In the Designer, people tend to not give much attention to the mapping properties, so what you write in the Copy condition might be overlooked when troubleshooting.
Sequence step guidelines
Sequence step must have child nodes
I am using SEQUENCE steps only if they have two or more children. Anything lower than that and, in my opinion, the SEQUENCE does not justify itself.
You should add comments to each SEQUENCE step you use.
I want, when reading a Flow code to get a certain level of understanding just by looking at the overall picture (and not drilling in every FLOW construct).
And I do believe that providing good comments is a way to achieve this.
Loop step guidelines
Loop step must have child nodes
No point in looping over something if you do nothing within the loop, right?
Loop step must have an input array
I guess you get an error if you do not provide an input array anyway. So, be careful to set the input array and save yourself few minutes.
Using dropped pipeline variables
I think I am missing a NOT here. So the rule is to NOT use dropped pipeline variables. But can this be done? Yes, it can.
Variables that are dropped at one step visually disappear from the service pipeline in the subsequent steps.
However, there are situations where such variables might still appear in the pipeline after they are dropped.
This usually happens when Flow code is copied from one service to another or when a Flow step is moved up within the service.
The principles that I use in such cases are the following:
- Do not copy Flow code from one service to another (except for the case when you copy from a template service)
- Carefully inspect the pipeline of every step to check for improper variable usage
I believe that later versions of webMethods have made the whole process of keeping the pipeline clean and sanitized more automatic and less painful, but at least for 9.8, this job is mainly manual. Therefore please pay attention.
Pipeline variable usage
You might be familiar with some of these rules from previous posts. I am reminding them here because I think that pipeline management is one of the most important aspects of Flow development. As such, please:
- name your pipeline variables accordingly; use meaningful names
- avoid giving general names to variables (size, length) or names that do not represent anything (x, y, z, myVar)
- do not create variables with the same or similar names
- do not create variables that are not used
- use the Investigate Pipeline References functionality*
* this functionality is available in Designer in the right-click context menu of a service. It will check for all the improper document references used in the service.
Use document references
When working with documents the Flow developer has 2 options: using a document reference (of a document that is already created) or using an inline document.
I encourage you to use document references as a rule. The usage of inline documents should be the exception.
Using inline documents feels like you are burying the structure of the document deep in the code and thus hiding the information.
Instead of using inline documents, use document references and reap the benefits of:
- easily finding dependencies of a certain document
- avoiding code duplication
- easily handling large documents
Using document references becomes very important if you are using a canonical data model. These models tend to be very large and complex.
If they get changed, the inline documents will never be updated automatically and would need to be edited manually, which is very error-prone.
Service invoke comments
I have a love-hate relationship with the service invoke comments. I think it is better to name your services meaningfully than to clutter the Flow service with useless information.
Provide comments to the service invokes only if they bring extra value to the table.
When using this step there are several possibilities. You can exit:
- from the nearest ancestor loop step
- from the parent step
- the entire flow service
What I recommend here is to always specify the correct Exit From value. What is the correct choice will depend on your particular case. Do not use an option before you asses that it fits your case and will do what you expect.
Repeat step must have child nodes
Again I would say this is a no-brainer. Like for the others, there is no reason for having a REPEAT step that does….well…nothing.
Usually, this kind of problems come from lack of attention. Maybe you created the REPEAT step, then changed your mind, chose another way but forgot to delete it.
To avoid this kind of problems, the following might be good ideas:
- give 2 extra looks to your service even after you tested it and was OK from the functional point of view
- request manual code review from a peer
- install and use an automatic code review tool (several are available)
We will discuss this stuff in another post.
Operating system independence
Your code should produce the same results independent of the OS webMethods is installed on. Make sure to respect this rule especially if you know that you are developing on one OS and the production environment is on another OS.
One small example to state my case:
Use the file.separator system property instead of explicitly using / or \.
No obsolete code
And by obsolete code, I mean code that will never be executed at runtime.
Example of such code:
- the code that comes after an EXIT step
- the code from the inner BRANCH of a sequence of imbricated branches with mutual exclusive conditions (ex: a BRANCH that checks for x>0 inside a BRANCH that checks x<0)
And here we are, at the end of the 3rd part of the Coding Guidelines miniseries. I hope that you will find some value in this post.
Before saying goodbye I want to recommend X-Y_Service_Development_Help.pdf (comes with the standard documentation). I believe it is a good read where you will find very helpful advice on building Flow services as well as hidden gems.
Do not forget to join me next time when we will talk about performance considerations.
All the best,