Notes of a (Java) developer

Compile-time checking in Java

Software developer Programmer

In a previous post I wrote about code quality: in a few words, I believe in static-checking. Static means without executing the program. In a software process point of view, this would imply before runtime, in other words at compile-time. For a developer, it can be very useful to have such a verification simply with a compilation, without executing a specific tool (by the way, some very interesting software of that kind are available, just Findbugs for example).

Here is the point: how would it be possible to proceed that kind of control without rewriting a compiler from scratch ?

The Java platform provides a very interesting feature to perform such operations: annotations (JSR 175). These are metadata defined as java types. Annotations have been introduced in the Java language starting with Java SE 5. Annotations can be processed at compile-time or runtime.

The Sun Java SE distribution provided from the starting point a facility for annotation processing at compile-time called APT (for Annotation Processing Tool). This was a vendor-specific feature (in Sun packages) executed in a specific and eponymous command line tool.

Since Java 6, that function is part of the platform with JSR 269 (javax.annotation.processing package, reference implementation part of the Java SE distribution). The contributed processing can be executed along compilation. With Java SE 8, the historical APT packaging and specific tool is removed (after deprecation in Java SE 7).

If the topic seems basic for the Java platform, there is a lack of exhaustive documentation for annotation processors development. I found some precious informations in , a blog post by . The Eclipse platform provide very precious functions with the JDT-APT project.

A very interesting by and from develops many important points about compile-time checking: what could be done with annotation processors and what requires more. For example, the processor does not provide the structure of the AST and thereby does not allow flow analysis.

A processor must implement the javax.annotation.processing.Processor interface. The implementation should be specified to the platform using the SPI system. An abstract class AbstractProcessor is provided to help implementations.

In a details the implementation of a compile-time processor for the @Transactional annotation of the spring framework .

Apple SSL case: code quality

Software developer Programmer

The point is clearly about programming practice. In February 2014, Apple faced an SSL bug. This was a very simple code mistake due to conditional sequences.

Because of the conditional aspect, we easily focus on curly braces. Two comments suggested the solution to such a problem could be about test cases (both articles provide simple code extracts of the guilty section):

  • Apple's SSL/TLS bug by
  • Reflections on Curly Braces by </li> </ul>

    For sure, testing is an important point in code quality. In an ideal world there would be a test case for any code piece. For sure, there are excellent other tools. I previously wrote about design by contract. Coding a verified program, checking 's axioms is also an important topic. When it comes to software quality, I won't say any practice is inappropriate.

    Stop dreaming about a world with perfect programs. Let the code verification/prove apart and come back to the code. Adam Langley also suggests code reviews are important. Curly braces ? Perhaps the point isn't central. What matter is a readable code. Some interesting code conventions exist, especially in large organizations such as Google (the naming section is especially interesting). But is respecting rules enough ? Many programmers write endless code sequences. What could be the solution ?

    We, French people, tend to be very verbose in our texts. At school, we are taught to be concise. We do not succeed in any case. How would it be possible in code ? Think about Twitter 140 characters. Just consider what a French journalist could write in 2011. Nowadays, very few journalists still criticize the system. Conciseness can be very precious.

    When it comes to quality control, human verifications are weak. I think the twitter limitation is an interesting idea. In writing programs, we have the advantage of compilation to induce strict checking. Why don't compilers warn when a function exceeds 100 lines (or any number that suits you, to be honest the guilty section is only 80 lines long) ? At first glance, this is not the exact topic because this would not have prevented programmers from coding that bug. In broader sight, I tend to think the solution to that kind of problem is in static checking . It won't be possible to automatically test any piece of written code, or even review it properly.

Design by contract, assertions and exceptions

Software developer Programmer

Understanding design by contract is, I think, important for software quality in OOP because the principles are clear and efficient.

introduced the idea in 1988. It takes advantage of assertions as defined by (1969), the seminal work of an eponymous logic.

Assertions are associated to an object method and qualified in one of three categories :

  • Preconditions are assertions true before executing the method
  • Postconditions are assertions true after executing the method
  • Invariants are assertions true before and after executing the method

In practice...

includes his idea in the programming language : the assertions are checked in a static way (at compile time).

If the Java programming language provides support for assertions, these are checked only in a dynamic way (at runtime) and disabled by default. Because of runtime checking, exceptions are largely used instead of assertions. In Java, a proper use of exceptions can be more meaningful to the programmer than a proper use of assertions because it provides more details about the malfunction conditions (the stack trace). At first glance, assertions (in the design by contract way) seem to be very far from exceptions. This is to some extent a paradox: I think the developer should consider assertions concepts every time he uses exceptions.

In Effective Java , defines checked exceptions as recoverable conditions and runtime exceptions as programming errors.

In an non-Java context, says an exception is a situation where preconditions are satisfied but postconditions can not be satisfied.

I think that, to respect Bloch terms,

  • Runtime exceptions should be used for checking preconditions
  • Checked exceptions should be used when preconditions are true but postconditions can not be satisfied, assuming that the method is correct (e.g. the network connection is broken). 

If a runtime exception is raised, the calling method should be bugged (or its preconditions are not properly checked).

Some extensions to the Java platform provide support for static testing (assertions checking at compile time). For example, JML takes advantage of Java comments: this is interesting for traditional compiling compliance.

Heisenbug - Concurrency case

Software developer Programmer

Solving an Heisenbug can be really tricky. This kind of bug occurs when the program execution conditions are changing. In many cases, using a debugger or a log output doesn't help. Such tools can have an influence on the execution.

I once faced such a bug in a Swing application. The problem occurred in a quite long process (half an hour)  at various steps with constant input data. I lost time with that bug because I had no methodology. I have to admit the final solution was rather simple.

I designed an activity diagram of the main activities involved in the failing process. I paid attention to swimlanes because I suspected a concurrency problem. For each activity there was a single log output. A custom logging level was set up so that only activity logs could be written (an attempt with the debug log level was completely helpless). The logging framework was also configured to print the current thread name. There I got the activity which was not in the right place and the name of the criminal. The random occurrence of the problem was probably due to the variable system load and user interactions.