Skip to content

Android Java 8 `java.time.Duration` postmortem

Tim van der Lippe edited this page Dec 19, 2019 · 1 revision

Android Java 8 java.time.Duration postmortem

Background

Mockito 3 is compatible with Java 8, compared to Java 6 for Mockito 2. The Android ecosystem supports the Java 8 runtime, but does not support all new methods introduced in Java 8. https://github.com/mockito/mockito/pull/1818 introduced a new API that relies on java.time.Duration, which does not exist on Android SDK's before 26. If an Android user has 1 test that has to run on an SDK < 26, they would be broken by Mockito 3.2.0. This constituted a breaking change. The PR in question was reverted in https://github.com/mockito/mockito/pull/1845 and published as Mockito 3.2.4 to Maven Central. For users who started using the new API introduced in Mockito 3.2.0 would be broken by Mockito 3.2.4. This also constituted a breaking change.

Overall, there are no breaking changes comparing Mockito 3.1.0 and 3.2.4, but there were breaking changes comparing Mockito 3.1.0 and 3.2.0 (for Android users) and 3.2.0 and 3.2.2 (for users of the new API). Thus far, 1 user reported they were using the new API and were broken by this change (https://github.com/mockito/mockito/issues/1843#issuecomment-567235571) and 1 user reported they were broken by the reference to java.time.Duration (https://github.com/mockito/mockito/issues/1843#issue-538087263).

Usage numbers and potential impact

The number of devices running SDK < 26 is ~60% (https://developer.android.com/about/dashboards). Mockito 3.2.0 has 190 reported usages on Maven Central (https://mvnrepository.com/artifact/org.mockito/mockito-core). Mockito 3.1.0 has 562 reported usages and Mockito 3.2.4 has 9 reported usages. For additional perspective: Mockito 3.0.0 has 954 reported usages, Mockito 1.10.19 has 5277 reported usages and the most commonly used Mockito 2 artifact is Mockito 2.23.4 with 2072 reported usages.

Lessons learned

Things that went well

Continuous deployment infrastructure was functional

Our Continuous deployment model allowed us to upload a newer version of Mockito in a relatively short amount of time. There was no need for waiting for authentication from a Maven Central owner or Mockito owner to allow for publication. This lead to a publication time to Maven Central of <1 hour.

Things that went poorly

We have not specified compatibility guarantees for Android users

Mockito is used in both the Java and Android ecosystems. While we do provide a compatibility promise for the Java ecosystem (via our "minimum Java version" policy), we do not have such a policy in place for our Android users. Currently Android users expect their tests to run if they can use Java 8 themselves. However, Android users require desugaring (https://jakewharton.com/d8-library-desugaring/), which users appear to be unaware of.

We do not test Android support in our main test suite

We were unaware of the breakage and published to Maven Central, resulting in a user report 16 days after we published. Adding small Android smoke tests could prevent downstream breakages that are caught late in the cycle.

Reverting the PR resulted in a 2nd-type breaking change

While the first change was a breaking change, the fix itself constituted a breaking change as well. We have no decision making process how to resolve such a situation. In this particular scenario, reverting was deemed the least intrusive option. We have no qualitative measurement on what "least intrusive" means.

Takeaways

We should teach users about desugaring

We should update our documentation to include guidance on how to apply desugaring and point users to resolution. This will allow us to make use of types that are desugarable.

We should not use types that can't be desugared

This is an unfortunate situation for Mockito to be in, but given our large Android userbase, it would be bad for Mockito's future to break these users. If a type can't be desugared, we should not be using it yet, to allow our users to remain using Mockito.

We should setup contact with Android toolchain owners

The previous point limits the evolution of Mockito, which is not a situation we want to be in. If we disocver that a type is not supported via desugaring yet, we should reach out to the Android toolchain owners to resolve the situation.

We should decide when to stop supporting users on SDK < 26

Right now, the number of devices running SDK < 26 is 60%. We should decide at which point we stop supporting this use case. Tentative proposal: less than 25% marketshare would be a good threshold. We should discuss the exact number and make this clear in our documentation.

Clone this wiki locally