Why you should use Quarkus in your next microservice
Tags: quarkus, java, developerjoy, microservices
Published: 2021-05-09 23:09:17

# Motivation

If you're lucky enough to work in a company where you can pitch ideas to your boss and teammates in a meet-up sort of setting, the following should help your argument in your next tech stack meeting. This article is part of an internal presentation I did for my team, in order to educate myself and also understand what the hype is all about.

## What I'm using
* Java 11
* Apache Maven 3.6.3
* IntelliJ IDEA
* sdkman
* macOS Catalina

# So what is Quarkus?

The official definition goes like "A Kubernetes Native Java stack tailored for OpenJDK HotSpot and GraalVM, crafted from the best of breed Java libraries and standards" - quarkus.io.
Sounds complex, right? Let's break it down a bit.
* _Supersonic_ - the main idea here is  _speed_ - fast booting, fast to respond to the 1st request, a time saver when it comes to changing and running code as a developer.
* _Subatomic_ - refers to size in terms of memory usage and reduced binary size.
* _Kubernetes Native_ - refers to the fact that it was designed for containers, meaning small binaries with fast startup. It also comes with Docker images and Kubernetes extensions for easy packaging and deploying. 
* _Java_ - Quarkus is polyglot, supporting several JVM languages, like Groovy and Scala.
* _Libraries and Standards_ - the programming model is not new, it builds on top of existing standards. Quarkus is designed to work with popular frameworks, and libraries such as Eclipse MicroProfile and Spring, as well as RESTEasy (JAX-RS), Hibernate ORM (JPA), Apache Kafka, Spring, Elasticsearch, Camel, Infinispan, and many more.
* _HotSpot and GraalVM_ - it offers support for the most used JVM, as well as first-class support for GraalVM, which is important because it can compile an application down to a native binary, which makes it start faster and run on a smaller heap than a standard JVM.

Although still young (born in 2018), Quarkus comes from a company with a rich history of open source, Java runtimes, distributed environments, microservices, cloud environment, etc. - Red Hat. This makes it even more convenient if you're already using some of their services and plan on including your next Quarkus application.

# What is the purpose and what problems does it solve

I think the clearest and simplest definition of its purpose that I came across belongs to Antonio Goncalves, and that is that it "pushes Java to the cloud".
To better understand this statement we only need to have a look back at the evolution of the industry, starting with the fact that Java transitioned from applets to server side **monolithic applications**. The machines that ran them were up 24/7 and memory usage was huge. Luckily the JIT compiler was there to optimize execution and the GC managed memory efficiently. Fast forward to today's mentality and you'll see that the direction we're going in comprises smaller and lighter components that we want to start/stop quickly and move around as we please. These are **microservices** and **tiny functions** that we can deploy, orchestrate and scale according to our needs. The future is now, we no longer scale up by adding CPU and memory, but rather by adding more instances with smaller binaries and low consumption.
Today, in a modern setup, either in the cloud or on premises, applications run on a container platform. On top of these you can run multiple JVMs, but they all have a relatively long startup time and consume resources. A lot of other technologies or native languages, that have low memory usage, are emerging in the cloud. For example, the density of NodeJS apps, for the same resources, is much higher than Java. In order to keep up with this demand, the *purpose of Quarkus* is to increase the density of applications, while preserving the good old Java platform that we love, by optimizing for fast startup times, small binaries, and low memory usage. 
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/wvbxwzsj0h8cfisvwqmp.png)

# So let's talk performance in action

A nice thing to have with Quarkus is its integration with IntelliJ IDEA. If you're using a different IDE, no worries, bootstrapping a Quarkus application is made super easy by visiting quarkus.io. Click on "Start Coding" and you'll be provided with everything you need.
A third way to generate your project's backbone is by running:
```mvn io.quarkus:quarkus-maven-plugin:1.13.3.Final:create \
-DprojectGroupId=com.example.demo \
-DprojectArtifactId=quarkus-demo \
-DclassName="com.example.demo.HelloResource" \
-Dpath="/hello"```
I'll be using my IDE:
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/uemjl02sfc68ukcnr6gj.png)
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/yreuw38t5520sr209d52.png)

You can choose your desired build tool as well as a multitude of extensions, all from the comfort of your own IDE. Pretty cool, huh? Let's just take RESTEasy JAX-RS for now. You'll have all the needed instructions in the README.md file.
Now that your project is generated, you're all set. 
Run `./mvnw compile quarkus:dev` in your Terminal.
Depending on your setup, you'll probably have some dependencies downloaded and you'll see the message in your Terminal, that Quarkus has started with **dev profile**.
What you're interested in is this message:
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/gfeqgw33dx9slotnvxv2.png)
So let's try out some live coding. You know what the original class looks like, we'll change it a bit, by renaming the endpoint from "hello" to "greeting", add a Logger and change the return message of the function. It will look like this:

```java
import org.jboss.logging.Logger;
import javax.inject.Inject;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;

@Path("/greeting")
public class ExampleResource {

    @Inject
    Logger logger;

    @GET
    @Produces(MediaType.TEXT_PLAIN)
    public String hello() {
       logger.info("You've called the renamed endpoint");
        return "Hello Quarkus";
    }
}
```

Don't forget about your tests in the ExampleResourceTest class. It should be adjusted like so:

```java
@QuarkusTest
public class ExampleResourceTest {

    @Test
    public void testHelloEndpoint() {
        given()
                .when().get("/greeting")
                .then()
                .statusCode(200)
                .body(is("Hello Quarkus"));
    }
}
```
In a new Terminal tab, run `curl http://localhost:8080/greeting`
and you'll be able to see the result:
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/cyas4hjfibn4et1rdyzj.png)
0.585s, not bad. Previously you would go grab another coffee, get on 9gag and scroll 15 more minutes past your build and deployment time.
Let's package the application by using `mvn package` and then run it with `java -jar target/quarkus-app/quarkus-run.jar`.
This will start your application with **prod profile** activated, in around 0.718s, even faster than initially with **dev profile**. The downside to this is that you don't get to hot-swap anymore, since you cannot change the application without packaging it, but it highlights exactly what we've discussed earlier, the capability of scaling as fast as possible.
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/bd58ckv2knpwgs5c2k2g.png)
The last and probably the most interesting part to see, regarding startup times, is building a binary with GraalVM. I highly recommend using *sdkman* (https://sdkman.io/ - an SDK manager that makes it a breeze to install and switch between Java versions.), and it should be as easy as `sdk install java x.y.z-grl`, after checking available distributions, and then `sdk default java x.y.z-grl`.
Once you have your GraalVM, run `mvn package -Dmaven.test.skip=true -Pnative`. It might take a little longer than you'd expect, as there's more work happening at build time now, but this is a topic I'd like to address in another post.The generated binary will be sitting in the *target folder*, ending in '-runner'.Let's try it out, by executing it like any command: `./target/demo1-1.0-SNAPSHOT-runner`. 
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/npacnp7d68crkxf52dta.png)
The starting time is 0.015 seconds, this is the actual moment we've been building up to. This is how quick and easy it is to scale up when experiencing high traffic at certain moments of the day.

# Pros & Cons

I'll start with the cons, to get them out of the way, and end this post on a happy note.
* _New and not so well known_ - some might have reserves in trying it out right away since Quarkus does not quite have the reputation yet.
* _It will need proper migration from Jakarta EE_ - so you'll have to allocate proper resources for this.
* _Not all libraries compile with GraalVM yet_ - but it's ok for HotSpot JVM; if and when the time comes, switching should be one step away.

There might be some other impediments depending on your project's needs, but let's talk about all the great advantages you can have:
 
* _Developer Joy_ - with the hot reload, do we even need to argue in favor of this one?
* _Performance and cost savings_ - Quarkus’ low memory consumption and fast startup time translate into more efficient resource utilization and better user experience. 
* _Reliability_ - Quarkus is built on the backbone of the proven and trusted enterprise Java ecosystem with an active user community with contributions from over 180 developers.
* _Reactive/Event-driven_ - ideal for reactive applications. It utilizes a non-blocking, reactive event loop for both imperative and reactive code meaning developers can choose the right option for their use case.
* _OpenShift integration_ - Quarkus is pre-integrated with OpenShift, which is providing a thriving environment for scalability and speed, and some companies have already adopted the platform. 
* _Extension ecosystem_ - it provides lots of extensions that configure, boot, and integrate a framework or technology into your own application so developers can just focus on their code.

# Conclusions

I know that "hello world" applications are not exactly reflecting reality, but the main point of this post is to highlight the potential of the Quarkus framework. Of course, everyone can decide, based on their use case, whether or not this is the right path for them, and perhaps the crucial point will be if or when they decide to move on from Jakarta EE.
As we've seen, getting started with Quarkus is really easy, there are plenty of good reasons to give it a try in your next application and if you ever get stuck, the available documentation is surprisingly comprehensive. What a time to be alive!
Since this framework is gaining a lot of traction, in the future I would like to tackle more topics related to Quarkus, as this is barely scratching the surface, and I believe it's an interesting subject, worth discussing.

## Resources:
In my journey learning about Quarkus I have been using the following resources:
* Quarkus Fundamentals by Antonio Goncalves - on Pluralsight
* Thoughts on Quarkus by Sebastian Daschner on dzone.com
* redhat.com - Quarkus dedicated pages
* quarkus.io - guides