Originally published at deepu.tech.
Do I like Go? Yes. Would I use it for every use case I have? Definitely not.
// Detect dark theme
var ...
For further actions, you may consider blocking this person and/or reporting abuse
Enjoyed that - a relatively balanced piece. Just a few corrections and observations
Was 'fixed' last year - making projects like Glide et al a bit obsolete. People are either moving to modules or are still using
dep
. Although that said it's not often that I need many dependencies as the standard library is very comprehensive.I looked at your ... um... I want to call it a struct, but I think "side pyramid of hell" would be a better term. If you're using this in a project - real world or any other world - then you've done something seriously wrong or you're trying to consume data the structure of which you have no prior knowledge about.
A huge smell is all the
map[interface{}]map[interface{}]interface{}
chaos. If you're usinginterface{}
as a type all the time then you're basically writing a very verbose dynamically typed language with no compile time checking. Try and refactor to named types. Useful tools exist for parsing JSON and XML into Go types which can then be massaged by loving human hands (ie. gojson.com).But it's the same as in TypeScript - structural sub-typing (on methods in Go). Could you explain what you dislike about Go interfaces as opposed to TypeScript?
Sure - but has anyone ever done this, ever implemented the
io.Writer
interface accidentally and then passed this offending type to a function that's expecting it?Sure, you can't implement
map
orreduce
in Go. There are no generics. Fine. When was the last time you needed to implementmap
orreduce
? When was the last time you needed a function to be polymorphic over more than three types? In reality, it rarely happens. You don'tmap
over a generically iterable type, you just write afor
loop and get on with your life. I've seen more good code spoiled by an attempt to dry it out through a bad abstraction than I have seen it improved by generification.Thank you. I agree with some of your points and differ with some, also some of my concerns were more personal nitpicks and might not apply to everyone. But I think its good that we have constructive criticism. As I said in the article I do like Go and think it has a purpose and It does some things really well, I appreciate that but the takeaway from the article should be "Using the right tools for the right Job"
I'm aware of modules and dep. Dep is still experimental and modules do look promising, but if you look at many popular Go projects in GitHub, seems like they are still using Glide or another system and not modules(of course it's their bad). But my point was that dependency management in Go is immature and I still stand by that. For example, if you have used NPM, Yarn, Maven or Gradle, its far better and mature than Go modules even with its shortcomings. Also in my project, we are using Gradle with Gogradle and it works fine but the experience is not as enjoyable as others as I mentioned. Also, I still don't see anything like
npm link
in Go modules. You have no idea how valuable it is unless you have developed some mode projects with dependencies, I'm seriously missing those here. Let me know if there is something similar in the Go world.Also, I don't agree with "it's not often that I need many dependencies" as a generic statement. May be projects you do are simple enough to avoid that or you are reinventing the wheel all the time using language features. In most real-world cases you would need many dependencies unless you are into reinventing the wheel for everything.
Maybe you misunderstood me. No one in their right mind should design structs like these, it was an example to show what is possible though. My pain point was when using generic parsing libs which indeed produce structures which look worse then these and hence is pain during debugging, mocking and test case creation. Also, it was a nitpick. And when you do generic data processing sometimes you don't know the structure or sometimes the structure has to be kept generic, for example, a yaml where a field can take values of different types. Many times when you work on real-world projects you have no control of what data structure will come in.
Agree, no one should ever write structs with
interface{}
as much as possible, but sometimes it's inevitable. As I said an example is when you have Yaml or Json doc that can take values of different types. We had a use case where our Yaml fields needed to take string, numeric, boolean values as well as complex Yaml expressions or functions. the only way to parse them is to declare those as interfaces and then do a type switch in code to process them.No, it is not the same. In Typescript, interfaces are implemented by intent as below unlike the implicit(which is what I don't like about it) way in Go and also interfaces in TS also represent type a bit similar to a struct IMO.
I don't think we can answer that unless people who do that come out and say so right? I at least always have to think twice before naming a method(Which might be a good thing in some cases :P). Anyway, my point was that it is possible and also its a nitpick.
Of course, everything can be done using the simple features Go provides and that is exactly my point, you have to write a lot of code for everything which is anything but DRY(I also believe in responsible DRY rather than doing it for the sake of doing it) and feels very verbose and annoying.
If you are used to doing map/reduce etc in other languages it just feels verbose doing the same all the time, again and again, using for loops. It's not an enjoyable experience at least for me. I can provide many examples of when you need map/reduce etc and when you need polymorphism but my intention is not to prove that Go is bad these are just reflections of someone who would like to see Go get better and better.
Anyways thanks for the comment, I really enjoy such healthy discussions and debate.
Also what Ben pointed out below also matters.
I must object. Although you can use interfaces to enforce contracts, they can also be used as structural sub-typing on fields - see this from the Typescript docs:
Oh Yes, you are right, I never thought of Duck typing coz I used to avoid it to the best of my abilities. Interestingly, it is considered as an issue by many and there is an open ticket in TS project to change this behavior as it can cause unexpected bugs.
My problems with Go is in enforcing contracts and not in typing but regardless I understand what you mean and to be fair the exact same implicit behavior can be achieved in Typescript as well which I hated.
But a difference, however, is that in TS its is not the only way and I have the choice to do things explicitly without relying on the implicit behavior. And I have always used the explicit way in TS projects as far as I could remember. And seems like there are ways to workaround but they are quite verbose
Anyways, unlike Go, TS is just a superset of JS which is completely dynamic(so in the end, all the types and interfaces, etc are only syntax sugars) and due to the weak typed nature of JS allowing structural typing is the only way to emulate how JS works so its more of a limitation than a feature IMO.
Today. Yesterday. The day before. Can we have generics now?
Only if you ask Father Christmas nicely.
Or rsc.
If you are planning next Google then Golang is good for you but for most people Java and it's huge ecosystem is more than enough. Also Java community is not just eating peanuts. They are evolving Java a lot that will take Golang next 10 years at least to achieve.
I understand this point of view. It sounds honest and fair, but I disagree.
I do not disagree with your feelings, but with some of your judgments.
I do some "real-world" project in Java, Ruby, TypeScript (nodeJs) and Go, and Golang structure wasn't particularly complex. There is no reason for your Go structure to be more complex than a POJO for instance. If you have to deal with complex Json, you may use
json.Marshaler
orjson.Unmarshaler
interface, like here.Hmm. Yes, and then ? It means that you may use an instance of your type as an instance of "someone's interface" only if you want, by passing it as a parameter of a function that explicitly ask for "someone's interface" for exemple. I don't see a use case when you may have an unwanted edge case with this feature.
Wrong. The content of maps and slices aren't passed by reference. Slice and Maps are references (default value is
nil
for them) see. It is something to know, that's true, but this is less confusing than Java primitive type behavior.You are right. Even with
module
, dependency management in Golang is much basic than what you can find with npm or maven.But you miss something important here. Even with big size project, you don't need a lot of dependencies. Unit tests ? All included. Web server ? Maybe a (small) router for dynamic route, and one for secure token if you need, but no more. Database access ? Only the driver. Linter and code inspection ? All included... Such limited dependency manager is consistent with one of the language principle : use the standard library the most (here an example).
DRY is not related to your complaints. The DRY principle is about bad business logic duplication. For instance, if you have in a bank system, two 90% identical functions to compute account balance, there is chance to have a DRY violation. Here, you are pointing out that Go do not have a lot of syntactic sugar (you are right) and have some idioms that are very C-like (and not so fun). I agree with that. But I think go approach is better for maintenance.
And almost one of your statements is out of date
Go is not the perfect tool (there is no perfect tool). But many of your points are just consequences of your preferences, and writing that Spring fit better than Go for complex web app, is just wrong. I experienced the two (Complex web app in spring (boot) and in Golang).
The two solutions eventually matched businesses and technical requirements.
With Spring, we had a lot of solution to write less code, and thanks to some magics, a lot of "autoconfigure" stuff. But This convenience came at a price of a steeper learning curve (in particular for new comers) and a sometime-hard configuration (I am looking at you spring-security !) when dealing with fine tuning, or very specific use case.
With Go, some task (in particular writing integration tests !) where longer to do. They where a little more boilerplate to write at the beginning of the project before shipping the first feature. But at the end, the code was much more simple and easy to understand. No need to have a deep knowledge of a complex framework like spring here. Just "basic" knowledge on HTTP, Database and so on, the absence of a framework finally turned as an advantage, when dealing with complex use case. The simplicity allow us to be focus on our problem, and not on how the framework want us to deals with such problem.
NB : you forget one (very) good point for Golang : easy to deploy !
Thanks for the detailed response. Most of my opinion is based on the real-world experience of building a CLI app using Go for the past 9+ months. It's not a super complex app but of fairly medium complexity.
In the beginning, we had some structs that were quite painful on the eye when parsing YAML. We then changed our model to simplify it. I agree you can get complex structures in every language but in Go, it looks a bit more ugly than others IMO. This is purely a personal view, you might find it beautiful. Also, regardless of what parser you use, if you have to transform the data you will end up using structs which looks really complex unless you have control over the data format.
I just stated a fact as I really don't like implicit stuff again a personal preference.
Yes, I didn't form that sentence correctly. I'll correct. They are references. But is still confusing, the same way Java primitives are.
I disagree. Yes, there is a lot of standard stuff provided but it's not enough unless you are building something simple. For my medium complex project, we have 31 direct dependencies(Including one for asserts, the default way of asserting in test sucks). Look at some of the popular OSS projects like kubectl etc, they have a lot of dependencies as well. For simple stuff, you can do that without any dependencies in any language if you ok to write verbose code same way you would do in Go. Also using libraries in other languages also is a choice to reduce boilerplate. I have used NPM, yarn, Maven, Gradle, Pip, Gem and so on and If I have to rate the user experience then Go is still at the last
May be but still, I cringe every time I have to duplicate a function and just change a type. I don't know why having Generics is bad? it's 2019.
Yes, I completely agree that Go has the best learning curve among modern languages(It took me just a few hours to start writing code for my application). Even easier than JavaScript I would say. It may be great for newcomers but once you learn it it's a bit annoying. I expect a high-level language to make my work as easy as possible with as less boilerplate possible. I don't want to implement a file walker or web server every time, I just want to use a library and get the job done as fast as possible. SO as I said this is my personal opinion based on my personal preference and I still don't see me writing a complex web application in Go.
But it's ok if you disagree. That's why we have options so you can choose what you like and I can choose what I like :)
This is weird. On many aspect Go may look different from language like Java or Javascript. But it is very similar on that point.
Is
Really uglier or different than :
Fair enough
For one "fairly medium complexity" app ? You should have special needs (a glue app ? integration with a lot of tools), or maybe, you keep habits from other language that doesn't fit much Go. Go isn't Javascript. Most of the time you don't need much dependencies. You maybe don't like how go standard lib will solve a problem, but that's another point.
That is wrong and a little bit arrogant. You don't like it, that's ok, but it doesn't sucks at all. I think you don't understand it.
First of all, I know some smart test lib too like Rspec, Mockito, AssertJ, junit (of course !), chai, karma, jest, etc... There are great ! And when I start to use Golang, I found confusing not having all the syntactic sugar I was accustomed... I found using mock unconvenient and strange that no assertion where available.
Then I become to realize that assertions are not so superior to a simple if... Every developer is able to understand the meaning of a simple "if"... That's no the case with all assertion lib (rspec for example is powerful, but do has his own learning steep).
But mock where still unconvenient, and hard to deals with, 'till I realize what was wrong. I was wrong. It was so easy to inject mock with Rails or Spring, that I didn't see the lack of values of this tests and how poor were some design choices. The need for mocks was just the symptom of a bad design :(.
Go testing package is not a shinny one, but it could help to write better tests, better code.
Well, that always far less that what node could require for a simple web app. But yes,
go mod
was necessary because it was one of the biggest weakness of the languageI never say that Generics are bad, but unrelated to DRY. By the way, lack of generics support is a weakness of the language. It may be useful in some cases.
oO ?
Yes, that's maybe easy as a reply, but http server is not where go has a lot of boilerplate ! With the error system yes (it's true it is verbose).
You hit the point. Go is annoying, because it is very simple. No magic, no shinning thing. And that's exactly what I expect from a language, but this is a personal opinion.
Yes, and I respect your opinion. BUT you decide to expose theses though on a platform that allow comments and discussion, so (respectful) contradictory opinions are part of the game :)
simpler structs does indeed look fine in Go, as per my original point, they look ugly IMO when there are complex stuff like maps of maps and stuff involved. Again its a personal preference. For the record I also find Java classes ugly :P
I don't agree here, it's not about keeping habits, I don't want to write 10 lines of boilerplate code if a library can do it in 2 line for me. I believe in community/oss and I hate reinventing the wheel. I'm not gonna go into why that approach is better as again its again opinionated.
Sorry if I sounded arrogant, that wasn't the intention. The default way in Go seems to using equals and when having structs and stuff its quite difficult to see what is the difference. Compare the default to
github.com/stretchr/testify/assert
and you will see what I mean. I want a nice output from my assertion failures.That's your personal preference. In general, as I stated, again and again, I expect a high-level language to make my work easier. I just don't want to bother about writing if..else for these and wasting my time trying to figure out diff from an assertion failure. Having said that so far I only needed to use an assert lib and not a full-fledged testing framework in Go, whi8ch is quite nice.
Well, actually you can also do almost everything you can do in Go in Node without using dependencies. Node also has standard libs for almost everything. the reason people end up using so many dependencies is coz they are so super easy to use and reduces boilerplate.
I don't see how it's useful
fair enough that was a bad example from my side, but I think you get my point
Absolutely, and that's my point, I personally prefer a middle ground. I don't like languages bloated with features as well. But Go is too simple for my taste. Maybe once Go has generics I would like it more.
Absolutely, that was the purpose so I can learn other views and may even change my mind on certain points. Thanks for your inputs they are indeed valuable. Another point I was trying to drive home was "using the right tools for the right job"
I wrote "It may be useful in some cases", "it" referring to Generics. So I guess we agree on this point.
I know this lib (using it in the past), and I exactly know what you mean. But I still disagree on this point. Assertion reduce test code verbosity, but doesn't really improve readability. here is an example from one of my pet project. I do not think the usage of assertion will bring a lot of value here.
But the most important is that it is not considered idiomatic to do so in Go. Some articles on the subject here and here.
That's precisely the reason why I still use assertion in Javascript, Java or Ruby, event if I don't find them useful as much as I used to.
Thank you too :)
I definitely agree with that sentence. And my reaction is mainly drive by the will to show that Go may be a good choice for a web application. It is very opinionated and may look ugly, but is eventually very effective and productive in that use case.
With it's GC and embedded Runtime, Go is more closed to many web-backend plateform than it looks like on the first sight :).
I was talking about the readability of the error messages printed during assert failures. The default way is not very readable whereas this lib provides a nice view with a diff, which IMO is really useful to spot issues.
I would still be open to building web backends for microservices using Go, but for full-fledged real-world web apps how would you handle stuff like security, filters, etc, etc(say stuff provided by spring framework). I have to agree maybe I might be more open if I see a real example of that.
For example, I was thinking about doing a version of JHipster app in Go but then wasn't sure it's worth the effort
There is two possibilities here.
The first is to used the (very good) lib
gorilla
which provide a full featured http router with many security options (secured cookies, sessions, CSRF protection, etc...). Not the option I prefers, but a very convenient and common one. If you wish to support Go with JHispster, this is the way to follow I guess.The second is to use the basic http router and to choose the lib you want to use (JsonWebToken, CSRF, etc ...) for security.
The http package is build in a way that make trivial to create filters (by chaining
http.Handler
orhttp.HandlerFunc
).I prefers using that way because I prefer to add explicitly security layers.
For SQL injection, the
sql
package provide automatically a protection against it, as long as you use parameterized requests withExec()
orQuery()
.You may notice that I am not against the use of dependencies :). Cryptographie and security are domains where I want to rely on a maintained, specialized libs.
Your What I don't like about Go section resonates with some of my experience. I like things about it in theory but in practice I do feel like I don't enjoy the verbosity, boilerplate and generally minimal tooling.
Exactly, thats well said I also had the same feeling. It was not as enjoyable as working in some other languages.
I agree about the dependency management but it's been quite a year since
go mod
birth. Today you can put your code wherever you want (outside of GOPATH) and have basic dependency management features like adding a new dependency, update an existing dependency, etc.I agree that there is a lot of boilerplate code but it's not a problem for me as it helps to understand what the code does and IDEs have snippet features to quickly write this kind of code.
I develop in Go since 9 months also and what was confusing for me is the lack of conventional project structure. I started with my good old MVC layer structure and ended up with a more pragmatic structure inspired from golang-standards/project-layout.
Another pain in the ass is the lack of reflection in unit tests mocking libraries. Unlike mockito or phpunit, you have to use tools like testify or mockgen to generate mocks that you can use in your UT. It's a lot of extra work compared to PHP and Java.
But in the end, I still love Go :)
I thought putting projects in Go path is still the official recommendation. At least the website says so golang.org/doc/code.html
Could you point me to doc or an article explaining how to do it outside of GOPATH? I'm defineley interested sop that I can get rid of my current workarounds.
It must be in the official go mod doc on the wiki. I'll put the link when I'll be back to my desktop.
you can put code in anywhere once using go module
github.com/golang/go/wiki/Modules
I never used Go before... it's on my list to try.
But really I just see Go as another hype just like React!
Really, lemme just write what I don't like about Go already:
The syntax is funky (comparing to Python).
Co-routine pattern for asynchronous programming never ticked for me... It's just weird. Aside from that, I think the only programming language that got async right is C#.
I see people saying it provides great features like references (and that's what C# and Java provided long ago).
Its frameworks/libraries are not mature... Cuz hey, it's a relatively new lang, and yeah no StackOverflow discussions when you get stuck!
From all those, I just ask myself again and again: what does Go bring new into the table? Not simplicity nor new features, so what?
TBH, I just hate to see people use a specific tech just because a big X company built it... Again, like React and Go 🤭
When people tell me it's for building high performance websites. Well, like: Google?!
While the 99.99 percent of websites they're building is never like Google needs 🙄
The only valid use case that I see is just building tools like Docker and Kuber in an easier lang than C/C++.
I wouldn't be that harsh. As I said I like Go for what it is, it's just that I think it could be a bit better. We can find issues in almost every programming language. The real takeaway from the article should be that we use the right tools for the right job.
Google has a serious case of “Not Invented Here” syndrome. Sometimes that works out, sometimes it doesn’t. I’ve not written any Go, but I’ve read enough of the Terraform codebase and of several k8s controllers to not be impressed. If they add generics I might take it for a spin, but I can’t yet see a usecase for Go where I wouldn’t just use Rust, Elixir, or F# instead.
Yeah exactly... I really can't understand what people think when they use the tools you mentioned just "cuz it's Google tool" 🤯
Awesome post!. It has actual examples and well written.
All the wrong things seems kinda fixed on nim-lang.org
It also has a Rust-like memory management, without BorrowChecker (Experimental).
👑
Nim does look like an interesting alternative to both Go and Rust. I've been holding off on seriously considering it until they release Nim version 1.0 (due to stability concerns), but it looks like they are nearing that point with a release candidate.
Nim looks interesting, but I'm looking for a language that fixes issues I have with Go, for that I think there are many options out there already. Go has a purpose and It does some things really well, we need to appreciate that.
looks good. what do you think of v-lang
V wont even has AST. Cant do Frontend.
It now has.
This is a great article, beyond the Go hipsterish trend.
I agree with all you said, both good and bad. I personally moved onto Rust because in my sense they found nice ways to cover the bad points of Golang however it comes with complexity and steep learning curve.
I feel like learning Go was actually a nice ladder to move onto Rust :D
Anyway spot on, great article, looking forward on your next ;)
As I said in the conclusion, we cannot brush aside Go like that. Go is still a great choice for many use cases like networking apps, concurrent apps, web servers and so on.
Well I agree on this too but as it happens I use Rust especially for those use-cases too ;)
Following are just my reflections over 9 years, please do not get me wrong.
In India, most students start with Java in their college, its taught to engineering students.
They land jobs from college fairs, TCS, Infosys... they train them. Some unlucky ones get to work on non-programming projects, and some lucky ones actually get programming projects.
When they start working they praise Java.. spring (the mess of magic world)
Then they start bitching about Javascript, how javascript doesn't have a private variable (when they don't know JS has its way via Module pattern)
and in the same way, they start writing every other language with Java in their thinking process.
I started learning GO because of one of my colleague (hardcore Scala guy) he told me not to learn Java or Scala, but go for GO. And I'm happy with that decision.
I think you are over generalising based on your experience. I don't see what nationality or experience has anything to do with my views here. And NO, I didn't have the background stereotype you mentioned above. I started with C/C++, then learned PHP, JavaScript and then Java. And Generics weren't available in Java always. If you do a real project in Go, you would understand why I'm looking for Generics. Any strictly typed language with generics will be a PITA to work with and that is the reason Go is trying to add generics support in Go v2
The pain of working with Java is immense.
The need of an IDE,
so tightly coupled community with Spring,
the configs you need to set up to get a basic test running,
the code's feedback has to wait until java finishes its build for 30mins+,
old Java, cannot run on newer versions of Java
Hence I would prefer simplicity over complexity. i.e. GO
Well. I don't know what you are implying. I didn't say I prefer Java for everything and I said I prefer it for usecases it is best suited for. Also seems like you have lot of false assumptions about it. Java is not a simple language but its much simpler than Scala. In terms of language complexity Java is slightly more complex than JavaScript and way more complex than Go.
Thanks for the article, Deepu, I enjoyed it and find myself agreeing with a lot of your thoughts. At the same time, most of the language issues you found problematic didn't bother me much -- then again, I loved working in C/Win32API back in the day so I may have issues with causing myself pain. ;)
The one thing that did make me bonkers was GOPATH, and I agree with you completely. I haven't been able to work with Go for a while, but I swear I saw a utility/feature in IntelliJ Go products/plugins that would change your GOPATH to the current project directory when you opened it or something similar so that you could work as you describe.
Then again, maybe it was a dream. It's an awful nice one.
Yes a colleague of mine told me there was such a plugin for IntelliJ
I would only use Go as an alternative to C or in some cases C++, as it is easier to deal with than those languages and can compete with their speed.
Otherwise I would never consider it.
My main reason is that its simplicity often forces over complicated solutions that can be pretty difficult to understand in reasonable time.
I would choose Rust as replacement for such cases as its much more memory safe and equally performant
Hello Deepu, well i dont agree with you. You can do every thing with go. From server to batch to cli to moon landing ;) etc. It is ligtweight, fast et efficient. I am fed up of the same thing again and again : generics, error bla bla...
It is simple just like a mac and you spend less time to thinking on what keyword to use but more on the business code.
People are trying to transpose what they have learned from previous language to go, it is none sense. Go has it Own paradigm.
One thing for sure, it is ok to copy paste in go in some extense. This is what i found And it is fine, i am not shocked when i am doing reviews and see some duplication for sake of simplicity instead of a complex code for kind of generics, go is not a language for framework makers but it is for developers !!!!!
To be honest with you, i habe reborned after i started programming in go, i was so disappointed of other languages and now i enjoy more than ever coding . I have 20 years of experience in programming.
Cheers
Well, if it works great for you, then great and I'm happy for you.
I didn't say that you can't do things with Go, well you can also do everything with assembly or any other language as well right. One of the reasons for using high level languages is that you don't have to do everything yourself. I don't want to write boilerplate code and that is why I expect some language features. No language is perfect and so is Go, my post is about using what makes you most productive for the given use-case and not about proving how smart one is.
I disagree with the point of using Spring for complex web application especially if you want to move into micro services architecture. It only adds complex configurations due to the poor documentation and Java isn't the best language for building web apps in my opinion.
Did you try frameworks like moleculerJS or Go micro?
Well, Java is used for building a lot of web applications(quite successfully) and IMO has the best ecosystem to do so. Also not everyone should be doing microservices since they are trendy, there is a lot issues in those which is a whole different topic. And Spring is perfectly suitable if you want to do microservices.
I haven't tried the frameworks you mentioned, will do when I find the time and will update the post if it changes my opinion.
Thank you for your great article , Can you recommend code or article for design patterns with golang ?
May be this could be useful golangbyexample.com/all-design-pat...
Good article bro, just wait for your next reflection on V -> github.com/vlang/v
I feel that pain all the time with arrays and maps