Micronaut 2.0: a full stack Java framework for modular, testable applications
docs.micronaut.io
docs.micronaut.io
Loom will present an ergonomic alternative for concurrency that is strictly superior to futures, but it will not replace or significantly simplify RxJava[1].
Project Loom is also orthogonal to actors - it really doesn't dictate any specific concurrency model, it just provides fiber support in the JVM. We will definitely see actor libraries once project loom is released, but these are already available now, and they are not widely used. The only thing Loom can help them with (I hope) is better performance, but I don't think that's the reason the actor model lost ground in the Java world.
[1] Project Loom can be the basis for some minor simplifications, as JetBrains did in kotlinx.coroutines.flow.
Use it only if you really really have to, then check if you can't do it in Kotlin instead with native async/await syntax, and only if the answer to those questions is "no", continue to shoot yourself in the foot.
And rejoice yourself, Kotlin Flow/coroutines has a clean API that feels synchronous and that still manage to be reactive streams compliant! It's mostly perfect and project loom will be the ice on the cake! Others platforms (non JVM) really have a lot to learn in this regard
I've done some vert.x and creating new Futures all the time is a bit cumbersome, but I understand it. With RxJava it's another layer on top, and you are even more removed.
The whole non-blocking experience in java feels like there is a lot of plumbing. I know it's fast for IO reasons, but it really feels like the JVM/CPU has to jump through a lot of glue code to make it work.
We solve this problem with APIs for asynchronous or nonblocking IO.
But such APIs must be cleverly designed if they are to permit you to propagate backpressure from the downstream end of your program's dataflow to the upstream end. And handle errors in a sane way, etc.
You're wasting resources when your application is already in a state where it knows it won't be able to handle the request. Eventually the memory taken by the partially processed requests is going to exceed what you can take in (unless you cap the number of concurrently processed requests, which is also an inelastic backpressure of sorts) and the service will crash.
What you mentioned is decent for inelastic blocking synchronous processing (you can have at most X concurrent requests, because that's how many threads for processing you've configured based on performance tests and production monitoring), but you can relatively easy fill in an internal queue somewhere if it's async.
The real advantage the reactive model offers is a more powerful abstraction for data flow than futures. I found it useful than straight coroutines or async/await in cases where I had to process complex data flows or combine periodically polled data from multiple sources, but in well over 99% of the use cases for an async REST API it's an overkill.
Removing the ceremony around asynchronous I/O, on the other hand, requires language support, so your best option right now is to just use Kotlin coroutines. Or wait for Project Loom, but I assume it's at least 2 years away from a stable release.
You're mostly stuck to Rx outside Kotlin, tho.
For example, this is a Hello World API in Groovy (this is almost literally the entire Application):
@Controller('/hello')
class HelloController {
String index() {
'Hello World'
}
}get("/", (req, res) -> "hello world")
Is just as clear to me.
Not saying micronaut doesn't have things to offer, but simplicity of setting up an http endpoint isn't unique.
They were also not invented by Java, other languages like Dylan, Python and .NET actually go them first.
Actually they are like a poor man's Lisp macros kind of.
Best description of annotations I read. Literally this, a lot of times I figure an annotation is way simpler than fighting the generic system and all it's flaws.
https://www.nongnu.org/txr/txr-manpage.html#N-00B4065C
An example is given of a memoization parameter macro that you invoke simply by adding :memo to the front of the parameter list, as in (lambda (:memo ...) ...). This inlines everything; the function itself rewritten to do the caching with open code, rather than wrapped with a caching function.
TXR Lisp's support for keyword arguments is also implemented as a parameter macro, using the documented define-param-expander public interface.
http://www.kylheku.com/cgit/txr/tree/share/txr/stdlib/keypar...
This is possible because the parameter macro can introduce identifiers into the scope of the function, and rewrite the parameter list.
(This is the exact opposite of the usual pattern, by the way! if anyone's curious: https://news.ycombinator.com/item?id=23071428)
Also, from all the benchmarks I've seen, GraalVM is not a free lunch. Native images trade peak performance for faster startup times and lower memory usage. It's a worthwhile trade for some people, but not for everyone.
And yes, I know there are features like Profile-guided Optimization that can theoretically bring Graal closer to JIT in terms of peak performance, but these requires a very expensive Enterprise license ($18 per core/month).
(Of course I've found more info by searching, but my real question is: why do teams proudly make major announcements without even including a link to their project, or at least an inline blurb about it for those first hearing about it via the announcement?)
(Yours is a lost cause.)
I like to think that's just a bad marketing tactic because I can't believe that they can't explain themselves clearly.
Helidon is spearheaded by Oracle and currently fails to get some tractions. Micronaut is the baby of Graham Rocher one of the father of Grail (RoR in Groovy) and Quarkus is the baby of Emmanuel Bernard one of the father of Hibernate and supported by RedHat.
All of them run on either a standard JVM or let you use Graal SVM which compiles Java to native with roughly the same trade off as Go (latency is more important than throughput).
At my company, we have prototyped the migrating of a Go application that relies heavily of Kafka to Micronaut or Quarkus. We have found that Micronaut is less polished and more buggy than Quarkus but take it with a pinch of salt because it's just 5k of code.
Are you talking about the app you're migrating or micronaut?
I'm a go developer that is on a Java team; trying to use a framework that offers a similar experience to building HTTP services that I've seen in Go. Quarkus, micronaut and Spring boot all "look" similar to me; I went through the getting started for Quarkus and it feels pretty fast. Your comment makes me want to stick with it for now.