Defensive Programming Pt 2 - Try Catch Throw, Finally.
If we use the example from before, but lets make a change so it
fails. We’ll change setValue(now); to SETvalue(now);
setDate : function(executionContext){
let formContext = executionContext.getFormContext();
Var dateFld == formContext.getAttribute("new_lastcontactdate");
if(null !== dateFld){
var fldType == dateFld.getAttributeType();
If (fldType == "datetime"){
var now = new Date();
formContext.getAttribute("new_lastcontactdate").SETvalue(now);
}
else {
return;
}
}
else {
return;
}
}
}
In the runtime, this will create an error with a message popping up in
the user interface. The standard
messages are designed for programmers and don’t mean much, if anything at all
to the end user, if anything it just annoys them and puts them off using it.
Let’s Try and Catch that error
NOTE: Let me reiterate, these posts are not meant
to be teaching you ‘How’ to write programs, or as any form of definitive guide,
they are here to trigger some thought processes and answer some questions at a
higher level.
JavaScript has this neat feature, shared with other languages too, that
allows you to trap an error and decide how you deal with it. It’s referred to
as the ‘Try-Catch’ and here in its most basic form is the skeleton code for the
JavaScript Try-Catch
Block of code to try
}
catch(err) {
Block of code to handle errors
}
The ‘try’ block braces go around your execution code. In our example for
the setDate function the code is really simple and there is only one real area that
is likely to cause an error. However, as you build up more code and
complexity, you may have multiple execution lines that could cause a potential
error. You don’t need to have 1 try
catch around each line, but also, you don’t want to have one try-catch around
your entire set of functions. It’s all
about getting the balance right. I like
to keep my try-catch blocks small and distinct, by which I mean I try and group
them to match the function, or areas within a function that makes sense (to me
at least). There are lots of software blogs out there
that can give you more guidance on when and where to use the try-catch, my
advise is start small and get comfortable with using it.
setDate : function(executionContext){
let formContext = executionContext.getFormContext();
Var dateFld == formContext.getAttribute("new_lastcontactdate");
if(null !== dateFld){
var fldType == dateFld.getAttributeType();
If (fldType == "datetime"){
var now = new Date();
try {
formContext.getAttribute("new_lastcontactdate").SETvalue(now);
}
}
}
else {
return;
}
}
else {
return;
}
}
}
In our example above the 'try' block is around the line that sets the last
contacted date only, so if, there is an error detected, we (as the programmer)
know where it is. The catch segment gets passed the error from the application
and it stores it in the parameter (err in this example) which we can then use. You can use google to find out more about the
error object created by the system and what’s available for you to use in your
code, the two key things you may want to look at are: ‘name’ and ‘message’.
So now we know that we can put a fence (try) around parts of our code that might error. Typically, I like to put them around pieces of code that I know will be an issue if there is a mistake or if there is something that could be influenced or changed later (like someone removing field that code updates, for example). We’ve also seen that we can ‘catch’ the error and put up a nicer more meaningful message. We can also put more code inside the catch block to do something else and this will only execute if there is an error that occurs inside the try block. But wait there’s more!
Throw
me something to work with
When we are working with a user and asking them to input data in a form,
for example, they don’t always do what we want or expect them to do. Lets say we have an unconstrained number
field as an input, but for some reason we want them to enter a number between 5 and 10.
We can use the ‘throw’ to create
an more elegant error message that is presented to the user. Here below is an example of a how we’d use
the ‘throw’ command. I’ve taken this example
directly from https://www.w3schools.com
which by the way, is great resource to help you learn more about programming languages
and their syntax. I refer to their website
all the time.
<!DOCTYPE html>
<html>
<body>
<p>Please input a number between 5 and 10:</p>
<input id="demo" type="text">
<button type="button" onclick="myFunction()">Test
Input</button>
<p id="p01"></p>
<script>
function myFunction() {
const message = document.getElementById("p01");
message.innerHTML = "";
let x = document.getElementById("demo").value;
try {
if(x.trim() == "") throw "empty";
if(isNaN(x)) throw "not a number";
x = Number(x);
if(x < 5) throw "too low";
if(x > 10) throw "too high";
}
catch(err) {
message.innerHTML = "Input is " +
err;
}
}
</script>
</body>
</html>
Let’s look at how it works. In
the try block, you can see there are multiple ‘if’s and they are checking the value
which has been entered by the user. At the end of the ‘if is the ‘throw’. It is really just setting that error object
we touched on a little while ago.
Depending on which ‘if’ gets activated, the error message in the ‘error’
object will be set to the value that is thrown.
Now we know how to do some simple form validation, verification, put a fence around potentially erroring creating code, and catch the error if one occurs, we can even create our own custom messages too.
finally!
Isn’t it great! We can check to
see if in advance if we expect there may be an issue, we can verify what the
fields on forms are (the type we expect),
we can put guards around the area that might create errors for things
outside our control (and our syntax or spelling mistakes ) and we can make the
messages to the user more palatable, but what we’d really like to do is ensure
that the program continues to work and the user or the appropriate person gets
what is expected and that the error can be dealt with appropriately. This is where the final piece of the puzzle comes
in, right at the end and it's the ‘finally’ clause. With
the ‘finally’ clause you can execute code after the try -catch regardless of the
result.
setDate : function(executionContext){
let formContext = executionContext.getFormContext();
Var dateFld == formContext.getAttribute("new_lastcontactdate");
if(null !== dateFld){
var fldType == dateFld.getAttributeType();
If (fldType == "datetime"){
var now = new Date();
try {
formContext.getAttribute("new_lastcontactdate").SETvalue(now);
}
}
Finally {
alert(“we’ve hit the finally clause, this will run after the try catch regardless”);
}
}
else {
return;
}
}
else {
return;
}
}
}
Summary
Defensive programming is all about doing our absolute best to elegantly
handle the unexpected. When using JavaScript for form manipulation
in D365 for example, we first looked at how using a NameSpace can avoid the wrong function
being called then we went on to look at how we can test to see if a field is
there (by assigning the field to a variable and checking it’s not null) , then we looked at how to check it’s the right
type of field (using the getAttributeType function) . Next, we looked at how we can add guard rails
around sections of code that might error (using the ‘try’ block). We then looked
at how we can handle errors that do happen (using the ‘catch’ block). We even
looked at how to create our own error messages (using the ‘throw’ function) and
then how we can make sure that the ‘critical’ or ‘must always happen’ code
still runs (using the 'finally’ clause).
No comments:
Post a Comment