Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

Essentially all of the quoted usecases switched from a slow dynamically typed language to Go. Of course that's an improvement.

But I still don't see why you would choose Go over Java (or Scala) for serious backend development. Java has more libraries, is faster, has generics (for the love of god), has better IDE support, and has a larger hiring pool. In summary, the ecosystem is more mature.

Java's checked exceptions are less painful then Go's C-style error handling. They could have gone with something sane like Rust/Haskell style error handling (using the type system), but they instead regressed to return value checking.

The complaints about Java's overwhelming verbosity are mostly dated both on the language-level and the ecosystem-level. Java 8 has lambdas, streams, and more. Spring Boot and Dropwizard are 2 modern, lightweight frameworks that do away with the XML configuration nonsense.

I'm actually genuinely asking why anyone would choose Go over Java and not trying to start a flame war. An API I'm working on is due for a rewrite and it's currently written in PHP. I'd like to give Go a chance but it just seems like a poor choice compared to Java.



I find java's ecosystem to be it's biggest drawback. Yes, there are libraries and frameworks available for everything. The drawback is that every simple task, from building to testing to servers is wrapped in so many useless layers of indirection and configuration I just want to tear my eyes out. If you could throw out all the nonsense that has infected java and just build simple things from scratch on the jvm that would be awesome. But it's too late.

I find that creating go backend services is super easy and simple. The builtin web server is amazingly performant. I've found it super easy to integrate with other services (cassandra, postgres, mysql, mongo, nsq). The result is always high performance apps with a low memory footprint and high test coverage.

When it comes to type systems, I find go's handling of errors to be closer to rust than c. Basically multiple return values encapsulate the same information Rusts's Result<T, E> does. You just deal with:

    if a, err := f(); err == nil {
        // do something with a
    } else {
        // do something with err
    }
 
rather than:

    match f() {
        Ok(a) => { // do something with a }
        Err(err) => { // do something with err }
    }
Rust certainly has the advantage in type safety, but I find the 2 forms mostly equivalent for the things I care about.


In the rust example error handling is enforced via the type system whereas with Go it depends on your (and others) discipline.


You're correct. Go doesn't leave it entirely to discipline, since unused (or unhandled) variables are a compiler error. You can silence that error with _, but it sticks out to the eye as broken code.

However I'm not trying to argue that go gives you the same type safety guarantees that rust does, it doesn't.


Thanks, I forgot about the warnings. It's been a while since I've used Go.


Its not a warning, its a "will not compile" :)


Isn't the technical term "error"?


I suppose the technical term would be "fatal error". I was just clarifying it was a warning since C compilers, for example, will happily spit out many warnings and then hand you binary-


Yeah, it's a worthwhile clarification. Of course, the distinction is less hard than it might be, given that a lot of us build with -Werror.


I'm much more productive (in terms of bug-free-functionality-per-hour) in Go than I am in Java (and even more so in Elixir than go).

It seems the value of those 3rd party libraries are not as much for me as for you and others. I guess cause the essential stuff is covered for Elixir and most other languages.


I like coffee and long walks.


Great point. If you switched to those language you might have more time to go for coffee and take long walks, because your system have a higher chance to manage errors and crashes and you don't have to rush to the office right away or at night to fix issue.


An experienced programmer friend of mine uses Go professionally. I was surprised to hear that he much prefers Java: he said that many concurrency libraries are available for Java and that Go's features are quite limited in comparison. He dislikes the fact that you have to break Go's poor type system to get many things (such as tests) to work. He has a pretty strong background in FP, so I think that perhaps Go's interfaces are the straw that broke the camel's back.

This made me realize that I'm still holding onto some biases about Java, and that it's worth a look. I did start to dabble in Scala (and I have experience with Clojure), but it seemed like I'd want to know some Java before doing Scala, whereas that didn't seem as necessary with Clojure.


An explanation for downvotes would be appreciated... perhaps "poor type system" was too strong wording, and for that I apologize. But it was surprising to hear his opinion re: concurrency, as from what I understand that's one of the biggest features of Go.


"poor type system" isn't too strong, it's just what it is.


Java actually doesn't have generics. It has syntactic sugar for generics, but they are so horribly broken they can't be fixed.

For example, because the generics are just sugar for casts, you can't specialize them. Because you can't specialize them, you have to put behavior in the "wrong place". Take for example a hash map from Double -> T. Because IEEE floats don't actually form an equivalence class (NaN != NaN), they don't make great keys to a hash table (if you put NaN in, you can't get it out). But, rather than specializing the hash table for floats to give special NaN handling, Java had to make Double(NaN) == Double(NaN), so when they're boxed, they do form an equivalence class.

And if that were the only inconsistent behavior in primitives versus their boxed counterparts, that would be great...

EDIT: To those who downvote, would you discuss your objections? I understand that I may come off a bit caustic, but having been burned by the myriad correctness issues in Java, it's hard not to. These aren't abstract problems that don't come up in practice -- for a public example, look at what Paul Phillips has to say about the JVM and standard libraries.


It won't be longer true in Java 9, latest Java 10.


Overall that's great to hear, but I can't help but feel that it's too little too late. Once they fix the generics, are they going to go back and fix the secondary issues too (like the issue with Doubles)?

I know this isn't a popular opinion, but these correctness issues really matter. For example, you can see the impact these choices in the JVM and the standard library had on the Scala community, ultimately forcing Paul Phillips to fork the compiler.


When people focus on a language, they tend to think only about the language and not the ecosystem around it. Yes, Java 8 has closures, but then again it will be a very long time until the ecosystem will move to using them. And for example, even though Scala has baked-in features to make functional programming much more pleasant / practical, it's not those features that position it as a functional programming language, but rather the ecosystem around it. In other words, even though you can mostly use a language that has closures in an FP fashion (and people did so with languages like Java or Javascript), it's painful doing so not only because of the language and the standard library, but also because the other people and the supporting libraries are not doing that and then you're the weirdo that swims against the tide.

On the other hand the JVM on the whole is an extremely good platform and given that one can use on top alternative languages that do make a difference, like Scala, Clojure, Ceylon or Groovy, well that's the comparison I'd like to see ... the JVM versus Go.

On your arguments - Java's checked exceptions are deeply broken IMHO, but something that works much better in the context of a static language are types such as `Try[T]`, `Either[L,R]`, `Option[T]` or `Validation[E,A]` from Scala. They achieve their purpose of documenting the error in the function's signature and can do much more than exceptions can, they force you to either deal with it or escalate and their API is very comfortable. Unfortunately whenever you bring these into a discussion, people dismiss them because you know, monads and applicative functors are apparently too "academical". But we keep reinventing broken wheels, because we can't bother to learn anything else that isn't in the gang of four.

On Go my personal opinion is that it is a very poor choice compared to the JVM, even when speaking about Go's strongest points, like performance and concurrency and yes, I believe that the JVM is a strong winner on all points. But then I wouldn't expect people that have chosen Node.js or Python/Gevent to start making good decisions.


The couple of things I've found (which are perhaps more niche) are the GC behavior of golang seems to be "nicer" / "easier" than that of java and I've found the concurrency of the channels to be easier to use and more predictable than the N different concurrency constructs within Java proper (that isn't to say using something more akin to Quasar isn't a nice alternative).

Like with any languages, there's lots of tradeoffs between systems. I would also suggest the "Java .. is faster" isn't always true.


>But I still don't see why you would choose Go over Java (or Scala) for serious backend development.

  1. Less verbose code
  2. Platform Ind. + native binaries, no runtime dependency
  3. Built in unit testing/benching
  4. Fast compile time
  5. Better tooling, no Ant etc needed
  6. Better core language support for multithreading/concurrency
  7. A memory model that makes it easier to read the code and understand how the resulting data will be layed out in memory
  8. Related to 7, better stack vs heap allocation control
>Java has more libraries

Many of which are of low quality / filled with code-rot, I used to play in the Java ecosystem the Go stdlib is cleaner and the Go 3rd party libraries tend to be better, more single function.

>is faster

This is not always the case and is changing for Go's better fast. To paint Go as non-competitive would be unfair as its in the same league as Java and it usually faster than C# Mono.

>has generics (for the love of god)

I used to miss this, but I find I don't anymore... I wrote proxies, databases, systems applications.

>has better IDE support

True. This used to pain me until I found LiteIDE and I started writing unit tests more and using the debugger less. Go's profiler is awesome though...

>and has a larger hiring pool.

Not really, any smart C/C++/C#/Java developer can be highly productive in Go in weeks.

>In summary, the ecosystem is more mature.

A double edged sword mind you, not to mention Go is maturing at faster rate then Java did.

>Java's checked exceptions are less painful then Go's C-style error handling.

No. C++/Java got it wrong, ignoring error paths lead or letting random low level errors bubble up are some of the horrible results of the Java way to handle exceptions.

Forcing programmers to consider which operations may fail- how to handle those failures is one of the best decisions Go made. Multiple returns make this much less painful than C.


> 2. Platform Ind. + native binaries, no runtime dependency

Also available in Java. It is just a matter of choosing the right compiler.

Java like many other languages, enjoys a standard, certification process and multiple implementations to choose from.


GCJ is dead. Are you referring to proprietary implementations?


Yes, who still bothers with GCJ? I really don't understand why GCC still ships it.

However there are also open source implementations like RoboVM and JikesRVM, among a few others.


> 1. Less verbose code

Go is much more verbose than Scala or Clojure. Go is just a language, whereas the JVM is a platform with multiple languages.

> 2. Platform Ind. + native binaries, no runtime dependency

In my opinion Java has a greater degree of platform independence. Wherever it runs, things just work. On runtime dependency, you're wrong, as Golang does have a pretty heavy runtime dependency. It's true that it doesn't get distributed as byte-code that needs a VM, but at the very least you're still dependent on a garbage collector and that makes it unsuitable for all those things one would naturally do in C/C++.

Also, Java being the standard that it is, has multiple implementations and it doesn't necessarily need a VM. The purpose of RoboVM (http://www.robovm.com/) for example being to build apps for iOS in Java meant compiling Java to native and RoboVM does just that. But there are advantages to distributing apps as bytecode - Android ART (the successor to Dalvik) is doing AOT compilation to native upon installing an app on your phone and the cool thing is that you don't have to worry about what processor your app will end up running on.

> 3. Built in unit testing/benching

I don't see how that is an advantage. Does Go have something like YourKit Profiler? Can you easily connect to a remote application for debugging or profiling?

> 4. Fast compile time

One can argue that fast compile times are a direct consequence of the compiler not doing pretty much of anything you'd expect a compiler to do - like optimizations or type-safety. For example the C++ compiler is slow, but the C++ compiler can optimize the shit out of anything. Scala's compiler is slow, but it can catch a lot of errors for which you'd normally have to run expensive third-party tools.

> 5. Better tooling, no Ant etc needed

Nobody is using Ant anymore. Go doesn't have Maven or anything like it (i.e. Gradle, SBT, Leiningen). As a personal opinion, whenever I have to work with other platforms, feels like going back to the nineties.

> 6. Better core language support for multithreading/concurrency

This is a common misconception, when the opposite is factually true.

On the JVM you'll find support for the Erlang-style actor model, Hoare's CSP, Futures/Promises, reactive streams (Rx), STM, parallel collections and the best concurrent data-structures that open-source can provide. See Akka, Quasar, Scala's and Clojure's standard libraries, LMAX Disruptor, etc...

> 8. Related to 7, better stack vs heap allocation control

This has always been a problem for the JVM, however stack-allocated values are coming in the next version. On the other hand the control on memory layout in Go is still weak and the JVM does have much better garbage collectors.


>Go is much more verbose than Scala or Clojure. Go is just a language, whereas the JVM is a platform with multiple languages.

There is a trade-off being verbosity and maintainability, IMGO Go hits that.

>In my opinion Java has a greater degree of platform independence. Wherever it runs, things just work.

LOL. Said no person who has actually distributed a multiplatofrm Java application ever- I should know. Both Java and Go are "write once, test everywhere", but in my XP Go has been smoother.

>On runtime dependency, you're wrong, as Golang does have a pretty heavy runtime dependency.

The key word here was dependency, specifically, external dependency. If Go'd runtime ships with the binary its not really a external dependency is it.

>Does Go have something like YourKit Profiler? Can you easily connect to a remote application for debugging or profiling?

Yes. It comes baked into the stdlib, its "http/pprof"

>Go doesn't have Maven or anything like it

Biggest plus ever, goes native simple tooling doesn't need an external life support system.

>This is a common misconception, when the opposite is factually true.

You are wrong, all the the stuff you are are talking about is library based, Go has channels/select/go build into the language as primitives. I wasn't talking about bolt on libraries.

>On the other hand the control on memory layout in Go is still weak

IMHO This is not the case, if you think it is, explain.


> There is a trade-off being verbosity and maintainability, IMGO Go hits that.

This is where we'll always disagree, because if you like Go, it's natural for you to come up with this argument, however the line you're drawing is completely arbitrary. I have yet to hear an argument about what makes Go strike a fine balance between verbosity and maintainability, when my feelings are the opposite - I find Go code to not be very maintainable in comparison with other static languages, because Go is not very statically type-safe.

> LOL. Said no person who has actually distributed a multiplatofrm Java application ever

Yet it happens all the time and a LOL is not an argument that disproves that. From my own experience, I have built stuff on top of Java / the JVM on OS X / Linux and deployed on Linux, Windows and OS X, without encountering any issues, ever, without worrying that Java's NIO will work or not, without worrying on whether the memory model will suddenly be different, without worrying on whether my app will leak on 32 bits platforms ;-)

Android is the only ugly duckling, but that's only because Android doesn't have a JVM on it. It still works out well though.

But if you have examples, I'd love to hear them out.

> The key word here was dependency, specifically, external dependency. If Go'd runtime ships with the binary its not really a external dependency is it.

Now that's an arbitrary distinction, isn't it? What stops one from bundling the VM in the same deployed binary? If you want this distinction, the only valid argument is one of size, but then again for the server-side (where most of the Go stuff is used) that's completely meaningless.

> Yes. It comes baked into the stdlib, its "http/pprof"

Are you seriously comparing something like YourKit's Profiler and Java's remote attach and debugging capabilities to http/pprof? IMHO, that's not a comparison you can make.

> Biggest plus ever, goes native simple tooling doesn't need an external life support system.

There are many issues wrong with this line of thinking - the simple tooling you're talking about doesn't do what I and many others want it to do. Also if you look throughout history, all the languages that came with batteries included have suffered once the people finally reached the conclusion that the included batteries have been shitty. Which is what happens when you don't let evolution pick a winner with the community acting as the fitness function. But we'll talk in about 5 years.

> You are wrong, all the the stuff you are are talking about is library based, Go has channels/select/go build into the language as primitives. I wasn't talking about bolt on libraries.

But that's the point mate, the JVM is capable enough to build anything you want on top of it as libraries, there's no point for something to be hard-coded in the language. Which is a good thing, because when speaking of concurrency and parallelism, there isn't a one size fits all.

For example, speaking of Go's channels - they are strictly about managing concurrency, they are not about parallelizing a workload and they do not work across address spaces / asynchronous boundaries. And if you think that Go's channels are the answer to everything, well, you would have been better off with Erlang, as there you might have had a valid argument.

> IMHO This is not the case, if you think it is, explain.

Can you take an arbitrary memory location and cast it to anything you want? Can you override how heap allocation happens? Can you allocate an array on the stack? Can you do RAII? Do you have the union type from C?

In practice you have no control on where Golang allocates stuff - the compiler decides that based on really simple rules for escape analysis and as a general rule of thumb AFAIK anything that is allocated with "new" goes on the heap. What you can do with Golang is to use the "unsafe" package. But that's not different than using Java's sun.misc.unsafe ;-)

The only real difference with Golang is that you can have stack allocated structs, as otherwise Java also does escape analysis. But besides this coming to Java 9, the real kicker is that .NET/C# has had stack allocated values since inception, in addition to much more potent "unsafe" constructs - in C# you can even do pointers and pointer arithmetic and the runtime will pin those memory addresses during execution for avoiding GC interference.


I could respond point by point and keep this going, but don't think we are going to change each-other's mind or add constructively to this conversation.

I think we would both like to think we are both right on technical grounds, but I think we would be deceiving ourselves as a great proportion of this is personal taste, ideological, and we are both heavily invested in our respective platform of choice.

Best of luck & code on.


Well yeah, but arguing programming languages is what we do - it's like talking about sports for us, isn't it? :-)

You're right of course.


I think one reason to choose Go is simplicity. You can run, say, a JSON REST service and build it with TDD out of the box with only the standard libaries. It's also such a small language that you can pick it up quickly.

I haven't done an serious Java development recently but my impression is that if I wanted to get up and running with it quickly there would be a ton of choices to make around frameworks, tooling, which conventions to stick to, etc. and it would all be difficult to navigate. (And maybe that's not even true, but if that's my impression I'm just gonna choose choose Go).


> Java is faster

Do you have any evidence to back that up? I am not disagreeing, just curious.



Go still beats Java sometimes: https://www.techempower.com/benchmarks/#section=data-r9&hw=i...

I'm not saying Go wins more, but they are very close compared to other languages.


I want to point that in fact Go is extremely performant on EC2 for every tests and average on Peak. So with that and all its features, it seems that Go is an awesome solution for startups.

And then Java when you start to be quite big.


I love the fact that lua is at the top, directly after java.




Consider applying for YC's Summer 2026 batch! Applications are open till May 4

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: