Hacker News new | ask | show | jobs
by pyjug 1881 days ago
As an experienced Java programmer , I decided to do a project in Golang to see for myself what the hype was all about. And it was...underwhelming. The Go plugin for VScode barely works - terribly slow, inconsistent autocomplete, hanging during debugging etc. I had to pay for Goland just to get a reasonable experience which is still worse than Java+IntelliJ community edition.

Language wise - you need for loops for everything, no maps or streams. Also where are the concurrent collections in the stdlib?

I wonder if all the Go love here is from people who never worked in earnest with Java ? Or only worked with dynamic languages before?

7 comments

This comment is so hilarious to me. I was a Java programmer for 8+ years. Go throws all the boilerplate away. The multiple layers of abstraction. The AbstractFactorySingletonProxyFactoryBeans. All the singleton static classes, and builder patterns, and the stuff that just makes me shudder these days. Instead what you get is a balance between needed features and beautiful simplicity. The code is almost always understandable in Go. It's right there in front of you! Yes! Everything is a loop or a "for range"! It's the most beautiful part. It means I can read a page or two of code and understand 100% exactly whats going on. Contrast that with Java, where you often had to dig, on average, 8 layers deep to get to the root functionality, it's a breath of fresh air. The best part about Go arguably is it's a get shit done language, and it detracts the type of architecture astronaut types that love to overcomplicate and overengineer everything, if not sheerly by the lack of ability to do so (which is why so many who love Go today fear the incoming generics)

Anyways, just my two cents as a almost decade long "enterprise" java developer, who has used his fair share of netflix packages as well.

> Go throws all the boilerplate away

Wait, what?

I spend my life nowadays writing boilerplate in Go. The language and ecosystem is riddled with boilerplate and needing to repeat yourself. That said, I find the language plenty productive, but concise and reusable Go is not.

The rest of your post has nothing to do with the Java programming language and instead has to do with your frustration at the Java enterprise ecosystem, the desire to make things abstract for extendibility etc etc... considering Go is now being adopted heavily in those same enterprise shops and often being written by former Java developers I predict it will suffer a similar souring of public opinion by 2030 or so.

Enterprise Go is coming.

The idea often ignored is: Choose the abstraction, which is simplest, yet powerful enough to express what you need to express and still allows for simple modification / extensibility of the code.

In many cases, that is a function. Functions you can keep mostly on the same level of nested-ness. Occasionally you will have a higher-order thingy. A class, which gets instanciated but then the instance is not used? Well, that's a code smell. Probably not a real class you're dealing with, but someone had the urge to hammer it into a class thingy. Then the next person will come along and inherit from that and the one after that will write an adapter around it and so it goes on, until a degree of complexity is reached, that is mind-boggling.

A lot of classes also disappear when you simply create a struct and write the functions that deal with the struct's members, decoupling state and behavior. Of course this is not how it is done in mainstream OOP. Some language have adopted this kind of approach. For example Rust with structs and traits being implemented for a struct separately.

What prevents you from using classes as only namespaces with static functions?
Nothing really. It would be unnecessary though.

Hypothetically speaking, when using the concept of a class, one would expect an instance creation somewhere and that instance to be actually used. If it is not used after creation, then that means, that the constructor can probably be written as a function, saving one level of nesting and also using a simpler concept to express the same thing. When looking at a class, I might need to also consider what its base/super class is and might need to look at what members and methods that one has. I might have to look at what interfaces it implements. When I see a class, I expect some kind of state to be stored in it. If there is no state or only a single attribute, then that might be another sign, that I am not actually dealing with a thing, that needs to be a class.

A class is quite a complex thing, wherein one needs to look out for a lot of things.

Often making everything a class comes with another disadvantage when writing unit tests. You always have to instantiate (assuming not everything is static) and, if you hold state in member variables, you need to account for that in tests, covering various values of that member variable. Writing things as a class makes it easy to have side-effects updating your object internal state. This can make testing even more difficult.

There is complexity, which is inherent to a problem, and there is complexity created by people trying to solve problems with more complex than necessary means. Use a class when necessary and useful. Not for everything that does not hide on the count of 3.

For the use I take from your question, I would recommend simply using namespaces for implementing namespaces. If the language does not provide such, then see if there are modules, which serve as namespaces. Only as a last resort use a class to build a namespace. In that case I would already ask myself, why my language does not support something as basic as a namespace.

How is using Math any difficult? And I don’t see not having namespaces as a bad thing. In a class-used-as-namespace, there are basically no restrictions. What benefit would using the `namespace` keyword instead of `class` give? Especially that you have static imports.
Reverse peristalsis
I’m not saying that it’s necessarily a good thing, but what problem does Math have for example?
Difference between Go and Java, Java drives developers to write bloated code. Bunch of abstract classes, interfaces, fancy inheritance, getters/setters, OOP patterns, classes for anything and everything .. all in a different file. Normally, some code can fit in a single file, a logic can be a method but Java way of doing it in 20 files, 20 classes, 3 sub-classes, 3 interface implementations. I think this is the boilerplate that matters most.

I think Go will not ever be as bad as Enterprise Java because language and community culture which is shaped by language, don't give you as much opportunity to abuse it. If Go gets some new features that may enable abusing it, then yeah, history will repeat :)

> Difference between Go and Java, Java drives developers to write bloated code.

Nothing in Java drives you to write bloated code with tons of classes. javac will not throw an error if you write proper simple code.

If you chose, or were forced by bad team culture somewhere, to write 20 classes for what should've been one function, that's a people problem. Java didn't make you do it.

That team who loves complex overengineering so much will do the same thing in whatever language they switch to someday.

No. Nothing about Java drives developers to write bloated code. You can write simple and concise code in Java, and i do.
Unfortunately Spring is a de-facto part of the language, for most enterprise codebases.
In ~20 years of developing in Java, I've never used Spring. It's certainly not a de-facto part of the langauge.
> Difference between Go and Java, Java drives developers to write bloated code. Bunch of abstract classes, interfaces, fancy inheritance, getters/setters, OOP patterns, classes for anything and everything .. all in a different file.

Or you could just not do that. The Java culture is heavy on those things, but nothing forces you to participate in this if you're building from the ground-up.

There is a big legacy of spring/j2ee or pre-dependency injection apps which either look like a pile of needless factories, or a pile of XML.

Modern Java is a much more pleasant developer experience than that. For extremely large applications it also comes with the benefit of being able to remove the boilerplate and ceremony required to do basic things like call an internal service, internal service auth, rate limiting, circuit breaking etc.

I don’t get the no boilerplate aspect of your comment. For all that Golang has going for it, avoiding boilerplate isn’t one of them. I’m thinking specifically about multiple clauses at the beginning of functions passing up return values and copy pasting the same code (or auto generating it) to work around lack of generics.

Most of the criticism about Java seem to be about old codebases that overused Gang of Four patterns, when that used to be more of a thing. Don’t blame the hammer for the shoddy building, blame the hammerer.

No true scotsman, err modern Java developer would ever write Java like that. The language has better ways to do these things now and it's just a small matter of rewriting every project in existence with modern tooling. Of course modern Java moves the complexity to reflection magic so it's even more difficult to figure out what's happening when something breaks.

I'm happy I don't have to work with any kind of Java any more.

> Of course modern Java moves the complexity to reflection magic so it's even more difficult to figure out what's happening when something breaks.

Are you 10 years behind? Modern Java moves the complexity into compile time annotation processors, so it's even more difficult to figure out what's happening when something breaks.

It's some time since I last touched Java, and even back then the projects I was involved with took care to use only stable releases (i.e. either oldest supported or already EOL'd) of anything.
I'm having Micronaut flashbacks...
AbstractFactorySingletonProxyFactoryBeans 8 layer deep is really the anti-pattern of reusability, you can't just copy/paste that code into another project without also including hundreds of dependencies. It's like "proof of work" in cryptocurrencies, eg. you need 50 people to produce the code. Or some type of DRM to make sure no one else can use it.
Every for-range loop is noise, a missed opportunity to take what you're doing and factor it out to something reusable (filter, map, flatMap, groupBy, join, whatever) that nobody should have to read more than once per project (or ideally, ever). There's no beauty to be found in repeating yourself when the computer is much better at that.
"AbstractFactorySingletonProxyFactoryBeans" I don't think that this meme phenomenon is prevalent in modern java projects, and I would say that it is even less in the Kotlin ones.
It's a bit prevalent, not very, but more importantly Spring is built entirely around AbstractBeanFactoryFactoryInstantiators and we're all using them by proxy.
Lol wut, why is there two factories in there? and an instantiator as well?
Every factory needs a factory, and the Instantiator design pattern is highly ergonomic compared to using "new".
haha ok I'm staying with Rails
Right. Who cares what class names the implementation uses? This is the downside of hacker news. Everything has to be implemented in rust or go or it's a bloated piece of crap
Please don't willfully misconstrue what GP commenter said.
I sympathize with the general sentiment of your argument, which is what initially drew me towards Go (in addition to the hype).

For better or worse, Go is where all the energy is in terms of OSS, so I do hope I see the light some day, but for now, the dev x for me is pretty underwhelming compared to Java

I don't see how enterprise culture has anything to do with language. You're implying that you can't do Go style programming with Java. Except you can, and it will be prettier and easier to read with streams.
if you think this way about go, you probably have a REALLY good team that can design in a really proper, DDD-ish way (in that case, go en masse to google asking for your hard earned 500k TC, since even google has confusion on the best way to structure go projects) or you simply program toy stuff/basic integrations which boils up to a map from a type to another. go doesn't scale to huge codebases in normal teams.

otoh, you are totally right about the 8 layers deep root functionality, but that IMHO reduces to mindless application of textbook oop patterns to applications (I still have to see a company randomly "changing databases" so the 8 layers of abstraction over the db are correct).

still, I adhere to a lost standard these days, which is less code as possible. golang is automatically disqualified since it thinks that a 8 LoC for loop with temp variables is "simpler" than a .map(fn) (so much for "throwing boilerplate away"). it likes to introduce point of failures, and I dislike point of failures

> The multiple layers of abstraction. The AbstractFactorySingletonProxyFactoryBeans. All the singleton static classes, and builder patterns, and the stuff that just makes me shudder these days.

If you chose to write that kind of code and then hate it, that's all on you. Neither the Java language spec nor the JDK make any effort to steer you into such baroque complexity. Keep it simple, best Java code is very simple.

I wrote Java for about 20 years (many of them at Sun) and have never written a AbstractFactorySingletonProxyFactoryBeans or anything like it. Don't do it.

By "throws away the boiler plate" you mean sets yeah?

And before the inevitable, a map[T]interface{} only provides part of what a real set does. The rest is for loops.

Totally agree. Except I went from Java to Scala to Go, so coming from Scala Go was even more underwhelming. Scala had just as simple aync sugar and doesn’t have stereotypical Java boilerplate, and had powerful collections functions. Golang felt like an antique.
> Golang felt like an antique.

And, IMHO, no implicit nulls, proper sum types, pattern matching was all it needed be considered modern. If left the last 40 years of compiler/language research outcomes on the table. Such a pity.

And give that the std lib is not riddled with implicit nulls that mean all kinds of things (like any kind of error, or absence), this will not be fixed in the next decade. What a waste.

Omg, implicit nils and "nil values" really bugged me.
> I wonder if all the Go love here is from people who never worked in earnest with Java ? Or only worked with dynamic languages before?

This is the type of non-constructive statement I’m used to seeing on programming forums elsewhere on the Internet. The thing is, it’s just dismissive and irritating. All it says is, “I don’t understand why this thing is popular. Could it be that all of the proponents are simply inexperienced and don’t know any better?” — of course it’s possible, the same way that it’s possible that everyone who says my cooking is terrible just has bad taste and doesn’t understand good cuisine.

It could just be that your experience of Go was not very complete. There are certainly sore spots in Go. Maybe gopls was broken when you tried (I just tested and VSCode Go is faster than Goland on my machine, so I actually suspect something was wrong.) Maybe you picked use cases that it was just not very good for, or possibly you missed some of its utility in the time that you used it. There’s no way for me to know. I’m sure you have enough Java experience to see how someone fiddling with Maven, Eclipse, Spring, Hibernate, Guice... and running into problems could spoil them on the language or its ecosystem early on.

And yet, what disappoints me more is that when I saw this comment, it was the second highest on the page. Meaning the statement seems to have resonated rather than raising red flags.

I kind of get it. Go is one of the trendiest languages to hate now. I would guess it is in third behind Perl and PHP. Don’t get me wrong — many people unfairly hated Java too, but let’s face it, it hasn’t been trendy to baselessly hate Java in a long time. Especially not with how much it has changed and improved. I still don’t like that people do this. It feels like on at minimum a weekly basis I get chastised or see others get chastised for expressing our satisfaction with Go. Thankfully it is uncommon here, but in other online programming circles it is common enough.

Imagine you’re a beginner who is learning Go as a first programming language and they read your message. What message is it really sending?

Perhaps you did not mean for this to come off this way, but to me this is the language of condescension.

What disappoints me upon seeing your comment is that someone chose to write nearly 400 words to complain about how irritating the parent's one-question was without answering the said question in the slightest.
I certainly did actually address the question:

> of course it’s possible, the same way that it’s possible that everyone who says my cooking is terrible just has bad taste and doesn’t understand good cuisine.

I could’ve answered anecdotally about my experience with Java, thus proving or at least claiming at least one person has earnestly used Java and still likes Go. I have no idea what value that could bring to this discussion. Does anyone actually believe there is a possibility that not even a small amount of users of Go, the ~14th most popular language according to TIOBE, have not used in earnest the ~2nd most popular language according to TIOBE?

I dislike the question. I repeat my own question and now ask you to answer it:

> Imagine you’re a beginner who is learning Go as a first programming language and they read your message. What message is it really sending?

>I could’ve answered anecdotally about my experience with Java, thus proving or at least claiming at least one person has earnestly used Java and still likes Go. I have no idea what value that could bring to this discussion.

The value would be highlighting the upsides of using Go for people who're comfortable with Java, in spite of the disadvantages mentioned in the parent comment.

That information is valuable to people considering picking up their Nth language.

What value does the comment that you ended up writing add to the discussion?

>I dislike the question. I repeat my own question and now ask you to answer it

I dislike the question. I repeat my own question and now ask you to answer it:

What value does the comment that you ended up writing add to the discussion?

Sorry, I didn’t mean to come off condescending at all, it was a genuine question! At the end of the day, these are all just tools and people have their preferences. I try not to get too attached to any of them personally.

Also, if it wasn’t clear I was addressing programmers with experience in more than 1 language, not absolute beginners. If someone who is learning Go as their first language, I wholeheartedly endorse learning it! (Although Python would be better :-))

Well, I apologize for taking it the wrong way. I hope that others who agreed with you read it the way it was intended and not the way that I did. I still think the answer to the question is a bit obvious; plenty of Go devs used Java before Go. That said, I would guess that most people who have migrated away from Java did so before it became more modernized.
> it’s just dismissive and irritating

It's not dismissive. I have worked in Java and Go, and i ask the same question, entirely genuinely. It's up to you if you find it irritating.

> it hasn’t been trendy to baselessly hate Java in a long time

It's happening on this page, today, my friend.

> Language wise - you need for loops for everything, no maps or streams.

I think that's library wise.

Language-wise I wish I could write a map interface in Java. But soon Go will get half-arsed generics and I won't be able to write a map interface in that either!

> Also where are the concurrent collections in the stdlib?

I think this is the crux of your issues with Go. If you're going to learn a new language, learn the new language. Don't try to recreate your existing language with a different syntax.

Java and Go have different strengths and weaknesses, and they are not used to build software with the same architecture. Java is useful for writing big monolithic servers while Go is better at building smaller independent modules communicating with each other, but there is much more to them than this.

I work with Java but still prefer to use Go for my hobby projects because it makes concurrent processing much easier to reason about. Also it's far less tedious than Java to install and use, but the bar isn't very high to start with.

> Java is useful for writing big monolithic servers while Go is better at building smaller independent modules communicating with each other, but there is much more to them than this.

There's nothing that makes Java any less suited than golang for writing small independent cross communicating modules.

For all the hype in golang about it being useful for concurrency, the fact that it lacks a concurrent collections library sticks out to anyone who used it.

It's interesting that you chose VSCode + Go plugin rather than IntelliJ Community + Go plugin?
Right, I wanted to have the “modern development experience” as much as possible. Most tutorials out there still recommend VSCode to get started with Go.
hmm, I even use VS Code for Java
Sure - OP seemed like they were implying they're already comfortable with IntelliJ. If you're trying a new language, and then also trying new tools to learn that language, it sounds like you're taking on too much at once.

If you're already comfortable with IntelliJ, you can continue to use IntelliJ.

Yup many migrated from node js