Unless you consider that basic support services are what the Java runtime should be providing on its own. Fundamentally, a command line Hello world should only take a few dozen bytes of bytecode.
The 11MB is (most likely) 11MB of the Java runtime (compared to 200MB for the full runtime which includes all the classes required by the standard library) + a few dozen bytes of bytecode.
Plus, you can strip down the Java bytecode even further using ProGuard, but convincing it to not delete code that's actually used is an error-prone dark art.
I've been hoping that a community project would come about to break java.base into smaller modules. Even if there are cross/circular dependencies, I wouldn't mind if many methods were stubbed out or just removed if I promised not to use them.
Yes, you can get smaller binaries using compile-to-native languages. But speaking as someone who had to install the JVM and our application on clients' computers, this is way better! You don't need to be the best to be good.
We've been counting the number of apps that use Electron at work (Windows machines) - ok, Microsoft Teams, Visual Studio Code, Slack, and few others!
Now all engineers are "angry" :) :) :) after seeing the same process spawned multiple times, and taking lots of gigabytes!!! (hehee)... I simply don't care and love the Slack app! (Teams is also nice looking, and Visual Studio Code rocks)
Well, I mean on my Arch Linux system libc is ~2M, so that's not exactly trivial either. The only reason hello world can be so small is that all the stdlib code already exists on your system -- not so for Java[1].
Of course there are far smaller libc implementations, but they may be missing functionality.
[1] Unless, of course you require an installation of Java... which would kind of go against the premise of this whole exercise.
so if the jvm is installed in your system, 11M out of the 11M in the example (since it includes the cut down jvm) is irrelevant? Then all you need for the example is a 1k .class file.
Note no NEEDED section, so we're indeed fully static.
# strip /tmp/hi
# du -hs /tmp/hi
16.0K /tmp/hi
16K for a fully static hello world sounds pretty decent to me vs 8k for dynamic. Will be faster than involving ld.so as well. I could probably improve that further, but I'm not about to golf this tonight.
> isn't this only true for the first time a function is used?
Yes, but it will happen each time the program loads, which means your LD_* variables will get parsed/iterated over. Statically linking stuff in can help if you have a program that needs to be exec()'d in a loop. While it'll probably only shave off 0.001 seconds per exec() call it can add up, more so if you have LD_LIBRARY_PATH set to look on some slow storage like nfs.
But its a bit of a hyper optimization at that point. I've used this to really annoy a c++ developer saying c++ was faster than c. Evil trick on my part but my euler solutions were always faster. >.<
Side Note: Nice to see you here. Thanks for your Alpine GHC package :) My Scotty+Haskell+Alpine service is the lightest container in the fleet. It's only using 1.3 MiB of RAM!
You're welcome! I made it more because I wanted a static pandoc binary. The rest came along for the ride, glad to hear its of use!
That said I really need to get back to debugging the segfault in building ghc 8.2.2 on armhf in the ghc rts. But its gotten me going through everything but ghc and whatnot. Annoying when things worked before and don't now. Even weirder that only the final stage build is at issue, the other two are fine.
Of course, and given the "crowd" I should probably have added a caveat about glibc[1], but using a non-glibc is pretty non-trivial for many developers (and thus, eventually, distros).
Even if you don't buy that reasoning, it's just not very common to use non-glibc on most common distros.
... and honestly, I should probably just have been more explicit about the absurdity of comparing "hello world". That would sort of agree with the OP's post, but not for the same reason. I think reasons are important.
[1] ... but then you end up with discussions about the importance of locales, nsswitch, etc. etc. Even though I didn't bring it up, it necessitated this footnote. You see what I mean?
Dunno if I'd call Java native. This is more like zero-dependecy Java apps — aka, you don't need to pre-install the JVM (and its "optional" adware on Windows).
I think it's reasonable to say that if the the user code is transmitted as a managed intermediate representation then it's not native. Arguing beyond that probably isn't productive.
But that's this particular blog post. Java can be native, if you compiled all the user code to machine code ahead of time.
If the VM is shipped as native code and the app is bundled with it as "code" that runs on the VM, is that fundamentally different from shipping an app written in compiled-to-machine code that bundles some data (JSON, XML, a SQLite database, etc.)? It definitely "feels" different, but I'm not convinced that the former is not "native" just because more of the logic is in the data rather than the machine code.
So, anything that uses a JIT, such as the LLVM JIT, is not "native"? Are programs written in C# not native, even on Windows? Are programs in Java for Android not native, even though it is the language much of the OS is written in and what the standard UI toolkit is built for?
Seems like lots of projects are likely to become non-native over time, by this definition, even if they start out "native" with a basic C/C++ codebase, since lots of projects accrete some sort of scripting or extension interface that might use a runtime of some sort. Is Emacs not native? Does it really matter if the runtime (which is machine code) was made by the compiler developer or by the application developer in some cases?
I feel like there's an arbitrary line, and it's not entirely useful distinction to make.
A native app can be big and slow and ugly and fail to follow the OS UI guideliness. An app with a runtime can be small(ish) and fast and beautiful and strictly adhere to the UI guidelines for the OS in question. I want the small, fast, beautiful, app with standard UI behavior, no matter whether it's delivered with a runtime embedded or built from C/C++ (and a few others) and without a JIT.
I mean, we're just arguing semantics here, which is kinda silly. I think it's pretty neat; I don't really like working in Java, but I'd rather work in Java than C/C++, so if I needed to deliver a cross-platform GUI app, I'd certainly consider it.
LLVM IR is transformed into native code only once. You don't ship the assembler to your users for a C program.
Of course the JVM has advantages that it can dynamically optimize code according to actual execution profiles.
If I am not mistaken with the right instrumentation LLVM can also makw your program generate a special optimization profile which you can then apply to your final build compilation.
> Are programs written in C# not native, even on Windows?
Well I think that's a different meaning of the word 'native'. They're native in terms of being written using the recommended techniques for that platform, but not native in terms of being natively compiled.
But as you say it's just a discussion of semantics.
> So, anything that uses a JIT, such as the LLVM JIT, is not "native"?
Correct.
> Are programs written in C# not native, even on Windows?
No they are not, because .Net uses an intermediate representation, being Windows and Microsoft confers no magic "native"-ness.
> Are programs in Java for Android not native, even though it is the language much of the OS is written in and what the standard UI toolkit is built for?
Programs in Java for Android are not native.
Much of the kernel (Linux) is written in C. According to "Francesco Iovine, AndroidStudio lover" over at Quora[0] the UI toolkit is written in Java and the virtual machines (Dalvik and Art) are written in C++.
> Is Emacs not native?
Emacs is a strange and evil beast whose name we shall not invoke. No, but seriously – I imagine Emacs is a hybrid native / Emacs lisp program. Many programs with embedded scripting languages are hybrid beasts but they ought to be thought of as native apps if they are compiled for a certain bare metal hardware platform. I presume the core of Emacs is C. Ergo, native.
> Does it really matter if the runtime (which is machine code) was made by the compiler developer or by the application developer in some cases?
Yes, I believe it does matter.
> I feel like there's an arbitrary line, and it's not entirely useful distinction to make.
No, I don't believe it's arbitrary.
> A native app can be big and slow and ugly and fail to follow the OS UI guideliness. An app with a runtime can be small(ish) and fast and beautiful and strictly adhere to the UI guidelines for the OS in question. I want the small, fast, beautiful, app with standard UI behavior, no matter whether it's delivered with a runtime embedded or built from C/C++ (and a few others) and without a JIT.
True. But that is neither here nor there, that's a whole other issue.
> I mean, we're just arguing semantics here, which is kinda silly.
No, we are not. A native app is one which is either hand-crafted assembly for a specific hardware platform or compiled ahead of time targeting a specific platform. Native code is non-portable, the source code might be portable, but generally is not unless care is taken. Assembly code is never portable. Non-native (whether by VM: Java, C#, … or interpreted: Ruby, Python, …) tends to be more portable.
Suppose I write a C program and then deploy it on a target machine where it is continuously running thereafter. Then I develop a loadable module (.so) which I compile, upload to the target and get the C program to load it with dlopen. Is that native or not?
If it's native, why isn't JIT to machine code not native? Because of the convenience of all of the above happening on a fine-grained level (individual functions), and all on the target machine?
Also, what is "compiled ahead of time"? Ahead of what time? Why is that specific time important? Obviously, code is compiled ahead of its compiled image being run; the compiled version cannot be run any sooner. Any JIT-ted function is compiled ahead of being called.
On most operating systems, we can load programs after the OS boots. Those programs can be developed after the OS booted.
I think that the only true definition of "native" is that the program image was compiled before the hardware was built and turned on for the first time, and was present in its ROM.
Anything else is not "ahead of time" and not native, damn it!
Installing a program on your PC is just a form of JIT. The system was fired up without that program being there, and the program was snuck in just moments before the user's intent to use that program. Not ahead of the True Scotsmans proper time: the time when components were stuffed into the circuit board and it was powered up.
I think you're looking a bit too manically for holes in what is a pretty informal term that's useful in everyday discussions. It's not a mathematical proof that you're a genius for finding a gap in.
The term is misused. Native means "native machine code", in any shape or form with no interpretation layer in between. OP seems to be confused between native vs. non-native axis and monolithic/static vs. modular/dynamic.
If the software image is compiled in its entirety before being installed on a target, that is "monolithic". If parts of it can be dynamically loaded, it is "modular". Dynamic loading of functions with JIT is just heaping on more modularity: hyper-modular.
A situation involving JIT is non-native only in the sense or to the extent that there is non-JIT-ted code in the image. If there is an interpreter so that some things execute without being JITted, those things are not native.
I don't believe that the term is not misused. What is happening perhaps is that you disagree with the term. And that's fine, that's your prerogative. I don't think that I am confused.
“Each program that is compiled on IBM i gets turned into a set of TIMI instructions. Essentially, it gets compiled down to a set of intermediate code. For decades, that’s been a pretty common step for a compiler to take – get to an intermediate representation of the program before creating the machine-level instructions. One big difference, though, is that the compiler on IBM i does not go any further. It leaves the intermediate code connected to the program object, and then the lower levels of IBM i act on the intermediate code to translate it into the instructions used by the Power hypervisor and Power processor beneath the OS. IBM i does this only when necessary, not every time the program executes. Typically, the translation takes place once when the program is moved from one release of the operating system to a later one, and never again while it runs on that later release.”
> Java is AOT compiled to native code on installation on Android 5 and 6.
Then by your reasoning and terminology I think you'd also call IBM's tech AOT compiled, not JIT'd given that it happens once per OS release or app move, not each time the app is executed.
And I would say that the applications that get delivered this way on AS/400 and Android 5 and 6 are delivered as non-native (intermediate code as the article says). And then get translated AOT to native which is stored somewhere else and the non-native code is kept around.
Neat, I didn't know that about Android 7 and Dalvik. Is it the same for Art?
> There are AOT compilers available for Java and C#, just as there are interpreters for C and C++.
>> So, anything that uses a JIT, such as the LLVM JIT, is not "native"?
> Correct.
Oh, come on. You can't seriously believe this nonsense. A native C++ program embedding (for example, to parametrically specialize some constructs at run time) an LLVM JIT which is in C++ again is going to be as native as they come.
> I presume the core of Emacs is C. Ergo, native.
And that C++ program I mentioned isn't, according to you, even though most of Emacs is delivered in interpreted byte code form. And if Emacs stated JITting the bytecode, it would cease being native. You really seem to have some weird and/or inconsistent definitions.
> Are programs written in C# not native, even on Windows?
C# always had AOT compilation to native code via NGEN.
Just that few people bother to use it, because it only allows dynamic linking, the optimizer is tailored for fast startup time and requires an extra effort with application signing.
Windows 8 apps were always AOT compiled on the store via a "cloud compiler", based on Bartok from Singularity project. Using a format known as MDIL.
Windows 10 apps are always AOT compiled via .NET Native, which shares the backend with Visual C++.
Mono always supported AOT compilation and it is the way Xamarin apps are deployed on iDevices.
Native used to mean machine code for the hardware but there's so little of that nowadays that I think people often use it to mean anything that's more tied to one platform than a web app so it's a bit ambiguous.
To be more precise, smaller zero-dependency Java apps --- the practice of bundling the app.jar with a JVM, into one file you can download, unzip, and run immediately, has been around for probably as long as Java itself.
I'm not obliged to. I just wanted to help the previous commentator out because I knew this would earn them negative karma for what could be a constructive discussion.
I'm pretty sure you would have gotten replies if it was just worded "Does anybody know any possible benefits of using gradle here?" or the like. I don't think it's much more than that.
That would also significantly narrow the scope of the question to something that's actually answerable. "but why gradle?" is basically impossible to decide between "are there advantages to using gradle here", "gradle is abjectly terrible, why are you even using it", "gradle isn't available when compiling on an android device, why don't you use something with better platform support" or any number of more/less extreme/trollish questions/"questions".
Is worth mentioning that SubstrateVM (https://github.com/graalvm/graal/tree/master/substratevm) is now open source, which does whole-world AOT compilation to produce a single executable or shared library. It does have substantial limitations (eg no runtime class generation/loading), so it might not be suitable for every project
The plan is to support all major OpenJDK platforms.
There is also Project Metropolis, which was recently started, with the long term goal of rewriting all existing C++ code into Java, so AOT needs to exist in all platforms.
Now combine it with JavaFX and we can have reasonably-sized cross-platform GUI apps again.
Yes, you can compile a QT or a GTK app for every platform, and use e.g. Python or Go to write the cross-platform part + package it into a single file. It's still as many files as you have platforms.
There is a large niche for utility GUI programs that don't usually get a lot of UI polish or native feel. As long as they don't break general conventions and muscle memory, the users are OK with that. I suppose that JavaFX is comparable to Qt, and feels better than Tk or AWT, let alone a hastily-built web-based UI.
I see e.g. my wife, not an IT person, use a number of them. An eBay betting app, several utilities for bead art, etc, most written in Java years ago. Do they look polished and native? Hell no. Do they get the job done? They do. Could they look and feel better with a JavaFX UI? Quite likely. Would having a single binary to download, without installing a JRE first, improve their adoption rates? Quite likely again.
I have worked on a Java desktop app with Swing UI for over a decade. Mid 2000s we would get asked to "modernise" our applications UI, which really meant: "make it look like Windows XP".
After Apple released iTunes, which totally ignored the native look and feel on Windows, people stopped caring so much as long as it looked ok and was intuitive. The boom in web apps with every SPA defining it own internal LAF through CSS and Javascript and the fad for flat UI components seems to have further watered down the arguments for conforming to a native LAF.
I haven't played much yet with JavaFX so can't answer your actual question but I believe it is more flexible than Swing and Swing is already very customisable (though you sometimes need to create your own widgets by extending/implmenting off the default widgets).
I don't need a native look a feel and most people probably don't even care about it, but I do care and I definitely prefer it. I loathe modern flat themes which completely lack affordance. However, I would like my applications to look like they belong on the host OS even if it has an unfortunate flat theme.
In order to practice what I preach, I'm looking for something that looks native for most cases that I can use for side projects and become proficient in. For my current project I chose SWT over Swing because SWT supports a native look on Linux (via GTK) while Swing doesn't (as far as I can tell). However, SWT is kind of clunky and I wonder if there are better options or if my previous research is out of date.
In my limited experience, it's hard, but in most cases that isn't a problem. JavaFX is powerful, separating layout and styling from code via FXML and their CSS like language. If you want to style the application like a webapp it's a piece of cake, but if you want to style it to look native then you'll have to use stylesheets such as http://www.aerofx.org/
On the otherhand, with Swing all you need to do is add the following line:
Okay, so for JavaFX you would need a specific style sheet for each OS version provided it doesn't support any theme customization. That's less than ideal, and a step backwards compared to Swing or SWT.
And the GC and the minimal stdlib and other things. If you are targeting multiplatform, Kotlin may be a reasonable choice so long as you don't need anything advanced the JRE provides (or are willing to abstract it and have a native equiv also). Otherwise, there are too many native options these days to use Kotlin solely for that purpose IMO.
Do you mean for Bazel itself or for building apps with bazel?
Bazel is still a bit away from having Java 9 support [1] and it still requires some system dependencies (for the other languages and cross system support).
I wish more tools would go the "static binary" path that make it easy to build and use wrappers without having to figure out system configuration every single time.
bazel itself. One of the complaints I here (not sure how valid they are) is that people's docker images tend to grow a lot, and I'm not proposing bazel yet, as it'll pull additional hundreths of megabytes, plus some more per WORKSPACE.
For Windows, it's mainly perception - if engineer sees that a tool is like 200mb in the depot, he/she be like - that's too much :) "Remember why we pulled boost, and no longer use it - as it's huuuge!" :)
This is definitely an improvement for Java, but it leaves me with a few thoughts as someone who has done Java professionally at times, but also professionally lived in other ecosystems including C++/Qt, Python, Ruby, Golang, and of course node/JS.
1. Setting up a project is still a pain in the butt. Tools like Gradle are a nice improvement over Ant (and some would say maven), but still most people don't even understand them. You have some serious reading ahead of you if you want to set something up that isn't already templated somewhere for you. You can lean on an IDE for sure, and for most Java devs this is probably a no-brainer. I'm weird in that I don't like magic. I prefer to know what the tool is doing on my behalf, and the Java IDE world is so complex that it isn't practical to learn that unless you're in the ecosystem for years. Then dealing with weird exceptions from the JVM can be maddening.
2. The Java world moves slowly. It could reasonably be years before many shops transition to Java 9, when you would actually realize the benefits of this in your work life.
3. So much Java runs on the server side anyway, where executable size and entrypoint doesn't really matter that much. Because of this, it may only be a small subset of Java shops that really get into Java 9/Jigsaw and iron out the bugs, and create tools/tutorials for others.
Currently I'm doing C++ with Qt, sometimes C# (game dev under Windows), but was at Google just few months ago doing Java.
While Qt is great, we've been running into logistic problems - like we have plenty of tools that use it, and we are forced to place all the binaries into one folder ("bin"), and the Qt dlls there for legal reasons, license, but buying the license for static linking won't be a problem for us reallly. The real problem is that once we link our binaries statically, then our plugins that also use Qt won't work with them, unless we do some magic, and forward all QtXxx.dll end points to be from the main executable, or use more abstract interfaces - e.g. our plugins should not use Qt directly.
I likewise have used these. Qt (really C++) development in general suffers from annoyingly slow compile times in my experience. Also, once you go beyond anything trivial, .pro files become complicated as do build systems around them.
We don't use .pro files or QtCreator - it's Visual Studio + custom build rules. Still slow, and nasty with generation.
As build system, we used to have IncrediBuild, but since we are PS4 developers we get SN-DBS for free - http://www.snsys.com/products/SN-DBS.asp - it speeds up the build, but once the Qt moc/etc rules come in, the build needs to wait for these to be generated, and then proceeds.
There are ways to overcome this, and we are looking into improving this.
I've tried using .pro files, but first, I can't sell them to the rest of the engineers, as pretty much almost everyone knows Visual Studio, .sln/.vcxproj files. There are some ideas about alternative build systems, but not there yet. (at the end most of these just generate .sln/.vcxproj, like CMake, or premake, etc.).
My application is cross platform. So I use .pro files + qmake, then make/nmake. As I started needing to move files around in cross platform ways, I just maintain a Go script now that does the build. Tired of custom DSLs and having to dig deep into build-system-specific things (e.g. Groovy w/ Gradle and the confusion around what code runs when like defs vs tasks, doFirst, etc).
My only experience with Java was through BAZEL, outside of it I'm mostly Visual Studio guy with some Makefile knowledge.
With BAZEL things were working pretty smoothly, but I've never used maven, gradle, ant, etc. Really weird, because If I post that I have 3 years experience with Java and not knowing any of these tools...
What I'm trying to say is that with BAZEL this might be easier for cross platform development (not sure though)...
Except accessibility for blind people (through screen readers), and probably people with other disabilities as well. I just tried the Red GUI with the NVDA screen reader on Windows, and it's mostly inaccessible.
BTW, this is a problem with nearly every GUI toolkit developed from the ground up (that is, from the host OS's low-level graphics primitives). The exceptions are mostly the big, "bloated" GUI toolkits, like those provided by the major operating systems, the major browser engines (and by extension Electron), Qt, JavaFX (though only on Windows and Mac), and maybe a few others.
Edit: SWT is one of the most accessible options for cross-platform desktop applications. That's mostly because SWT primarily uses the host platforms' native widgets. But it does have some custom controls, and for those, it implements the platform-specific accessibility APIs. I understand that a lot of people don't like the conventional desktop look and feel though.
> other ecosystems including C++/Qt, Python, Ruby, Golang, and of course node/JS [...] Setting up a project is still a pain in the butt
I find this is not Java specific and many of those other technologies have similarly painful project config, especially as soon as you do something non-trivial.
> The Java world moves slowly.
"Vendoring" the stdlib, which essentially is what is happening here, alleviates that (at the cost of not sharing source, which is usually OK for the JVM in non-security contexts). As for work life vs home life, that is not very Java specific. Many companies hang back on old standards by choice.
I find this is not Java specific and many of those other
technologies have similarly painful project config,
especially as soon as you do something non-trivial.
My experience with Java has indicated that the problem is actually in the opposite direction. I agree that all packaging systems suck for larger or unusual projects, but for small stuff there's a clear distinction - there is nothing in Java packaging that's trivial. Or you could see it as "nontrivial" being very different for different toolchains.
If I'm doing something that'll never exceed 1KLOC and doesn't depend on any exotic libraries, I can throw together a crate, module, bundle, package, etc in a matter of minutes and then forget about project configuration. Java... anything other than "local-machine CLI project with no dependencies and an IDE" will have you spending more time on config than code.
I find it's pretty straightforward using gradle (except that it doesn't build fat jars out of the box). Can you elaborate on what you're having trouble with?
I didn't try gradle and my experiences weren't incredibly recent (three-five years in most cases), so maybe that's what I was missing.
Dependencies and portability were by far the biggest issues. eclipse, netbeans, idea, et al didn't seem to do dependencies at all; even if you had a library jar actually on your filesystem it was a huge PITA to point at it, and getting a project that'd also compile on someone else's machine was horrible. leiningen didn't have a single tutorial that I could find and I voodoo'd my way through a clojure tutorial before giving up. maven broke in strange ways when I tried pulling in deps and figuring out the correct incantations in the pom files was a pain. More recently, I could probably have gotten along with sbt if I'd had a week to play with it, but it also has the "no useful tutorials" problem and I was on a time limit.
Some of this is certainly lack of experience, or even simple Doin It Rong. I could see maven being much easier with a directory full of examples to look at, for example, and sbt I'm sure is great once you wrap your head around it. I just feel like, even if I was limited by typing bandwidth instead of figuring-things-out bandwidth, those tools wouldn't hold a candle to python's or rust's tooling. Even makefiles and cmake seem to have better happy paths.
I'll look at gradle next time. There are situation where I could use a jar.
> eclipse, netbeans, idea, et al didn't seem to do dependencies at all; even if you had a library jar actually on your filesystem it was a huge PITA to point at it, and getting a project that'd also compile on someone else's machine was horrible.
These things are oriented towards working with a dependency management/project management thing rather than manually specifying libraries. I'd really recommend maven, using the IDE's integration with it, particularly if you're getting started - Gradle can be more concise but it's definitely buggier and less well documented/supported.
> maven broke in strange ways when I tried pulling in deps and figuring out the correct incantations in the pom files was a pain
Dependencies should just work unless you were trying to do something weird like using jars from the local filesystem - don't do that (if you really must, install them into the local maven repository and use them from there: https://maven.apache.org/guides/mini/guide-3rd-party-jars-lo... ). You shouldn't need any incantations, just simple XML that should autocomplete in the IDE, or you can use a GUI rather than directly - e.g. in eclipse you just right click on the project -> maven -> add dependency, and search/select the library you want. Do you remember what problem you had more specifically?
> Some of this is certainly lack of experience, or even simple Doin It Rong. I could see maven being much easier with a directory full of examples to look at, for example, and sbt I'm sure is great once you wrap your head around it. I just feel like, even if I was limited by typing bandwidth instead of figuring-things-out bandwidth, those tools wouldn't hold a candle to python's or rust's tooling. Even makefiles and cmake seem to have better happy paths.
SBT is awful throughout, but my experience is that Maven is much much better than anything in Python-land (no messing around and mode switching with virtualenv, no need to separately run pip, one consistent tool that everyone uses, one packaging format, one central repository, better integration of testing with the project), and directly comparable to Cargo.
I can start one of thousands of pre-configured projects instantly from maven central's archetype catalog (http://repo.maven.apache.org/maven2/archetype-catalog.xml). I don't even have to know what I'm doing to get a karaf-camel-amq-archetype or aws-lambda-s3-example project up in seconds. Java tooling is just so amazing.
How do I get a preconfigured quickstart project for say iron and diesel with rust? I read the rust book. I must have missed it.
> How do I get a preconfigured quickstart project for say iron and diesel with rust? I read the rust book. I must have missed it.
The book doesn't cover everything. That said, we currently don't have a built-in solution for this feature; we had one but it never hit stable. Since it didn't get accepted before the impl period late last year, the discussion was effectively on-hold; it can get started up again now that it's past the new year.
That said, many projects provide their own way to get started. Diesel's CLI has a "diesel setup" command to get going with it, for example. I'm not aware of one for Iron.
Iron and Diesel are pretty new, so they may not have very sophisticated templates yet. If you just mean setting up a rust project though it's as simple as 'cargo new --bin [project_name]'. I've found cargo to be a lot simpler to use than Gradle with the added bonus of not having to learn Groovy!
> It could reasonably be years before many shops transition to Java 9
Java 9 is short term support release, ending support with the release of Java 10 / Java 18.3 (March 2018). Next LTS JVM release is supposed to be 11 in 1.5 - 2 down the road.
A lof to large organizations will be holding back for the next LTS release before considering migration.
Maven is complicated but also very stable and powerful. It's no less arcane than webpack and if you're using any decent IDE all the available options will autocomplete. Fat jar deploys were always super simple and having a self-contained executable is even better.
Maven at its core is very simple. The lifecycle is well-documented and so is the dependency resolution.
Many coworkers I've worked with have called it complicated and then I find out they really haven't learned the (very simple) lifecycle and how build behavior gets attached, etc. This is all very simple but it is something to learn.
I don't know why this happens. I think programmers are so used to imperative (ant/Grunt/etc/etc) programming/building that it becomes confusing for them when they encounter a declarative system. And their brain revolts. Because they are like how do I just do a thing (i.e., copy some file somewhere, call a "build" method, etc, etc.)!? Instead of realizing the value of the declarative + idiomatic Tao and learning it...they say no, no gimme gimme let meee do it. Much like my two year old. And then I'm left fighting non-reproducible builds and getting their projects going in my IDE like it's somehow 2005 again. But Maven is great, declarative systems -- especially declarative build systems are the optimal way to do builds (in most cases).
>I don't know why this happens. I think programmers are so used to imperative (ant/Grunt/etc/etc) programming/building that it becomes confusing for them when they encounter a declarative system.
Because, after all is said and done, programming is about having your computer "do" something - whether it be to write some bytes to the disk or to send some bytes to the network.
It's just that sometimes there's an advantage to use an abstraction - such as say "SELECT * FROM TABLE WHERE ROW_ID =14" is an abstraction over something like "for (int i =0;i<table.size();i++) if(table.row[i].elem[1] == 14) ... ", but often you don't need such a complicated abstraction, you just "need something done" before (or after) building. Whether it be that you want to download an HTML file to package, or to move the resulting file to a certain directory, or to clean a certain directory, your build language shouldn't be that arcane that you have to create a "build.sh" to get things done.
— “SELECT...” is not an abstraction for “for...”, by the way. Abstractions are not for specific implementations. “SELECT...” is an abstraction for specifying Sets etc.
— Maven is simple, not arcane. I’ve produced countless “custom” builds with wild variations of need and never has Maven let me down. In some sense this is easy to prove (see maven-antrun-plugin); however, Maven’s core plugin/idioms supports 90+% of use cases I’ve seen over many many “weird” build requirements. To your example, “copying files” is fundamental; however you have to learn the idiomatic way to do it if you want to reap the benefits. Otherwise, just call out to maven-antrun- or similar. But then you’re chasing your tail.
> after all is said and done, programming is about having your computer "do" something - whether it be to write some bytes to the disk or to send some bytes to the network.
Not always. Often, particularly in scientific computing, you just want to ... compute ... a result. I mean sure, the computer needs to display the result to you, but the computation isn't about displaying it, it's about computing it. Just like adding up a bunch of numbers on a calculator isn't about getting the calculator to "do" anything.
> often you don't need such a complicated abstraction, you just "need something done" before (or after) building.
Abstractions should be simpler than the thing they abstract over, that's their whole point. Treating my computer's memory as a flat array of numbers is simpler than thinking about how much current is flowing through each RAM wire. "Compile all source files" is simpler than "execute javac Foo.java, then execute javac Bar.java, then..."
> Whether it be that you want to download an HTML file to package, or to move the resulting file to a certain directory, or to clean a certain directory, your build language shouldn't be that arcane that you have to create a "build.sh" to get things done.
You shouldn't need a build.sh, agreed, but nor should you need particular things to happen to particular directories. Maven has great support for things like "package my documentation in the standard way". It's only when people try to fight it about the low-level details that they really shouldn't be caring about that they run into trouble.
Could not agree more. Every time I have seen an implementation the imperative type (ant etc) it leads to different ways of doing the same things so over multiple projects things just gets really complicated and difficult to maintain.
I think it happens because maven has poor documentation, a ton of unexplained "convention over configuration", and very strong poorly explained opinions about how you must structure your project. Basically it's a ton of inflexible magic. Also, the attitude in the maven community that people that want to deviate from the god-given-way are two year old children.
This is basically the exact opposite of my experience with Maven. The documentation feels very clear and good to me and I've always found answers to my questions. I don't recall ever encountering "unexplained inflexible magic".
In around 2008 I co-wrote a set of maven javascript mojos (before NodeJS), incl QUnit test integration et all. I collaborated with another fellow on the other side of the world. Documentation was stellar. IIRC, to extend, even the upgrade from M2 to M3 didn't affect most community mojos.
For example, if you have a multi-pom project with a parent pom (not unusual in a medium-sized codebase, never mind large), and you have unit tests in your child poms, they'll get executed with dependencies resolved locally for that child pom, and not with the global dependency resolution that satisfies all constraints that need satisfying at the parent level.
The upshot is that you easily end up running tests using different versions of dependencies than what you deploy with, misleading you into thinking things are working, and can end up with hilarious NoSuchMethodError at runtime.
The "solution" is to pin your versions using dependencyManagement, but that's no real solution at all, not least because it's neither automatic (though dependency convergance using Maven Enforcer helps, and I've developed some scripts that help further) nor is there an easy route forward when you want to bump versions safely.
Having the choice to pin versions separately per module is a desirable feature, especially for multi-module builds with different deploy artifacts. So this is no problem at all; deciding which versions to pin per artifact/module is the programming job — no tool can automagically decide this for you correctly.
I'd prefer the choice to specify versions in submodules, with the versions of dependencies chosen and pinned via the global resolution, producing a fixed set of dependencies in a file I can check in, like Gemfile.lock in the Ruby world.
> For example, if you have a multi-pom project with a parent pom (not unusual in a medium-sized codebase, never mind large), and you have unit tests in your child poms, they'll get executed with dependencies resolved locally for that child pom, and not with the global dependency resolution that satisfies all constraints that need satisfying at the parent level.
As it should, otherwise you'd get the even more hilarious situation where your tests pass when you run the single-module build but fail when you run the multi-module build.
> The "solution" is to pin your versions using dependencyManagement, but that's no real solution at all, not least because it's neither automatic (though dependency convergance using Maven Enforcer helps, and I've developed some scripts that help further) nor is there an easy route forward when you want to bump versions safely.
This is not a maven issue, it's a combination of Java's flat classpath and the reality of diamond dependencies on versioned libraries in any system. We could allow multiple versions of a transitive dependency on the classpath but then you get Rust's hilarious "expected Foo but was Foo" type errors. Java 9 modularisation should reduce the problem by allowing modules to have explicitly private dependencies, but the problem exists everywhere.
This is not a maven issue, it's a combination of Java's flat classpath and the reality of diamond dependencies on versioned libraries in any system
This isn't true; there are better solutions already existing. E.g. Ruby with the Gemfile.lock approach. I'd like to be able to do a two-step: do a global analysis of dependencies and pin the common versions for diamond situations, but not need to maintain or calculate those pinned versions manually. And I still get to use the pinned versions from the global resolution for executing tests etc. on submodules.
As it is, I've had to write a bunch of tools to rewrite the dependencyManagement as and when required. The main app I work on is linked into the Hadoop ecosystem, and that dependency set ends up being quite large.
Another issue with Maven is rebranding: when the groupId of an artifact changes, but the package and class names don't; see e.g. asm / asm vs org.ow2.asm / asm, or the whole codehaus debacle.
I have spent more than two weeks of my life updating, maintaining, fixing, researching and tooling Maven pom files, and it was almost all around deficiencies in dependency management.
Let's not get started on trying to get builds to work reliably offline, caching maven repositories, etc.
> This isn't true; there are better solutions already existing. E.g. Ruby with the Gemfile.lock approach. I'd like to be able to do a two-step: do a global analysis of dependencies and pin the common versions for diamond situations, but not need to maintain or calculate those pinned versions manually. And I still get to use the pinned versions from the global resolution for executing tests etc. on submodules.
I dislike this for the same reason as before: I find it really valuable that building a single module on its own behaves the exact same way as building that module as part of a multi-module project. If you want to ensure that the tests run against the same version as in the final product, I do that by making eviction an error.
> Another issue with Maven is rebranding: when the groupId of an artifact changes, but the package and class names don't; see e.g. asm / asm vs org.ow2.asm / asm, or the whole codehaus debacle.
Maven has better handling of this than most; it can at least warn/error when this has happened, and if you're using the shade plugin or similar it will warn or error when two jars contain the same classes. Yes it's a problem, but it's much more of a problem in other ecosystems.
> As it is, I've had to write a bunch of tools to rewrite the dependencyManagement as and when required. The main app I work on is linked into the Hadoop ecosystem, and that dependency set ends up being quite large.
There are standardized plugins for the common use cases e.g. "mvn versions:use-latest-releases". Most things that can be automated are. But since most of the library ecosystem predates version ranges and semVer, there simply isn't an automated way to know when using a newer version of a transitive dependency is safe or not.
> they really haven't learned the (very simple) lifecycle
Building is a simple concept: dependency DAG + inputs -> artifacts. The "->" here can involve arbitrary intermediate artifacts and steps.
Maven ignores this fundamental concept of building. Rather than treat interim dependencies as part of the DAG, there's a hard-coded recipe of lifecycle steps.
This is why I personally cringe at maven - it has nothing to do with the fact that it's declarative (virtually every build system is largely declarative). It has everything to do with hard-coding one particular set of build steps into a supposedly general build tool.
I was under the impression that the build chain in maven is pretty defined and not arbitrary. It performs the same thing over and over again, being highly reliable. It’s pretty extensible since you can tweak your own build steps if you want. And in the general case you don’t need to define a thing?
I used to use Maven but I've moved completely to Gradle.
With Maven, if you follow Maven's way of doing things, everything just works. But, if you need to do something different, or have some rare use case Maven's designers weren't focused on, you start struggling a lot to get Maven to do what you want.
Gradle is a lot more flexible and if you have some uncommon requirement you are far more likely to successfully implement it using Gradle than using Maven.
> But, if you need to do something different, or have some rare use case Maven's designers weren't focused on, you start struggling a lot to get Maven to do what you want.
You'll be fine as long as you realise the Maven-ey way of doing the thing is to write your own plugin.
But most of the time people just want their build to do something different for no real reason, IME.
Oh wow! A complete maven project after only a few cryptic commands in weird generated subdirs and a -D switch! It's so simple and obvious it's almost criminal! I bet the OP is eating humble pie now!
I'm not feeding OP humble pie. I'm sharing information with people who are unfamiliar with Java, so they don't believe what professional Java developers can clearly see is obvious bait.
I'm glad freedomben likes nodejs, but he shouldn't talk dirty about Java while pretending to know something about Java. His one comment to this story dominated what could have been an otherwise interesting discussion about a new feature of Java 9. Sad.
> 3. So much Java runs on the server side anyway, where executable size and entrypoint doesn't really matter that much.
My read is that Java is doing this now because they ignored microservices and containerization at their own peril. 8 and 9 between them include a bunch of things to squeeze runtime and disk size to be comparable to other systems.
> ...squeeze runtime and disk size to be comparable to other systems.
Really? Most of the "microservice era" or "cloud native" or $timely_buzzword platforms are really big. Golang binaries for large services are bloody huge.
TL;dr don't assume other systems have small footprints until you deploy a Node.JS app and do "du -h node_modules/"
When I was coming up, I overheard a conversation amongst a bunch of greybeards about how these big computing organizational changes are not a fad, they're a cycle. Like the tides. Since I started working right at the cusp of a switchover I had one more opportunity to observe this behavior and test this theory than most people do, and it does appear to match reality.
People make monoliths for performance reasons and then can't maintain the monolith, so they go back to forced independence. Every company does this on a different cycle but the epicycles are the 'fads' you see, and it's been going on since at least the 70's.
Similarly and perhaps more forgivably, people organize a system (think, client-server, peer to peer) for reasons of the current laws of physics as they apply to clocks per second, storage space, and latency. Those inequalities shift with each new generation of hardware. So what was the right thing to do 15 years ago might be the right thing to do again next year. It's not that we've been wrong for 15 years, it's that we are wrong now. And will be wrong again in another half a dozen years. But we have to use the tools available to accomplish the goal now, and that means we have to adapt, repeatedly.
Good points. If you go back to java development and want to try a fringe build system, Kobalt is nice and straight-forward compared to maven/gradle. You configure the project in a kotlin file using a DSL. You may never need a plugin and the DSL + Kotlin give you a hybrid of Maven and Gradle.
Setting up a Java/Kotlin/Groovy project takes two clicks these days: http://start.spring.io
And that is a simple template that just takes advantage of curated OSS ecosystem dependencies by the Spring team.
There’s really no magic, I find Maven or Gradle to be as opaque as say Gem bundles, Bower, or NPM and Grunt (Or whatever the new flavour du jour in Node land is). That is to say, the core concepts are all mostly similar but just slightly different enough to cause hair loss. And let’s not talk about Golang dependency managers...
I vividly remember starting my first java project a few years back and starting my first node project a year back, personally getting started with node was easily 5x more complicated with so many weird tooling before a first line of code is written.
Are you thinking of node or a web project? Node requires zero tooling and is distributed as a single executable ~10-20MB on all platforms + already comes with npm.
I’m still confused. Webpack is a frontend build tool and completely unnecessary for writing a web service.
Also, from the Dropwizard tutorial:
1) configure Maven
2) create a config class
3) write a mapping.yaml for “Jackson”
4) create an application class
5) create a representation class
6) create a resource class
7) register the resource
8) configure maven again (!) for building a .jar
9) finally run it.
With node you literally write 5 lines of code importing the http module and run `node server.js`. I can’t possibly imagine what steps could be more complicated than Dropwizard. I consider webpack overly complex myself, but it’s a completely self-inflicted option and not a standard for nodejs development at all. I’d be curious to know what docs you were trying to follow if you can recall.
1. Dependency management is probably a lot easier with Maven than with C++ or Python. Hope that needs no reference...
2. No idea why, but Java is backwards compatible. So not updating to the latest version is only laziness.
3. Having much smaller containers or virtual machine disk sizes should lower your AWS/Google/Cloud... bill a (little, but whatever) bit and therefore make your CFO happy...
You're wrong about point 2. Java has backward compatibility but there are a few exceptions. On top of that, the library's that come bundled with the jdk have a few backward incompatibilities of their own.
These might be small things to fix when your codebase is small, but for enterprises with codebases of millions of lines, these issues turn an upgrade in a major challenge.
Apart from that, there is another reason why companies don't upgrade and that's because they are locked to a certain java version by their application server. Upgrading to a new java version would require upgrading the application server as well, which would cost a lot in terms of licensing and which would introduce some risks and overhead of its own.
I can confirm all of what you said.
That's the reason application servers AND big monolithic applications NEED to die and they need to die right now.
Just have clear defined boundaries for services, deploy them inside a docker/rkt whatever container; just let whatever legacy application run with java 1.4 until you replace it completely.
Well, that is a good thing: You still can buy regular support for Java 6, which was released more than 10 years ago. So if you really think updating your monolith to Java 9 is worth less than paying for that support, you can do so. Not all software generates such a huge margin that updating it would be a viable option for your business. How many other languages provide such long-term support for releases that are a decade old, even if you were willing to pay for it?
Not saying that monoliths needs to die, but you won’t get defined boundaries just by going with microservices/Docker. And from personally updating a “monolith” to java 9 was a pretty straightforward (yes some of it entirely unrelated, were actually put in a separate container). If you did modules from the start “monoliths” could be broken down into ms if needed just by deploying them separately.
I will also add that libraries that operates at bytecode level (such as AspectJ) may be incompatible with newer JVM versions. This can be a problem since they are often used by higher level frameworks to do their "magic" (one example being Spring) [1].
The solution is that you have to update either the library (which may not be compatible with the framework using it), or the whole framework.
Yet, all that is besides the point: In essence, those reasons would apply to any installation you have once you run it long enough. I.e., those particular problems are not Java-specific, and in fact, I would even dare speculate that such issues are through the bench worse in any other language than Java.
ADDENDUM: Yes, C++ is technically even more backwards compatible - if your code base and all dependencies was/were 100% standards compliant (har har). But again, for me, the main point is that most newer languages first have to prove they can keep up to such levels of backwards compatibility (e.g., see the Python 3 fiasco...).
+1 for wanting to know what actually happens. I do not like the direction web dev is heading, with prepossessing, and transpiling a language that is already an embedded scripting language.
I didn't understand the article, can someone explain what it means for java development, please??
Will we be able to create runtime-less executables that are fully dependency free? That would be awesome to write a bootloader in Kotlin or any other Java Synthax Substitute.
How are .so, .dll files handled during Java packing? This is more open question, but say you have one ".exe" file. Now you need to extract the DLL in a place, and make sure everytime it's the right one (gets tricky if the tool is ran simualtnenously, like spawned from a build process).
While I was at Google, instead of having multiple .so files, the main launcher was a C++ binary, and all external C++ dependencies were linked into it (that's it if you have the source code), then you didn't need that.
I guess now it's up to the BUILD system to achieve that, where if you have more flexible BUILD language you can instruct everything to go in the main launcher file, then have all the .jars into one, slapped at the end of the file.
At the end, ship or update only one binary to your service, desktop machine, etc.
> How are .so, .dll files handled during Java packing?
Native libraries used by JNI can be shipped in the jar files and are read from the classpath, in addition to reading them from the ordinary linker path.
But on Windows you must "extract" and copy the DLL file somewhere (ok, possibly you might be able to do in-memory load, but that is very non-standard and might trigger antiviruses).
I think the same is with the Python packagers, or C# shadow copy.
You need to package up the JAR with the shared object / dll and install both on the local filesystem in order for the SO to be accessible from the classpath. For example you could apply a package manager (RPM) and include the JAR and .so at install for available use.
But if you were able to "contain" all the source code from your DLL into your main "java.exe" launcher, and then slap the all the .jars at the end of the "java.exe" and then renamed it to "mycoolapp.exe" then it might be just that... off course if licensing agrees with you, and you have the source code, and want to deal recompiling these like that... also compiling it along with the java launcher.
This way there is no need for extra install, uninstall. Possibly too much over-engineering for full blown product, but if it's something that needs to be run, and updated on tons of machine - not having to deal with extra artifacts might be a win.
I've definitely seen Java code extract a DLL from a JAR at runtime, stick it somewhere (C:\Users\foo\AppData\Local for example) and then use load library to load it (I've seen this leak DLLs as well - with each execution creating a new DLL...).
You can't load a native library from inside the .jar file. Typically things that need them extract them to a temporary location and load them from there - there's no standard interface to `dlopen` or similar that lets you load directly from inside a zipfile.
on linux with fuse this could be done (possibly tricky), and on windows there are several ways, but I agree - they are non-standard, hence you are on your own when it doesn't work.
I've tried loading dlls from memory (there are several examples on the net) only to understand that there is more to be done (like getting the PDB information correctly loaded, and then some more).
"and superior to web-hybrid options like Electron"
Superior exactly in what way? Electron allows access to an enormous audience of developers and the web ecosystem. You really can't compete with that and would be silly to try at this point.
How about comparing a hello world app to another hello world app? Or do you consider that comparison invalid because Electron/Chromium don't have ways to strip unused features? To me, a comparison of similar end results is reasonable. Arguments about whether hello world apps represent reality, or comparisons between WebGL/WebAudio apps vs LWJGL apps, would be more apt.
The point is that even if you add the module for the browser, you’re still significantly smaller than Electron – while, at the same time, Java can actually eliminate unused modules for you, which Electron doesn’t.
They didn't. They compared a hello world app with minimal GUI (implemented with Electron) to a hello world app with minimal GUI (implemented with Java).
The author misses the point when he says this might help Java regain share in the space of DevOps tools which is currently mostly Go.
The problem is not artifact size but the JVM slow start-up time. This is made worse by almost all Java frameworks that by definition do all their own stuff before passing control to your real app code.
Such executables are not something you would put in a loop in a shell one liner, and that is the space for command line utilities Go has occupied successfully.
But frameworks (and runtimes for things like Clojure) absolutely do. It would be possible to write a fast-starting framework for Java, but i suspect nobody has because there's no demand for it, because nobody who needs fast startup uses Java, because it doesn't start up fast!
That said, i think the real reasons Go has done so well in devops are (1) it's easy to pick up for devopsists coming from Perl/Ruby/etc backgrounds, (2) static binaries are easier to deploy than a jar plus a JVM (not massively easier - but easier enough), (3) a focus on systemsy stuff in the standard library and community, and (4) sheer snowballing momentum, in that Go has become the default choice for stuff like that.
That's actually pretty fast. Starting the JVM, grabbing the memory for the heap, and then exiting takes one tenth of a second.
Things like this are why all the "Java isn't slow" articles miss the point completely --- 100ms to do nothing useful, on a presumably quite fast machine, is ridiculous.
For comparison, 100ms is roughly the time it takes to grep an 18MB file:
> Things like this are why all the "Java isn't slow" articles miss the point completely --- 100ms to do nothing useful, on a presumably quite fast machine, is ridiculous.
"Ridiculous" is like "unprofessional", it's what you say when you don't have a real argument. Yes, ha ha, 100ms, very droll. What does it matter in practice?
By "DevOps tools", I wasn't thinking in terms of `sed`, `awk`, etc. I was thinking in terms of Consul and Vault. Docker and Kubernetes, etc.
The major pillars of DevOps today are long-running processes, very complex pieces of infrastructure. Which might play into the strengths of the JVM, if the packaging and deployment story simplifies and becomes more competitive with Go.
Sure, "shell one liner" utilities might (?) be best served by native compilation. But DevOps is not merely another word for sysadmin.
It actually starts surprisingly fast. We had a massive Java / Scala codebase at a previous place and one of our engineers wrote a fairly comprehensive set of command line tools (even featuring command completion) entirely in Scala / Java on a 1.7 jvm just on the off chance it would be fast enough.
It actually was totally fine and surprisingly snappy. I’d suggest giving it a shot.
I don’t know how to revert the jvm can’t be used for command line tools because of slow startup times zeitgeist but I don’t think it’s accurate anymore.
Yes, it is a pita, but it is a price to pay for the dependency injection, where many components, services, configs from different projects/libs have to be searched (annotations can hide everywhere), started and then wired together in the order they define 'globally'. And once you change a config property, that tree can change as well.
I hope some work will be done there. One could scan the libs in parallel, caching results, building/shipping a search tree on packaging time and so on.
In pure servlet times you could directly define your starting points, define, which libs to exclude or include for the search and so on.
At least no one has to edit xml files anymore to wire components and impls together.
This statement doesn't necessarily generalize, but I can't say I'm a huge fan of what the Spring-flavoured Dependency Injection ended up looking like around here either. It's like... we've taken on ridiculously long startup times, to turn what would be compile-time errors into run-time errors. Seems like a double-whammy of bad.
Maybe I'm a little overly jaded, but the Java apps I've worked on (which is admittedly only a handful) have all had these giant sprawling messes of dependencies; it feels like there's a lot of code to accomplish very little. The Golang-based services I've worked on feel like the opposite; very little code to accomplish a lot of things, without much ceremony.
Edit: And that's not to say that I'm opposed to dependency injection; rather, I'm quite happy to do constructor-based dependency injection by hand. When that starts to feel painful, I look at the system I'm working on and wonder if it's getting too complicated/has too much coupling/etc.
I do not know golang-services. But in the end, somewhere is the code written and it must be shipped, started, maintained and so on. Someone must also write the drivers for used technologies and must bring them into the golang world.
For us as a little company without access to many developers with affordable pay expectations, it is a big relieve, that a lot of specialist knowledge is bundled together in spring. Such as how to do central configuration, logging, monitoring, failover, loadbalancing, streaming, backpressure support, db connection pooling, message queuing, and so on. And you need special knowledge only when something fails. And when it fails, you can assume, its done the same on each service. It helps a lot. You have then a wider pool of people you can ask to help you to do the actual business coding work.
It reminds me a little on how maven defaults said: code belongs into src/main/java and test below src/test/java and then have a little pom.xml,that describes your project. It has brought sooo much relieve to get rid of so many flavors, how people have structured the code. Not to forget the style of make scripts. You can now open many projects in any IDE without any hassle, you do not have to search forever, where the starting point is and so on. I always forget that. Less work for my little brain, when navigating between projects.
So, even with the dependency hell (i totally agree), i am ok with it, as i seem to forget, what i dont have to do on each individual service anymods. And i have access to a rich ecosystem, that is maintained and supported and people react on issues.
I generally agree! The unfortunate thing for me is that when that stuff breaks in some obscure way, I end up being the one to debug it. Magically having private fields populated during application launch is great, until the junior guys can't figure out why one of them is null sometimes.
Yes i share the pain with you. When it does not work, you still must have a senior or a junior willing to dig into it and become senior after some time as well. Pushing the responsibility away to magic sauce is good and bad. Yup.
Take a look at dagger2. It does compile-time dependency injection through generated .java files, so it wastes no time scanning classes at runtime, and you can look at the quite readable generated source code to see exactly what it's doing.
Well, I figure if that was ported to C it still would take a while to start. I don't think it necessarily demonstrates that the JVM is too slow for command line apps. Just more that Spring takes a while to startup.
That's the thing... I've been porting some of the functionality to Golang, and slicing out many layers of abstraction and baggage at the same time. There's some tradeoffs; e.g. I'm actually writing some SQL queries instead of just declaring interfaces that JPA auto-populates with methods, but overall it just feels like a way lighter and less magical codebase.
I see, how you are writing your go code sounds similar to how we wrote our code on the JVM. e.g. We didn't use Spring or other enterprise frameworks like that and would write pretty much direct SQL with jdbc (after several misadventures in various Scala db-wrappers de-jour).
In fact, JVM doesn't start slow. The fact is most Java web apps start slow. The more libraries a Java web app depends, the slower it starts.
The current dominant culture of the Java community is very weird. Although Java has a huge standard library, if you don't use a lot of third-party libraries, you will be viewed as a non-professional Java programmer.
Most popular Java tech stack look open sourced, but are backed by lots of money provided by many companies with bad reputations on pure open source culture.
BTW, slow start-up is not the only problem of many Java apps. GUI Java apps often lag for one or more seconds from time to time, which hurts the experiences of Java GUI apps much.
The third problem of Java apps is they often consume much more memory than apps written in other languages, in particular for the long running Java apps. The longer they run, the more memory they will eat.
[edit] the library use way of Java, by putting library jars into your projects, is not good as the way of other languages, by putting library sources into your projects. By putting library sources in your projects, you can view how the libraries are implemented easily. Yes, you can also put Java library sources into your projects, but the main stream culture of Java doesn't recommend to do this. Just look at maven.
[edit 2] just my personal opinion. I don't like the way to use a separated VM to run many apps. This makes it is hard for me to use a different permission setting for each app. Sometimes I want to block a Java app to access network, but I must block the whole Java VM to achieve this.
There is nothing bad about opensource stack backed by big money, in my eyes.
Second, i am surprised to read, that people would still put dependencies/libs into their projects, even in their source code form? I thought, that was one of the reasons, why dependency management was introduced, to get rid of that. One ships a descriptor, what libs were required/used, when the lib has been packaged. And in one's IDE one can view all the dependencies as one wishes, in binary or source code form. I am very confused about your statement.
(though in the final App, one ships all the libs in the packaged form of the app, unless provided by the runtime environment. But only then. Though its optional, one could also download the deps when starting the App)
And third: The longer an App runs, the more memory it eats?
Its like with any other App: if it needs that much memory and it does not release it afterwards, well, then it is a feature or a bug. If it releases the memory, then it is only released within the JVMs memory space. The common default for thag is 4gb per JVM.
Its like the page cache in linux. Once a file has been read into memory, it will usually sit there for a while, unless someone else needs that memory. Thats why on a system with 128gb and a lot of file access, you see free memory going down and down. But its most of the time the page cache eating up that memory and is mostly not a problem. But can be confusing, when one is not familiar with it.
Maybe a misunderstanding. What is the difference between putting a jar as a dependency (pure binary or with sources) or putting its actual content into the project, that uses it?
Hm. Okay. Interesting idea. I would argue, that it defeats the purpose of a shared library, if you have a branched copy of a dependency with your own patches in your own library project. Plus if you work on, say, 10 libraries at the same time, each having its own branched copy with individual patches, oh well, i wouldnt want to do that manually. You would have to send the patches upstream, so that all other libraries can also profit from it. And you blow up the final jar size. And you get in namespace conflicts (maybe modularization solves it) and so on.
If i own the code of a library, then i have a git repository. I have a build server and i always publish the binary and the source jar to an artifact repository.
Now, when i use this library, my IDE knows how to lookup the source jar, so i can always browse the source code. When i see a bug or need a feature, i go to the repository, patch the code and release a new version of that library. And then i bump up the version number of that library in my own project as well.
If i do not own the code, then i ask for a change with a patch (in best case). And use a workaround in the meantime in my project. Earlier or later the updated version of thr library has been shipped (maven repo) and i bump version number as well and remove my patch.
And worst case: owner does not want to change, well, then i fork the code and add it myself, tag the library, release it to my artifact repository and so on. But i barely do that.
In any way, it all relates to my artifact repository (which proxies through official repos such as maven repo) and dependency management from maven, gradle, ant, and so on.
My Go way is similar but I don't maintain such artifact repository things. I directly fork the dependency project on github (or elsewhere), then change the dependency path from something like "others.com/projects/foo" to "github.com/myaccount/foo".
But the fork will only be made if I have confirmed the fork is worthy to make. Before the potential fork, I temporarily modify the code in the local clone of "others.com/projects/foo" directly. If I find my modifications are useless, I will revert the modifications so no forks will be made.
Other processes are like what you described.
Yes, there is still not a perfect dependency management tool in Go world, but there is one official dependency management tool in developing, which will be released alongside with Go 1.10.
> Although Java has a huge standard library, if you don't use a lot of third-party libraries, you will be viewed as a non-professional Java programmer.
The standard library is where modules go to die. The fact that this phrase originates in the Python world tells you that this isn't a Java peculiarity.
> Most popular Java tech stack look open sourced, but are backed by lots of money provided by many companies with bad reputations on pure open source culture.
The sad reality is that those companies are the only organisations that commit serious resources to open-source development, outside a couple of specific niches (web development, unix-like OSes, scientific research up to a point). Those stacks aren't open-sourced in other languages, they just don't exist. And the whole point of open-source is that it benefits everyone regardless of how pure or otherwise the original motives were.
> the library use way of Java, by putting library jars into your projects, is not good as the way of other languages, by putting library sources into your projects. By putting library sources in your projects, you can view how the libraries are implemented easily. Yes, you can also put Java library sources into your projects, but the main stream culture of Java doesn't recommend to do this. Just look at maven.
WTF are you talking about? You declare your maven dependencies and they can be resolved as source or binary. In eclipse I can click through to any library function and see its source immediately. (It's one of the best dependency-management systems going, in any language; there's a single central repository that everyone uses in practice, but it's easy to run your own if you want. It's years ahead of everyone else in terms of package signing. There are multiple independent codebases using the same repositories, not just in theory but in practice).
> [edit 2] just my personal opinion. I don't like the way to use a separated VM to run many apps. This makes it is hard for me to use a different permission setting for each app. Sometimes I want to block a Java app to access network, but I must block the whole Java VM to achieve this.
Again completely normal - Python, Ruby, C#, OCaml... will have exactly the same issue. Get a better firewall.
> You declare your maven dependencies and they can be resolved as source or binary. In eclipse I can click through to any library function and see its source immediately.
Surely, you can view Java dependency sources. It is just that most Java programmers don't care about the sources, they are just care about the jars (the default culture).
In my honest opinion, cross-platform by bytecode has few advantages over cross-platform by source nowadays, on the other hand, cross-platform by bytecode has many inconveniences.
And, (in my taste), single central repository is bad. That's why I don't like Node also. The npm central repository is the source of many Trojans. Many Java and Node developers are not aware of and have no ideas on what they have downloaded through chain dependencies.
> Again completely normal - Python, Ruby, C#, OCaml... will have exactly the same issue. Get a better firewall.
> Surely, you can view Java dependency sources. It is just that most Java programmers don't care about the sources, they are just care about the jars (the default culture).
Not my experience. Actually getting to the source of your dependencies, in practice, is easier in Java - just one click in your IDE - than in any other language. Doesn't that suggest that Java programmers care more about sources than other language users, not less?
> In my honest opinion, cross-platform by bytecode has few advantages over cross-platform by source nowadays, on the other hand, cross-platform by bytecode has many inconveniences.
Well you're entitled to your opinion but you should probably back it up with something more specific if you want to convince anyone else.
> And, (in my taste), single central repository is bad. That's why I don't like Node also. The npm central repository is the source of many Trojans. Many Java and Node developers are not aware of and have no ideas on what they have downloaded through chain dependencies.
You don't have to use a central repository if you don't want to, and some people don't, but it's very convenient to have the option if you want it. Maven central requires PGP signatures on anything published there, so it's very easy to enforce that all the dependencies you depend on come from trusted people if you really want to - as far as I know there's no non-JVM language that does that, certainly not with anything like as large a base of signed libraries available.
> Normal != good.
Agreed, but you started out by claiming that Java's culture is very weird. It isn't.
> Well you're entitled to your opinion but you should probably back it up with something more specific if you want to convince anyone else.
The only benefit of bytecode is to save compiling time. Nowadays, CPU becomes much faster than the time Java was invented, 20 years ago. So the benefit is weak now. Another promoted benefit of bytecode is compile-once-run-anywhere. However, I think this is a hoax. It is not special, for script languages code runs anywhere without compiling.
> Another promoted benefit of bytecode is compile-once-run-anywhere. However, I think this is a hoax.
I was once working on a large project on the JVM: our Fat-JAR was really working on Linux, Mac and Windows. The exact same JAR. And it didn't matter on which system we have built that JAR. This may not be possible for every use case - but I don't think it is a hoax.
> It is not special, for script languages code runs anywhere without compiling.
IMHO scripting languages like Ruby, Python, etc. are quite hard to deploy, especially if they have dependencies. In comparison to languages like Java, Go or Rust.
> The only benefit of bytecode is to save compiling time. Nowadays, CPU becomes much faster than the time Java was invented, 20 years ago. So the benefit is weak now.
In terms of throughput I agree with you. But start-up latency is already Java's weakest point, and having to compile on startup would make it worse.
> Another promoted benefit of bytecode is compile-once-run-anywhere. However, I think this is a hoax. It is not special, for script languages code runs anywhere without compiling.
True as far as it goes, but certain types of code simply aren't practical in scripting languages. You'll never see people implementing e.g. an image format decoder in a scripting language; they'll use bindings to a native-compiled (C) library instead, with all the problems distributing that entails. This is why things like docker are so popular with Python users: in theory Python is write-once-run-anywhere, but in practice most Python codebases end up depending on one or more native modules and need to have the correct version compiled. Whereas Java bytecode is adequate for things like image codecs, and in the real world you really do see large Java codebases that don't use any bindings to (non-JVM) native libraries.
> In fact, JVM doesn't start slow. The fact is most Java web apps start slow. The more libraries a Java web app depends, the slower it starts.
Depending on what definition for "slow" you are using it absolutely starts slow.
As mentioned in a cousin comment, the JVM takes ~100ms to get to user code. This makes it impractical for small applications where the user's code takes less than a second to complete. It certainly gets slower with more libraries, but for some applications ~100ms added to startup makes using Java not viable.
Just some hard data to support Java being slow. I ran Hello Worlds in Java, C, Node, Python, and Ruby. Java is the slowest out of all the languages I tested.
time java HelloWorld
Hello, World
real 0m0.170s
user 0m0.148s
sys 0m0.012s
time helloWorld
Hello, World!
real 0m0.028s
user 0m0.004s
sys 0m0.008s
time nodejs hello.js
hello world
real 0m0.136s
user 0m0.104s
sys 0m0.012s
time python hello.py
Hello World
real 0m0.050s
user 0m0.016s
sys 0m0.020s
time ruby hello.rb
Hello World
real 0m0.111s
user 0m0.064s
sys 0m0.028s
Java can be compiled to a native binary now, thanks to Java 9. No bytecode, interpreter, or JIT left in the resulting file. (Only available for Linux x86_64 right now).
Please note that Native binary is not always Native API.
Does the app use the most efficient methods provided by operating system? Is the graphical user interface consistent with the other applications on the same system? Is number of syscalls predictable?
That's really a separate issue. You can make native calls if you want to, but then you lose the benefits of writing high-level cross-platform code. Trade offs.
I'm not sure I follow. You're suggesting Oracle invest resources in Java bindings for Cocoa, Qt, and whatever the flavour of the week is on Windows?
That wouldn't make sense. Not only would it go against the Java philosophy of write-once-run-anywhere (Java is very hostile to cosying up to platform-specific frameworks), it would also be a mistake in practical terms - they're right to just keep maintaining JavaFX, which is a perfectly competent GUI framework.
If you are talking about Java's AOT feature (JEP 295: http://openjdk.java.net/jeps/295) then I don't think it is true AFAICS. The JVM is still needed, Java-Code can be compiled into a shared library but this is "just" a code-cache that can be passed to the JVM when starting the application. This feature is mainly aimed for improving startup.
Ah thanks, I got confused because you mentioned Java 9. I really hope Substrate VM or something similar gets into the JDK. Having the option of AOT-compilation or using jlink for bundling would be amazing.
For the purposes of this article, Clojure is "just" a library to process text, generate & run JVM byte code, and the workflow could be applied to a Clojure project.
The AOT compiling though would require Clojure-AOT followed by JVM-AOT I guess.
231 comments
[ 2.8 ms ] story [ 151 ms ] threadUnless you consider that basic support services are what the Java runtime should be providing on its own. Fundamentally, a command line Hello world should only take a few dozen bytes of bytecode.
Now all engineers are "angry" :) :) :) after seeing the same process spawned multiple times, and taking lots of gigabytes!!! (hehee)... I simply don't care and love the Slack app! (Teams is also nice looking, and Visual Studio Code rocks)
Of course there are far smaller libc implementations, but they may be missing functionality.
[1] Unless, of course you require an installation of Java... which would kind of go against the premise of this whole exercise.
you only pay for what you use if you dynamically link it.
Note, this on 32 bit arm, size might differ on different arches, all I have access to off the cuff:
ungh, go home ldd and file, you're both drunk and dead to me right now: Note no NEEDED section, so we're indeed fully static. 16K for a fully static hello world sounds pretty decent to me vs 8k for dynamic. Will be faster than involving ld.so as well. I could probably improve that further, but I'm not about to golf this tonight.isn't this only true for the first time a function is used?
once all of the linking is done, the GOT will just contain the address of the function and it's just as if it were linked statically, right?
Yes, but it will happen each time the program loads, which means your LD_* variables will get parsed/iterated over. Statically linking stuff in can help if you have a program that needs to be exec()'d in a loop. While it'll probably only shave off 0.001 seconds per exec() call it can add up, more so if you have LD_LIBRARY_PATH set to look on some slow storage like nfs.
But its a bit of a hyper optimization at that point. I've used this to really annoy a c++ developer saying c++ was faster than c. Evil trick on my part but my euler solutions were always faster. >.<
That said I really need to get back to debugging the segfault in building ghc 8.2.2 on armhf in the ghc rts. But its gotten me going through everything but ghc and whatnot. Annoying when things worked before and don't now. Even weirder that only the final stage build is at issue, the other two are fine.
Even if you don't buy that reasoning, it's just not very common to use non-glibc on most common distros.
... and honestly, I should probably just have been more explicit about the absurdity of comparing "hello world". That would sort of agree with the OP's post, but not for the same reason. I think reasons are important.
[1] ... but then you end up with discussions about the importance of locales, nsswitch, etc. etc. Even though I didn't bring it up, it necessitated this footnote. You see what I mean?
https://www.gnostice.com/nl_article.asp?id=225
The difference in abstraction level is amazing.
I think it's reasonable to say that if the the user code is transmitted as a managed intermediate representation then it's not native. Arguing beyond that probably isn't productive.
But that's this particular blog post. Java can be native, if you compiled all the user code to machine code ahead of time.
Seems like lots of projects are likely to become non-native over time, by this definition, even if they start out "native" with a basic C/C++ codebase, since lots of projects accrete some sort of scripting or extension interface that might use a runtime of some sort. Is Emacs not native? Does it really matter if the runtime (which is machine code) was made by the compiler developer or by the application developer in some cases?
I feel like there's an arbitrary line, and it's not entirely useful distinction to make.
A native app can be big and slow and ugly and fail to follow the OS UI guideliness. An app with a runtime can be small(ish) and fast and beautiful and strictly adhere to the UI guidelines for the OS in question. I want the small, fast, beautiful, app with standard UI behavior, no matter whether it's delivered with a runtime embedded or built from C/C++ (and a few others) and without a JIT.
I mean, we're just arguing semantics here, which is kinda silly. I think it's pretty neat; I don't really like working in Java, but I'd rather work in Java than C/C++, so if I needed to deliver a cross-platform GUI app, I'd certainly consider it.
Of course the JVM has advantages that it can dynamically optimize code according to actual execution profiles.
If I am not mistaken with the right instrumentation LLVM can also makw your program generate a special optimization profile which you can then apply to your final build compilation.
Well I think that's a different meaning of the word 'native'. They're native in terms of being written using the recommended techniques for that platform, but not native in terms of being natively compiled.
But as you say it's just a discussion of semantics.
Correct.
> Are programs written in C# not native, even on Windows?
No they are not, because .Net uses an intermediate representation, being Windows and Microsoft confers no magic "native"-ness.
> Are programs in Java for Android not native, even though it is the language much of the OS is written in and what the standard UI toolkit is built for?
Programs in Java for Android are not native.
Much of the kernel (Linux) is written in C. According to "Francesco Iovine, AndroidStudio lover" over at Quora[0] the UI toolkit is written in Java and the virtual machines (Dalvik and Art) are written in C++.
> Is Emacs not native?
Emacs is a strange and evil beast whose name we shall not invoke. No, but seriously – I imagine Emacs is a hybrid native / Emacs lisp program. Many programs with embedded scripting languages are hybrid beasts but they ought to be thought of as native apps if they are compiled for a certain bare metal hardware platform. I presume the core of Emacs is C. Ergo, native.
> Does it really matter if the runtime (which is machine code) was made by the compiler developer or by the application developer in some cases?
Yes, I believe it does matter.
> I feel like there's an arbitrary line, and it's not entirely useful distinction to make.
No, I don't believe it's arbitrary.
> A native app can be big and slow and ugly and fail to follow the OS UI guideliness. An app with a runtime can be small(ish) and fast and beautiful and strictly adhere to the UI guidelines for the OS in question. I want the small, fast, beautiful, app with standard UI behavior, no matter whether it's delivered with a runtime embedded or built from C/C++ (and a few others) and without a JIT.
True. But that is neither here nor there, that's a whole other issue.
> I mean, we're just arguing semantics here, which is kinda silly.
No, we are not. A native app is one which is either hand-crafted assembly for a specific hardware platform or compiled ahead of time targeting a specific platform. Native code is non-portable, the source code might be portable, but generally is not unless care is taken. Assembly code is never portable. Non-native (whether by VM: Java, C#, … or interpreted: Ruby, Python, …) tends to be more portable.
[0] https://www.quora.com/What-programming-language(s)-is-Androi...
If it's native, why isn't JIT to machine code not native? Because of the convenience of all of the above happening on a fine-grained level (individual functions), and all on the target machine?
Also, what is "compiled ahead of time"? Ahead of what time? Why is that specific time important? Obviously, code is compiled ahead of its compiled image being run; the compiled version cannot be run any sooner. Any JIT-ted function is compiled ahead of being called.
On most operating systems, we can load programs after the OS boots. Those programs can be developed after the OS booted.
I think that the only true definition of "native" is that the program image was compiled before the hardware was built and turned on for the first time, and was present in its ROM.
Anything else is not "ahead of time" and not native, damn it!
Installing a program on your PC is just a form of JIT. The system was fired up without that program being there, and the program was snuck in just moments before the user's intent to use that program. Not ahead of the True Scotsmans proper time: the time when components were stuffed into the circuit board and it was powered up.
If the software image is compiled in its entirety before being installed on a target, that is "monolithic". If parts of it can be dynamically loaded, it is "modular". Dynamic loading of functions with JIT is just heaping on more modularity: hyper-modular.
A situation involving JIT is non-native only in the sense or to the extent that there is non-JIT-ted code in the image. If there is an interpreter so that some things execute without being JITted, those things are not native.
So AS/400 applications are not native, given that they use an intermediate representation with a kernel level JIT?
Same applies to other mainframes that use a micro-coded CPU to execute the portable binaries using intermediate representation on their executables.
This includes C and C++ on those platforms, by the way.
.NET has had AOT support since early days, even though NGEN is not that good.
> Programs in Java for Android are not native.
Java is AOT compiled to native code on installation on Android 5 and 6.
https://source.android.com/devices/tech/dalvik/#AOT_compilat...
Starting with Android 7, it is interpreted in a tight Assembly interpreter, JITted with PGO, finally AOT compiled into a code cache.
https://source.android.com/devices/tech/dalvik/jit-compiler
There are AOT compilers available for Java and C#, just as there are interpreters for C and C++.
> So AS/400 applications are not native, given that they use an intermediate representation with a kernel level JIT?
Thanks for making me read up on AS/400 (or System i as IBM now calls[0] it.) I found this article: [TIMI – Protecting Investments and Integrity in IBM i](http://ibmsystemsmag.com/blogs/you-and-i/archive/timi-protec...) – it says,
“Each program that is compiled on IBM i gets turned into a set of TIMI instructions. Essentially, it gets compiled down to a set of intermediate code. For decades, that’s been a pretty common step for a compiler to take – get to an intermediate representation of the program before creating the machine-level instructions. One big difference, though, is that the compiler on IBM i does not go any further. It leaves the intermediate code connected to the program object, and then the lower levels of IBM i act on the intermediate code to translate it into the instructions used by the Power hypervisor and Power processor beneath the OS. IBM i does this only when necessary, not every time the program executes. Typically, the translation takes place once when the program is moved from one release of the operating system to a later one, and never again while it runs on that later release.”
> Java is AOT compiled to native code on installation on Android 5 and 6.
Then by your reasoning and terminology I think you'd also call IBM's tech AOT compiled, not JIT'd given that it happens once per OS release or app move, not each time the app is executed.
And I would say that the applications that get delivered this way on AS/400 and Android 5 and 6 are delivered as non-native (intermediate code as the article says). And then get translated AOT to native which is stored somewhere else and the non-native code is kept around.
Neat, I didn't know that about Android 7 and Dalvik. Is it the same for Art?
> There are AOT compilers available for Java and C#, just as there are interpreters for C and C++.
This I did know. :)
Always welcome your insights, thanks!
[0] https://en.wikipedia.org/wiki/IBM_System_i
> Correct.
Oh, come on. You can't seriously believe this nonsense. A native C++ program embedding (for example, to parametrically specialize some constructs at run time) an LLVM JIT which is in C++ again is going to be as native as they come.
> I presume the core of Emacs is C. Ergo, native.
And that C++ program I mentioned isn't, according to you, even though most of Emacs is delivered in interpreted byte code form. And if Emacs stated JITting the bytecode, it would cease being native. You really seem to have some weird and/or inconsistent definitions.
C# always had AOT compilation to native code via NGEN.
Just that few people bother to use it, because it only allows dynamic linking, the optimizer is tailored for fast startup time and requires an extra effort with application signing.
Windows 8 apps were always AOT compiled on the store via a "cloud compiler", based on Bartok from Singularity project. Using a format known as MDIL.
Windows 10 apps are always AOT compiled via .NET Native, which shares the backend with Visual C++.
Mono always supported AOT compilation and it is the way Xamarin apps are deployed on iDevices.
Which the method described in this particular blog post is going to support very soon – today you still need to invoke subtratevm or jaotc separately.
I still remember a Oracle JRuby / Truffle Ruby developer said Orcale has no plan to open source SubstrateVM.
This is Great News!
Edit: https://news.ycombinator.com/item?id=13653239
The plan is to support all major OpenJDK platforms.
There is also Project Metropolis, which was recently started, with the long term goal of rewriting all existing C++ code into Java, so AOT needs to exist in all platforms.
Yes, you can compile a QT or a GTK app for every platform, and use e.g. Python or Go to write the cross-platform part + package it into a single file. It's still as many files as you have platforms.
I see e.g. my wife, not an IT person, use a number of them. An eBay betting app, several utilities for bead art, etc, most written in Java years ago. Do they look polished and native? Hell no. Do they get the job done? They do. Could they look and feel better with a JavaFX UI? Quite likely. Would having a single binary to download, without installing a JRE first, improve their adoption rates? Quite likely again.
I have worked on a Java desktop app with Swing UI for over a decade. Mid 2000s we would get asked to "modernise" our applications UI, which really meant: "make it look like Windows XP".
After Apple released iTunes, which totally ignored the native look and feel on Windows, people stopped caring so much as long as it looked ok and was intuitive. The boom in web apps with every SPA defining it own internal LAF through CSS and Javascript and the fad for flat UI components seems to have further watered down the arguments for conforming to a native LAF.
I haven't played much yet with JavaFX so can't answer your actual question but I believe it is more flexible than Swing and Swing is already very customisable (though you sometimes need to create your own widgets by extending/implmenting off the default widgets).
In order to practice what I preach, I'm looking for something that looks native for most cases that I can use for side projects and become proficient in. For my current project I chose SWT over Swing because SWT supports a native look on Linux (via GTK) while Swing doesn't (as far as I can tell). However, SWT is kind of clunky and I wonder if there are better options or if my previous research is out of date.
On the otherhand, with Swing all you need to do is add the following line:
If you do, you need to make it look different on different platforms. That's not a step back.
Bazel is still a bit away from having Java 9 support [1] and it still requires some system dependencies (for the other languages and cross system support).
I wish more tools would go the "static binary" path that make it easy to build and use wrappers without having to figure out system configuration every single time.
[1] https://github.com/bazelbuild/bazel/issues/3410
For Windows, it's mainly perception - if engineer sees that a tool is like 200mb in the depot, he/she be like - that's too much :) "Remember why we pulled boost, and no longer use it - as it's huuuge!" :)
1. Setting up a project is still a pain in the butt. Tools like Gradle are a nice improvement over Ant (and some would say maven), but still most people don't even understand them. You have some serious reading ahead of you if you want to set something up that isn't already templated somewhere for you. You can lean on an IDE for sure, and for most Java devs this is probably a no-brainer. I'm weird in that I don't like magic. I prefer to know what the tool is doing on my behalf, and the Java IDE world is so complex that it isn't practical to learn that unless you're in the ecosystem for years. Then dealing with weird exceptions from the JVM can be maddening.
2. The Java world moves slowly. It could reasonably be years before many shops transition to Java 9, when you would actually realize the benefits of this in your work life.
3. So much Java runs on the server side anyway, where executable size and entrypoint doesn't really matter that much. Because of this, it may only be a small subset of Java shops that really get into Java 9/Jigsaw and iron out the bugs, and create tools/tutorials for others.
While Qt is great, we've been running into logistic problems - like we have plenty of tools that use it, and we are forced to place all the binaries into one folder ("bin"), and the Qt dlls there for legal reasons, license, but buying the license for static linking won't be a problem for us reallly. The real problem is that once we link our binaries statically, then our plugins that also use Qt won't work with them, unless we do some magic, and forward all QtXxx.dll end points to be from the main executable, or use more abstract interfaces - e.g. our plugins should not use Qt directly.
As build system, we used to have IncrediBuild, but since we are PS4 developers we get SN-DBS for free - http://www.snsys.com/products/SN-DBS.asp - it speeds up the build, but once the Qt moc/etc rules come in, the build needs to wait for these to be generated, and then proceeds.
There are ways to overcome this, and we are looking into improving this.
I've tried using .pro files, but first, I can't sell them to the rest of the engineers, as pretty much almost everyone knows Visual Studio, .sln/.vcxproj files. There are some ideas about alternative build systems, but not there yet. (at the end most of these just generate .sln/.vcxproj, like CMake, or premake, etc.).
You can statically link with LGPL code, as long as you provide a means to relink (typically, shipping .o files if requested).
https://www.gnu.org/licenses/gpl-faq.html#LGPLStaticVsDynami...
With BAZEL things were working pretty smoothly, but I've never used maven, gradle, ant, etc. Really weird, because If I post that I have 3 years experience with Java and not knowing any of these tools...
What I'm trying to say is that with BAZEL this might be easier for cross platform development (not sure though)...
http://www.red-lang.org/p/about.html
I gather the GUI story on Linux isn't great at present, and there's no iOS support, but all of the other important bases seem to be covered.
I've tinkered with it a bit today, and so far it's as advertised.
Except accessibility for blind people (through screen readers), and probably people with other disabilities as well. I just tried the Red GUI with the NVDA screen reader on Windows, and it's mostly inaccessible.
BTW, this is a problem with nearly every GUI toolkit developed from the ground up (that is, from the host OS's low-level graphics primitives). The exceptions are mostly the big, "bloated" GUI toolkits, like those provided by the major operating systems, the major browser engines (and by extension Electron), Qt, JavaFX (though only on Windows and Mac), and maybe a few others.
Edit: SWT is one of the most accessible options for cross-platform desktop applications. That's mostly because SWT primarily uses the host platforms' native widgets. But it does have some custom controls, and for those, it implements the platform-specific accessibility APIs. I understand that a lot of people don't like the conventional desktop look and feel though.
I find this is not Java specific and many of those other technologies have similarly painful project config, especially as soon as you do something non-trivial.
> The Java world moves slowly.
"Vendoring" the stdlib, which essentially is what is happening here, alleviates that (at the cost of not sharing source, which is usually OK for the JVM in non-security contexts). As for work life vs home life, that is not very Java specific. Many companies hang back on old standards by choice.
If I'm doing something that'll never exceed 1KLOC and doesn't depend on any exotic libraries, I can throw together a crate, module, bundle, package, etc in a matter of minutes and then forget about project configuration. Java... anything other than "local-machine CLI project with no dependencies and an IDE" will have you spending more time on config than code.
Dependencies and portability were by far the biggest issues. eclipse, netbeans, idea, et al didn't seem to do dependencies at all; even if you had a library jar actually on your filesystem it was a huge PITA to point at it, and getting a project that'd also compile on someone else's machine was horrible. leiningen didn't have a single tutorial that I could find and I voodoo'd my way through a clojure tutorial before giving up. maven broke in strange ways when I tried pulling in deps and figuring out the correct incantations in the pom files was a pain. More recently, I could probably have gotten along with sbt if I'd had a week to play with it, but it also has the "no useful tutorials" problem and I was on a time limit.
Some of this is certainly lack of experience, or even simple Doin It Rong. I could see maven being much easier with a directory full of examples to look at, for example, and sbt I'm sure is great once you wrap your head around it. I just feel like, even if I was limited by typing bandwidth instead of figuring-things-out bandwidth, those tools wouldn't hold a candle to python's or rust's tooling. Even makefiles and cmake seem to have better happy paths.
I'll look at gradle next time. There are situation where I could use a jar.
These things are oriented towards working with a dependency management/project management thing rather than manually specifying libraries. I'd really recommend maven, using the IDE's integration with it, particularly if you're getting started - Gradle can be more concise but it's definitely buggier and less well documented/supported.
> maven broke in strange ways when I tried pulling in deps and figuring out the correct incantations in the pom files was a pain
Dependencies should just work unless you were trying to do something weird like using jars from the local filesystem - don't do that (if you really must, install them into the local maven repository and use them from there: https://maven.apache.org/guides/mini/guide-3rd-party-jars-lo... ). You shouldn't need any incantations, just simple XML that should autocomplete in the IDE, or you can use a GUI rather than directly - e.g. in eclipse you just right click on the project -> maven -> add dependency, and search/select the library you want. Do you remember what problem you had more specifically?
> Some of this is certainly lack of experience, or even simple Doin It Rong. I could see maven being much easier with a directory full of examples to look at, for example, and sbt I'm sure is great once you wrap your head around it. I just feel like, even if I was limited by typing bandwidth instead of figuring-things-out bandwidth, those tools wouldn't hold a candle to python's or rust's tooling. Even makefiles and cmake seem to have better happy paths.
SBT is awful throughout, but my experience is that Maven is much much better than anything in Python-land (no messing around and mode switching with virtualenv, no need to separately run pip, one consistent tool that everyone uses, one packaging format, one central repository, better integration of testing with the project), and directly comparable to Cargo.
How do I get a preconfigured quickstart project for say iron and diesel with rust? I read the rust book. I must have missed it.
The book doesn't cover everything. That said, we currently don't have a built-in solution for this feature; we had one but it never hit stable. Since it didn't get accepted before the impl period late last year, the discussion was effectively on-hold; it can get started up again now that it's past the new year.
That said, many projects provide their own way to get started. Diesel's CLI has a "diesel setup" command to get going with it, for example. I'm not aware of one for Iron.
Java 9 is short term support release, ending support with the release of Java 10 / Java 18.3 (March 2018). Next LTS JVM release is supposed to be 11 in 1.5 - 2 down the road.
A lof to large organizations will be holding back for the next LTS release before considering migration.
I guess you could argue this might allow Java on the Desktop to be feasible again, but it might be too late.
I surely get to use it more than Electron apps, thankfully.
Many coworkers I've worked with have called it complicated and then I find out they really haven't learned the (very simple) lifecycle and how build behavior gets attached, etc. This is all very simple but it is something to learn.
I don't know why this happens. I think programmers are so used to imperative (ant/Grunt/etc/etc) programming/building that it becomes confusing for them when they encounter a declarative system. And their brain revolts. Because they are like how do I just do a thing (i.e., copy some file somewhere, call a "build" method, etc, etc.)!? Instead of realizing the value of the declarative + idiomatic Tao and learning it...they say no, no gimme gimme let meee do it. Much like my two year old. And then I'm left fighting non-reproducible builds and getting their projects going in my IDE like it's somehow 2005 again. But Maven is great, declarative systems -- especially declarative build systems are the optimal way to do builds (in most cases).
Because, after all is said and done, programming is about having your computer "do" something - whether it be to write some bytes to the disk or to send some bytes to the network.
It's just that sometimes there's an advantage to use an abstraction - such as say "SELECT * FROM TABLE WHERE ROW_ID =14" is an abstraction over something like "for (int i =0;i<table.size();i++) if(table.row[i].elem[1] == 14) ... ", but often you don't need such a complicated abstraction, you just "need something done" before (or after) building. Whether it be that you want to download an HTML file to package, or to move the resulting file to a certain directory, or to clean a certain directory, your build language shouldn't be that arcane that you have to create a "build.sh" to get things done.
— Maven is simple, not arcane. I’ve produced countless “custom” builds with wild variations of need and never has Maven let me down. In some sense this is easy to prove (see maven-antrun-plugin); however, Maven’s core plugin/idioms supports 90+% of use cases I’ve seen over many many “weird” build requirements. To your example, “copying files” is fundamental; however you have to learn the idiomatic way to do it if you want to reap the benefits. Otherwise, just call out to maven-antrun- or similar. But then you’re chasing your tail.
The issue with convention over configuration is that you don't see how things should happen, because they're hidden behind the convention.
For example, what are the steps behind your Android build? Can you tell me exactly what steps gradle takes when you run gradlew assembleDebug?
So if for whatever reason you need to modify something, you're completely on your own.
$ gradlew -m assembleDebug
Learn the tools you use..
Not always. Often, particularly in scientific computing, you just want to ... compute ... a result. I mean sure, the computer needs to display the result to you, but the computation isn't about displaying it, it's about computing it. Just like adding up a bunch of numbers on a calculator isn't about getting the calculator to "do" anything.
> often you don't need such a complicated abstraction, you just "need something done" before (or after) building.
Abstractions should be simpler than the thing they abstract over, that's their whole point. Treating my computer's memory as a flat array of numbers is simpler than thinking about how much current is flowing through each RAM wire. "Compile all source files" is simpler than "execute javac Foo.java, then execute javac Bar.java, then..."
> Whether it be that you want to download an HTML file to package, or to move the resulting file to a certain directory, or to clean a certain directory, your build language shouldn't be that arcane that you have to create a "build.sh" to get things done.
You shouldn't need a build.sh, agreed, but nor should you need particular things to happen to particular directories. Maven has great support for things like "package my documentation in the standard way". It's only when people try to fight it about the low-level details that they really shouldn't be caring about that they run into trouble.
For example, if you have a multi-pom project with a parent pom (not unusual in a medium-sized codebase, never mind large), and you have unit tests in your child poms, they'll get executed with dependencies resolved locally for that child pom, and not with the global dependency resolution that satisfies all constraints that need satisfying at the parent level.
The upshot is that you easily end up running tests using different versions of dependencies than what you deploy with, misleading you into thinking things are working, and can end up with hilarious NoSuchMethodError at runtime.
The "solution" is to pin your versions using dependencyManagement, but that's no real solution at all, not least because it's neither automatic (though dependency convergance using Maven Enforcer helps, and I've developed some scripts that help further) nor is there an easy route forward when you want to bump versions safely.
As it should, otherwise you'd get the even more hilarious situation where your tests pass when you run the single-module build but fail when you run the multi-module build.
> The "solution" is to pin your versions using dependencyManagement, but that's no real solution at all, not least because it's neither automatic (though dependency convergance using Maven Enforcer helps, and I've developed some scripts that help further) nor is there an easy route forward when you want to bump versions safely.
This is not a maven issue, it's a combination of Java's flat classpath and the reality of diamond dependencies on versioned libraries in any system. We could allow multiple versions of a transitive dependency on the classpath but then you get Rust's hilarious "expected Foo but was Foo" type errors. Java 9 modularisation should reduce the problem by allowing modules to have explicitly private dependencies, but the problem exists everywhere.
This isn't true; there are better solutions already existing. E.g. Ruby with the Gemfile.lock approach. I'd like to be able to do a two-step: do a global analysis of dependencies and pin the common versions for diamond situations, but not need to maintain or calculate those pinned versions manually. And I still get to use the pinned versions from the global resolution for executing tests etc. on submodules.
As it is, I've had to write a bunch of tools to rewrite the dependencyManagement as and when required. The main app I work on is linked into the Hadoop ecosystem, and that dependency set ends up being quite large.
Another issue with Maven is rebranding: when the groupId of an artifact changes, but the package and class names don't; see e.g. asm / asm vs org.ow2.asm / asm, or the whole codehaus debacle.
I have spent more than two weeks of my life updating, maintaining, fixing, researching and tooling Maven pom files, and it was almost all around deficiencies in dependency management.
Let's not get started on trying to get builds to work reliably offline, caching maven repositories, etc.
I dislike this for the same reason as before: I find it really valuable that building a single module on its own behaves the exact same way as building that module as part of a multi-module project. If you want to ensure that the tests run against the same version as in the final product, I do that by making eviction an error.
> Another issue with Maven is rebranding: when the groupId of an artifact changes, but the package and class names don't; see e.g. asm / asm vs org.ow2.asm / asm, or the whole codehaus debacle.
Maven has better handling of this than most; it can at least warn/error when this has happened, and if you're using the shade plugin or similar it will warn or error when two jars contain the same classes. Yes it's a problem, but it's much more of a problem in other ecosystems.
> As it is, I've had to write a bunch of tools to rewrite the dependencyManagement as and when required. The main app I work on is linked into the Hadoop ecosystem, and that dependency set ends up being quite large.
There are standardized plugins for the common use cases e.g. "mvn versions:use-latest-releases". Most things that can be automated are. But since most of the library ecosystem predates version ranges and semVer, there simply isn't an automated way to know when using a newer version of a transitive dependency is safe or not.
Building is a simple concept: dependency DAG + inputs -> artifacts. The "->" here can involve arbitrary intermediate artifacts and steps.
Maven ignores this fundamental concept of building. Rather than treat interim dependencies as part of the DAG, there's a hard-coded recipe of lifecycle steps.
This is why I personally cringe at maven - it has nothing to do with the fact that it's declarative (virtually every build system is largely declarative). It has everything to do with hard-coding one particular set of build steps into a supposedly general build tool.
With Maven, if you follow Maven's way of doing things, everything just works. But, if you need to do something different, or have some rare use case Maven's designers weren't focused on, you start struggling a lot to get Maven to do what you want.
Gradle is a lot more flexible and if you have some uncommon requirement you are far more likely to successfully implement it using Gradle than using Maven.
You'll be fine as long as you realise the Maven-ey way of doing the thing is to write your own plugin.
But most of the time people just want their build to do something different for no real reason, IME.
A short while later I was wondering why I'd never tried that before: Maven plugins are really quite simple to write.
This assumption is why developers are abandoning Java in troves with the serverless trend, where exe size and init time matter immensely.
And good riddance!
>You have some serious reading ahead of you if you want to set something up that isn't already templated somewhere for you.
Start with a maven project,
$cd /path/to/maven/project/
Create your archetype,
$mvn archetype:create-from-project
Install it in your local repo,
$cd target/generated-sources/archetype
$mvn install
$mvn archetype:crawl
Generate a new project from your new template,
mvn archetype:generate -DarchetypeCatalog=local
I'm glad freedomben likes nodejs, but he shouldn't talk dirty about Java while pretending to know something about Java. His one comment to this story dominated what could have been an otherwise interesting discussion about a new feature of Java 9. Sad.
My read is that Java is doing this now because they ignored microservices and containerization at their own peril. 8 and 9 between them include a bunch of things to squeeze runtime and disk size to be comparable to other systems.
Really? Most of the "microservice era" or "cloud native" or $timely_buzzword platforms are really big. Golang binaries for large services are bloody huge.
TL;dr don't assume other systems have small footprints until you deploy a Node.JS app and do "du -h node_modules/"
I am yet to do any enterprise Web project that isn't a classic application server.
Not everyone and his dog are jumping into it.
People make monoliths for performance reasons and then can't maintain the monolith, so they go back to forced independence. Every company does this on a different cycle but the epicycles are the 'fads' you see, and it's been going on since at least the 70's.
Similarly and perhaps more forgivably, people organize a system (think, client-server, peer to peer) for reasons of the current laws of physics as they apply to clocks per second, storage space, and latency. Those inequalities shift with each new generation of hardware. So what was the right thing to do 15 years ago might be the right thing to do again next year. It's not that we've been wrong for 15 years, it's that we are wrong now. And will be wrong again in another half a dozen years. But we have to use the tools available to accomplish the goal now, and that means we have to adapt, repeatedly.
http://beust.com/kobalt/home/index.html
And that is a simple template that just takes advantage of curated OSS ecosystem dependencies by the Spring team.
There’s really no magic, I find Maven or Gradle to be as opaque as say Gem bundles, Bower, or NPM and Grunt (Or whatever the new flavour du jour in Node land is). That is to say, the core concepts are all mostly similar but just slightly different enough to cause hair loss. And let’s not talk about Golang dependency managers...
Also, from the Dropwizard tutorial:
1) configure Maven 2) create a config class 3) write a mapping.yaml for “Jackson” 4) create an application class 5) create a representation class 6) create a resource class 7) register the resource 8) configure maven again (!) for building a .jar 9) finally run it.
With node you literally write 5 lines of code importing the http module and run `node server.js`. I can’t possibly imagine what steps could be more complicated than Dropwizard. I consider webpack overly complex myself, but it’s a completely self-inflicted option and not a standard for nodejs development at all. I’d be curious to know what docs you were trying to follow if you can recall.
1) Install node.
2) Write script. e.g.
3) Run script: Java1-10) Download Java *
11) Ensure JAVA_HOME is set right
12) Write java
13) Compile java 14) Run java * Yes, this is obviously facetious.EDIT: Code formatting thanks to https://news.ycombinator.com/formatdoc
1. Dependency management is probably a lot easier with Maven than with C++ or Python. Hope that needs no reference...
2. No idea why, but Java is backwards compatible. So not updating to the latest version is only laziness.
3. Having much smaller containers or virtual machine disk sizes should lower your AWS/Google/Cloud... bill a (little, but whatever) bit and therefore make your CFO happy...
Apart from that, there is another reason why companies don't upgrade and that's because they are locked to a certain java version by their application server. Upgrading to a new java version would require upgrading the application server as well, which would cost a lot in terms of licensing and which would introduce some risks and overhead of its own.
[1] https://stackoverflow.com/questions/23801950/spring-4-and-ja...
ADDENDUM: Yes, C++ is technically even more backwards compatible - if your code base and all dependencies was/were 100% standards compliant (har har). But again, for me, the main point is that most newer languages first have to prove they can keep up to such levels of backwards compatibility (e.g., see the Python 3 fiasco...).
Will we be able to create runtime-less executables that are fully dependency free? That would be awesome to write a bootloader in Kotlin or any other Java Synthax Substitute.
Obviously it's Spring centric.
While I was at Google, instead of having multiple .so files, the main launcher was a C++ binary, and all external C++ dependencies were linked into it (that's it if you have the source code), then you didn't need that.
I guess now it's up to the BUILD system to achieve that, where if you have more flexible BUILD language you can instruct everything to go in the main launcher file, then have all the .jars into one, slapped at the end of the file.
At the end, ship or update only one binary to your service, desktop machine, etc.
Native libraries used by JNI can be shipped in the jar files and are read from the classpath, in addition to reading them from the ordinary linker path.
(edit: turns out I'm wrong about this on Windows)
I think the same is with the Python packagers, or C# shadow copy.
This way there is no need for extra install, uninstall. Possibly too much over-engineering for full blown product, but if it's something that needs to be run, and updated on tons of machine - not having to deal with extra artifacts might be a win.
Looking at an example of a library that does native binding: https://mvnrepository.com/artifact/com.github.fommil.netlib/...
It appears the artifact is a DLL, and not a JAR. Thus your original question stands.
I've tried loading dlls from memory (there are several examples on the net) only to understand that there is more to be done (like getting the PDB information correctly loaded, and then some more).
http://openjdk.java.net/jeps/178
http://openjdk.java.net/jeps/178
Superior exactly in what way? Electron allows access to an enormous audience of developers and the web ecosystem. You really can't compete with that and would be silly to try at this point.
The problem is not artifact size but the JVM slow start-up time. This is made worse by almost all Java frameworks that by definition do all their own stuff before passing control to your real app code.
Such executables are not something you would put in a loop in a shell one liner, and that is the space for command line utilities Go has occupied successfully.
https://purelyfunctional.tv/article/the-legend-of-long-jvm-s...
But frameworks (and runtimes for things like Clojure) absolutely do. It would be possible to write a fast-starting framework for Java, but i suspect nobody has because there's no demand for it, because nobody who needs fast startup uses Java, because it doesn't start up fast!
That said, i think the real reasons Go has done so well in devops are (1) it's easy to pick up for devopsists coming from Perl/Ruby/etc backgrounds, (2) static binaries are easier to deploy than a jar plus a JVM (not massively easier - but easier enough), (3) a focus on systemsy stuff in the standard library and community, and (4) sheer snowballing momentum, in that Go has become the default choice for stuff like that.
Things like this are why all the "Java isn't slow" articles miss the point completely --- 100ms to do nothing useful, on a presumably quite fast machine, is ridiculous.
For comparison, 100ms is roughly the time it takes to grep an 18MB file:
http://dtrace.org/blogs/brendan/2011/12/08/2000x-performance... (look near bottom of post).
"Ridiculous" is like "unprofessional", it's what you say when you don't have a real argument. Yes, ha ha, 100ms, very droll. What does it matter in practice?
The major pillars of DevOps today are long-running processes, very complex pieces of infrastructure. Which might play into the strengths of the JVM, if the packaging and deployment story simplifies and becomes more competitive with Go.
Sure, "shell one liner" utilities might (?) be best served by native compilation. But DevOps is not merely another word for sysadmin.
It actually was totally fine and surprisingly snappy. I’d suggest giving it a shot.
I don’t know how to revert the jvm can’t be used for command line tools because of slow startup times zeitgeist but I don’t think it’s accurate anymore.
I hope some work will be done there. One could scan the libs in parallel, caching results, building/shipping a search tree on packaging time and so on.
In pure servlet times you could directly define your starting points, define, which libs to exclude or include for the search and so on.
At least no one has to edit xml files anymore to wire components and impls together.
Maybe I'm a little overly jaded, but the Java apps I've worked on (which is admittedly only a handful) have all had these giant sprawling messes of dependencies; it feels like there's a lot of code to accomplish very little. The Golang-based services I've worked on feel like the opposite; very little code to accomplish a lot of things, without much ceremony.
Edit: And that's not to say that I'm opposed to dependency injection; rather, I'm quite happy to do constructor-based dependency injection by hand. When that starts to feel painful, I look at the system I'm working on and wonder if it's getting too complicated/has too much coupling/etc.
For us as a little company without access to many developers with affordable pay expectations, it is a big relieve, that a lot of specialist knowledge is bundled together in spring. Such as how to do central configuration, logging, monitoring, failover, loadbalancing, streaming, backpressure support, db connection pooling, message queuing, and so on. And you need special knowledge only when something fails. And when it fails, you can assume, its done the same on each service. It helps a lot. You have then a wider pool of people you can ask to help you to do the actual business coding work.
It reminds me a little on how maven defaults said: code belongs into src/main/java and test below src/test/java and then have a little pom.xml,that describes your project. It has brought sooo much relieve to get rid of so many flavors, how people have structured the code. Not to forget the style of make scripts. You can now open many projects in any IDE without any hassle, you do not have to search forever, where the starting point is and so on. I always forget that. Less work for my little brain, when navigating between projects.
So, even with the dependency hell (i totally agree), i am ok with it, as i seem to forget, what i dont have to do on each individual service anymods. And i have access to a rich ecosystem, that is maintained and supported and people react on issues.
Edit: and very very fast startup.
The current dominant culture of the Java community is very weird. Although Java has a huge standard library, if you don't use a lot of third-party libraries, you will be viewed as a non-professional Java programmer.
Most popular Java tech stack look open sourced, but are backed by lots of money provided by many companies with bad reputations on pure open source culture.
BTW, slow start-up is not the only problem of many Java apps. GUI Java apps often lag for one or more seconds from time to time, which hurts the experiences of Java GUI apps much.
The third problem of Java apps is they often consume much more memory than apps written in other languages, in particular for the long running Java apps. The longer they run, the more memory they will eat.
[edit] the library use way of Java, by putting library jars into your projects, is not good as the way of other languages, by putting library sources into your projects. By putting library sources in your projects, you can view how the libraries are implemented easily. Yes, you can also put Java library sources into your projects, but the main stream culture of Java doesn't recommend to do this. Just look at maven.
[edit 2] just my personal opinion. I don't like the way to use a separated VM to run many apps. This makes it is hard for me to use a different permission setting for each app. Sometimes I want to block a Java app to access network, but I must block the whole Java VM to achieve this.
Second, i am surprised to read, that people would still put dependencies/libs into their projects, even in their source code form? I thought, that was one of the reasons, why dependency management was introduced, to get rid of that. One ships a descriptor, what libs were required/used, when the lib has been packaged. And in one's IDE one can view all the dependencies as one wishes, in binary or source code form. I am very confused about your statement. (though in the final App, one ships all the libs in the packaged form of the app, unless provided by the runtime environment. But only then. Though its optional, one could also download the deps when starting the App)
And third: The longer an App runs, the more memory it eats? Its like with any other App: if it needs that much memory and it does not release it afterwards, well, then it is a feature or a bug. If it releases the memory, then it is only released within the JVMs memory space. The common default for thag is 4gb per JVM.
Its like the page cache in linux. Once a file has been read into memory, it will usually sit there for a while, unless someone else needs that memory. Thats why on a system with 128gb and a lot of file access, you see free memory going down and down. But its most of the time the page cache eating up that memory and is mostly not a problem. But can be confusing, when one is not familiar with it.
Ah, so many things one can tell.
What I mean is dependencies presented as sources, vs presented as Jars. It has nothing related to dependency management.
Did you mean that?
Now, when i use this library, my IDE knows how to lookup the source jar, so i can always browse the source code. When i see a bug or need a feature, i go to the repository, patch the code and release a new version of that library. And then i bump up the version number of that library in my own project as well.
If i do not own the code, then i ask for a change with a patch (in best case). And use a workaround in the meantime in my project. Earlier or later the updated version of thr library has been shipped (maven repo) and i bump version number as well and remove my patch.
And worst case: owner does not want to change, well, then i fork the code and add it myself, tag the library, release it to my artifact repository and so on. But i barely do that.
In any way, it all relates to my artifact repository (which proxies through official repos such as maven repo) and dependency management from maven, gradle, ant, and so on.
How do you do it?
But the fork will only be made if I have confirmed the fork is worthy to make. Before the potential fork, I temporarily modify the code in the local clone of "others.com/projects/foo" directly. If I find my modifications are useless, I will revert the modifications so no forks will be made.
Other processes are like what you described.
Yes, there is still not a perfect dependency management tool in Go world, but there is one official dependency management tool in developing, which will be released alongside with Go 1.10.
The standard library is where modules go to die. The fact that this phrase originates in the Python world tells you that this isn't a Java peculiarity.
> Most popular Java tech stack look open sourced, but are backed by lots of money provided by many companies with bad reputations on pure open source culture.
The sad reality is that those companies are the only organisations that commit serious resources to open-source development, outside a couple of specific niches (web development, unix-like OSes, scientific research up to a point). Those stacks aren't open-sourced in other languages, they just don't exist. And the whole point of open-source is that it benefits everyone regardless of how pure or otherwise the original motives were.
> the library use way of Java, by putting library jars into your projects, is not good as the way of other languages, by putting library sources into your projects. By putting library sources in your projects, you can view how the libraries are implemented easily. Yes, you can also put Java library sources into your projects, but the main stream culture of Java doesn't recommend to do this. Just look at maven.
WTF are you talking about? You declare your maven dependencies and they can be resolved as source or binary. In eclipse I can click through to any library function and see its source immediately. (It's one of the best dependency-management systems going, in any language; there's a single central repository that everyone uses in practice, but it's easy to run your own if you want. It's years ahead of everyone else in terms of package signing. There are multiple independent codebases using the same repositories, not just in theory but in practice).
> [edit 2] just my personal opinion. I don't like the way to use a separated VM to run many apps. This makes it is hard for me to use a different permission setting for each app. Sometimes I want to block a Java app to access network, but I must block the whole Java VM to achieve this.
Again completely normal - Python, Ruby, C#, OCaml... will have exactly the same issue. Get a better firewall.
Surely, you can view Java dependency sources. It is just that most Java programmers don't care about the sources, they are just care about the jars (the default culture).
In my honest opinion, cross-platform by bytecode has few advantages over cross-platform by source nowadays, on the other hand, cross-platform by bytecode has many inconveniences.
And, (in my taste), single central repository is bad. That's why I don't like Node also. The npm central repository is the source of many Trojans. Many Java and Node developers are not aware of and have no ideas on what they have downloaded through chain dependencies.
> Again completely normal - Python, Ruby, C#, OCaml... will have exactly the same issue. Get a better firewall.
Normal != good.
Not my experience. Actually getting to the source of your dependencies, in practice, is easier in Java - just one click in your IDE - than in any other language. Doesn't that suggest that Java programmers care more about sources than other language users, not less?
> In my honest opinion, cross-platform by bytecode has few advantages over cross-platform by source nowadays, on the other hand, cross-platform by bytecode has many inconveniences.
Well you're entitled to your opinion but you should probably back it up with something more specific if you want to convince anyone else.
> And, (in my taste), single central repository is bad. That's why I don't like Node also. The npm central repository is the source of many Trojans. Many Java and Node developers are not aware of and have no ideas on what they have downloaded through chain dependencies.
You don't have to use a central repository if you don't want to, and some people don't, but it's very convenient to have the option if you want it. Maven central requires PGP signatures on anything published there, so it's very easy to enforce that all the dependencies you depend on come from trusted people if you really want to - as far as I know there's no non-JVM language that does that, certainly not with anything like as large a base of signed libraries available.
> Normal != good.
Agreed, but you started out by claiming that Java's culture is very weird. It isn't.
The only benefit of bytecode is to save compiling time. Nowadays, CPU becomes much faster than the time Java was invented, 20 years ago. So the benefit is weak now. Another promoted benefit of bytecode is compile-once-run-anywhere. However, I think this is a hoax. It is not special, for script languages code runs anywhere without compiling.
I was once working on a large project on the JVM: our Fat-JAR was really working on Linux, Mac and Windows. The exact same JAR. And it didn't matter on which system we have built that JAR. This may not be possible for every use case - but I don't think it is a hoax.
> It is not special, for script languages code runs anywhere without compiling.
IMHO scripting languages like Ruby, Python, etc. are quite hard to deploy, especially if they have dependencies. In comparison to languages like Java, Go or Rust.
In terms of throughput I agree with you. But start-up latency is already Java's weakest point, and having to compile on startup would make it worse.
> Another promoted benefit of bytecode is compile-once-run-anywhere. However, I think this is a hoax. It is not special, for script languages code runs anywhere without compiling.
True as far as it goes, but certain types of code simply aren't practical in scripting languages. You'll never see people implementing e.g. an image format decoder in a scripting language; they'll use bindings to a native-compiled (C) library instead, with all the problems distributing that entails. This is why things like docker are so popular with Python users: in theory Python is write-once-run-anywhere, but in practice most Python codebases end up depending on one or more native modules and need to have the correct version compiled. Whereas Java bytecode is adequate for things like image codecs, and in the real world you really do see large Java codebases that don't use any bindings to (non-JVM) native libraries.
Depending on what definition for "slow" you are using it absolutely starts slow.
As mentioned in a cousin comment, the JVM takes ~100ms to get to user code. This makes it impractical for small applications where the user's code takes less than a second to complete. It certainly gets slower with more libraries, but for some applications ~100ms added to startup makes using Java not viable.
Just some hard data to support Java being slow. I ran Hello Worlds in Java, C, Node, Python, and Ruby. Java is the slowest out of all the languages I tested.
Maybe in SV, because I am yet to see it being used in any of our projects or hiring processes.
Docker and Kubernetes are the most prominent, but there is a whole ecosystem behind them.
Again, yet to use any of them, beyond watching some talks at a few conferences.
Still classical server deployment processes.
Of course, companies using software written in Go, are open to use Go somehow.
> [...]
> and superior to web-hybrid options like Electron
How is Java or Electron (JavaScript+WebKit) considered native nowadays?
Please use native APIs, so my laptop can actually hold 10h load on battery.
edit: can we remove native from the title?
Does the app use the most efficient methods provided by operating system? Is the graphical user interface consistent with the other applications on the same system? Is number of syscalls predictable?
That wouldn't make sense. Not only would it go against the Java philosophy of write-once-run-anywhere (Java is very hostile to cosying up to platform-specific frameworks), it would also be a mistake in practical terms - they're right to just keep maintaining JavaFX, which is a perfectly competent GUI framework.
I haven't done much more than dabble, but it was an enjoyable dabble. Unlike vanilla Java.
It even compiles to JS with a relatively small-ish runtime. It's big enough to cause problems embedding it, but it's small enough to be workable.
https://github.com/JetBrains/create-react-kotlin-app
The AOT compiling though would require Clojure-AOT followed by JVM-AOT I guess.
https://news.ycombinator.com/item?id=15521611