Hacker News new | ask | show | jobs
The pleasure of writing Go (fakturo.io)
39 points by elementi 1734 days ago
14 comments

> In Python, everything must be indented with 4 spaces. It was a great idea…. or not? I think probably it was one of the worst idea to apply in the development industry. Not even TABS! It’s literally impossible to have a consistent indentation, especially when you have more than 2 nested loops/functions/switch.

Pretty sure that's not accurate. You can use whatever number of spaces, provided it's consistent for a specific block of code.

Ups! As you might have noticed, I'm a beginner on Python but that thing was REALLY annoying. Nice to know that you can use whatever number of spaces, but... consistency is hard to keep with spaces (I'm not able :/)
I'm not a big fan of python but I use it a lot for quick stuff, and syntax is just a non-issue. Any half-decent editor will handle that for you (and yes, this includes Vim).

Criticize the wonky static typing tools and I'm with you. Criticize the unpredictable performance and I'll join the choir. Criticize dependency management and I'll unleash my rage. But come on, this is just not a thing. IME even data analysts with non-cs backgrounds and very limited programming ability never see this as a problem.

It's fine if you don't like it (I prefer my {s as well!) but I'll be honest: it really feels like a nitpick.

As you said before, you can use tabs. You just need to use tabs everywhere (on Python 3, on Python 2 you can pretty much mix tabs and spaces, however this is a very bad idea).
Yeah, Python even support tabs. On Python 2 you could even mix tabs and spaces, but this turned out to be a very bad idea.

So Python 3 enforces that the whole file uses either X number of spaces or tabs, you can use either of them.

At one place I worked, when we couldn't agree on 4 spaces (Python standard) vs. 2 spaces (existing company standard) someone suggested Fibonacci increments of indentation levels: 1, 1, 2, 3, 5, 8 etc. Would have worked from a technical point of view.
On a related note, we've been using editorconfig files to enforce consistency across our python files. It does away with 2 spaces vs 4 spaces vs tabs.
This is great. I too enjoy working with Go coming from a Swift, Obj-C, Java and C# background. The problem that the latter 4 languages have is keyword bloat. For example, Swift has 23 keywords just for declarations (Source: https://docs.swift.org/swift-book/ReferenceManual/LexicalStr...)

The entire Go language has 25 keywords. That's it. That includes declarations, control, errors and multithreading.

Language design of the latter 4 along with this keyword bloat make for unfettered methods of writing code. Want a simple HTTP request to process JSON? You can open a Go file from the last 5+ years and expect that to look exactly the same. Try doing that in the other languages, and you will find every possible combination of the same thing.

Generics has so much indirection and emphasis placed on re-usability, that readability for debugging and understanding become exponentially difficult. In fact, almost every use of generics ultimately ends in type erasure or forced casting. And let's be honest: every generic has to conform to a super generic or protocol, so it's not really as generic as you thought it was going to be.

Highly opinionated, reverse compatibility and the lack of generics make Go extremely powerful for it's purpose. Type safety make for easy refactoring, and when refactoring needs to take place, your code is forced to follow the conventions laid out in idiomatic Go: https://golang.org/doc/effective_go

> Generics has so much indirection ...

I don't understand. What do you mean?

> almost every use of generics ultimately ends in type erasure or forced casting

Again, not understanding. Would you mind giving an example of this?

Oh, another thing. Their date formatter is hilariously easy to remember: https://pkg.go.dev/time#pkg-constants

"01/02 03:04:05PM '06 -0700" // The reference time, in numerical order.

That is a very interesting approach to the problem. It is just a shame they didn't go with the third of February 2001 for their reference date, that would have been even easier to remember.
You do know go is adding generics right?
Because Go doesn't support userland generic types, I see liberal use of `interface{}` types in APIs. There must be a better way.
I find generics are overused in most languages. Go will be getting generics to handle the very few situations in which they are a genuine value. But the most common uses cases for generics in other langues are already handled by Go interfaces.

For example Go's `sort.Interface` provides a mechanism to implement generic sort, find and set operations on any type of collection that implements those three methods (Len, Swap, and Less).

I nearly never find myself having to use `interface{}` in my Go code, and those that do usually don't have to, they just don't want to define an appropriate interface.

Generics are coming in next version, go 1.18 in around 6 months ;)
That would be such great! I'm pretty new with Golang, where could I keep myself updated with the latest news?
I'd say keeping an eye in the issue tracker https://golang.org/issues + golang-nuts mailing list https://groups.google.com/g/golang-nuts?pli=1 might be a good start.

I wrote an article about where to find Go-related content a while ago: https://henvic.dev/posts/go/

Thanks a lot!!!
I recommend https://golangnews.com/ too, Not just because of its utility or that it has HN interface but also because Kenny Grant has been contributing to the Go ecosystem for a long time and his code is a pleasure to read.
anxiously awaiting :)
There is nothing wrong with a well documented interface. The `is-a` pattern and `has-a` pattern are all I have ever needed when composing "objects" in golang.
I guess I see it mostly used without accompanying documentation
Usually, the `interface{}` is named something like `Xer` to denote an interface which satisfies `X`. So - `Dialer` would be the interface and any struct is free to implement the `Dialer` methods to qualify as one (for example). Presumably requiring some way to `Dial` something.

What I like most about `go` is how standard a lot of the "good practices" are, with a focus on getting stuff implemented. There is no time to argue about spacing and bracing, just run `go fmt`.

I dread the appearance of generics. It's not just that they lead to longer compile times for very little benefit, it's that everybody wants every thing to be generic, just in case. Like the C++ dogmas around how many of which type of constructor you need, generics encourage fast-spreading, deleterious memes.
The "better way" is coming in an upcoming go release (generics)
instead of taking an empty interface, take an interface with defined methods. Then the caller can conform their type to whatever the API needs.
This is what people due when generic types (parametric polymorphism) wouldn't be involved.

But if you need type parameters, then you wouldn't be able to do this.

Well they will be landing pretty soon
Can anyone link to a project that they would consider elegant? I have never cruised through a golang project and felt that emotion.
I am working with Go with more than 3 years quite full time and I could say that it's a real pleasure to work with a performant language.

After having some internal libraries to make repetitive jobs (while waiting for generics in Go 1.18), that's a good match for all the team!

That's also a well-documented language and easy to get started in!

I just started a month ago. Man, I literally became again a full time developer. No stress, only ideas, beautiful code that is a little bit verbose but really understandable. I think I could explain my code ELI7.
That's great. Thank you for your feedback!
go has been so far a very enjoyable and consistent language. you can come back to code you wrote several years ago and not be surprised by it. the other consistent programming language i know of is java. java code from ten years ago won't be surprising to any java programmer reading it today.

programming language designers often forget how important consistency is. many languages have changed their syntax so much that we should just call them something else.

I regularly write Go code and I mostly enjoy programming in the language, but this post captures nothing important about what makes writing code in Go pleasurable.

Having biultin library features is nice but is not the reason. Python also has a lot of builtin library features, but I don't enjoy working with it.

Static typing matters a great deal, but Java is also statically typed yet I don't enjoy working with it.

For me I think what makes Go pleasurable to write in is that it has structs with value semantics and it also has pointers, and it also has none of the recent (incorrectly labeled "modern") ideas such as enfoced null-checking or enforced error handling.

I can write the code in a very direct and straight forward way. I can decide myself how much abstraction to introduce. I can decide myself which errors are worth handling and which are not.

I can write functions that take complicated arguments as structs without worrying about how it will degrade performance. Because structs have value semantics, creating an instance of a struct will not trigger a heap allocation unless you return a pointer to it or let it escape the current scope via other means.

This matters a lot because a lot of performance degradation in other languages comes not only from being interpreted but from the model of programming that requires lots of tiny allocation.

Another thing that makes go pleasurable is that a package is well defined and you can import packages written by other people. But that's only secondary IMO.

Go's performance is reasonable but it's far from C/C++ level. I think a well written server in C/C++ can outperform a go webserver by a factor of 10. That said, Go is about 40x faster than Python so that's great, and it means you can write a program in Go and run it on a single machine to get the same performance to a website written in Python and hosted on 40 web servers with an insane infrastructure and requires an entire team to manage.

That said, the language also has some warts, such as lack of real typed enums that can be introspected. For example, there's currently no way to dynamically introspect an enum type and find out all the defined values/constants. You must resort to code generation.

Also the lack of generics, but hopefully those will land soon (within a year from now, if nothing goes wrong).

But, what the language lacks in features, it compensates for in tooling.

No where else have I seen a language that makes it such a breeze to cross compile. I can write code on my macbook and compile it for linux to get a valid linux executable binary that I can then `scp` to a server and have it running right away.

The compiler speed is not the greatest but it's reasonable compared to pretty much everything else out there.

I'm always slightly confused by the language speed comparisons for I/O heavy applications like networked services. On the one side you are taking in, for example, HTTP requests, on the other you are talking to a database, maybe some other networked APIs. A caching layer picks up plenty of load - how often is the program really cpu-bound here?

For me fastAPI [0] and async Python call the performance statements into question; good to run some benchmarks with real world use cases

[0] https://fastapi.tiangolo.com/async/

In my experience, the performance of carefully written Go is not far from the performance of C. Perhaps between a factor of 1.5x and 2x slower, if that. Otherwise, I agree with your comments.
Carefully written Go vs uncarefully written C? Sure.

Carefully written Go vs carefully written C? I still think C would win by a factor of 10.

Like I said, most slowness comes from memory access and fragmentation. In C you can use strategies like arena allocations. In Go you cannot turn of the GC.

If you want to build a custom allocator (use freelists and vectors of types) you can do all of that in Go and C. There's nothing stopping you from writing custom memory allocators in Go.
Most of all, it’s simple. You can’t do fancy and clever stuff which might feel bad in the moment but 6 months from now you’ll be much happier to read the simple but slightly verbose version.
I agree at 2000%!
I wouldn't call Go 'slightly verbose'.
Show me the least verbose way to process things in parallel in Python and I'll show you the least verbose way to do it in go:

    go f()
Go is really good and fun to write until you have to care how you write it. Adding sync.Pool, limiting concurrency, these are not some of my favourite things
Interesting content marketing piece for an invoice PDF generator leveraging wkhtmltopdf. I would like to hear more from people working with PDF directly in Go.
On nodejs and dependencies, it’s kind of irrelevant but I suggest the author check the size of their .go modules folder, it’s most likely also a few GB in size.
Can nodejs be ran as a portable binary? (Electron?)
go is indeed a pleasure to write, especially if you have vscode auto-format on save with the official go formatter. Not worrying about getting the formatting just right takes a huge cognitive load off I didn't even know I had.

One minor mistake in the article:

> Fortunately, Python and Go removes colons by default at the end of every expression. To quote someone, “Colons are for compilers, not for human!”.

Just to clarify for non-native english speakers,

a colon is ":"

a semi-colon is ";"

Ah. I meant semi-colon. Ups ^_^
Beautiful website by the way
We do not like the over-fancy CSS. By the way, we love UX, not UI.
I've been paying the rent/mortgage with Python since 2013:

> In Python, everything must be indented with 4 spaces

no

> It’s literally impossible to have a consistent indentation

it's trivial

> as most programmers will agree, they often make the code harder to understand when reading someone else’s work

No, swapping things is easy to pattern match against once you know the language.

This is even dumber than complaining about Lisp parentheses.

Ive been using python to pay the mortgage since about 1999. With respect to indentation, realistically it depends on how many morons you have to share the code with and how many broken ass misconfigured editors those morons are wielding.

At least you can actually see everything with semantic value in Lisp!

I really prefer writing Go now for a number of reasons if I’m honest which are too numerous to list here.

With the widespread availability and use of code formatters like black, pre-commit hooks and ci/cd pipelines, complaining about indentation seems like a deeper problem in the engineering org. Files that are inconsistently formatted should never make it to code review, much less be merged.
Exactly. I've used Python for 5+ years now and I can't remember indentation ever being a problem. Not even when I started out.

And even if you somehow f-up the indentation. About every editor has a formatter that fixes it for you.

Thanks for your feedback. We'll correct that thing about Python as soon as possible. However please agree with me that with an educational background of C/C++, learning Go was easier than learning Python.
I used to be a C++ dev for 10 years. I tried to learn go after hearing about how great it is. IMO - it's a hot garbage practical joke made by googlers that became popular because it was made by googlers and then it was too late to tell its was a prank. It's a corrupt amalgam of "clever hacks" and "only one good way to do things - my way".

Its concurrency is awful, and makes shooting oneselves in a foot easy. Effective go teaching you how to basically make mutex using channels is just a practical joke, right?

As for C++ and libraries - Boost was and is a big one. Want HTTP? There's a full server implementation you can reuse easily https://www.boost.org/doc/libs/1_55_0/doc/html/boost_asio/ex...

Go's success in the cloud native infrastructure is really impressive - the language has enjoyed widespread adoption in many large engineering orgs. Having a hard time seeing where you're coming from when you talk about a "hot garbage practical joke"
JavaScript is an awful language, we all can agree on that, right? But it has reached universal adoption, it's widespread from in-app scripts, through embedded devices, back-end services and front-end.

I have the same opinion on Go - it's awful, it fails to deliver its promises, but it became popular because it was "a google thing".

Google itself supports go internally, but it is nowhere near being ubiquitous or even recommended - I think that tells you something about it too.