PeopleCode | Creating a series of readable data validations
A. The Nested If Strikes
This particular tip is more of a strategy rather than an actual piece of code. It came about when I noticed a developer creating a series of validations in the following manner:
If &condition1 then Error MsgGet(99999,9, "Error 1"); Else If &condition2 then Error MsgGet(99999,9, "Error 2"); End-if; End-if;
This might not seem like a big deal, but then another developer came along and added a further series of validations:
If &condition1 then Error MsgGet(99999,9,"Error 1"); Else If &condition2 then Error MsgGet(99999,9,"Error 2"); Else If &condition3 then Error MsgGet(99999,9,"Error 3"); Else If &condition4 then Error MsgGet(99999,9,"Error 4"); End-if; End-if; End-if; End-if;
You can probably see where this is heading. The code is becoming more complicated than what it needs to be. A series of nested ‘If’ statements can be quite a challenge to interpret, especially when you start getting towards the end of a very long piece of code and are desperately trying to match up each ‘end-if’ with its corresponding ‘if’. And what if another developer now comes along and wants to add further validation?
B. Basic Validation
In most cases, setting up the nested structure for data validations is unnecessary. Because the ‘Error’ statement immediately terminates the code, there is no need to worry about the effect of any further code in the validation block. You can simply list the validations one-after-the-other, knowing as soon as one error is triggered, the code stops at that point.
If &condition1 then Error MsgGet(99999,9,"Error 1"); End-if; If &condition2 then Error MsgGet(99999,9,"Error 2"); End-if; If &condition3 then Error MsgGet(99999,9,"Error 3"); End-if; If &condition4 then Error MsgGet(99999,9,"Error 4"); End-if;
C. Extended Validation in Processes
If the validation is intended to run as part of a batch process, you might instead prefer to log each error in a log file or database table. You’d also prefer that the AE not terminate upon encountering any error. All validation checks should be performed in sequence, making a note of all errors found along the way. So a block of code similar to the above would work in this scenario. You would simply replace the ‘Error’ statements with an appropriate insert into a log file or database table.
All good, but sometimes you have a situation where each error is contingent on a previous validation. So if error 1 is fired, this has the effect of firing errors 2,3 and 4. You don’t particularly want to fill up a log file with dozens of error messages when just one error message will do. This therefore suggests that a construct similar to our original code would be helpful after all. Each error would be included within in its own ‘If’ statement, so as soon as one error is encountered, it won’t have a cascading effect onto subsequent errors. But then we get back to the original problem of having a piece of code with lots of nested if’s.
One way to get around this is to have a local variable, say a boolean variable called &errorFlag. This is initialised to ‘False’, but then set to ‘True’ on encountering any error. For each error validation, the code therefore checks the &errorFlag to see if an error has occurred up until that point. If yes, then do not continue with the next validation.
So this code will appear as follows:
&errorFlag = False; If &condition1 And Not &ErrorFlag Then &ErrorFlag = True; /* Write message to log file */ End-If; If &condition2 And Not &ErrorFlag Then &ErrorFlag = True; /* Write message to log file */ End-If; If &condition3 And Not &ErrorFlag Then &ErrorFlag = True; /* Write message to log file */ End-If; If &condition4 And Not &ErrorFlag Then &ErrorFlag = True; /* Write message to log file */ End-If;
This allows you to stick to a simple, If/end-if structure, avoiding the need for nested loops.
Finally, in the last example, you might be thinking that the ‘&errorFlag’ check is redundant on the very first validation. The &errorFlag variable will always be False at this point. While this is true, I often find in practice that validations are shuffled about over time, or new validations are added at the start of the code. So just to be safe that the validation only needs to be performed if there is no prior error, it’s safer to add the check to all validations.