Ask HN: Does Java need a modern Java UI toolkit for desktop/web?
If Java had a modern UI toolkit to create & run apps natively on the desktop and in the browser, could it rescue Java Client development?
I've been working on SnapKit for several years (+) to rescue my apps from obscurity by deploying in the browser and it's gone reasonably well, so I'm wondering whether it could be more:
GitHub: https://github.com/reportmill/SnapKit
Demos: https://www.reportmill.com/snaptea/
jeff
177 comments
[ 5.2 ms ] story [ 626 ms ] threadDemos: https://www.reportmill.com/snaptea/
What limitations have frustrated you the most in working on this?
The big challenge was having to write most of a UI kit to basically abstract Swing. But there is a surprising symmetry between basic Swing+Java2D and HTML 5.
:-)
I'm really into these kinds of projects because I'm trying to create a "design language" - a DSL built specifically for UI/UX designers. The idea is to provide them with something kinda like CSS, but using their own vocabulary and mental models. My thinking is that if they can write code describing interfaces in a way that makes sense to them, then all a developer would have to do is wire it up with behavior. No more handoff or recreating UIs from design mockups.
So no, a new UI toolkit is not going to revive Java in the mainstream.
Saying "Android's UI is Java" is like saying "Apple's macOS Cocoa is x86" - technically true, but belies the sheer volume of transitive dependencies.
The new JetPack Compose ui toolkit is cleanly abstracted from Android and works on the desktop as well.
Java has two modern UI frameworks. Swing and JFX. They blow Microsoft's offerings out of the water--while being proven cross-platform.
I hope you're being sarcastic there...
Swing is decidedly not "modern" at all: its active development period only lasted from 1998 ended by 2005, and saying that Swing is "cross platform" is really overselling it because it always looks out-of-place, if not downright hideous (default skin) on every platform;
While JavaFX is/was so unpopular that it was removed from Java SE and Oracle will stop supporting it by 2025.
Otherwise, JavaFX was axed from the JDK because there is absolutely no reason to tie a frontend lib’s lifecycle to that of the JDK’s. Swing could not be axed due to the insane amount of dependencies on it, but JavaFX has it in a way, better as being developed separately.
And even though it is not huge in terms of marketshare, it is doing good with proprietary solutions, cross-platform compilation to web, desktops, and both android and ios being available.
Truth is that the only advantage Desktop Java has over electron is that it is a bit faster and less leaky, but the advantage above Qt is only that you don't need to learn C++.
This doesn't affect the uselessness of client java as competition has also improved and java doesn't offer anything extra. If you want it quick & dirty you use electron, if you want to have it nice & smooth - QT. Desktop Java is neither a fish, nor a crab in a way.
Indeed, I'd argue that apps like IntelliJ are exactly why nobody wants Java on the Desktop. I had to buy a computer with more RAM specifically because IntelliJ uses so much. Even Electron apps aren't so bad with regard to RAM usage.
Intellij would require notable memory and cpu regardless of whether or not it was Java. See XCode and Visual Studio for comparison, as they are probably closer to the same feature profile than something like VSCode would be. Their memory footprint and performance is not what I'd call substantially better than Intellij (and as with most comparisons of this nature, many caveats exist around which plugins/addons/features are in use).
Would Intellij have a better resource profile if it were native? Ya, possibly, but it's also possible that another language/platform would have been a significant barrier to long-term success. Not many cross-platform UI toolkits from 2000 to choose from, and many fewer have continued to be well-maintained and usable today.
I haven't used Visual Studio, but I think IntelliJ comes out pretty unfavourably in comparison to XCode. On my machine XCode would only slow it down when it was actively compiling (which I would expect from any compiler - it uses pretty much all of the resources of the system), whereas IntelliJ would slow it down just having it open in the background. I had to close down everything else when I wanted to use IntelliJ, or deal with a laggy system. The only other app that had a similar effect was Figma.
It's like a carpenter using a hatchet because a bench plane costs more money.
Also keep in mind what IDEA is doing with that memory. It's storing indexes to all your code and libraries for near instant bidirectional navigation and search.
Also be weary of supposed high memory usage with Java. The JVM will allocate memory from the operating system for the application but then not actually use it. It's doing this so that in the event the memory is needed, it's already been allocated to the process. I've seen other apps increase the overall memory load and the JVM then relinquish it's pre-allocated-but-unused memory.
https://docs.oracle.com/en/java/javase/11/tools/jlink.html
There's projects like deno and esbuild that should help mitigate those issues, and Yarn's Plug'n'Play to reduce file amount and size overhead by using .zip files and centralized repositories. I mean it's only a patch but still.
Every organization with whom I've been affiliated since 2017 has a fairly strict policy of dependency audit. Dependencies are NOT allowed to be added unless there's a really good reason. And even then, we pay a lot of attention to what that dependency will bring with it.
Satire is dead...
Maybe I’m getting old but I’m a bit sad for all the open source apps that where abandoned over the years because the tech stack stopped being cool.
Hell, websites don’t hold up as well to time with all the missing links/resources.
https://duktape.org/ https://github.com/webview/webview
"Blazor", actually.
I can only assume web technologies and electron got popular because all of the Desktop platforms where trying to jump to tablets and phones and whatever else they considered new and shiny so that while web tech was a terrible stack it was at least stable.
P.S.: I sort of hope for Griffon to make a come back. Griffon framework + Groovy + JavaFX looked nice to me.
No no no. Web tech was/is terrible, but it's dirt cheap. You can hire JS hacks by the boatload, and retrofit whatever they build into an electron app relatively easily. Whereas desktop developers are few and expensive, and they tend to optimise for this or that platform or toolkit.
Electron didn't win on quality or features - it won on the back of commercial realities of the development world.
Even way before they came out I wondered why more native apps didn’t just reuse HTML/CSS at least (many did).
Of course we all know of the downsides of Electron (basically Chromium + An App in every app; ridiculously heavy-weight.
I’m fond of the webview project and Tauri, being built on top of it. It reuses the available system browser view and doesn’t bundle Node, so it’s very light.
It's 'light' in terms of download size, it's not far off from Electron in terms of resource usage. Most complaints about Electron are about resource usage, not really download size (though there are some).
As problematic as CSS is, getting things in the right place is still dramatically easier than with Swing LayoutManagers, and when you do have problems, you have great tools in the browser to explain what's going on.
Browsers particularly shine in text rendering, naturally; text styling, font selection, word wrapping, etc. are all easily configurable. You want bold text next to regular text in Swing? You either need two JLabels, or you wrap your text in <html> tags and let the embedded HTML 3.2 renderer do it.
JavaFX has much more intuitive layout for apps than HTML and also has CSS. So you can get the best of all worlds. HTML5 has been trying to catch up with CSS flex-box, but it's all just retrofitted and shows.
Also, word wrapping? HTML is quite terrible to read compared to Latex-rendered text so I wouldn’t say that it is all that good in fonts either.
I mean, people seem to put up with electron these days, and the few modern JVM GUI apps feel generally better than electron stuff (for instance the all-pervasive UI latency that you get with things like vscode and slack is largely absent from IntelliJ).
Most complaints about UI toolkit in "Java" are really about the JDK, its startup time, and the fact that the UI toolkit in the AWT/Swing days never closed the gap with native apps.
Kotlin would just be using the core library UI (or android UI API), so it's no real advantage.
Kotlin compiles some of these newer features’ equivalents to java 8, that’s why it is used. But that is a failure of android, not of Java.
Yes there are still niche domains that would need a desktop app but those are probably more rare as time goes on and/or already have established players.
Web apps also have major downsides. It's easy to forget about them as developers, but for example, one is the lack of versioning. Someone pushes a new version of the app that's buggy/an UI downgrade/causes an outage and the users can't do anything about it.
Often you want an app to be local because it's interacting with local data, or local hardware, or it suffers from latency, or you don't want your data to go outside your jurisdiction, or it's doing something else where distance between you and the app is problematic.
Client side apps written using normal toolkits (not HTML) have a lot of major end user advantages, which is why:
• Mobile apps beat web apps, despite devs trying to make users accept them (recall the history of the Facebook app for example).
• HTML5 keeps sprouting features that desktop apps have had since the beginning. Filesystem access is a recent example.
Any time you want your data to be independent of the apps that work with it, web apps just faceplant.
In my view developers push web apps on users usually for our own convenience, e.g. being easier to bypass IT department bureaucracy. But there's a lot of ways to do better than web apps, and yes, the JVM is pretty good platform to do that on (JavaFX is a great toolkit for instance, and JetPack Compose is very interesting). What it needs is a great distribution and update solution.
Pushing buggy/UI problematic software is a process/people problem not really a technology problem. I would bet the feedback loop for getting fixes in on web apps can be much shorter than client desktop apps (or mobile). Once a fix/change is tested we can have it out in production on a web app for 100% of users in 20 minutes.
Stand-alone apps are a great niche where the native UI kit or other UI kits that work for the problem being solved are a great solution, there isn't a need for web tooling.
An extreme example of where this matters is in the military. You cannot have an army in battle being brought to a halt because some web dev pushed a syntax error in a PHP file. You must have a qualification procedure that tests it in the scenarios that matter, which the developers may not even understand all that well.
Another example is medical software. If you push an app update to equipment in an operating theatre and a button stops rendering because the doctor had the font size wound up higher than expected, then people might die. You just cannot do that. Heck you cannot even allow it to depend on working internet. It has to be a desktop app (well, embedded, but a lot of embedded apps are just desktop apps on kiosk mode operating systems).
Now you're right that if you do push a bug, then due to all the data collection and the way browsers commingle data and code, you can fix things faster than the slower more async process preferred in the desktop world. But there's no fundamental reason it has to be that way, it's just a question of social norms. You can make a desktop app that can be force updated immediately or even on a per-screen basis. People just don't do it because often if you're writing a desktop app in the first place, it's because your users want or need more control than a web app would give them.
https://github.com/HumbleUI/HumbleUI/
This gave java a reputation for sluggish UIs which would mysteriously hang. In an era where new CPU generations provided meaningful performance improvements to client applications, why would a developer commit to a platform which rolled back the clock by 2 CPU generations?
Then Java 9 came out, but 8 didn't go away, so you needed both.
Btw the demos are really good.
https://github.com/edvin/tornadofx
Before I worry you too much let me tell you that I’m not at all religious about programming languages. It’s just that using the same language for the front and back end is very convenient, and now that Typescript (and Node) are actually good enough, also possible. Which leads me to the point I want to make here. Over the years both C# and Java have also gotten much, much, better. But because programming languages and environments in general, have become much, much better, there is rarely a reason to chose a technology based on its tech-specs. Heresy to most people, I know, I know, but we aren’t Netflix. Our most expensive resource isn’t how much iron we burn in Azure, it’s our developers and the speed at which they can deliver reliable and safe applications.
I think it will become increasingly hard to “bring developers back” in this world. Because why would we come back? .Net has seen some really awesome innovation in recent years, and is still seeing it, and yet we’ve moved away from C# and onto Typescript (still benefiting from a lot of .net stuff in azure functions), and .Net moves much faster than Java. So I doubt it, but I hope someone makes it anyway.
Clojure + ClojureScript has been doing the "same language on front and back" as well for a long time and a lot of the developers were not working on JVM platform before getting into the language.
I think it's not a battle of languages exactly, but of battle of runtime platforms, like is now evident on the JS side as well. Kotlin and TypeScript are the mass appeal examples of this lately. But I think Clojure is the stand out one so far that is good at covering both backend/frontend and crossing between runtime platforms (JVM and JS).
Java does a fine job on the backend. It honestly shines there. So let it do that. And let the modern front end platform (the web) do what it's good at.
It's close to malpractice, however, to develop desktop applications at all in 2022. That is, you can write a web application, upload it to your server and you deployed a web application.
If you write a desktop application that's just the beginning because now you have to do the installer engineering, possibly deal with cross-platform problems, possibly deal with different versions of the same platform, etc.
Another thing we forget is that web browsers are on an entirely different level than other GUI applications because a web browser is designed to stay responsive to the user when loading multiple streams of data over a slow network. Contrast that to desktop applications where the "beachball" or whited-out windows is normal and unavoidable. Browsers are still written in C++ by the most advanced software development organizations because you just can't manage that in a managed language.
If you develop for a browser or a browser-based environment like electron you can take advantage of all that work... Even if it means using a maddening async I/O model.
I too was disgusted with electron's "bloat" but when I went looking for a cross-platform GUI framework I looked at gtk, tk, qt and many others and compared to electron it was like going from 1850s technology to 2050.
If desktop development is "malpractice", this is actually a clear-cut case of slander and libel.
Beachballs are absolutely avoidable, with some basic thread management - which is fairly trivial in any half-decent modern toolkit.
If you like, structure your desktop app as two threads. One does the UI. The other does processing stuff. Exchange only messages back and forth. I've actually written a desktop app this way in the past. However it's not the silver bullet you might expect, largely because expectations users have for desktop apps are significantly higher than on a web app. In particular they expect something obvious to happen when they click buttons or menu items, and they definitely don't expect long delays simply because the backend is busy. So I ended up having to introduce some shared memory and read/write locks back again, as the pure message passing model was occasionally introducing UI stalls. In a web app you'd just ignore them because standards are low. On the desktop it's like on mobile, you have to care about the responsiveness a lot more.
The funny thing is that, despite thall this, often those piles of hacks are still compared favourably with Electron apps and browser-based apps.
Agreed that beginners using desktop GUI toolkits often make the mistake of putting long-running code in a button press callback, and then the GUI freezes.
But it's pretty easy to avoid this, so long as you know about it. If you're doing network/IO related stuff, make your callback async and await the data. GUI toolkits often have an event loop built in that can run user-supplied async code. If you're doing CPU intensive work, spawn a thread (maybe in a threadpool), and send data back to the GUI thread over a channel (the GUI thread uses async callbacks to check the channel). Not as easy as async, but often GUI toolkits encapsulate this into some kind of "Task" object for you that can take out some of the boilerplate.
It's still a chronic problem with major applications from vendors like Microsoft and Adobe because their applications (Office, Creative Cloud) have complex internal state that needs to be managed. The easy way to do it correctly is to put one big lock on the shared data structures which means a minute of beachball at boot and the app locking up periodically.
The counter to that in the asynchronous world (web browsers, electron) is that you search for something and you always see "0 search results" before the search results load. Even when I manage to banish this from an app by putting loading indicators in all the right places somehow this gets lost as soon as another developer patches something. Yet that's what you get when you trade the "dead by default" behavior of desktop UIs for "live by default."
The discipline and effort required to build the proper framework-level abstractions to be portable to future UI toolkits is extremely impressive.
And unlike some other projects, most of the demos are non-trivial, substantial apps. Even Swing doesn't have demos like these.
Congrats, Jeff!
If it doesn’t have that at a minimum then it’s basically a non-starter for business use.
I've put a part of the sentence in quotes because actually they've written a new desktop backend based on skia for the already existing Android Compose UI API.
Different OSs have different norms, expectations and design languages.
What I'd like to see is something that abstracts as much as it can but still allows you to make something look like a native app on that platform. That would mean you'd need to do some programming for each platform but honestly I don't think there's a good way around that.
The solution isn't Electron. Way too heavyweight. Wayy too resource intensive. Way too risky by having a huge attack surface.
An additiojnal problem with Java is bundling such an app. Requiring a JRE on a target platfrom is (IMHO) a big problem. They're far from universal now. Something that compiles to a static binary. There have been efforts to create self-contained standalone packaging for Java applications. My understanding (which may be incorrect) is that all of these solutions are still somewhat suboptimal.
Then after that maybe add a cross-platform toolkit that doesn't try to look or feel local, but treat that as a peer with the other UI kits, not a replacement.
Sorry, but the problems you are talking about are first-world problems imho. If the button looks like a button, and clicks like a button, what is the problem really?
platform design choices are much more than the look of a button. it's choice and arrangement of ui elements, navigation systems, metaphors, ...
if you just see it as "button on windows" vs. "button on macos" it's not that obvious, but think about how you'd design an email client on windows vs. command line vs. mobile phone vs. smart watch.
a simple "button" might be roughly the same on every platform, but the overall design would be quite different.
it happened all the time when almost all of the graphic designers (which were thrust into the roles of UI designers) were on mac and usually ios but got the task of "designing an app", which meant _one_ design for both ios and android. as an android developer i had to fight the OS, the framework and pretty much everything else to make the designers vision work, which resulted in buggy apps that felt unintuitive to use.
E.g. visit https://twitter.com/ and select Sign-up. I don't know what OS you are on, but the sign-up box probably doesn't look native. Users accept this. So what is the problem, really?
It's better to have one developer per platform, than two (or more!) working on a cross-platform application. And you get true native applications; think of things like accessibility options, which are often overlooked in cross-platform toolkits, or performance.
https://git-fork.com
SWT (the UI library which drives Eclipse) would give you that on Windows, OSX and Linux. But it's not exactly light-weight...
Exactly this -- every cross platform GUI toolkit ends up falling into an uncanny valley where it looks sort of native but subtle things are just off.
This is, I think, a key part of Electron's popularity. Apps made with Electron are so very obviously non-native that they avoid this uncanny valley effect.
You can try pursuing it, but it is a field littered with the dead project before you that have tried the same thing. Xamarin, Flutter, Qt, React Native, the list goes on. Some of these projects are mostly-dead, others are heavily used but no user is actually fooled.
I would propose something different: for Java to develop their own design language, which has "good enough" native platform integration but otherwise doesn't try to pretend. Cross-platform platform users generally belong into two camps:
- Ok with something that appears visibly different from true native apps, but the cost savings are worth it and the users don't care so much about native-feeling-ness.
- Under the expectation that their cross-platform app will be so good that it is totally indistinguishable from a true platform-native app.
My contention is that Java (and other xplat projects) should focus on the first group; the second group is not worth serving because it has always failed, and will always fail.
The problem with the state of Java GUI development isn't so much that it fails to emulate the native platform GUI sufficiently, it's that it's ugly and janky. Improving it should be the goal.
JavaFX is not that?
It used to be so consistent and poweruser friendly.
Windows 11 has just broken a lot of the poweruser keyboard shortcuts for doing things, on top of all their ads, nagware, telemetry/stalking and various antifeatures, it's like they are begging power users to go to Linux.
Yes, I’ve long thought this as well.
I think it’ll take an entirely different approach than cross platform UI libraries typically take — rather than implementing widgets itself, it would have the developer provide a somewhat loose “UI spec” document that then gets compiled into a UI befitting each target platform. Not only widget appearances and behaviors would vary between platforms, but also window layouts. The only exception to the rule of not implementing widgets itself would be where one platform lacks a widget to avoid least common denominator problems (for example, WinUI and GTK have nothing resembling Cocoa’s miller column NSBrowser control, so those platforms would get an implementation of that view built from other native controls).
It wouldn’t fit every use case since it wouldn’t provide down-to-the-pixel control but it would work for a lot of software.
TeaVM converts Java code to run in the browser. It provides the ability to call JS functions to access browser features like canvas and XHR. However, unless you want to be coding like Vanilla JS, you'll want a framework on top. SnapKit provides that.