Simplicity and a great concurrency model are the two biggest selling points. When Clojure steals your concurrency primitives and calls them "go" in your honor, you're doing something right. Blazing fast, consistent tooling don't hurt either. Personally, I find Go code to be imminently readable - I can dive into a new codebase and start understanding/navigating it almost immediately.
But I don't know if I'd choose to write a Golang project from scratch. It's got a garbage collector and sketchy C interop - not low-level enough to be used for most systems programming. But it's also not expressive enough and lacks the rich ecosystem of Python or Javascript. Jack of all trades, master of none, IMO. Golang is a solid language for HTTP web services for big teams with varied abilities, but there are better languages based on their technical merits alone.
I find channels more or less mirrors thinking with unix pipes. Writing many tiny "programs" (packages in Go) and chaining them means testing is very simple.
I prefer go because of its minimalism. Besides the basics and concurrency part, all you have is structs, Interfaces and type aliases. Even generics were absent for a while.
That prevents over engineering to a great deal unless like languages such as Python. Looking at Django for instance, tons of side mixin based views and what not. Sure, clever but hard to comprehend whereas the primary purpose of programming languages was that they were aimed at humans.
Net result is that read the code from docker to kubernetes, it's generally more understandable because the authors didn't have much margin or incentive to over engineer.
Coming from Ruby: it is fast, and compiled, but still very easy to use.
Lacking fancy features and having types and structs is a bonus when it comes to reading other people's code.
When you come back to a program that is 5 years old there's very little bit-rot and it recompiles easily. In this regard, the tendency to have everything built in Go (avoiding external OS dependencies) is a plus.
One more: the ability for one application to have different versions of libraries imported by different modules. This makes maintenance and upkeep easier, especially after years have passed.
Package management. Being able to clone a random open source repository and you can more or less count on `go run .` doing what you expect. And you don't even have to wait that long because how fast it compiles.
I would however disagree on it being simple. I wouldn't use that word. The language is so barren that you end up having insufficient abstraction power to make simple things simple. Instead simple things are verbose.
As for concurrency, well the language is so simple that it's easy to misuse when you are writing concurrent programs. This is required reading for anyone beginning to write concurrent programs in Go: https://news.ycombinator.com/item?id=31698503
- gofmt. The fact that it comes with an opinionated formatter means I don't waste time with bikeshedding.
- Simplicity. I love how Go just gets out of my way and lets me do my work. I also don't need to worry about crazy abstractions and deep levels of inheritance.
- I usually don't need to worry about performance bottlenecks. Go is pretty fast.
- Typed. Over time I ended up hating languages like Python and JavaScript because of the lack of typing. Typed languages let me catch a large amount of errors at compile-time, and it also serves as documentation.
- Go-routines are a very elegant way to deal with concurrency.
- The standard library has a great selection of tools like JSON parsing that are usually not native in other languages.
- Dependency management is pretty good. Not the best, but definitely better than languages like C++.
- Single binaries. You can compile a Go application into a single binary and have it as the entry point of a container.
The result are very small containers that start up very quickly.
Thing I don't like about it:
- Error handling got better over time, but it's still annoying to find out if an error is of a specific type in legacy code.
- It would be nice to have more built-ins for lists, such as .includes(), .filter(), .map(), etc.
- Nil pointers. It would be great if there was a way to ensure points will never be nil.
I was really skeptical about it at first, but it quickly became my favourite language.
Some good points are presented. Interestingly, Vlang (https://vlang.io/) has the .filter(), .map(), etc... and addresses Nil/Null (relegating it to unsafe). Error handling is done differently (with many liking that style), but this point tends towards a programmer's preferences.
- I love golang's build toolchain. Cross-compilation is just an environment variable.
- I love its go:embed functionality, as it removes the necessity of crappy squashfs based solutions, and allows embedding all assets e.g. a webserver/website needs.
What I both like and dislike:
- Marshalling. It can be a joy to use marshalling when you are in control of the data structures, but it also can be PITA when you have to parse external JSON data structures that do not conform to the same types.
- Something like parsing an arbitrary package.json, where fields can be e.g. a string, an array of objects or a single object is real pain to do in golang because it requires to use the reflections API.
- Having to use signal channels to synchronize threads/routines. Sometimes it's just easier to use a for true loop than using a signal channel, because a signal channel isn't compatible with the program architecture. It would be nice if there was a cleaner way to spawn channels via goroutines (e.g. channel = append(channel, go func...?)
All of this. Another thing I love is its test tooling and test conventions. Go makes it very intuitive, efficient, and (for me) fun to write tests early and often. _Not_ testing feels like a waste of really great tooling shipped right with the language.
I never used Dart, but from the examples I saw online, seems to check out.
Go is more similar to languages like C, where you use a * to declare a type as a pointer. So an int is just a value in the stack and cannot be null, but an *int is a pointer to somewhere in memory and can be null. It would be lovely to have a third option in this list, something like *int for non-nullable pointers and *int? for nullable pointers.
> - Typed. Over time I ended up hating languages like Python and JavaScript because of the lack of typing. Typed languages let me catch a large amount of errors at compile-time, and it also serves as documentation.
Funny, I actually think golang typing to be extremely weak and hard to use, especially with all the pointers vs non-pointer values. Typescript is by far the best type system I ever used, but even compared to Java/C#/C++ the golang types are archaic and basic, more akin to ANSI C in power
Yes the types are better than dynamic languages, but compared to modern type systems it is not very good
There’s a great “lo” package which implements these JS-like array and map functions using generics in Go. Coming back from a JS/TS job I’ve been really happy to find this.
I like being able to unmarshal a json response into a typed struct. That gives me the ability to get intellisense in my IDE. Then I don't have to guess what the json response shape looks like. It also helps me prevent issues with trying to access invalid keys in the json response.
This really helps when dealing with an external API.
.NET is ok, but the classes you make serializable generally aren't how you'd write a normal class, which is what I mean by "ergonomic." As far as I know, you need your fields to be public for both reads and writes, and you need to write a separate constructor if you want to create the types programmatically. Go lets you serialize objects more-or-less how you'd write them without serialization, as does Kotlin.
I think golang is a terrible replacement for applications that require a proper framework-level library to allow you to crank out a lot of functionality very fast.
The language is too weak to allow frameworks to be built on top of it. At the same time the standard library is the sanest I have ever seen in a language, both low-level, cross-platform and elegant. As someone else mentioned in this thread: "The language is so barren that you end up having insufficient abstraction power to make simple things simple. Instead simple things are verbose."
Its primitives and standards (concurrency, error-handling, context, etc) are very powerful, but also not the best solution for every type of problem, often they make the code more verbose for little benefit (go routines vs async/await is the main example I can think of).
What is REALLY nice though is that the language takes its primitives to heart, the standard library uses them and most open source projects all kinda use the same primitives and in the same ways. You don't see that in most languages, for example Java has tons of ways of doing concurrency (even within the standard lib) and each lib you use might do it in a different way which leads to a lot of library-wrapping code required when your application uses a lot of libs as well as strange bugs due to bad assumptions
So it is great for building low-level focused applications, things that do one thing and do it really well (in my company we implemented a custom network protocol in it for example). But it is not ideal for large applications that has a lot of business logic.
The way I see it golang is a very good language if you write a lot of algorithms, it is a bad language if you write lot of templaty code
Special note on golang dependency management: it is nice it is part of the core of the language, but using code-repositories as the source of truth was not a good idea and causes tons of issues
I am not an expert in Go but have written code for internal tools for my company and here is what I love about Go:
- I found its syntax to be very easy to pickup compared to other languages. Something about it is so easy at least for me
- It is fast enough and built for http and backend APIs with great library support.
- Single Binary (Not just Go but another plus for me)
- Concurrency
- Error handling. This gets a lot of hate but the simpleton me loves doing if err != nil because I prefer explicit error handling like that.
It is awesome for building lower level/network applications ideally but you could surely build things like REST APIs and even full web apps.
The downside is that if you are looking to build a full Web Application with Front and Backend, you are better off with tested frameworks where Go doesn't shine as much because die hard Go people dont suggest using frameworks in Go even though few exist.
Tabs let everyone see the indent width they prefer. Some people get eye strain with indent width 2. This is why spaces are evil.
Using spaces for indent is like hard coding the color-theme of the editor into your code file. It's simply wrong.
Tabs are perfection.
--I like the tooling surrounding it. LSP server. code formatter gofmt. Build tools to X-compile for anything.
--I like the C-style error handling. Doing a check after every action with the potential for failure. Probably the biggest turn off for most people becuase errors bleed into the main flow of the program. Maybe for things like CRUD apps it's not ideal. But for really critical fundamental things error handling should be a first class part of the flow/logic, not just something that's chucked off, hidden away. Trade offs in all things though.
I like the color analogy. Using spaces is like using a green chroma screen. Using tabs is like having an alpha channel, as long as everything supports the alpha channel it is the best.
--I like how Go fills this little niche that no one else quite fills. Combining garbage collection while defaulting to value types. A savvy programmer has a lot of leeway to avoid creating garbage, while still "feeling" like Javascript.
Sure other languages are even better for avoiding garbage, but they also don't have the care-free feeling of JavaScript. Or they might feel care free but are living in Heap City.
It's a great relaxation language for hobby projects. After a day of cranking out tight functional style Typescript at $DAYJOB it's refreshing to work in a "stupid" language where the space to search for the most elegant solution is rather limited. You're just telling the computer what you want it to do in a very explicit and plain way.
Low cognitive load, both for developing and writing it. There's very little "debugging the language" instead of "debugging the program" compared to other languages, it's just too simple to do anything too clever.
43 comments
[ 3.6 ms ] story [ 96.3 ms ] threadBut I don't know if I'd choose to write a Golang project from scratch. It's got a garbage collector and sketchy C interop - not low-level enough to be used for most systems programming. But it's also not expressive enough and lacks the rich ecosystem of Python or Javascript. Jack of all trades, master of none, IMO. Golang is a solid language for HTTP web services for big teams with varied abilities, but there are better languages based on their technical merits alone.
- compiled. So I can release a binary quite easily
- I can usually reach far without relying on third-party libraries/frameworks (e.g., http servers, json parsing, testing)
- it’s relatively easy to understand other’s people Go code
Things I don’t enjoy:
- pedantic compiler (e.g., I cannot leave unused variables in my POC/prototype code)
- hard-coding dependencies’ URLs in imports. Why not just a simple mapping in go.mod from canonical URL to friendly name?
- lack of a more powerful standard library (like Python’s)
- error handling. It’s simple, but it becomes tiring after a while. Not a huge deal, though
That prevents over engineering to a great deal unless like languages such as Python. Looking at Django for instance, tons of side mixin based views and what not. Sure, clever but hard to comprehend whereas the primary purpose of programming languages was that they were aimed at humans.
Net result is that read the code from docker to kubernetes, it's generally more understandable because the authors didn't have much margin or incentive to over engineer.
Yes, this is what makes me so interested in Go!
Lacking fancy features and having types and structs is a bonus when it comes to reading other people's code.
When you come back to a program that is 5 years old there's very little bit-rot and it recompiles easily. In this regard, the tendency to have everything built in Go (avoiding external OS dependencies) is a plus.
I would however disagree on it being simple. I wouldn't use that word. The language is so barren that you end up having insufficient abstraction power to make simple things simple. Instead simple things are verbose.
As for concurrency, well the language is so simple that it's easy to misuse when you are writing concurrent programs. This is required reading for anyone beginning to write concurrent programs in Go: https://news.ycombinator.com/item?id=31698503
- gofmt. The fact that it comes with an opinionated formatter means I don't waste time with bikeshedding.
- Simplicity. I love how Go just gets out of my way and lets me do my work. I also don't need to worry about crazy abstractions and deep levels of inheritance.
- I usually don't need to worry about performance bottlenecks. Go is pretty fast.
- Typed. Over time I ended up hating languages like Python and JavaScript because of the lack of typing. Typed languages let me catch a large amount of errors at compile-time, and it also serves as documentation.
- Go-routines are a very elegant way to deal with concurrency.
- The standard library has a great selection of tools like JSON parsing that are usually not native in other languages.
- Dependency management is pretty good. Not the best, but definitely better than languages like C++.
- Single binaries. You can compile a Go application into a single binary and have it as the entry point of a container. The result are very small containers that start up very quickly.
Thing I don't like about it:
- Error handling got better over time, but it's still annoying to find out if an error is of a specific type in legacy code.
- It would be nice to have more built-ins for lists, such as .includes(), .filter(), .map(), etc.
- Nil pointers. It would be great if there was a way to ensure points will never be nil.
I was really skeptical about it at first, but it quickly became my favourite language.
- I love golang's build toolchain. Cross-compilation is just an environment variable.
- I love its go:embed functionality, as it removes the necessity of crappy squashfs based solutions, and allows embedding all assets e.g. a webserver/website needs.
What I both like and dislike:
- Marshalling. It can be a joy to use marshalling when you are in control of the data structures, but it also can be PITA when you have to parse external JSON data structures that do not conform to the same types.
- Something like parsing an arbitrary package.json, where fields can be e.g. a string, an array of objects or a single object is real pain to do in golang because it requires to use the reflections API.
- Having to use signal channels to synchronize threads/routines. Sometimes it's just easier to use a for true loop than using a signal channel, because a signal channel isn't compatible with the program architecture. It would be nice if there was a cleaner way to spawn channels via goroutines (e.g. channel = append(channel, go func...?)
These were the highlights for me: - Simplicity - Typed - Go-routines - Single binaries (Cross-compilation is just an environment variable)
> - Nil pointers. It would be great if there was a way to ensure points will never be nil.
Like Dart sound null safety?
Go is more similar to languages like C, where you use a * to declare a type as a pointer. So an int is just a value in the stack and cannot be null, but an *int is a pointer to somewhere in memory and can be null. It would be lovely to have a third option in this list, something like *int for non-nullable pointers and *int? for nullable pointers.
Funny, I actually think golang typing to be extremely weak and hard to use, especially with all the pointers vs non-pointer values. Typescript is by far the best type system I ever used, but even compared to Java/C#/C++ the golang types are archaic and basic, more akin to ANSI C in power
Yes the types are better than dynamic languages, but compared to modern type systems it is not very good
I wonder how does it compare to go's implementation
It's now as simple as
record SomeData(string Name, int Id);
Which gives you an immutable object, auto generated constructor, and some additional helpers to make life easier.
The language is too weak to allow frameworks to be built on top of it. At the same time the standard library is the sanest I have ever seen in a language, both low-level, cross-platform and elegant. As someone else mentioned in this thread: "The language is so barren that you end up having insufficient abstraction power to make simple things simple. Instead simple things are verbose."
Its primitives and standards (concurrency, error-handling, context, etc) are very powerful, but also not the best solution for every type of problem, often they make the code more verbose for little benefit (go routines vs async/await is the main example I can think of).
What is REALLY nice though is that the language takes its primitives to heart, the standard library uses them and most open source projects all kinda use the same primitives and in the same ways. You don't see that in most languages, for example Java has tons of ways of doing concurrency (even within the standard lib) and each lib you use might do it in a different way which leads to a lot of library-wrapping code required when your application uses a lot of libs as well as strange bugs due to bad assumptions
So it is great for building low-level focused applications, things that do one thing and do it really well (in my company we implemented a custom network protocol in it for example). But it is not ideal for large applications that has a lot of business logic.
The way I see it golang is a very good language if you write a lot of algorithms, it is a bad language if you write lot of templaty code
Special note on golang dependency management: it is nice it is part of the core of the language, but using code-repositories as the source of truth was not a good idea and causes tons of issues
- I found its syntax to be very easy to pickup compared to other languages. Something about it is so easy at least for me
- It is fast enough and built for http and backend APIs with great library support.
- Single Binary (Not just Go but another plus for me)
- Concurrency
- Error handling. This gets a lot of hate but the simpleton me loves doing if err != nil because I prefer explicit error handling like that.
It is awesome for building lower level/network applications ideally but you could surely build things like REST APIs and even full web apps.
The downside is that if you are looking to build a full Web Application with Front and Backend, you are better off with tested frameworks where Go doesn't shine as much because die hard Go people dont suggest using frameworks in Go even though few exist.
Tabs let everyone see the indent width they prefer. Some people get eye strain with indent width 2. This is why spaces are evil.
Using spaces for indent is like hard coding the color-theme of the editor into your code file. It's simply wrong.
Tabs are perfection.
--I like the tooling surrounding it. LSP server. code formatter gofmt. Build tools to X-compile for anything.
--I like the C-style error handling. Doing a check after every action with the potential for failure. Probably the biggest turn off for most people becuase errors bleed into the main flow of the program. Maybe for things like CRUD apps it's not ideal. But for really critical fundamental things error handling should be a first class part of the flow/logic, not just something that's chucked off, hidden away. Trade offs in all things though.
--I like how Go fills this little niche that no one else quite fills. Combining garbage collection while defaulting to value types. A savvy programmer has a lot of leeway to avoid creating garbage, while still "feeling" like Javascript.
Sure other languages are even better for avoiding garbage, but they also don't have the care-free feeling of JavaScript. Or they might feel care free but are living in Heap City.