How to Create a Good MCVE (Minimal Complete Verifiable Example)

Reporting a bug takes time, and trust me, every vendor appreciates your reporting of a bug! Your voice counts as many voices, for all the other customers of a product who do not want to or cannot take the time to report the same bug are numerous.

So, first off, thanks for taking that time and reaching out to us vendors. We really appreciate your help!

Having said so, reporting a bug can be a tedious exercise. For both parties, the one reporting the bug and the one receiving it. There are extremely simple bugs, such as typos in documentation. They can be easily pointed to and just as easily be fixed. There are much trickier bugs, such as concurrency issues in complicated project setups. They take time to reproduce. This is why an MCVE (Minimal Complete Verifiable Example) is so useful. The linked stack overflow page explains why it is so useful to answer questions. But the same arguments apply when reporting a bug.

And that’s where the tricky part starts. It isn’t easy to create an example that is:

  • Minimal: Your real world application code is huge. You cannot dump the entirety of it to the vendor for various reasons. And the vendor cannot look through it all to try to reproduce it. So, the problem has to be isolated into an example of minimal scope, with no unnecessary additional functionality. That’s hard too, because your project has been set up months or years ago. You don’t want to spend too much time setting up a new project
  • Complete: When reducing the problem to a minimal one, we’re tempted to just describe it in prose. But that can be difficult as well, because prose is hardly complete. It’s difficult to describe a problem when it would be quite easy to show the code. But that brings us back to the minimal part. We want to show only the relevant code, not all of it.
  • Verifiable: Ultimately, the ideal example can be used by the vendor to reproduce the problem, because once that’s possible, the vendor can start debugging it and finding the right spots to fix quite easily. Otherwise, it’s just guessing and going back and forth with the reporter, just to write more prose. That’s tiring on both sides.

This is why we now have an example project on GitHub to help you create that MCVE:

https://github.com/jOOQ/jOOQ-mcve

It is a minimal example that uses:

This example can be forked on GitHub and modified by you directly, in order to show how to reproduce your issue. In the future, we’ll add more example setups that may be helpful to reproduce your specific issue.

Thanks again for taking the time to report issues. We vendors really appreciate your work!

One Year After Java 8’s Release, IDEs and Compilers are not Fully Ready Yet

One year ago, on March 18, 2014, Java SE 8 was released, and with it, the bliss of functional programming through lambda expressions and the streams API. These were great news for all of our Java ecosystem, and many people have already upgraded to Java 8. Stack Overflow already yields almost 2500 questions about Java 8 (with Brian Goetz himself answering). Also, Google Trends shows a massive increase in search volume

java-8-trends

But even after one year, neither the javac compiler, nor the three major IDE compilers are fully Java 8 ready yet. This question by user meriton was asked on Stack Overflow, recently:

Lambda type inference infers an exception type not thrown by the lambda

The question shows the following piece of code:

class TestException extends Exception {
}

interface Task<E extends Exception> {
    void call() throws E;
}

public class TaskPerformer {

    private <E extends Exception> void perform(Task<E> task) throws E {
        task.call();
    }

    public static void main(String[] args) {
        // compilation error
        new TaskPerformer().perform(() -> {
            try {
                throw new TestException();
            } catch (TestException e) {
                return;
            }
        });
    }
}

The false positive compilation error has probably been fixed with issue 429430. In any case, it is not reproducible with Eclipse 4.5.0 M5, available as a developer build

With Java 8, compiling Java code hasn’t really become any easier than before. The above bug has been produced by a very subtle combination of:

  • Checked vs. unchecked exceptions
  • Generics (and exceptions)
  • Lambda expressions
  • Type inference
  • Flow analysis

If you’ve ever had a look at compiler source code, you cannot help but be glad that someone else is doing that job for you (the same is true when you look at jOOQ’s or Hibernate’s sources, by the way).

Where are we at with our compilers?

We’re getting there. My personal feeling is that early access releases of javac work best. For instance, I’m using

build 1.8.0_40-ea-b23

(disclaimer: this article was written before it was published. many problems are now gone with 1.8.0_40)

… although, you probably don’t want to go to production with such an early access release. IDEs building with javac, and Maven, of course, work equally well. Eclipse is lagging a little bit – which can be annoying at times.

Some of you non-Eclipse users might smirk and get your Eclipse vs. IntelliJ rants ready, and you know… there’s a saying about that:

A vegan, an IntelliJ user, a Mac user, and a Linux user walked into a bar.

How do I know?

AFTER 2 MINUTES, THE WHOLE DARN BAR KNEW!

(We actually have a whole article on that topic)

The fact is, all of the compiler teams are working hard to fix loads of bugs. IntelliJ, even while using javac to compile, may still display some false positives, visually in your IDE. Geertjan from NetBeans has just recently fixed a whole pile of bugs that we’ve reported. And Eclipse, well, Eclipse ships with their own very sophisticated incremental Java compiler. It’s a great compiler for rapid prototyping, but the drawback is that it compiles stuff slightly differently from others.

While developing jOOQ and also jOOλ, we’ve discovered quite a few bugs in Eclipse – many of them having been fixed already in Eclipse Mars. For instance:

We’re getting there. If you can, make use of lambdas and streams, and apply as much type inference in your code as possible. And please, if you do discover a bug, report it. We’re probably all using one of those three IDEs. Every bug that you report, is one less obstacle towards Java 8 adoption.

Here are the links to start registering bugs:

JDBC 4.0’s Lesser-known Clob.free() and Blob.free() Methods

When I talk about jOOQ at conferences, I always show this slide containing a bunch of very common JDBC mistakes that people often commit:

Six common JDBC bugs in this image

Six common JDBC bugs in this image

Can you find the bugs? Some of them are obvious, such as:

  • Line 4: Syntax errors resulting from bad concatenation on line 3
  • Line 7: Syntax errors and SQL injection risk due to variable inlining
  • Line 8: Wrong bind index resulting from a potential mismatch on line 3
  • Line 14: Wrong column name due to sloppy rename
  • Line 18: Bad resource management

But then, there’s another very subtle bug that most people are unaware of because the fix was only possible since the upgrade in Java 6 / JDBC 4.0. See the solution, below:

Solution to the previous six bugs

Solution to the previous six bugs

With JDBC 4.0, the Clob.free() and the Blob.free() methods were introduced. While calling them is optional, it may be a very bad idea not to call them as early as possible, as you should not rely on the garbage collector to kick in early enough to free these resources. In fact, in certain databases / JDBC drivers, LOBs can outlive individual statements and/or transactions. They’re beasts of their own. If you’re reading through the JDBC tutorial (and also in the JDBC specification), it says:

Blob, Clob, and NClob Java objects remain valid for at least the duration of the transaction in which they are created. This could potentially result in an application running out of resources during a long running transaction.

The same is true for arrays, which also have an Array.free() method since Java 6 / JDBC 4.0.

So if your application has long-running transactions, do call these free() methods, or make it a habit to always call them. We’ll file an issue to FindBugs to make this a potential bug pattern.