New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Learning Go as a Node.js Developer #14

gergelyke opened this Issue Feb 8, 2018 · 12 comments


9 participants

gergelyke commented Feb 8, 2018

No description provided.

@gergelyke gergelyke added the comments label Feb 8, 2018


This comment has been minimized.

tothandras commented Feb 8, 2018

I think this line wasn't intentional: i, file := i, file. 🙂


This comment has been minimized.

theckman commented Feb 9, 2018

@tothandras I think it was intentional. When using the range operator, Go doesn't initialize new variables on each loop. This means it's setting the value each loop (=), instead of creating a new variable (:=). If you aren't using goroutines that's not an issue. However, this is important when it comes in to using goroutines with inline functions like this.

If you're using goroutines where you aren't explicitly passing the variables in, you can actually end up in a situation where the goroutines all start with the last value returned from the range operator. This is because they are the same variable.

One way to get around this is to make a locally scoped variable, or variables in this case. The other way is to pass the variables in to the function you're invoking.

You also see this pattern used in Go unit tests, where parallel tests are executed. They do it for the same reason.


This comment has been minimized.

judwhite commented Feb 9, 2018

@tothandras This shadows the iterator variables to prevent access to modified closures inside the goroutines. I would have used different variables names to make it more clear. You can use go vet to fail CI when there's shadowing as it's often more confusing than it's worth. Here's an example which I think makes it more clear:

@theckman The heck, man? You got me by a few minutes 😄


This comment has been minimized.

ayuryshev commented Feb 9, 2018

It's only natural that you're trying to find solutions for problems you encountered in past.

But exploring new technology this way leads to absolutely natural mistakes.
You're are worring about wrong things.

  1. Dependency management

This problem is not (and never was) in such terrible scale as in javascript.

You can forget about this problem while you learn go.
I suppose that dep will be released offically when you will really need this.

  1. Asynchronicity

I did the same mistake as you: I thought that channels and messages are similar to Actor pattern in Erlang, Akka.

Don't try to think about promises, futures and other abstraction when you programming in go.

In fact, you need learn synchronicity now, golang already asynchronous in its nature.


This comment has been minimized.

theckman commented Feb 9, 2018

@ayuryshev We did have our own leftpad moment just a few days ago... 😞


This comment has been minimized.

donatj commented Feb 9, 2018

I'd be surprised if someone else hasn't already said this, but I'd say it's better to come to terms with the built in HTTP server before looking at a Framework like Gin.

It's added dependency / overhead and in practice usually not necessary. The built in server is quite mature and production ready.

We personally have production servers fielding several thousand requests per second using the built-in HTTP server.

It's honestly very flexible when you get your head around the interfaces it uses, and for things like more complex routing, CORS, etc – Gorilla components can be used to supplement rather than replace.


This comment has been minimized.

tothandras commented Feb 9, 2018

@theckman, @judwhite Thank you for the explanation!


This comment has been minimized.

robbrit commented Feb 9, 2018

Re: The async Go code

No Go developer would write code like this. Asynchronous calls are useful when you have a limited number of threads in a pool and you want to re-use them while waiting for I/O to come back. Go's internal goroutine scheduler handles this already, so there is no need to complicate your life by writing async code.


This comment has been minimized.


gergelyke commented Feb 11, 2018

Thanks a lot @robbrit - makes sense. Still have to learn a lot about Go


This comment has been minimized.

chanlito commented Feb 15, 2018

I still don't understand why go sync code is async? 🤨


This comment has been minimized.

robbrit commented Feb 15, 2018

It's not async actually, it's sync. Async calls are only needed when you have a limited number of threads. In Node.js you only have one thread, so you are very limited, but even in Java/C#/etc. which typically use thread pools of a small size you are still limited. If you have high throughput (like with a web server) you can end up running out of threads; async solves that problem by returning threads to the pool when they are waiting for I/O.

In Go (and any other system that uses fibers) you are not as limited. You can just fire off goroutines without really worrying. If a goroutine is blocked because it is waiting on I/O, it doesn't matter since you're not wasting a scarce resource and so dealing with the complexity that async introduces is not worth the effort.

Example (Go-ish pseudocode):

x = http.Get(url)
y = someServiceCall(x)
z = someOtherServiceCall(y)
// stuff


http.Get(url, func(x) {
  someServiceCall(x, func(y) {
    someOtherServiceCall(y, func(z) {
      // stuff

Technically you could use promises/futures here, but they are still conceptually weird compared to sync code, especially when you have to start dealing with failure scenarios.


This comment has been minimized.

truonglvx commented May 15, 2018

waiting for new articles about: goroutines, middlewares, errors handling...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment