Java records should be no longer considered as a “new concept”. Introduced in early 2020 (with version 14) have already been adopted in many projects and organizations. Yet, while we all know that they provide getters, equals, hashCode, and toString for free, there is one feature that still feels a bit unknown. Let’s see how compact constructors can help us write more idiomatic code.
Record construction Recent versions of Java come with concise syntax for declaring records:
When bytes
meet Mike
Hi! 👋 I'm Mike, a.k.a @mikemybytes, building distributed systems for fun and living. While I specialize in JVM technologies (mainly Java, Kotlin, Spring), my professional interests go far beyond that. Let me show you what I found interesting!

We want our applications to be maintainable, reliable, resilient, and scalable. All these features seem to share the same idea: being flexible. This flexibility is often manifested in the early design documents close to the buzzwords and technology names. But that’s only the marketing. The true test of flexibility comes with the first go-live. “Production will verify” as my former colleagues used to say.
Flexibility is usually a good thing. It means being able to adapt.
Running tests sequentially seems to be the current status quo in the Java community, despite the number of CPU cores our computers have these days. On the other hand, executing all of them in parallel may look great on paper, but it’s often easier said than done, especially in the already existing projects.
With version 5.3, the JUnit framework has introduced experimental support for the parallel test execution, which can allow selective test parallelization driven by the code.
Parameterized tests are definitely my favorite feature of JUnit 5. Defining multiple sets of arguments for the same test can significantly reduce the amount of the test code. Recent additions to the JUnit 5 enable us to write such tests in a whole different way, improving both readability and expressiveness.
This article won’t be yet another primer/overview (like this great introduction from @nipafx). Instead, I’d like to show some not-so-obvious ways of defining test inputs in an elegant, tabular way with JUnit 5.
While browsing Twitter a few days ago, I’ve been reminded about a quite controversial topic in the Java community, which (apparently) still is using interface default methods. To be honest, I’ve been a bit skeptical as well when I’ve first seen them coming as a part of Java 8. However, today I’ll write a few words in defense of default methods, as when used carefully, they can turn out to be extremely handy.
The world has changed quite a lot since 1999 when Eric Brewer formulated his famous conjecture, known as the CAP Theorem today. Back then, the systems were running mostly on a self-hosted and rather expensive infrastructure, often related to the software components in use (due to licensing, etc.). A proper understanding of availability & consistency trade-offs in the presence of network partitions was simply yet another responsibility on the list.
There seems to be a lot of interest in improving application startup time these days, driven by the discussions on languages and technologies (like Go, Node, or GraalVM), that provide almost instant startup for serverless functions (a.k.a. lambdas) being run in the cloud. However, such a speedup brings benefits to other types of processing as well.
In this post, I’d like to present a different perspective on the topic of application startup time.
Syntactic sugar (like the introduction of var) is often not enough to convince somebody (especially non-developer) to move forward. This is one of the reasons why Java 8, almost 7 years after its first release, is still widely used. However, many things have improved apart from the syntax. When taking all of them into account, it may turn out that you can’t afford to run Java 8 anymore. And no, I don’t mean migrating the code, but simply updating the JVM used as a runtime!
What could be kind of surprise even for some experienced Java programmers, the java.util.Stream interface extends java.lang.AutoCloseable. This (in theory) puts it on par with files, DB connections, and other resources requiring manual closing. Should we close all our Streams in the same way as any other resources?
In this post, I’d like to explain which Streams have to be closed and how the closing actually works. We will also go through some of the interesting under-documented properties of this feature.
Apache Kafka has been designed with scalability and high-performance in mind. Thanks to its architecture and unique ordering guarantees (only within the topic’s partition), it is able to easily scale to millions of messages. However, there are some specific situations when using a topic with just one partition (despite being against mentioned features) might be a valid and simple solution to some complex problems of the distributed world.
In this post, I’d like to describe the so-called single-partition topic pattern and to list some valid use cases for it.