Coding Techniques

University of Nantes — LS2N, France

Goals of Coding

column
  • Translate the design of system into a computer language format

  • Reduce the cost of other activities (evolution)

  • Make the program more readable

Outline

Assertive Programming

Assertive Programming

There is a luxury in self-reproach. When we blame ourselves we feel no one else has a right to blame us.

The Picture of Dorian Gray
— Oscar Wilde

Assertive Programming

  • 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

  • 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!

Java Assertion Example

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";
		// (...)
}

Improving Assertions with Atlanmod Commons

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);
		// (...)
}

Outline

Defensive Programming

Defensive Programming

defensive
Technique for developing maintainable code
  • 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.

Guard Checking

  • Most spread technique form of Defensive Programming.

  • Guarantee that a method can be executed only when some requirements are met.

Guard Checking in Java
 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 ...
}

Improving Guards with Atlanmod Commons

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 ...
}

Guards in Apache Commons

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 ...
}

Guards in Google Guava

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 ...
}

Guards and Assertions

Different goals:
  • Assertions are for situations that should never happen

  • Guards are for expected errors

Use Guards for public and Assertions for private methods!

Outline

Manipulating Null Values

Dealing with Null Values

  • 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

Good Practice: Call Methods Safely

boolean isEnd(String str) {
    return str.equals("end"); (1)
    return "end".equals(str); (2)
    return Objects.equals("end", str); (3)
}
If str is null:
1Raises a NullPointerException
2Returns false
3Returns false

Good Practice: Use Ternary Operator

  • Ensure that a parameter is not null before using it

boolean isEnd(String str) {
    String nonNullValue = (str != null) ? str : "";
    // (...)
}

Good Practice: Use Null Safe Methods

  • Some classes handle nulls safely

Apache Commons StringUtils
boolean isEnd(String str) {
    return StringUtils.equals(str, "end");
}

Good Practice: Use Java Annotations

  • 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.

Good Practice: Static Checking with a Tool

Annotation Example

@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>

Good Practice: Use Option Types

  • Available in Java, C#, TypeScript, etc.

Option Types in Java

Optional.empty() : Optional<T> (1)
Optional.of(T t) : Optional<T> (2)
Optional.ofNullable(T t) : Optional<T> (3)
1Returns an Optional object with no value
2Returns an Optional object with the value t
3Returns an Optional object that may contain a value (calls empty() or of(T) depending whether t is null)

Option type in C#

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);
        }
    }
}

Option Type in TypeScript

  • Uses the union type

Example:
bar(): string | undefined

Outline

Logging

Logging

Technique for keeping a log of events that occur during the execution of a software:
  • Events 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

Logging in Java

Java Logging API Example
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");
	}
}

Using Log Levels

Lowest level (FINEST, TRACE)

very detailed info, e.g. the steps of an algorithm

Low level (FINER, DEBUG)

coarse-grained level info, e.g., entering and leaving method, throwing an exception

Medium level (INFO)

information that shows the progress of the application, e.g., the arrival of a request

Highest level (SEVERE, FATAL)

errors that force the application to stop (assertions)

Remarks

Logs can be filtered by class and level!
Logging impacts performance!

Outline

Automatic Code Generation

Automatic Code Generation

automated code generation
Code generation from a higher level language (graphical or textual)
  • Goals:

    • Productivity

    • Simplification

    • Portability

    • Consistency

  • Different Techniques

    • Templates

    • Specific APIs

    • Cross-platform code generation toolkits.

Templates

  • Templates are simple text files enriched with template notation elements in order to work with placeholders.

acceleo example
Figure 1. Acceleo Template Example

JavaPoet

JavaPoet Example

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);

Google Protocol Buffer

protobuf logo

Protobuf Example

Definition
message Person {
  required string name = 1;
  required int32 id = 2;
  optional string email = 3;
}
Usage in Java
Person john = Person.newBuilder()
    .setId(1234)
    .setName("John Doe")
    .setEmail("jdoe@example.com")
    .build();
output = new FileOutputStream(args[0]);
john.writeTo(output);

Apache Thrift

apache
  • 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

Apache Thrift Example

Definition
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()
}
Python Client
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)

Conclusion

  • 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