11 ms·
Some Rookie Mistakes in Go
- matiasb 11y agoLoved the article!
- daveguy 11y agoFYI: golang not the game of Go. Recent news has skewed my expectation of go in article titles.
- qz_ 11y agoYep, good news I like both ;)
- pka 11y agoI am constantly amazed at how people will find a way to fly to Mars in a bucket just so they don't have to learn how to operate a rocket :)
- RodericDay 11y agoI'm constantly amazed at what people consider a "rocket" these days.
- jshen 11y agoI'm constantly amazed at how people find a justification to fly a rocket just to get to the McDonalds a block from their house.
- hguant 11y agoObviously you need to spend more time playing Kerbal Space Program. Rockets are their own justification. On a more serious note, I think that's just human nature - if you're invested in something - a technology, a stack, a business model, a car - you value that investment more than its worth, because it is yours. I think there's also an element of "I put in the effort to learn this, so damnit I'm going to use it". Or just people like challenges.
- kzhahou 11y agoSorry, I don't get it. What is the bucket, what is the rocket, and what is Mars?
- comex 11y agoRespectively: Go (which is criticized by some for its prioritization of language simplicity over features), more complex languages, and the task that the program needs to perform.
- kough 11y agoFound myself agreeing with all of this. I very much second the decision to not use a framework and instead use the core to libraries and a standalone multiplexer. Another huge benefit of this is that you can write some glue code and test your end points without using the http mocking interfaces, which are absolutely terrible for testing.
- deleted 11y ago[deleted]
- otraore 11y agoI personally use gin https://github.com/gin-gonic/gin https://github.com/gin-gonic/gin and have never looked back
- marcc 11y ago+1 here. Gin is a pretty reasonable web framework that sticks to the core go patterns and practices, but provides some good built in helpers. It includes http router (a high performance route handlers and dispatcher), and the implementation of middlewares is nice. We've tried with Revel, and I completely agree with the post here. We could use net/http directly, but gin is working super well for us right now.
- shwouchk 11y agoMost of these mistakes are mistakes for any language you write in.
- kzhahou 11y agoThese specific mistakes are useful for new Go programmers. For example, knowing that a pointer-to-slice is (usually) useless.
- pcwalton 11y ago"Don't use a Web framework" (#1), "use panics wisely" (#2), "be careful when reading from request.body more than once" (#3), "be careful of hidden allocations from pointers-to-slices" (#5), "be careful with the surprising behavior of naked-return-implies-return-0 feature of Go" (#6), and "be careful with the interactions between mutation and shadowing" (#7) are all Go-specific. Among popular languages, issues #5, #6, and #7 apply only to Go.
- TheOtherHobbes 11y agoYou may have an off-by-one error. :) Otherwise you're right - but all languages have sharp edges. I'm using Go on my current project and I've gotten a lot further a lot more quickly and with better performance and reliability than I would have using Django, Rails, or Node. Because I'm not in a hurry I thought it would be fun to write a simple custom server/router/middleware bundle around net/http without using any 3rd party packages. From a cold start it all turned out much easier than expected, and so far the whole thing is under 500 loc. Being careful around a few sharp edges seems like a small price to pay.
- shwouchk 11y ago1) Be judicious regarding your choice of tools 2) Be careful with signalling errors 3) Don't read twice from a stream and expect the same data 4) Don't write SQL? 5) Understand pointers 6) Make it easy for readers of your code 7) Understand Scoping 8) Don't use objects concurrently unless they were designed for it 9) Keep track of which versions of dependencies you use
- 11y ago
- znemz 11y agoCan someone follow up with more details on vendor for those not using go currently? What is the best practice for locking versions of libraries down. I am comparing this to gemfile.lock and shrinkwrap.json . Ty
- pm90 11y agoThere are multiple ways to do this. Personally, I've used and liked govendor https://github.com/kardianos/govendor https://github.com/kardianos/govendor. As of go 1.5, its supported by the language itself: https://github.com/golang/go/wiki/PackageManagementTools https://github.com/golang/go/wiki/PackageManagementTools
- fpoling 11y agoIt is spot on observation about rather bad rules in Go about := and scopes that hit me as well. For example, the following compiles without warnings and even runs the first invocation of test successfully, https://play.golang.org/p/tYQSNjudGT https://play.golang.org/p/tYQSNjudGT : package main func test(n int) { for { n := n - 1; if n == 0 { break } } } func main() { test(1); test(2) }
- kyrra 11y agoThe 'go vet' command has a -shadow flag to check for this. And as the author points out, editors can point it out as well. It definitely isn't ideal, but it can be dealt with. I believe Rob Pike had called out that the number of ways you can do variable assignment/declaration is something he disliked, but it's impossible to change in Go 1 at this point.
- Veedrac 11y agoThat seems somewhat natural to me, to be honest. The same could happen in Rust, or most languages with shadowing. IMO, allowing it is the lesser evil.
- fpoling 11y agoThe issue here is not shadowing in general but shadowing withing a single statement like in n := n + 2. A sane rule would not allow to refer to the declared name in the right-hand side expression.
- azinman2 11y agoI'm not sure that using a custom panic filter is idiomatic...
- HeyImAlex 11y agoIt's used in the stdlib I think, you just need to recover the panics at your api boundaries.
- csense 11y ago> Go has multiple returns from functions so a very typical scenario is a function that returns something and also an error, which would be nil if everything worked okay This is one of the problems I have with C. You basically have to remember to manually check for an error on every function call, which means (1) an algorithm with short and simple pseudocode becomes lengthy and hard to read real code, because you need to add a ton of error handling, (2) it is easy to forget to handle an error in some place. Exception-based error handling lets you delegate errors to a top-level handler without cluttering up intermediate code (i.e. an exception anywhere in webpage rendering logic should be handled by 500'ing the entire page, which exception-based error handling lets you do without cluttering intermediate functions between the function producing the error and the function handling the error with error-handling logic). I've been thinking about learning Go, but if its only error handling mechanisms are "pack it into a return value" or "panic() which is like exit(1) in C" then it's a black mark against the language. It's still a black mark if the language has exception-like error handling but it's not considered "idiomatic Go" and the stdlib and a good chunk of third-party libs report errors in return values.
- sdegutis 11y agoSwift alone gets this right: It uses error values like in Go, but you must prefix any function which can throw with a try statement or it fails with a compile time error. That way you never forget to handle it, but it's not really an exception either.
- pcwalton 11y agoRust effectively does this too with the warn-unused-result lint (on by default) and the try! macro.
- knughit 11y agoTo understand Go, you need to stop thinking in terms of black marks and start thinking in terms of tradeoffs across a whole language.
- 11y ago
- knughit 11y agoGolang, not Baduk :-(
- Natsu 11y agoI know. I was waiting for some life or death problems...
- logingone 11y agoWhy does Rust get articles about eg an operating system written in Rust, but all the Go posts are how to tie your shoe laces? Somebody explain, please.
- steveklabnik 11y agoI would acually prefer that there were many more "getting started" posts in Rust-world, personally. I think it's a very under-served area.
- eropple 11y agoAgreed - getting started was really hard. I think, as my sibling post notes, that's a function of the existing community - unlike many languages where adoption trends heavily towards the wide end of the pyramid and moving upward over time, Rust seems to be starting at the tip and broadening (more slowly than one might like) on its way down. Or maybe that's the result of a scarcity of those kinds of resources. Hard to say.
- steveklabnik 11y agoI think it's also because people undervalue these kinds of posts. Many people think that the idea must be novel to be worth a post, but that's not true! There's a lot of value in posts that cover the basics. Sometimes, seeing a concept explained in a different way is all that's needed to get something to click.
- eatonphil 11y agoProps for understanding this! Many communities around non-mainstream projects have difficulty grasping this, I think.
- Retra 11y agoRust is a pretty tricky language. So there's the fact that you need to learn more before you can write an accurate article, and if you learn too much, you start losing the beginner's perspective. And if you don't learn enough, you don't have a good enough picture to teach. Thus the number people in a position to write high-quality introductory articles is deflated. That's my excuse, anyway.
- pm90 11y agoI was intrigued about the part about not being able to ready the response body more than once. Can anyone more experienced explain why this decision was made in the core libraries? And if there is a good reason to not read the body more than once, is the author making a mistake by trying to get around it?
- jerf 11y agoGo's core library specifies several interfaces for reading, writing, and closing streams. Here's Reader, for instance: https://golang.org/pkg/io/#Reader https://golang.org/pkg/io/#Reader Those interfaces do not promise seeking, so they apply to as many things as possible. (See https://golang.org/pkg/io/#Seeker https://golang.org/pkg/io/#Seeker .) The HTTP body is provided as an "io.Reader" which actually backs to the network stream, and since TCP streams can't be seeked, it's an error to think you can. This means that native Go HTTP handlers can handle a multi-gigabyte upload or download without consuming all that RAM at once (assuming there is some way to stream), but you lose seeking. You can easily recover read-only access by using io.ReadFull to fully consume a reader into a byte buffer, but then you pay the price of consuming all the RAM, of course. (https://golang.org/pkg/io/#ReadFull https://golang.org/pkg/io/#ReadFull ) Whether or not it's a mistake depends on your situation. Fortunately, in the HTTP context, you have a Content-Length that you can examine to make decisions if you need to; the generalized io.Reader does not have that, either. This all comes from the nature of HTTP itself. I tend to consider it a basic requirement for any web development environment that there be a way to correctly deal with an HTTP upload as a stream, and that the environment not "helpfully" unconditionally load the entire stream into memory for me.
- Someone 11y agoIf you want efficiency, I think it is the only way to do it. Responses can be huge. Why would the library commit to storing them at all, and determine the data type to store them in? Yes, you could make an API that allows the library user to control that, but that would be needlessly complex compared to having a single call "give me the response stream", and letting the caller of that decide how much of the data to read, and what to do with it.
- saturn_vk 11y agoactually, for error handling, panic is a lot more like exceptions than exit. much like java, panic acts like throw, and defer/recovery like try/catch. and you can use it like that in the depths of your library, recovering from panics in your exported functions.