Translate the design of system into a computer language format
Reduce the cost of other activities (evolution)
Make the program more readable
University of Nantes — LS2N, France
Gerson Sunyé gerson.sunye@univ-nantes.fr

Translate the design of system into a computer language format
Reduce the cost of other activities (evolution)
Make the program more readable
There is a luxury in self-reproach. When we blame ourselves we feel no one else has a right to blame us.
Technique that follows the principle of fail fast and fail visibly
It reduces the error propagation because of side-effects.
It forbids(kind of sanity-check) the system to enter an inconsistent state because of user-data or by subsequent code changes.
Assertions are predicates that check conditions that should never occur, and blow up catastrophically if they do.
Goals:
Ensure the state of variables.
Improve code readability.
Improve error localization.
Can be disabled.
| Assertions prevent the impossible! |
1
2
3
4
5
6
7
class Example {
// (...)
private double calculate(int x, int y) {
assert x != 0 : "X should not be zero";
assert y <= 10 : "Y should be less than or equal to 10";
// (...)
}
1
2
3
4
5
6
7
class Example {
// (...)
private double calculate(int x, int y) {
Preconditions.ensureThat(x).isNotZero();
Preconditions.ensureThat(y).isLessThanOrEqualTo(10);
// (...)
}

ensures the code to behave in a correct manner, despite incorrect input.
guarantees that a method can be executed only when some requirements are met.
Most spread technique form of Defensive Programming.
Guarantee that a method can be executed only when some requirements are met.
1
2
3
4
5
6
7
8
9
10
11
public static void foo(String name, int start, int end) {
// Guards
if (null == name) {
throw new NullPointerException("Name must not be null");
}
if (start >= end) {
throw new IllegalArgumentException("Start (" + start + ") must be " + "smaller than end (" + end + ")");
}
// Do something here ...
}
1
2
3
4
5
6
7
public static void foo(String name, int start, int end) {
// Guards
Guards.checkNotNull(name, "Name must not be null");
Guards.checkArgument(start < end, "Start (%s) must be smaller than end (%s)", start, end);
// Method body ...
}
1
2
3
4
5
6
7
8
public static void foo(String name, int start, int end) {
// Guards
Validate.notNull(name, "Name must not be null");
Validate.isTrue(start < end, "Start (%s) must be smaller than end (%s)", start, end);
// Do something here ...
}
1
2
3
4
5
6
7
8
public static void foo(String name, int start, int end) {
// Guards
Preconditions.checkNotNull(name, "Name must not be null");
Preconditions.checkArgument(start < end, "Start (%s) must be smaller than end (%s)", start, end);
// Do something here ...
}
Assertions are for situations that should never happen
Guards are for expected errors
| Use Guards for public and Assertions for private methods! |
Java allows references (fields, parameters, variables) to be assigned with null values
However, nulls are evil! Consequences:
Application crashes
Unpredictable behavior
Complex debugging
Security vulnerabilities
Null Pointer Exceptions (NPE) are the largest cause of app crashes on Google Play
| Apply good practices for avoiding NPE |
boolean isEnd(String str) {
return str.equals("end"); (1)
return "end".equals(str); (2)
return Objects.equals("end", str); (3)
}str is null:| 1 | Raises a NullPointerException |
| 2 | Returns false |
| 3 | Returns false |
Ensure that a parameter is not null before using it
boolean isEnd(String str) {
String nonNullValue = (str != null) ? str : "";
// (...)
}Some classes handle nulls safely
boolean isEnd(String str) {
return StringUtils.equals(str, "end");
}JSpecify defines annotations that describe whether a Java type contains the value null: @Nullable, @NotNull
JSR 305 defines similar annotations for software defect detection
These annotations are useful to (for example):
programmers reading the code,
static checkers that help developers avoid NullPointerExceptions,
tools that perform run-time checking and test generation, as well as documentation systems.
Eclipse, IntelliJ IDEA, Checker Framework, NullAway, SpotBugs, etc.
Sling, from the Apache foundation, defines and uses such annotations
EISOP Checker Framework: Enforcing, Inferring, and Synthesizing Optional Properties (EISOP) Framework
@Override
public int indexOf(@Nullable Object object) {
return (object == null) ? -1 : Lists.indexOfImpl(this, object);
}Warnings are raised when a nullable object is accessed without any nullity check
Ease the detection of NullPointerExceptions
<dependency>
<groupId>com.google.code.findbugs</groupId>
<artifactId>jsr305</artifactId>
<version>3.0.0</version>
</dependency>Available in Java, C#, TypeScript, etc.
Optional.empty() : Optional<T> (1)
Optional.of(T t) : Optional<T> (2)
Optional.ofNullable(T t) : Optional<T> (3)| 1 | Returns an Optional object with no value |
| 2 | Returns an Optional object with the value t |
| 3 | Returns an Optional object that may contain a value (calls empty() or of(T) depending whether t is null) |
class NullableExample {
static void Main() {
int? num = null;
// Is the HasValue property true?
if (num.HasValue) {
System.Console.WriteLine("num = " + num.Value);
}
else {
System.Console.WriteLine("num = Null");
}
// y is set to zero
int y = num.GetValueOrDefault();
// num.Value throws an InvalidOperationException if num.HasValue is false
try {
y = num.Value;
}
catch(System.InvalidOperationException e){
System.Console.WriteLine(e.Message);
}
}
}Uses the union type
bar(): string | undefinedEvents are logged according to a severity level hierarchy.
For instance:
JDK levels: SEVERE, WARNING, INFO, CONFIG, FINE, FINER, FINEST
Log4j levels: FATAL, ERROR, WARN, INFO, DEBUG, TRACE
import java.util.logging.Logger;
private final static Logger LOG = Logger.getLogger(MyClass.class.getName());
public MyClass {
public MyCLass() {
LOG.setLevel(Level.INFO);
}
public void foo() {
LOG.severe("Important Log");
LOG.warning("Less important Log");
LOG.info("Not important Log");
LOG.finest("Really not important");
}
}very detailed info, e.g. the steps of an algorithm
coarse-grained level info, e.g., entering and leaving method, throwing an exception
information that shows the progress of the application, e.g., the arrival of a request
errors that force the application to stop (assertions)
| Logs can be filtered by class and level! |
| Logging impacts performance! |

Goals:
Productivity
Simplification
Portability
Consistency
Different Techniques
Templates
Specific APIs
Cross-platform code generation toolkits.
Templates are simple text files enriched with template notation elements in order to work with placeholders.

Specific API for Java Code Generation
MethodSpec main = MethodSpec.methodBuilder("main")
.addModifiers(Modifier.PUBLIC, Modifier.STATIC)
.returns(void.class)
.addParameter(String[].class, "args")
.addStatement("$T.out.println($S)", System.class, "Hello, JavaPoet!")
.build();
TypeSpec helloWorld = TypeSpec.classBuilder("HelloWorld")
.addModifiers(Modifier.PUBLIC, Modifier.FINAL)
.addMethod(main)
.build();
JavaFile javaFile = JavaFile.builder("com.example.helloworld", helloWorld)
.build();
javaFile.writeTo(System.out);
A language-neutral, platform-neutral, extensible mechanism for serializing structured data.
message Person {
required string name = 1;
required int32 id = 2;
optional string email = 3;
}Person john = Person.newBuilder()
.setId(1234)
.setName("John Doe")
.setEmail("jdoe@example.com")
.build();
output = new FileOutputStream(args[0]);
john.writeTo(output);
Framework for scalable cross-language services development
Code generation engine to build services between C++, Java, Python, PHP, Ruby, Erlang, Perl, Haskell, C#, Cocoa, JavaScript, Node.js, Smalltalk, OCaml, and Delphi
service Calculator extends shared.SharedService {
void ping(),
i32 add(1:i32 num1, 2:i32 num2),
i32 calculate(1:i32 logid, 2:Work w) throws (1:InvalidOperation ouch),
oneway void zip()
}def main():
# Make socket
transport = TSocket.TSocket('localhost', 9090)
# Buffering is critical. Raw sockets are very slow
transport = TTransport.TBufferedTransport(transport)
# Wrap in a protocol
protocol = TBinaryProtocol.TBinaryProtocol(transport)
# Create a client to use the protocol encoder
client = Calculator.Client(protocol)
# Connect!
transport.open()
client.ping()
print('ping()')
sum_ = client.add(1, 1)Defensive and Assertive programming
Similar syntax but different goals
Use Assertions for private and Guards for public methods
Logging must be planned
Too much information is counter-productive
Use levels to simplify log analysis
Use a different logger instance for each class