QCon London Andrzej Grzesik, principal engineer at UK neobank Revolut, spoke at the recent QCon London, - back in the days when in-person tech conferences were a thing - about the company's shift to Java 11, which it has now been running for over a year.
Revolut was launched in July 2015 and now has 2,200 employees, over 10 million retail users and over 340,000 business users around the world.
The issue with Java is that changes introduced in Java 9, such as a new modular architecture and the deprecation of a number of features, mean that applications written for Java 8 often do not run without modifications. Java also now has a six-monthly release cycle, with only the current version supported, except for long-term support (LTS) releases every three years. Java 11 was the first LTS release after Java 8. Despite the age of Java 8, released in March 2014, it is the most popular version in production. A recent small survey referenced by Grzesik showed 58 per cent of developers using JDK 8.
Some parts of JDK 8 are removed in JDK 11, warned Grzesik, including the web services stack
The new lifecycle means that for most organisations it is impractical to migrate to anything other than an LTS release. The current version at the time of writing is JDK 13, for example, but it is about to go out of support. JDK 14 will be released shortly, but until very recently the Gradle build tool did not work with JDK 14 because it uses the Groovy language that was incompatible. This is just an example of the kind of issues you can expect with these short-life releases.
Revolut deploys its Java applications in Docker containers, and uses a framework called Java Spark. "We don’t use Spring, because debugging annotation-driven problems is not fun," said Grzesik. "We have to move fast and not break anything," he said, "because as a financial company we are under a lot of scrutiny."
The bank faced some compliance questions from the FCA last year. The FCA authorised e-money institution has been valued at £4.bn after a £387m funding round earlier this year.
Yep - it upgraded all the apps
Why did Revolut upgrade? Grzesik gave several reasons, and while none were overwhelming, his key point is that the move is unavoidable. "We would have to upgrade anyway. Software gets new features," he said. It turned out though that there are real technical benefits as well.
He also noted that "hiring good people is easier" – because if developers can choose where to work, they are more likely to choose a job where they can work with a modern version of Java.
JDK 11 is licensed differently than JDK 8, with Oracle requiring a commercial licence for its distribution. "We went away from Oracle JDK. There is a licence that is very complicated. I find it tiresome," said Grzesik. The solution was to use OpenJDK, which gets all the same code and fixes.
Revolut's approach was to upgrade all its apps to Java 11, rather than take a piecemeal approach.
There were issues. The biggest was with dependencies. You can fix your own code, but if a library or tool you rely on is not working, there is less you can do. In addition, Grzesik said that the moment when a vendor or community announces compatibility is not always the moment it is ready to use. "Official support does not always mean it will work as expected," he said. He gave as an example the Mockito mocking framework, which formally supported JDK 11 "since 2.20.1", but was not really ready until a later version. The firm had similar issues with a database migration tool called Flyway. Extensive testing is critical.
"The number of test cases is counted in tens of thousands," he told us.
Some parts of JDK 8 are removed in JDK 11, warned Grzesik, including the web services stack, documented in JEP 320.
The team ran into some intricate problems with time precision. Since JDK 9, the precision of java.time.Clock differs according to the underlying OS. This caused problems when working with the Postgres database, for example, where "some code assumes 3 digits, some assumes 6."
The result is that "you get a lot of strange bugs and test failures," said Grzesik. His solution is to use a wrapper function that you control for working with time, so you can be consistent.
Grzesik ran through a number of issues and tips for dealing with them, though what you encounter in your own applications will vary. Oracle has its own migration guide here.
What are the benefits though, aside from simply keeping up to date?
A few were mentioned. One is the Compact String. Strings in Java 8 use a char array internally, whereas Java 9 on has a byte array. If you are not using double-byte characters, "you will use half the memory," said Grzesik.
Another improvement is that since JDK 10, garbage collection (GC) is multi-threaded, which means it no longer causes short pauses in an application. "We don't have to do magic with GC tuning to achieve pauseless, on a human perception level, for our services. This a life-changer compared to JDK 8," he said.
Since JDK 10, Java supports type inference with the var keyword. "At first people were a bit cautious, but then the feature quickly caught on. People actually like using var… it's just less characters, less reading. Usually the code that it replaces is quite obvious," said Grzesik, showing how adoption increased for one of Revolut's projects.
Scaling containers is easier in JDK 11, Grzesik said. "As usage grows, we just give the containers more memory." This is a benefit, even though Java 11 uses slightly more memory than Java 8 (which caused some tightly specified containers to die).
Grzesik also praised the open source and free-to-use Java Flight Record and Mission Control. "You can analyse your JDK 11 application with those excellent tools."
Does this add up to a compelling case for upgrade? It is a trade-off. There are advantages, but it is not a painless process and there will be issues. As Grzesik noted, it is an upgrade that all Java teams will have to face at some point.
How do you go about upgrading? "Just try to compile your applications," he said, and take it from there. ®