Poutsma Principles Consulting & Training

From Look and Feel to Idioms and Style

One of the promises of Java, when it was introduced, was Write Once, Run Anywhere. This promise applied as much to user interfaces as it did to other code. With Java AWT, developers could create applications that offered a reasonable degree of fidelity to the underlying native windowing toolkit.

AWT was not alone. In the mid-to-late nineties, several frameworks emerged to offer cross-platform graphical user interfaces: Qt, wxWindows, and later Swing.

The upside was that these frameworks allowed desktop GUI applications to be distributed beyond Windows, which dominated the nineties, to less common platforms such as the Mac.
The downside was that applications built this way were never able to perfectly simulate the native look and feel of the operating system. At worst, you got a Frankenstein of user interface design.

There are exceptions—JetBrains’ IntelliJ being the obvious one. But nowadays even IntelliJ no longer tries to mimic a native desktop application. Instead, it embraces a consistent, custom look and feel across platforms.

Why? Because web and mobile apps have changed expectations. Despite the continued existence of design guidelines, most phone apps no longer rely on native widgets. Instead they introduce their own, consistent across iPhone and Android. The same holds even more true for the web. Seen in that light, it is not surprising that the modern way to create a cross-platform desktop app is simply to build a web app and bundle it with a browser engine, i.e. Electron.

I have written previously about treating APIs as a kind of user interface, and I am going to make another comparison in this post.


The Java Virtual Machine was not designed to run polyglot code, but it grew into that role with Jython (1997), JRuby (2001), Groovy (2003), Scala (2004), Clojure (2007), and Kotlin (2010).
Some of these were attempts to bridge the JVM with other languages, while others—Scala and Kotlin—were designed specifically for the JVM.

Of the two, Kotlin has embraced the Java ecosystem much more than Scala. In my experience, while you can use Java libraries in Scala, it is often frowned upon. A “pure Scala” library such as Slick is generally preferred over a Java library like Hibernate.

Kotlin, by contrast, was designed with Java interoperability in mind and feels much more at home on the platform. It is common to use a popular Java library such as Spring, even when a Kotlin-native alternative exists (Ktor).

Despite starting as a JVM language, Kotlin has since become cross-platform, targeting JavaScript and native code as well. The goal is to let developers use one language consistently across platforms—just as IntelliJ now delivers one consistent look and feel across operating systems.

Still, Kotlin and Java continue to evolve in parallel. The Kotlin team must bridge the gap between features—for example, mapping Kotlin data classes to Java records, or aligning Kotlin coroutines with Java Virtual Threads. It will be interesting to see how the relationship develops, knowing that each new feature Kotlin pioneers risks drifting away from a similar future feature on the JVM itself.


For the last couple of months, I have been working on Embabel, an agent framework on the JVM that mixes LLM-prompted interactions with code and domain models.

Although written in Kotlin, Embabel is designed to work just as well in Java environments. In future posts, I plan to share what it takes to build a framework that feels at home everywhere: usable, and idiomatic in both Java and Kotlin.

About the Author

I am Arjen Poutsma, and I help teams improve Java code, design better APIs, and manage open source—through reviews, training, and coaching. If that sounds useful, please contact me.