Welcome, we will now discuss a few points about designing programs for analyzability. Why does analyzability matter? Because the programs we write tend to have faults and tests may not always reveal the faults. So, we need other techniques like static analysis, reviews, and dynamic monitoring to check for faults. Following a few good program design practices can make this easy and make your program amenable to set checks. So, it can make the static analysis tools, take some hints that you provide, and use that to determine if there is some potential fault in the program, or it might help a reviewer looking at the code to see if there are issues. How do we do that? The first thing to do is to identify the expectations that you have in the program. Typically, these come in the form of different conditions that you expect to be true at various points in the program. One such thing is a precondition. For example, when you invoke a method, what do you expect to be true of the parameters that are passed? Maybe you want some objects to be not null. Maybe you want some relationship to be true between the arguments. So, this is, in general, a predicate that you want to hold true before some method is called or before some piece of code is executed, we call that a precondition. The other things to think about is, what is always true when you're executing some piece of code? Typically, this manifests in loops. Whenever you go through a loop, some condition you expect to be true. For example, in the GCD program you expect that the numbers are positive or the divisor is positive. That could be an invariant that you want to check. So, what is true whenever the code is executed? That's called an invariant. The other thing to think about is the post-condition, when you run a code and you're done executing, what you expect to be true after the program has executed. So, thinking about these when we design the program and then providing appropriate hints to the compiler or are other tools to check for these conditions or these expectations, would greatly help in identifying bugs early and at times even in avoiding bugs, because you will be thinking a little more logically and systematically about the program that you're writing. So, once you identify these expectations, we are to document this, so that people looking at the program can review and give feedback. Tools like static analysis tools that we are looking at in this session can actually use those hints that you provide in the code to do that analysis. Runtime monitors can check the program when they are executing to see if your expectations hold. This could be particularly useful when we are testing the code because even though the output may appear to be correct, some state might have incorrect code, and if you're putting an appropriate expectation on the state of the program at a particular point, a runtime monitor can probably check and give you feedback that something doesn't work. How do we do that? Typically, these come in the form of assertions. When you write code, it's a good practice to write down these as assertions. These are simply Boolean expressions that we expect to be true at the point at which they are inserted in the code. We are basically telling to everyone, the humans, or the tools, or the monitors that it doesn't matter how you got to this point of the code. When this code is at this point, I expect this condition to be true. The other sets of documentation that we provide are annotations. So, for example, here is an assertion in the GCD program that we saw earlier. We want to return a non-negative value as the result of the GCD, at least that's the mathematical expectation that we have. So, we put in an assert statement just before the return, saying that the return value that I'm going to send back from this routine is positive. Now think for a minute, will this assumption be always true? It might be easy to come up with a test case where you passed in 0 and 0, and you never enter the while loop and the assertion fails. Such a straightforward thing can be immediately obvious to a human reviewer, and that's a good feedback. Maybe you forgot to put in a precondition in this case to say that we are expecting numbers that are positive. Then we will go and add those as assertions, so that precondition is checked before we enter gcd(). The other forms of documenting these checks are in the form of annotations. These do not change the semantics of the program. Annotations are metainformation, information about certain things in the program that you are documenting for various reasons, maybe for producing nice-printed documentation. We often see these things in Java code like @Override, @Deprecated. @Deprecated, for example, tells the user that that routine is not to be used and there are alternative or better ways to do it. But it's being held in place for backward compatibility. Another important annotation that we often see are about nullability. The dreaded null pointer exception that comes up in any nontrivial code, is because of not being careful about checking whether a value is null or not when it is required. And it's difficult, so we need some tools to help. In this case, we would like a compiler or some checker framework, that's in the compiler to do some analysis, and let us know that, "Hey! Here is a potential value that you're accessing and that's nullable." So, there must be a check. Or here is a point where you expect the variable to be not null. So, these kinds of annotations can then let the compiler do their analysis and warn the user that the expectation that is documented may not hold. So, annotations are advisory in nature in the sense that it tells some tools or some analyst or some monitor that something is expected to be true. Program semantics do not change the tools that understand the annotations process and give feedback. This is typically done by some static analysis tool. So, writing down these assertions and annotations is a good practice, not just for doing analysis but also for documenting and communicating to other designers and testers what is the expectation at various points in the design.