17 ms·
My Go Resolutions for 2017
- xiaoma 10y ago>"My goal every year is to help Go developers. " I believe that if one were truly concerned with helping Go developers, they'd be helping them migrate to a more productive, more community-driven language, such as Rust or Elixir, depending on their needs. It is the doom of Go to remain Google's play-thing and that has and will continue to lead to choices at odds with the needs of most developers.
- geodel 10y agoYour comment will hardly lead to productive conversation. The fact is a lot of people are perfectly fine with current Go capabilities and prefer writing useful software solution as compared to debating on PL theories and community agendas.
- throwaw199ay 10y ago> The fact is a lot of people are perfectly fine current Go capabilities and prefer writing useful software solution as compared to debating on PL theories and community agendas. How many? how many didn't use Go because it lacked of a sane type system? because Go relies way too much on runtime behavior (AKA type switches and reflection) to be called a modern statically typed language. In all my time using Java I never had to cast something once or use reflection, or to do a type assertion, all these are common practice in Go, especially when the std lib is now getting API like Context.Value(interface{})interface{}. This isn't PL theory, these are flaws that aren't going anyway and will become more apparent as users will have to maintain all that "productive Go code" written 5/10 years ago. With Go the developers basically do the compiler's job manually. These problems are absolutely not going away, and people will write about how they ditched Go for these reasons.
- karmacoda 10y agoI think the striking point is that you're forced to use a throwaway to have an opinion.
- deleted 10y ago[deleted]
- geodel 10y agoYou may not have used reflection in Java but we have a very large application in production which is heavily dependent on reflection. It is in use for many years and serves business purpose just fine. Could there be a better way? maybe, but a working solution now is better for our business than promised solution in remote future.
- fauigerzigerk 10y agoAbsolutely. Many people will decide not to use Go for these reasons. But others will come to the conclusion that things like complex name lookup rules, or generally too many possible interpretations of individual syntactical expressions, cause hugely greater mental load than any of Go's shortcomings. That said, I have a lot of complaints about Go too. Especially error handling.
- twblalock 10y agoI agree with you about Go's flaws. However, if you have never used a cast or reflection in Java, you have either not done much Java, or you have used libraries and frameworks that do the casts and reflection for you.
- zaphar 10y agoAlmost every dependency injection framework in Java uses reflection extensively. And nearly every java project I've ever seen used one of them. Your claim that you didn't have to do reflection may be correct but I'm betting you were consuming code that used a lot of reflection.
- saturn_vk 10y agoReflection is pretty predominant in java, even if you don't use it yourself. Many frameworks (like spring) rely on reflection to do their magic.
- xiaoma 10y agoPerhaps not in the short term, but I hope the comment does lead to some benefit in the long term, despite semi-religious attachment of some to a particular technology. Even the most flippant of downvoters will perhaps remember these words months or years into the future.
- PopsiclePete 10y agoNah. Your post will be forgotten. You repeat the same tired old points - Go isn't Haskell/C++/Rust. That's correct, it's not. Those complaints have been said a thousand times already, will no doubt will be said a thousand times more. And all will be ignored, as they should.
- xiaoma 10y agoPeople generally need to see a message many times before it sinks in, especially if it's one they disagree with. Perhaps for you, there remain many more before any benefit is accomplished. That's okay. It's also possible that your needs align particularly well with those of those who control the project. That's okay, too!
- chc 10y agoI don't use or particularly like Go, but I don't see what use is supposed to come from this. These comments aren't reasoned criticism — they just come across as bashing and sneering, as though you have some kind of grudge against a programming language. If you actually mean to contribute to the discussion, I think you might benefit from taking a few steps back.
- xiaoma 10y agoNo sneering involved at all, I assure you! Just an interest in programmer productivity, which I see as genuinely helpful. Perhaps you see all languages as roughly equivalent and that is the cause of our differing opinions. In any case I've known quite a few engineers who have really drunk the koolaid, invested heavily in Go, become zealots for of the language and suffered for it before moving to options like Rust, Elixir, Kotlin or even Java or C++. I'm just trying to prevent some of that suffering going forward. Nothing more nefarious than that!
- openasocket 10y ago> The fact is a lot of people are perfectly fine with current Go capabilities and prefer writing useful software solution as compared to debating on PL theories and community agendas. Citation needed. Has anyone actually done any sort of survey of users or potential users of Go to see what the opinion is regarding generics? How many would prefer Go with generics to Go without (I use Go almost exclusively at work, and would really appreciate generics, so there's at least one)? How many would prefer Go to not have generics? How many are ambivalent? If there is, could you please cite it? I'm kind of frustrated by phrases like this being bandied about without evidence to back it.
- geodel 10y agoYou can certainly put some effort to create exhaustive surveys and ask people to take it. For me existence of lot of software which are build with Go like Docker/Kubernetes and http based tools I develop and use it internally at work is good enough to assume Generics are not that important.
- cflewis 10y agoYou'll never get that evidence; the type of people who are willing to fill out a survey are not the same type of people who don't care and are just Getting Things Done. FWIW internally the Go team has a survey of all Googlers each year about why they are or are not using Go, but I am guessing even then getting responses about why they aren't is hard to come by. I personally have other axes to grind that are much higher on my list (like os.File not being an interface) than generics.
- deleted 10y ago[deleted]
- 0xCMP 10y agoWell, it's been pretty productive for me. It's also been productive for Docker, InfluxDB, and Kubernetes (among other prominent, complex, open source projects).
- jjuel 10y agoYeah it has also been productive for me. And we cannot forget Hashicorp's use of it for a lot of stuff.
- geodel 10y agoExcellent read. Official package management looks more about 'when' than 'if' now. As someone in Java world who did not graduated to Maven/Gradle and stuck to ANT I hope it will be minimalistic and immediately useful to Go users.
- Traubenfuchs 10y agoAfter three years of rogue Java development, maven was an epiphany to me. At the beginning it has a very, very shallow learning curve.
- throwaw199ay 10y ago> Not enough Go code adds context like os.Remove does. Too much code does only Well, the error interface is { Error()string } and gophers were told to use errors as values, not errors as type because supposedly "exceptions are bad". By providing context you are just re-inventing your own mediocre exception system. Why use errors as value at first place if you need context? just put exceptions in Go, therefore people don't need to use a third party library to wrap errors in order to trace the execution context.
- 0xCMP 10y agoI think their views on this are changing from experience with the language. Part of the problem I think is that the way they wanted people to use the language isn't clearly explained on their posts about errors. Some how I read it over and over and I never quite get the gist of when they think I should create a custom error type or not.
- echlebek 10y agoBecause Go considers errors to be values, and exceptions are control flow.
- hota_mazi 10y agoBut there is value in providing a different control flow for errors, which is why exceptions have become prevalent in most programming languages in the past decades. The value is that your code's happy path is clean and not encumbered with error checks every ten lines, like we see in Go sources all the time. Separating the happy path and the error handling in different sections of the code contributes to clean code, especially if exceptions are checked and cannot be ignored by the developer.
- sethammons 10y agoIn my experience, separating the happy path from the error handling leads to unhandled errors. Just yesterday, one of our python projects (an API with about 600 endpoints) started barfing an error for non-parseable JSON because something at the top level caught it. I have no clue where it came from nor how to reproduce it. Had we been handling errors when and where they occur, I would have a vastly shorter debugging period in front of me.
- vendakka 10y agoThe go vet integration with go test looks interesting. I'm currently using github.com/surullabs/lint [1] to run vet and a few other lint tools as part of go test. It provides a nice increase in productivity for my dev cycle. Having vet + other lint tools integrated into my dev+test cycle has caught a number of bugs before they hit CI. [1] https://github.com/surullabs/lint https://github.com/surullabs/lint Disclaimer: I'm the author of the above library.
- zyxzkz 10y agoI really enjoyed reading this thoughtful post. He addresses a lot of the pain points I've encountered when writing Go. I know there probably won't be immediate fixes, but it gives me confidence in Go's future.
- bsaul 10y agoAlong with generics, they should probably also reconsider algebraic data types, such a enums with values. This is the best feature swift adds to the table hands on, and it seems to me as it's pretty orthogonal to the rest of the language ( although it carries a lot of other features with it, such as pattern matching). They wrote that they considered it to be redundant with interface programming, but really i don't understand why. Interface is about behavior, not data. An int doesn't "behave" like one, it is one. And something that's either an int or an array of string, doesn't "behave" like anything you'd want to describe with an interface... As an example, one should see how protobuf "one of" messages are dealt with in go : switch on arbitrary types followed by manual typecasting. That's just gross...
- xyzzy_plugh 10y agoI see where you are coming from, but that isn't the go way. Switch on arbitrary types, followed by typecasting? That's the go way. No surprises. Explicit instead if implicit behavior.
- dbaupp 10y agoMaybe you're visualising something different, but I don't see how ADT enums are implicit. Could you explain?
- coldtea 10y agoIf anything, ADT's would make it even more explicit. And pattern matching will make it impossible to miss cases.
- rwj 10y agoNot recommending either way, but if the language supported algebraic types with pattern matching, it would still be explicit.
- bsaul 10y agoIf you have a look at swift, it's also very explicit, and non-magical ( which is why i like it so much). The difference with go is that you can't make any type error when unwrapping the enum, because the compiler knows what are the different possibilities. I see no reason for go not to adopt it, in all honesty. it's nothing like generics, because it doesn't seem to add complexity to the rest of the language ( imho ).
- davekeck 10y agoRegarding error context: I'd advocate simple error-chaining using a linked list. If a function fails, it returns an error wrapping the underlying error as the cause, and so on up the stack. The top of the stack can inspect or print the error chain ("A failed because B failed because ..."), or pinpoint the error that was the root cause. I would love for Go to include something like this: type Error struct { Description string Cause error } func NewError(cause error, descriptionFmt string, args ...interface{}) error { return Error{ Description: fmt.Sprintf(descriptionFmt, args...), Cause: cause, } } func (me Error) Error() string { if me.Cause == nil { return me.Description } return fmt.Sprintf("%v: %v", me.Description, me.Cause.Error()) } func RootCause(err error) error { if err, ok := err.(Error); ok && err.Cause != nil { return RootCause(err.Cause) } return err }
- tptacek 10y agoMany Go error libraries exist mostly to provide this kind of functionality.
- bjacokes 10y agoCheck out https://github.com/pkg/errors https://github.com/pkg/errors
- bmurphy1976 10y agoGreat library.
- rogpeppe1 10y agoor gopkg.in/errgo.v1 which is a bit more opinionated about error causes.
- ekidd 10y agoI've always wanted to like Go, but every time I get ~1,500 lines in a project, I remember my pain points. I totally see why other people like the current version of Go, but as it stands, it's not an ideal match for my brain. Dependency management is a big pain point for me. I'm really glad to see several of my pain points on the list for this year, including another look at generics. Generics are genuinely tricky: They allow you to write many kinds of useful functions in a type-safe manner, but every known approach for implementing them adds complexity to the language. C#, Java and Rust all bit the bullet and accepted (some) of this complexity. Maybe Go will find a sweet spot, preserving its simplicity but adding a bit of expressiveness? Anyway, it pleases me to see that the Go team is thinking hard about this stuff. At the bare minimum, I'm going to be contributing code to other people's open source Go projects for the foreseeable future. :-)
- geodel 10y agoI think it is no surprise that one goal of Go is coding at large where large teams are involved. For single person projects that I think you are doing, many people want intellectually stimulating language where Go may fall short.
- throwaw199ay 10y ago> I think it is no surprise that one goal of Go is coding at large where large teams are involved. I don't buy that. There is no proof Go programming at large scales better than Java programming at large. Go didn't reach the scale of Java programs yet. And no, Kub or Docker, while fairly large, are nothing compared to 15 y.o. multi-million line Java codebases. Go certainly needs less bureaucracy due to the ease of deployment, but it doesn't mean Go projects scale better in large teams. > For single person projects that I think you are doing, many people want intellectually stimulating language where Go may fall short. I really hate this kind of arguments. Features like generics aren't intellectually stimulating, they are here because people want to write type safe code. Context.Value(interface{})interface{} isn't type safe code. Now tell me, what is more intellectually challenging? writing concurrent programs free of race conditions or generics?
- BuuQu9hu 10y agoIt is nice that Go is trying to learn from Pony and Midori. I wonder whether any Gophers have started to learn about object-capability theory and the reasoning behind why so many values are immutable in Pony, Midori, Monte, and other capability-safe languages. To expand on this a bit, in ocap theory there is a concept of "vat", an isolated memory space for objects which has its own concurrent actions isolated from all other vats. In a vat model, data races are nearly nonexistent; in order to race, one would have to choose a shared variable in a single vat, and then deliberately race on it. But this is not common because ocap theory enforces heavy object modularity, and so shared variables are uncommon. Additionally, a "deliberate race" is quite tricky. Vats prepare work with a FIFO queue. In the Monte language: # A flag. We must start it as `false` because Monte doesn't allow uninitialized names. var flag :Bool := false def setFlag(value :Bool) :Void: flag := value # Set the flag to `true` immediately. setFlag(true) # Set the flag to `false` on the next turn. def first := setFlag<-(false) # Set the flag to `true` on the next turn. def second := setFlag<-(true) # And finally, when those two actions are done, use the flag to make a choice. when (first, second) -> if (flag) { "the flag was true" } else { "the flag was false" } You might think that this is non-deterministic, but in fact the delayed actions will each execute in order, and so the flag will be set first to `false` and then to `true`.
- deleted 10y ago[deleted]
- sbov 10y ago> all the way up the call stack, discarding useful context that should be reported (like remove /tmp/nonexist: above). It's simple. With exceptions, we got used to "errors" that are, by default, debugable. But Go got rid of default debugable errors, and programmers are lazy.
- voidlogic 10y agoThe problem isn't the methodology. Its the library support. I (for my employee) wrote a library a few years ago (~go 1.1) with "errs.New" and "errs.Append(err, ..work like fmt..)" that generates error that look like: main.go:13 main.main(): highest level error; Details: foo.go:8 foo.ExportedMethod(): mid level error; Details: foo.go:42 foo.innerMethod(): low level error! It provides handy helpers like GetRootErr and PanicToError too. I hope we can opensource it in the next month or two.
- notheguyouthink 10y agoYup, my solution as well. As well as a couple other common libraries (eg: https://github.com/pkg/errors https://github.com/pkg/errors) The only downside to this is you can no longer treat errors as values. Eg, you can't do: err := Func() if err == ErrBadThing { // do stuff } So you have to implement some type of `Cause()` method. In my lib, i have `errors.Cause()` which returns the root error, as well as a shorthand func `errors.Equals(err, ErrBadThing`)`
- lobster_johnson 10y agoThere's already a good library like that: https://github.com/pkg/errors https://github.com/pkg/errors It is API-compatible with the errors package, and you get errors.Wrap(err, message), errors.Wrapf(err, message, args) and errors.Cause(err).
- voidlogic 10y agoWe wrote ours around the time Go 1.1 was released so its way older and featureful than that package.
- kibwen 10y ago> Test results should be cached too: if none of the inputs to a test have changed, then usually there is no need to rerun the test. This will make it very cheap to run “all tests” when little or nothing has changed. I'll be curious to see how this pans out, because it sounds like a very deep rabbit hole. Is there any precedent for this in other language toolchains? I've seen some mondo test suites in Java that could desperately use it.
- secure 10y agohttps://bazel.build/ https://bazel.build/ supports this. Bazel is Google’s build system, open-sourced.
- kibwen 10y agoFrom reading https://bazel.build/versions/master/docs/test-encyclopedia.html https://bazel.build/versions/master/docs/test-encyclopedia.h... , it looks like Bazel's rules are quite strict (not to mention Unix-specific), and requires writing a separate rules file to configure test behavior (e.g. an "external" tag to denote tests that cannot be cached). I anticipate that it would be difficult to retrofit such things onto Go's existing ecosystem in-place (or any language's, for that matter), especially without sacrificing Go's minimalist philosophy (i.e. "this function is a test if its identifier begins with `Test`, end of story"), especially considering Go's documented aversion to config files WRT package management. As an optional external tool it may work quite nicely, however.
- zaphar 10y agoBazel's rules are extremely strict. For what it's worth when I was at Google all the Go code was built with Bazel. Most of the google engineers don't experience this pain internally I imagine.
- paulddraper 10y agoI'm not sure that operates at the same granularity though.
- 10y ago
- deleted 10y ago[deleted]
- nine_k 10y agoPosts like this really return me the confidence in the future of Go the language. I very much wish Go to succeed, it's built on a few nice ideas, but where it currently is it has a number of usability impairments that stop me from wanting to work with it. But I see that these impairments are seen as problems by key developers, and work is underway to eventually fix these problems. (And this is besides the "routine", incremental but very important improvements, such as GC or stdlib.)
- xienze 10y ago> But I see that these impairments are seen as problems by key developers, and work is underway to eventually fix these problems. What will inevitably happen is that Pike et al will argue that such things are merely problems because "you're doing it wrong" or "there's no way to do this without any tradeoffs of any kind" (generics), and ultimately very little will change.
- twic 10y agoThe other alternative is that they allow them, and Go slowly loses its magic and becomes another Algol, C++, or Java.
- meddlepal 10y agoGod forbid it become as useful and ubiquitous as C++ or Java.
- enneff 10y agoRuss Cox, the guy who wrote this post, is the technical lead for the Go project. He authored more of Go's code base than anyone else (by a huge margin). His opinion about these issues holds more weight than pretty much anyone. I wouldn't downplay it.
- maxekman 10y agoI would really like to see best practices in the documentation on how to include the right amount of error context, as mentioned in the article. Also what to put and not put in context objects is really important to document as it could easily snowball into a catch-all construct and be totally misused after a while.
- munificent 10y ago> Part of the intended contract for error reporting in Go > is that functions include relevant available context, > including the operation being attempted (such as the > function name and its arguments). I know the Go folks don't like exceptions, but this is an example of them learning the hard way that about one useful thing they lost by deciding to not do exceptions. Exceptions give you stack traces automatically. All of that context (and more) is there without library authors having to manually weave it in at every level of calls. > Today, there are newer attempts to learn from as well, > including Dart, Midori, Rust, and Swift. For what it's worth, we are making significant changes to Dart's generics story and type system in general [1]. We added generic methods, which probably should have been there the entire time. Generics are still always covariant, which has some plusses but also some real minuses. It's not clear if the current behavior is sufficient. Our ahead-of-time compilation story for generics is still not fully proven either. We don't do any specialization, so we may be sacrificing more performance than we'd like, though we don't have a lot of benchmark numbers yet to measure it. This also interacts with a lot of other language features in deep ways, like nullability, whether primitive types are objects, how lists are implemented, etc. [1]: https://github.com/dart-lang/dev_compiler/blob/master/STRONG_MODE.md https://github.com/dart-lang/dev_compiler/blob/master/STRONG...
- whateveracct 10y ago> Generics are still always covariant, which has some plusses but also some real minuses. How is this even possible? Does the compiler just fail if you try to put a type parameter in contravariant position? Or does it allow it and then blow up at run time?
- munificent 10y agoNo, you can use a type parameter in a covariant or contravariant position. What it means is that it treats all generic classes as covariant with respect to their type parameters, even when the type parameter is used in a contravariant position. So, for example, List<T> is covariant—you can assign a List<int> to List<Object>—even though add() takes a T. This isn't statically safe, so the language inserts runtime checks to ensure you don't break soundness.
- brightball 10y ago> In the long-term, if we could statically eliminate the possibility of races, that would eliminate the need for most of the memory model. That may well be an impossible dream, but again I’d like to understand the solution space better. Unless I'm mistaken, this is an impossible dream as long as shared memory exists. It's the core tradeoff that distinguishes the Erlang runtime from the Go runtime (there are others, but they all stem from this). Your goals are either memory isolation for better distribution/concurrency/clustering/fault tolerance/garbage collection or shared memory for ability to work with large datasets more efficiently. It's one of those details that changing it would essentially create a new language. You'd have code, packages and libraries that either worked that way or they wouldn't. IMO, this is an area where Go gets into dangerous territory of trying to be all things to people. Be great at what you're good at which is the "good enough, fast enough, portable enough, concurrent enough, stable enough" solution for backend services in most standard web architecture. If people need distributed, fault tolerant, isolated, race proof, immutable run times that aren't quite as top end fast and aren't ideal for giant in RAM data structures...there's already a well established solution there by the name of Erlang (and Elixir). They made the tradeoffs already so you don't have to reinvent them.
- zzzcpan 10y ago> Your goals are either memory isolation for better distribution/concurrency/clustering/fault tolerance/garbage collection or shared memory for ability to work with large datasets more efficiently. The isolation is not physical, but logical. Implementations are free to use zero-copying and make everything just as efficient. Theoretically compiler could even optimize message passing overhead away for systems with shared memory in some cases. The opposite is also true, shared memory is also logical and there is a lot of room for a lot of clever things, like eliminating races.
- brightball 10y agoHow can you eliminate races with shared memory in a concurrent environment?
- 10y ago
- jaekwon 10y agoRe dependencies: Glide takes our team 90% of the way, but is a bit glitchy (need to wipe ~/.glide sometimes) & lacks a command for `npm link` type functionality.
- deleted 10y ago[deleted]
- jimbokun 10y ago"I don’t believe the Go team has ever said “Go does not need generics.” " I think that's true, but I do think its been said by a number of Go users and advocates, which is where the perception comes from.
- kasey_junk 10y agoMeanwhile I've said "even if they don't introduce user defined generics it would be nice if they fixed the language defined ones" The builtin generics are a mess. At this point I don't trust the go team to implement any more complicated generic system.
- tomjakubowski 10y ago> The builtin generics are a mess. Could you elaborate on this? I must not have used arrays, slices, maps, or channels enough to find that there's some common issue with all of them, other than that the user can't write her own functions generic over them.
- kasey_junk 10y agoThe most obvious problem is that variance doesn't work. You cannot pass a []string to something that expects a []interface{} for instance, even though you can put every item in the first in an instance of the second.
- stouset 10y ago> Not enough Go code adds context like os.Remove does. Too much code does only if err != nil { return err } Is anyone else surprised that forcing programmers to do the tedious, repetitive, and boring work of being a manual exception handler overwhelmingly results in people doing the least amount of effort to make it work? I feel like so many of the headaches of go could have been avoided had the developers spent any time whatsoever thinking about the programmers using it.
- tombert 10y agoI think that the Go team worked very hard to make something that programmers actually like using. Yes, it is annoying to do a lot of `check if err is nil`, but at the same time, exception handling is something that can be esoteric, whilst it's trivial to see what your example does. I also feel like there has been a lot of emphasis put on keeping the APIs consistent, which is something that a lot of developers will tell you makes PHP a nightmare sometimes.
- stouset 10y ago> Yes, it is annoying to do a lot of `check if err is nil`, but at the same time, exception handling is something that can be esoteric People keep saying this, but the alternative doesn't have to be exceptions. Rust strikes a great balance here. There's no nil, you must handle the Err case of a Result enum, or the None case of an Option enum (this is much nicer than go; in go after `val, err := failingThing()`, it's entirely possible to accidentally use `val` as a meaningful value, which is strictly impossible in Rust), and you can use functions like `map` and `and_then` on these types which has the benefits of explicit error handling without the absurd loss of readability caused by dozens of identical error handling clauses. > I also feel like there has been a lot of emphasis put on keeping the APIs consistent This isn't something special about go. This is a minimum requirement for a language nowadays. Rust, Ruby, Python, Swift, and others all do this.
- jnlknl 10y agoGreat !
- vorg 10y ago> it would be nice to retroactively define that string is a named type (or type alias) for immutable []byte Perhaps an array is better than a slice, so `immutable [...]byte` Also, the for-range loop would have to behave differently so I guess it's a version 2 change. And if semantics are changing anyway, I'd prefer a `mutable` keyword to an `immutable` one.
- tomjakubowski 10y ago> Perhaps an array is better than a slice, so `immutable [...]byte` Slice is the right choice, I think. Were they to choose array as the alias, the language would need to "bubble up" the "array length" type parameter to the string type, which would make strings of different byte lengths incompatible types. But hey, Go is already pretty clearly inspired by Pascal, so maybe we'll see that after all :-)
- vbernat 10y agoHappy to see that being able to not use GOPATH is at last considered seriously! During years, Go people wanted to force people to work their way. We can still this state of mind in the associated bug report: https://github.com/golang/go/issues/17271 https://github.com/golang/go/issues/17271.