Using Java 9 Modularization to Ship Zero-Dependency Native Apps
steveperkins.com
steveperkins.com
It feels like the tools are almost where they need to be and finally coming together!
-Kotlin to speed up development
-Gradle as a dependency manager
-Retrofit + OkHTTP to create a type safe backend API definition
-JavaFX for the GUI components
-Gluon's scene builder if you like creating your FX views in xml, with a visual editor
-RX as a powerful library for async tasks
-Gson or Jackson as a JSON parsing library
-IntelliJ if you like coding with IDEs, for its massive refactoring capabilities
It's a lot to take in if you're unfamiliar, but together they all come to form really solid desktop applications.
For cross-platform desktop GUI apps, I would argue that JavaFX combined with Java 9 modularization is hands-down the best choice available today.
Electron is succeeding in the desktop GUI space because it tears down the barriers to desktop app development. While the author's article is excellent, when it comes to Electron, he (like most engineers) is still missing the point: the choice between Electron and its alternatives doesn't pivot on file size.
I've honestly seen only one properly written Electron app and it's VSCode. Everything else electron sucks. VSCode is not great either but it's much better than say, Atom or Slack.
But I assume these apps have spent a considerable amount of time in optimizing electron, which not everyone can do.
I don't think anyone doubts that a high-quality website wrapped in a webview won't be at least the same quality. The question is whether "web-native" platforms can do more than just be a branded browser.
For example, Spotify eats 100% CPU if I leave it open for 24 hours yet I don't think I've met someone in the last year that doesn't have Spotify running on their computer.
Shocking, when I look back at it.
Text input lag is an issue every editor has to deal with, and many go to extreme lengths to optimise it. Electron makes it far more difficult than most editors to fix, and every lag issue opened on VS Code seems to get decent attention, (and patches), and comparisons to Sublime Text.
Seems to be something I'm not alone in caring about.
Yes, then it replaces them with the barriers to web app development.
Having a beautiful, easy to develop, and easy to maintain native stack means nothing when you don't have an answer to, "How do we then reuse our code in a browser?".
Use the browser for what it was meant for, hyperactive documents.
Everything that matters is on the backend accessed via Web APIs.
Granted I do like the distinct app icon. But electron should mean more than that to qualify as meaningfully native.
So Slack gets an icon on the homescreen and possibly offline notification + notification integration with the OS.
That might be pretty limited from a technical perspective, but it's a massive product thing from a product perspective.
Also, it's possible they may use file access for caching/storage etc..
However, as mentioned in the article, "Hello World" in Go is an order of magnitude smaller. The article may be right that Java is "the best choice available" for cross-platform GUI apps, but for cross-platform command-line tools, I think Go is currently the best option. IMO Go provides the best tradeoff between ease of development, ease of distribution and runtime performance.
I just tried building a statically linked 'hello world' c++ program, and co-incidentally, the binary also happened to be 2.1 MB!
#include <iostream>
int main( int, const char *[] )
{
std::cout << "Hello World!" << std::endl;
return 0;
}
'g++ -static -o hello hello.cpp' produces a binary of 2191112 bytes (Linux x64). Stripping it of debug symbols leaves a 1.7 MB file.After all, back in the days we had 360k floppy disks, and executable written in C which did much more than just printing out "Hello world" would fit comfortably into less than half of that.
Modern C and C++ runtimes are bloated, because a 2MB executable isn't considered huge anymore and dynamic linking is common.
But you can have a 5k static executable printing "hello world" on Linux if you just trade in your stdlibc to musl. People have also managed to use musl with Rust to produce pretty small executables: https://lifthrasiir.github.io/rustlog/why-is-a-rust-executab...
And when rid of debugging symbols, even when importing the fmt package :
package main
import "fmt"
func main() {
fmt.Print("Hello World")
}
go build -ldflags "-s -w" hello.gois 1.3MB .
The library creates a full-screen webview window and lets you write UI code in HTML5/CSS/JS connecting it to the core app logic written Go. It provides JS-to-Go bindings allowing to call Go code from JS and vice versa.
The whole library is a single header file of ~800LOC with a thin Go wrapper. It supports Windows 7+, MacOS, Linux and OpenBSD.
Executables are 5-10MB in size and take about the same amount of RAM. No external libraries are used on Windows and MacOS, on Linux gtk-webkit is required, but it is typically one "apt-get" command to run.
Another question is around intercepting xls/doc responses to load them into office. Is there a way to do this with this framework?
Thanks!
Sorry, can't tell much about xls/doc. It's aimed to be a web UI for your app. Normally, you app would be a web server then. So if you want to handle certain requests and open external apps - you surely can do it.
If we "compare by Hello World" then Assembly/handwritten bytecode would win, but what's the point?
It's been a while since I've used Java to program, has the memory situation changed? or are there any other solutions for lowering the JVM memory usage?
AFAIK Java uses less ram than Python and JavaScript, only common languages that beat it are Golang and C/C++
http://www.jesperdj.com/2015/10/04/project-valhalla-value-ty...
Java applications use much less memory, unless their coders weren't paying attention during algorithms and datastructures lectures.
Compiling to small, native binaries (i.e. JRE not needed) is possible since at least 10 years ago. Let's examine this application as an example: http://sancho-gui.sf.net
/tmp/sancho-0.9.4-59-linux-gtk$ ls -hs ./sancho
13M ./sancho
/tmp/sancho-0.9.4-59-linux-gtk$ du -hs ./lib
740K ./lib
/tmp/sancho-0.9.4-59-linux-gtk$ ldd ./sancho
linux-gate.so.1 (0xf7f71000)
libm.so.6 => /lib/libm.so.6 (0xf7e30000)
libpthread.so.0 => /lib/libpthread.so.0 (0xf7e11000)
librt.so.1 => /lib/librt.so.1 (0xf7e07000)
libdl.so.2 => /lib/libdl.so.2 (0xf7e02000)
libc.so.6 => /lib/libc.so.6 (0xf7c29000)
/lib/ld-linux.so.2 (0xf7f73000)Given the already large ecosystem built on these lanuages, its unlikely they'll pivot to a JVM based system.
As others have pointed out you could compile the Java code to native code before submitting the app, the way C# apps are put in the store.
So far Oracle has shown little interest into integrating such features into OpenJDK, but the ongoing efforts to add AOT compilation to it, might become a possible solution.
Graal and Truffle are progressing along. I wonder what happen to SubstrateVM, which allows AOT of Java. I assume with SVM the binary size can be further reduced and much faster startup time.
It's frustrating how we're wallowing in problems that had already been solved for most of my career.
And server apps don't really switch that fast to newest Java release. Only now we're seeing JDK7 based things for example.
Just in case you aren't, what do you think is required for a platform to support Hi-DPI displays?
When I use a hi-DPI display (like 4K displays), a lot of old software renders text and widgets too small to see, because they were programmed to display things as so-many pixels high, without concern for DPI. It's frequently a problem with old video games, though it affects regular applications too.
Nitpick but hello-world in Go :
package main
func main(){
print("Hello World")
}
is < 1MB on most computers (900KB on windows). No need to import the "fmt" package.In my experience, Go exhibits human-scaling problems long before even dynamically typed languages and significantly before Java, Kotlin, or the like. And the arguments to deployment are defanged both by Docker and by that it's usually not the developer who picks it who ends up building the CM around it in the first place (that's why they hire people like me, and why I have had to become uncomfortably familiar with Golang, its ecosystem, and the habits of your average Golang developer: because the person running the systems it runs on is inevitably the backstop for when those programs spit the bit).
But in the five-minute-demo-to-make-production-decisions universe, it plays really well.
"The print built-in function formats its arguments in an implementation-specific way and writes the result to standard error. Print is useful for bootstrapping and debugging; it is not guaranteed to stay in the language."
Debugging symbols are over 50% of most Go binaries I see, and you don't even need them to get stack traces from panics.
Combined with `upx --ultra-brute`, you can get static Go binaries down to about 12-15% of their plain `go build` size in my experience. (This also assumes CGO_ENABLED=0)
Ita not really zero cost, but neither is an app that only has binaries for an OS you don't run.