1. 33

    return err is almost always the wrong thing to do. Instead of:

    if err := foo(); err != nil {
    	return err
    }
    

    Write:

    if err := foo(); err != nil {
    	return fmt.Errorf("fooing: %w", err)
    }
    

    Yes, this is even more verbose, but doing this is what makes error messages actually useful. Deciding what to put in the error message requires meaningful thought and cannot be adequately automated. Furthermore, stack traces are not adequate context for user-facing, non-programming errors. They are verbose, leak implementation details, are disrupted by any form of indirection or concurrency, etc.

    Even with proper context, lots of error paths like this is potentially a code smell. It means you probably have broader error strategy problems. I’d try to give some advice on how to improve the code the author provided, but it is too abstract in order to provide any useful insights.

    1. 17

      I disagree on a higher level. What we really want is a stacktrace so we know where the error originated, not manually dispensed breadcrumbs…

      1. 31

        maybe you do, but I prefer an error chain that was designed. A Go program rarely has just one stack, because every goroutine is its own stack. Having the trace of just that one stack isn’t really a statement of the program as a whole since there’s many stacks, not one. Additionally, stack traces omit the parameters to the functions at each frame, which means that understanding the error means starting with your stack trace, and then bouncing all over your code and reading the code and running it in your head in order to understand your stack trace. This is even more annoying if you’re looking at an error several days later in a heterogeneous environment where you may need the additional complication of having to figure out which version of the code was running when that trace originated. Or you could just have an error like “failed to create a room: unable to reserve room in database ‘database-name’: request timed out” or something similar. Additionally, hand-crafted error chains have the effect that they are often much easier to understand for people who operate but don’t author something; they may have never seen the code before, so understanding what a stack trace means exactly may be difficult for them, especially if they’re not familiar with the language.

        1. 6

          I dunno. Erlang and related languages give you back a stack trace (with parameters) in concurrently running processes no problem

          1. 4

            It’s been ages since I wrote Erlang, but I remember that back then I rarely wanted a stack trace. My stack were typically 1-2 levels deep: each process had a single function that dispatched messages and did a small amount of work in each one. The thing that I wanted was the state of the process that had sent the unexpected message. I ended up with some debugging modes that attached the PID of the sending process and some other information so that I could reconstruct the state at the point where the problem occurred. This is almost the same situation as Go, where you don’t want the stack trace of the goroutine, you want to capture a stack trace of the program at the point where a goroutine was created and inspect that at the point where the goroutine failed.

            This isn’t specific to concurrent programs, though it is more common there, it’s similar for anything written in a dataflow / pipeline style. For example, when I’m debugging something in clang’s IR generation I often wish I could go back and see what had caused that particular AST node to be constructed during parsing or semantic analysis. I can’t because all of the state associated with that stack is long gone.

        2. 9

          FWIW, I wrote a helper that adds tracing information.

          I sort of have two minds about this. On the one hand, yeah, computers are good at tracking stack traces, why are we adding them manually and sporadically? OTOH, it’s nice that you can decide if you want the traces or not and it gives you the ability to do higher level things like using errors as response codes and whatnot.

          The thing that I have read about in Zig that I wish Go had is an error trace which is different from the stack trace, which shows how the error was created, not the how the error propagates back to the execution error boundary which is not very interesting in most scenarios.

          1. 6

            The nice thing about those error traces is that they end where the stack trace begins, so it’s seamless to the point that you don’t even need to know that they are a thing, you just get exactly the information that otherwise you would be manually looking for.

          2. 8

            In a multiprocess system that’s exchanging messages: which stack?

            1. 2

              see: erlang

            2. 5

              You don’t want stack traces; you want to know what went wrong.

              A stack trace can suggest what may have gone wrong, but an error message that declares exactly what went wrong is far more valuable, no?

              1. 8

                An error message is easy, we already have that: “i/o timeout”. A stack trace tells me the exact code path that lead to that error. Building up a string of breadcrumbs that led to that timeout is just a poorly implemented, ad-hoc stack trace.

                1. 5

                  Indeed and I wouldn’t argue with that. I love a good stack trace, but I find they’re often relied upon in lieu of useful error messages and I think that’s a problem.

                  1. 2

                    Building up a string of breadcrumbs that led to that timeout is just a poorly implemented, ad-hoc stack trace.

                    That’s a bit of an over-generalization. A stack trace is inherently a story about the construction of the program that originated the error, while an error chain is a story about the events that led to an error. A stack trace can’t tell you what went wrong if you don’t have access to the program’s source code in the way that a hand crafted error chain can. A stack trace is more about where an error occurred, while an error chain is more about why an error occurred. I think they’re much more distinct than you are suggesting.

                    and of course, if people are just bubbling up errors without wrapping them, yeah you’re going to have a bad time, but I think attacking that case is like suggesting that every language that has exceptions encourages Pokémon exception handling. That’s a bad exception-handling pattern, but I don’t think that the possibility of this pattern is a fair indictment of exceptions generally. Meanwhile you’re using examples of bad error handling practices that are not usually employed by Go programmers with more than a few weeks experience to indict the entire paradigm.

                2. 4

                  Stack traces are expensive to compute and inappropriate to display to most users. Also, errors aren’t exceptions.

                  1. 1

                    That’s why Swift throws errors instead. Exceptions immediately abort the program.

                  2. 3

                    What really is the “origin” of an error? Isn’t that somewhat arbitrary? If the error comes from a system call, isn’t the origin deeper in the kernel somewhere? What if you call in to a remote, 3rd party service. Do you want the client to get the stack trace with references to the service’s private code? If you’re using an interface, presumably the purpose is to abstract over the specific implementation. Maybe the stack trace should be truncated at the boundary like a kernel call or API call?

                    Stack traces are inherently an encapsulation violation. They can be useful for debugging your internals, but they are an anti-feature for your users debugging their own system. If your user sees a stack trace, that means your program is bugged, not theirs.

                    1. 5

                      I get a line of logging output: error: i/o timeout. What do I do with that? With Ruby, I get a stack trace which tells me exactly where the timeout came from, giving me a huge lead on debugging the issue.

                      1. 5

                        I get a line of logging output: error: i/o timeout. What do I do with that?

                        Well, that’s a problem you fix by annotating your errors properly. You don’t need stack traces.

                        1. 3

                          When your Ruby service returns an HTTP 500, do you send me the stack trace in the response body? What do I do with that?

                          Go will produce stack traces on panics as well, but that’s precisely the point here: these are two different things. Panics capture stack traces as a “better than nothing” breadcrumb trail for when the programmer has failed to account for a possibility. They are for producers of code, not consumers of it.

                        2. 2

                          There’s definitely competing needs between different audiences and environments here.

                          A non-technical end user doesn’t want to see anything past “something went wrong on our end, but we’re aware of it”. Well, they don’t even want to see that.

                          A developer wants to see the entire stack trace, or at least have it available. They probably only care about frames in their own code at first, and maybe will want to delve into library code if the error truly doesn’t seem to come from their code or is hard to understand in the first place.

                          A technical end user might want to see something in-between: they don’t want to see “something was wrong”. They might not even want to see solely the outer error of “something went wrong while persisting data” if the root cause was “I couldn’t reach this host”, because the latter is something they could actually debug within their environment.

                      2. 9

                        This is one reason I haven’t gone back to Go since university - There’s no right way to do anything. I think I’ve seen a thousand different right ways to return errors.

                        1. 9

                          Lots of pundits say lots of stuff. One good way to learn good patterns (I won’t call them “right”), is to look at real code by experienced Go developers. For instance, if you look at https://github.com/tailscale/tailscale you’ll find pervasive use of fmt.Errorf. One thing you might not see – at least not without careful study – is how to handle code with lots of error paths. That is by it’s very nature harder to see because you have to read and understand what the code is trying to do and what has to happen when something goes wrong in that specific situation.

                          1. 6

                            there is a right way to do most things; but it takes some context and understanding for why.

                            the mistake is thinking go is approachable for beginners; it’s not.

                            go is an ergonomic joy for people that spend a lot of time investing in it, or bring a ton of context from other languages.

                            for beginners with little context, it is definitely a mess.

                            1. 9

                              I thought Go was for beginners, because Rob Pike doesn’t trust programmers to be good.

                              1. 17

                                I’d assume that Rob Pike, an industry veteran, probably has excellent insight into precisely how good the average programmer at Google is, and what kind of language will enable them to be productive at the stuff Google makes. If this makes programming languages connaisseurs sad, that’s not his problem.

                                1. 9

                                  Here’s the actual quote:

                                  The key point here is our programmers are Googlers, they’re not researchers. They’re typically, fairly young, fresh out of school, probably learned Java, maybe learned C or C++, probably learned Python. They’re not capable of understanding a brilliant language but we want to use them to build good software. So, the language that we give them has to be easy for them to understand and easy to adopt.

                                  So I have to wonder who is capable of understanding a “brilliant language” …

                                  1. 7

                                    So I have to wonder who is capable of understanding a “brilliant language” …

                                    Many people. They don’t work at Google at an entry-level capacity, that’s all.

                                    There’s a subtle fallacy at work here - Google makes a lot of money, so Google can afford to employ smart people (like Rob Pike!) It does not follow that everyone who works at Google is, on average, smarter than anyone else.

                                    (edited to include quote)

                                    1. 8

                                      Let’s say concretely we are talking about OCaml. Surely entry-level Googlers are capable of understanding OCaml. Jane Street teaches it to all new hires (devs or not) in a two-week bootcamp. I’ve heard stories of people quickly becoming productive in Elm too.

                                      The real meaning of that quote is not ‘entry-level Googlers are not capable of it’, it’s ‘We don’t trust them with it’ and ‘We’re not willing to invest in training them in it’. They want people to start banging out code almost instantly, not take some time to ramp up.

                                      1. 7

                                        Let’s say concretely we are talking about OCaml. Surely entry-level Googlers are capable of understanding OCaml. Jane Street teaches it to all new hires (devs or not) in a two-week bootcamp.

                                        I suspect that Jane Street’s hiring selects for people who are capable of understanding OCaml; I guarantee that the inverse happens and applicants interested in OCaml self select for careers at Jane Street, just like Erlang-ers used to flock towards Ericsson.

                                        Google has two orders of magnitude more employees than Jane Street. It needs a much bigger funnel and is likely far less selective in hiring. Go is “the law of large numbers” manifest as a programming language. That’s not necessarily bad, just something that is important for a massive software company and far less important for small boutiques.

                                        1. 2

                                          applicants interested in OCaml self select for careers at Jane Street,

                                          As I said, they teach it to all hires, including non-devs.

                                          Google has two orders of magnitude more employees than Jane Street. It needs a much bigger funnel and is likely far less selective in hiring

                                          Surely though, they are not so loose that they hire Tom Dick and Harry off the street. Why don’t we actually look at an actual listing and check? E.g. https://careers.google.com/jobs/results/115367821606560454-software-developer-intern-bachelors-summer-2022/

                                          Job title: Software Developer Intern, Bachelors, Summer 2022 (not exactly senior level)

                                          Minimum qualifications:

                                          Pursuing a Bachelor’s degree program or post secondary or training experience with a focus on subjects in software development or other technical related field. Experience in Software Development and coding in a general purpose programming language. Experience coding in two of C, C++, Java, JavaScript, Python or similar.

                                          I’m sorry but there’s no way I’m believing that these candidates would be capable of learning Go but not OCaml (e.g.). It’s not about their capability, it’s about what Google wants to invest in them. Another reply even openly admits this! https://lobste.rs/s/yjvmlh/go_ing_insane_part_one_endless_error#c_s3peh9

                                          1. 2

                                            And I remember when Google would require at minimum a Masters Degree before hiring.

                                            1. 1

                                              I had a master’s degree in engineering (though not in CS) and I couldn’t code my way out of a paper bag when I graduated. Thankfully no-one cared in Dot Com Bubble 1.0!

                                          2. 3

                                            They want people to start banging out code almost instantly, not take some time to ramp up.

                                            Yes, and? The commodification of software developers is a well-known trend (and goal) of most companies. When your assets are basically servers, intangible assets like software and patents, and the people required to keep the stuff running, you naturally try to lower the costs of hiring and paying salary, just like you try to have faster servers and more efficient code.

                                            People are mad at Rob Pike, but he just made a language for Google. It’s not his fault the rest of the industry thought “OMG this is the bee’s knees, let’s GO!” and adopted it widely.

                                            1.  

                                              Yes, I agree that the commodification of software developers is prevalent today. And we can all see the result, the profession is in dire straits–hard to hire because of bonkers interview practices, hard to keep people because management refuses to compensate them properly, and cranking out bugs like no tomorrow.

                                    2. 8

                                      No, Rob observed, correctly, that in an organization of 10,000 programmers, the skill level trends towards the mean. And so if you’re designing a language for this environment, you have to keep that in mind.

                                      1. 4

                                        it’s not just that. It’s a language that has to reconcile the reality that skill level trends toward the mean, with the fact that the way that google interviews incurs a selection/survival bias towards very junior programmers who think they are the shit, and thus are very dangerous with the wrong type of power.

                                        1. 4

                                          As I get older and become, presumably, a better programmer, it really does occur to me just how bad I was for how long. I think because I learned how to program as a second grader, I didn’t get how much of a factor “it’s neat he can do it all” was in my self-assessment. I was pretty bad, but since I was being compared to the other kids who did zero programming, it didn’t matter that objectively I was quite awful, and I thought I was hot shit.

                                        2. 3

                                          Right! But the cargo-cult mentality of the industry meant that a language designed to facilitate the commodification of software development for a huge, singular organization escaped and was inflicted on the rest of us.

                                          1. 3

                                            But let’s be real for a moment:

                                            a language designed to facilitate the commodification of software development

                                            This is what matters.

                                            It doesn’t matter if you work for a company of 12 or 120,000: if you are paid to program – that is, you are not a founder – the people who sign your paychecks are absolutely doing everything within their power to make you and your coworkers just cogs in the machine.

                                            So I don’t think this is a case of “the little fish copying what big bad Google does” as much as it is an essential quality of being a software developer.

                                            1. 1

                                              Thank you, yes. But also, the cargo cult mentality is real.

                                        3. 2

                                          Go is for compilers, because Google builds a billion lines a day.

                                    3. 2

                                      return errors.Wrapf(err, "fooing %s", bar) is a bit nicer.

                                      1. 12

                                        That uses the non-standard errors package and has been obsolete since 1.13: https://stackoverflow.com/questions/61933650/whats-the-difference-between-errors-wrapf-errors-errorf-and-fmt-errorf

                                        1. 1

                                          Thanks, that’s good to know.

                                        2. 7

                                          return fmt.Errorf("fooing %s %w", bar, err) is idiomatic.

                                          1. 7

                                            Very small tweak: normally you’d include a colon between the current message and the %w, to separate error messages in the chain, like so:

                                            return fmt.Errorf("fooing %s: %w", bar, err)
                                            
                                        3. 1

                                          It makes error messages useful but if it returns a modified err then I can’t catch it further up with if err == someErr, correct?

                                          1. 2

                                            You can use errors.Is to check wrapped errors - https://pkg.go.dev/errors#Is

                                            Is unwraps its first argument sequentially looking for an error that matches the second. It reports whether it finds a match. It should be used in preference to simple equality checks

                                            1. 2

                                              Thanks! I actually didn’t know about that.

                                            2. 2

                                              Yes, but you can use errors.Is and errors.As to solve that problem. These use errors.Unwrap under the hood. This error chaining mechanism was introduced in Go 1.13 after being incubated in the “errors” package for a long while before that. See https://go.dev/blog/go1.13-errors for details.

                                          1. 5

                                            I posted a similar thread with fantastic results in the past https://lobste.rs/s/eprvjp/what_are_your_favorite_non_standard_cli

                                            1. 1

                                              The sentiment behind the idea is a good one, though the terminology is too imprecise to be applicable, e.g. “Relatively frugal … images and video”, “Heavily restricted to no use of JavaScript”. Frugality and heaviness are hard concepts to pin down.

                                              Also as others have said, HTML 4 and CSS 2 are arbitrary technology decisions. Those technologies are neither good nor bad; merely “old”. If oldness is the goal, these technologies will indeed achieve it. But limiting web pages to these technologies certainly does not achieve “better”, “more useful”, or “more accessible” web pages.

                                              While well-intention, the only thing I see achieved here is a framework for oldness, and oldness for oldness’ sake is not good.

                                              1. 7

                                                I don’t want to 💩on the author’s writeup here, because it is a decent one. I’m using it to launch another public objection to Go Generics.

                                                A lot of proposals for and write ups about Go Generics seem to miss that there’s a very large group of Go users who object to Generics, and for good reason. It’s not because this group questions the efficacy of generics in solving very specific problems very well – objectors are generally well attuned to Generics’ utility. What’s objected to is the necessity of Generics. The question that we pose is do we need generics at all? Are the problems that Generics solve so important that Generics should pervade the language?

                                                From the author’s conclusion

                                                I was able to solve a problem in a way that was not previously possible.

                                                Being able to solve problems in new ways isn’t always valuable; it can even be counter-productive.

                                                1. 24

                                                  Nothing is necessary except an assembler. Well, you don’t even need the assembler, you can just flip the bits yourself.

                                                  Go has an expressiveness gap. It has some kind of big classes of algorithms that can’t be made into libraries in a useful way. Most people advocate just rewriting basically the same code over and over forever, which is kind of crazy and error-prone. Other people advocate code-generation tools with go generate, which is totally crazy and error-prone, even with the decent AST tools in the stdlib. Generics close the gap pretty well, they’re not insanely complex, and people have had decades to get used to them. If you don’t want to use them yourself, don’t use them, but accept that there are people for whom, say, the ability to just go get a red-black tree implementation that they can use with a datatype of their own choosing, without loss of type-safety or performance, will greatly improve the usefulness of the language.

                                                  Plus, from a purely aesthetic standpoint, it always seemed criminal to me to have a language that has first-class functions, and lexical closure, but in which you can’t even write map because its type is inexpressible.

                                                  1. 9

                                                    Go has an expressiveness gap.

                                                    That’s true. You’ve identified some of the costs. Can you identify some of the benefits, too?

                                                    1. 12

                                                      Easy: not having a feature protects you from bright idiots that would misuse it.

                                                      Honestly though, that’s the only argument I can make against generic. And it’s not even valid, because you could say this about almost any feature. It’s a fully general counter argument: give people hammers, some will whack each other’s heads instead of hitting nails.

                                                      Assuming basic competency of the users and assuming they were designed from the ground up, generics have practically no downsides. They provide huge benefits at almost no marginal cost. There is a sizeable up-front cost for the language designer and the compiler writer, but they were willing to pay that kind of price when they set out to build a general purpose languages, didn’t they?

                                                      1. 2

                                                        They provide huge benefits at almost no marginal cost.

                                                        If this huge benefit is only one in a minor part of the project, or even, in a minority of projects, then it has to be balanced and thought through.

                                                        Right now, I don’t know many people that work Go daily, telling me that not having generics makes their day a pain.

                                                        Most of them told me that it’s sometimes painful, but that’s actually pretty rare.

                                                        There is a sizeable up-front cost for the language designer and the compiler writer, but they were willing to pay that kind of price when they set out to build a general purpose languages, didn’t they?

                                                        Is the burden really on them? To me the it is on the program writer.

                                                        1. 8

                                                          There’s likely a survivorship bias going on there.

                                                          I used Go as a programming language for my side projects for years. The thing that finally got me to give it up was the lack of generics. In writing PISC, the way I had approached it in Go ended up causing a lot of boilerplate for binding functions.

                                                          Go is something I’d happily write for pay, but I prefer expressiveness for my side projects now, as the amount of effort that goes into a side project is a big determining factor in how much I can do in one

                                                          1. 3

                                                            There is a sizeable up-front cost for the language designer and the compiler writer, but they were willing to pay that kind of price when they set out to build a general purpose languages, didn’t they?

                                                            Is the burden really on them? To me the it is on the program writer.

                                                            Assuming we are a collaborative species (we mostly are, with lots of exceptions), then one of our goals should be minimizing total cost. Either because we want to spend our time doing something else, or because we want to program even more stuff.

                                                            For a moderately popular programming language, the users will far outnumber and outproduce the maintainers of the language themselves. At the same time, the languages maintainers’ work have a disproportionate impact on everyone else. To such a ludicrous extent in fact that it might be worth spending months on a feature that would save users a few seconds per day. Like compilation speed.

                                                            Other stuff like generic will affect fewer users, but (i) it will affect them in a far bigger way than shaving off a few seconds of compilation time would have, and (ii) those particular users tend to be library writers, and as such they will have a significant impact on the rest of the community.

                                                            So yes, the burden really is on the language creators and compiler writers.


                                                            Note that the same reasoning applies when you write more mundane software, like a train reservation system. While there is rarely any monetary incentive to make that kind of thing not only rock solid, but fast and easy to work with, there is a moral imperative not to inflict misery upon your users.

                                                        2. 5

                                                          I haven’t used Go in anger but here are some benefits from not including generics.

                                                          • Generics are sometimes overused, e.g. many C++ libraries.
                                                          • The type system is simpler.
                                                          • The compiler is easier to implement and high quality error messages are easier to produce.
                                                          • The absence of generics encourages developers to use pre-existing data structures.
                                                        3. 2

                                                          If red-black trees and map were just built in to Go, wouldn’t that solve 90% of the problem, for all practical purposes?

                                                          What I really miss in Go is not generics, but something that solves the same problems as multiple dispatch and operator overloading.

                                                          1. 3

                                                            Sort of, but no. There’s too many data structures, and too many useful higher-order functions, to make them all part of the language. I was just throwing out examples, but literally just a red-black tree and map wouldn’t solve 90% of the problem. Maybe 2%. Everyone has their own needs, and Go is supposed to be a small language.

                                                            1. 1

                                                              Data structures and higher-order functions can already be implemented in Go, though, just not by using generics as part of the language.

                                                        4. 15

                                                          Technically Go does have generics, they just aren’t exposed to the end developer, except in the form of the builtin map and array types, and are only allowed for internal developers. So in a sense, Go does need generics and they already pervade the language.

                                                          I don’t personally have a horse in this race and don’t work with Go, but from a language-design perspective it does seem strange to limit user-developed code in such a way. I’d be curious what your thoughts on why this discrepancy is OK and why it shouldn’t be fixed by adding generics to the language.

                                                          1. 14

                                                            I don’t personally have a horse in this race and don’t work with Go, but from a language-design perspective it does seem strange to limit user-developed code in such a way.

                                                            Language design is all about limiting user defined code to reasonable subsets of what can be expressed. For a trivial example, why can’t I name my variable ‘int’? (In Myrddin, as a counterexample, var int : int is perfectly legal and well defined).

                                                            For a less trivial example, relatively few languages guarantee tail recursion – this also limits user developed code, and requires programmers to use loops instead of tail recursion or continuation passing style.

                                                            Adding generics adds a lot of corner cases to the type system, and increases the complexity of the language a good deal. I know. I implemented generics, type inference, and so on in Myrddin, and I’m sympathetic to leaving generics out (or, as you say, extremely limited) to put a cap on the complexity.

                                                            1. 3

                                                              I see only two legitimate reasons to limit a user’s capabilities:

                                                              1. Removing the limitation would make the implementer’s life harder.
                                                              2. Removing the limitation would allow the user to shoot themselves in the foot.

                                                              Limiting tail recursion falls squarely in (1). There is no way that guaranteeing tail recursion would cause users to shoot themselves in the foot. Generics is another matter, but I strongly suspect it is more about (1) than it is about (2).

                                                              Adding generics adds a lot of corner cases to the type system, and increases the complexity of the language a good deal.

                                                              This particular type system, perhaps. This particular language, maybe. I don’t know Go, I’ll take your word for it. Thing is, if Go’s designers had the… common sense not to omit generics from their upcoming language, they would have made a slightly different language, with far fewer corner cases they will inevitably suffer now that they’re adding it after the fact.

                                                              Besides, the complexity of a language is never a primary concern. The only complexity that matters is that of the programs written in that language. Now the complexity of a language does negatively impact the complexity of the programs that result from it, if only because language space is bigger. On the other hand, this complexity has the potential to pay for itself, and end up being a net win.

                                                              Take C++ for instance. Every single feature we add to it increases the complexity of the language, to almost unbearable levels. I hate this language. Yet, some of its features definitely pay for themselves. Range for for instance, while it slightly complicates the language, makes programs that use it significantly cleaner (although only locally). That particular feature definitely pays for itself. (we could discuss other examples, but this one has the advantage of being uncontroversial.)

                                                              As far as I can tell, generics tend to massively pay for themselves. Not only do they add flexibility in many cases, they often add type safety (not in C++, they don’t). See for instance this function:

                                                              foo : (a -> b) -> [a] -> [b]
                                                              

                                                              This function has two arguments (where a and be are unknown types): a function from a to b, and a list of a. It returns a list of b. From this alone, there is a lot we can tell about this function. The core idea here is that the body of the function cannot rely on the contents of generic types. This severely constraints what it can do, including the bugs it can have.

                                                              So, when we write let ys = foo f xs, here’s what we can expect before we even look at the source code:

                                                              • Assuming f is of type a->b, then xs is a list of a, and the result ys is a list of b.
                                                              • The elements of ys, if any, can only come from elements of xs.
                                                                • And they must have gone through f.
                                                                • Exactly once.
                                                              • The function f itself does not affect the number or order of elements in the result ys
                                                              • The elements of xs do not individually affect the number or order of elements in the result ys
                                                              • The only thing that affects the number or order of elements in the result ys is the size of xs (and the code of foo, of course).

                                                              This is quite unlike C++, or other template/monomorphisation approaches. Done right, generics have the opportunity to remove corner cases in practice. Any language designer deciding they’re not worth their while better have a damn good explanation. And in my opinion, the explanations offered for Go weren’t satisfactory.

                                                              1. 4

                                                                Complexity of a language is the primary concern!

                                                                Languages are tools to express ideas, but expressiveness is a secondary concern, in the same way that the computer is the secondary audience. Humans are the primary audience of a computer program, and coherence is the primary concern to optimize for.

                                                                Literary authors don’t generally invent new spoken languages because they’re dissatisfied with the expressive capability of their own. Artful literature is that which leverages the constraints of it’s language.

                                                                1. 4

                                                                  Literary authors don’t generally invent new spoken languages because they’re dissatisfied with the expressive capability of their own. Artful literature is that which leverages the constraints of it’s language.

                                                                  Eh, I have to disagree here. Literary authors try to stretch and cross the boundaries the of their spoken languages all the time, specifically because they search ways to express things that where not yet expressed before. To give some uncontroversial examples, Shakespeare invented 1700 new words and Tolkien invented not one, but a couple of whole new languages.

                                                                  I am but a very low level amateur writer, but I can tell you: the struggle with the tool to express your ideas is as real with spoken languages as it is with programming languages. It is an approach from another direction, but the results from spoken languages turn out to be as imperfect as those from programming ones.

                                                                  1. 1

                                                                    I’d argue that constrained writing is more common, if nothing else than showing ones mastery of a shared language is more impressive than adding unknown elements.

                                                                    Tolkien’s Elvish languages, while impressively complete, are simply used as flavor to the main story. The entire narrative instead leans heavily on tropes and language patterns from older (proto-English) tales.

                                                                    1. 1

                                                                      Yes, you have a point. I mentioned Tolkien because that was the first writer that created a new language that I could come up with. But in the end, if you want to express an idea, then your audience must understand the language that you use, otherwise they will not get your message. So common language and tropes can help a lot.

                                                                      However, I think your mention of constrained writing is interesting. Because in a way, that Go does not have generics, is similar to the constraint that a sonnet must follow a particular scheme in form and content. It is perfectly possible to add generics to Go, the same way as it is very possible to slap another tercet at the end of a sonnet. Nothing is stopping you, really, Expect that then it would no longer be a sonnet. Is that a bad thing? I guess not. But still almost no-one does it.

                                                                      I’d say that the rules, or the constraints, are a form of communication too. If I read a sonnet, I know what to expect. If I read Go, I know what to expect. Because some things are ruled out, there can be more focus on what is expressed within the boundaries. As a reader you can still be amazed. And, the same as in Go, if what you want to express really does not fit in the rules of a sonnet, or if it is not worth the effort to try it, then you can use another form. Or another programming language.

                                                                    2. 1

                                                                      Your points don’t conflict with my points, and I agree with them.

                                                                    3. 2

                                                                      Can we agree that the goal of programming languages is to reduce costs?

                                                                      • Cost of writing the program.
                                                                      • Cost of errors that may occur.
                                                                      • Cost of correcting those errors.
                                                                      • Cost of modifying the program in the face of unanticipated new requirements.

                                                                      That kind of thing. Now we must ask what influences the costs. Now what about increased expressiveness?

                                                                      A more expressive language might be more complex (that’s bad), more error prone (that’s bad), and allow shorter programs (that’s good), or even clearer programs (that’s good). By only looking at the complexity of the language, you are ignoring many factors that often matter a whole lot more.

                                                                      Besides, that kind of reasoning quickly breaks down when you take it to its logical extreme. No one in their right mind would use the simplest language possible, which would be something like the Lambda Calculus, or even just the iota combinator. Good luck writing (or maintaining!) anything worth writing in those.

                                                                      Yes, generics makes a language more complex. No, that’s not a good enough argument. If it was, the best language would only use the iota combinator. And after working years in a number of languages (C, C++, OCaml, Ptython, Lua…), I can tell with high confidence that generics are worth their price several orders of magnitudes over.

                                                                      1. 2

                                                                        I agree with you that generics can be hugely net positive in the cost/benefit sense. But that’s a judgment that can only be made in the whole, taking into account the impact of the feature on the other dimensions of the language. And that’s true of all features.

                                                                        1. 1

                                                                          Just popping in here because I have minimal experience with go, but a decent amount of experience in languages with generics, and I’m wondering: if we set aside the implementation challenge, what are some examples of the “other dimensions” of the language which will be negatively impacted by adding generics? Are these unique to go, or general trade offs in languages with generics?

                                                                          To frame it in another way, maybe a naive take but I’ve been pretty surprised to see generics in go being rejected due to “complexity”. I agree that complexity ought to be weighed against utility but can we be a little more specific? Complexity of what specifically? In what way will writing, reading, compiling, running, or testing code become more complicated when my compiler supports generics. Is this complexity present even if my own code doesn’t use generics?

                                                                          And just a final comparison on language complexity. I remember when go was announced, the big ticket feature was its m:n threaded runtime and support for CSP-style programming. These runtimes aren’t trivial to implement, and certainly add “complexity” via segmented stacks. But the upside is the ability to ergonomically express certain kinds of computational processes that otherwise would require much more effort in a language without these primitives. Someone decided this tradeoff was worth it and I haven’t seen any popular backlash against it. This feature feels very analogous to generics in terms of tradeoffs which is why I’m so confused about the whole “complexity” take. And like, maybe another naive question, but wouldn’t generics be significantly less tricky to implement than m:n threads?

                                                                          1. 5

                                                                            It isn’t just implementation complexity of generics itself. It’s also sure to increase the complexity of source code itself, particularly in libraries. Maybe you don’t use generics in your code, but surely some library you use will use generics. In languages that have generics, I routinely come across libraries that are more difficult to understand because of their use of generics.

                                                                            The tricky part is that generics often provides some additional functionality that might not be plausible without it. This means the complexity isn’t just about generics itself, but rather, the designs and functionality encouraged by the very existence of generics. This also makes strict apples-to-apples comparisons difficult.

                                                                            At the end of the day, when I come across a library with lots of type parameters and generic interfaces, that almost always translates directly into spending more time understanding the library before I can use it, even for simple use cases. That to me is ultimately what leads me to say that “generics increases complexity.”

                                                                            1. 2

                                                                              what are some examples of the “other dimensions” of the language which will be negatively impacted by adding generics?

                                                                              From early golang blog posts I recall generics add substantial complexity to the garbage collector.

                                                                              The team have always been open about their position (that generics are not an early priority, and they will only add them if they can find a design that doesn’t compromise the language in ways they care about). There have been (numerous proposals rejected)[https://github.com/golang/go/issues?page=3&q=generics++is%3Aclosed+label%3AProposal] for varied reasons.

                                                                              Someone decided this tradeoff was worth it and I haven’t seen any popular backlash against it

                                                                              There’s no backlash against features in new languages, because there’s nobody to do the backlash.

                                                                              Go has already got a large community, and there’s no shortage of people who came to go because it was simple. For them, adding something complex to the language is frightening because they have invested substantial time in an ecosystem because of its simplicity. Time will tell whether those fears were well-founded.

                                                                        2. 1

                                                                          No, expressiveness is the only reason for languages to exist. As you say, humans are the primary audience. With enough brute force, any language can get any task done, but what we want is a language that aids the reader’s understanding. You do that by drawing attention to certain parts of the code and away from certain parts, so that the reader can follow the chain of logic that makes a given program or function tick, without getting distracted by irrelevant detail. A language that provides the range of tools to let an author achieve that kind of clarity is expressive.

                                                                          1. 2

                                                                            I think we are using “expressive” differently. Which is fair, it’s not really a well-defined term. But for me, expressiveness is basically a measure of the surface area of the language, the features and dimensions it offers to users to express different ideas, idioms, patterns, etc. Importantly, it’s also proportional to the number of things that it’s users have to learn in order to be fluent, and most of the time actually exponentially proportional, as emergent behaviors between interacting features are often non-obvious. This is a major cost of expressiveness, which IMO is systemically underestimated by PLT folks.

                                                                        3. 3

                                                                          I implemented generics. You’re trying to convince me that it’s worth implementing generics. Why?

                                                                          Besides, the complexity of a language is never a primary concern.

                                                                          I disagree. I think implementation matters.

                                                                      2. 2

                                                                        That’s an intersting observation; thanks for sharing it.

                                                                        they just aren’t exposed to the end developer

                                                                        I think this supports my point better than I’m able to. Language design is just as much about what is hidden from developers as what is exposed. That generics are hidden from end users is something I greatly appreciate about Go. So when I refer to generics, I’m referring to generics used by every day developers.

                                                                        I’d be curious what your thoughts on why this discrepancy is OK and why it shouldn’t be fixed by adding generics to the language.

                                                                        In my opinion the greatest signal that Go doesn’t need generics is the wonderfully immense corpus of code we have from the last decade – all written without generics. Much of it written with delight by developers who chose Go over other langauges for it’s pleasant simplicity and dearth of features.

                                                                        That is not to say that some of us offasionally could have written less code if generics were available. Particularly developers writing library or framework code that would be used by other developers. Those developers absolutely would have been aided by generics. They would have written less code; their projects may have cost less to initially develop. But for every library/framework developer there are five, ten, twenty (I can’t pretend to know) end user application developers who never had the cognitive load of genericized types foisted on them. And I think that is an advantage worth forgoing generics. I don’t think I’m particularly smart. Generics make code less readable to me. They impose immense cognitive load when you’re a new developer to a project. I think there are a lot of people like me. After years of Java and Scala development, Go to me is an absolute delight with its absence of generics.

                                                                        1. 6

                                                                          In my opinion the greatest signal that Go doesn’t need generics is the wonderfully immense corpus of code we have from the last decade

                                                                          I don’t have a ready example, but I’ve read that the standard library itself conspicuously jumped through hoops because of the lack of generics. I see it as a very strong sign (that’s an understatement) that the language has a dire, pervasive, need for generics. Worse, it could have been noticed even before the language went public.

                                                                          If you had the misfortune of working with bright incompetent architects astronauts who used generics as an opportunity to make an overly generic behemoth “just in case” instead of solving the real problem they had in front of them, well… sorry. Yet, I would hesitate to accuse the language’s semantics for the failings of its community.

                                                                      3. 7

                                                                        I don’t remember exact details, it was super long ago, but I once wanted to write an editor centered around using a nontrivial data structure (“table chain” or “string table” or whatever was the name). Also the editor had some display aspect structures (~cells of terminal). At some point I needed to be able to experiment with rapidly changing the type of the object stored both in the “cells” and “chains” of the editor (e.g. to see if adding styles etc. per character might make sense from architectural point of view). If you squint, those are both kind of “containers” for characters (haskeller would maybe say monads? dunno). I had to basically either manually change all the places where the original “character” type was used, or fall back to interface{} losing all benefits of static typing that I really needed. Notably this was long before type aliases which would have possibly allowed me to push a bit further, though it’s hard for me to recall now. But the pain and impossibility of rapid prototyping at this point was so big I didn’t see it possible to continue working on the project and abandoned it. Not sure if immediately then or some time later I realized that this is the rare moment where generics would be valuable in letting me explore designs I cannot realistically explore now.

                                                                        In other words, what others say: nontrivial/special-purpose “containers”. You don’t need them until you do.

                                                                        Until then I fully subscribed to “don’t need generics in Go” view. Since then I’m in “don’t need generics in Go; except when do”. And I had one more hobby project afterwards that I abandoned for exactly the same reason.

                                                                        And I am fearful and do lament that once they are introduced, we’ll probably see everyone around abusing them for a lot of unnecessary purposes, and that this will be a major change to the taste of the language. That makes me respect the fact that the Team are taking their time. But I do miss them since, and if the Team grudgingly accepts the current draft as passabke, this is such a high bar that it makes me extremely excited for what’s to come, that it will be one of the best ways how this compromise can be introduced. Given that most decisions in languages are some compromises.

                                                                        1. 7

                                                                          Yeah, Go is very much not a language for rapid prototyping. It expects you to come to the table with a design already in mind.

                                                                          1. 2

                                                                            Umm, what? Honestly not sure if you’re meaning this or being sarcastic (and if yes, don’t see the point). I prototyped quite a lot of things in Go no problem. I actually hold it as one of the preferred languages for rapid prototyping if I expect I might want to keep the result.

                                                                            1. 5

                                                                              I’m being totally serious. Go is chock full of stuff that makes typical rapid prototyping extremely difficult. A lack of a REPL. Compiler errors on unused variables. Verbose error handling. And so on. All of these things combine to make it harder to “design on the fly”, so to speak, which is what rapid prototyping frequently means.

                                                                              With that said, Go works great for prototyping in the “tracer bullet” methodology. That’s where your prototype is a complete and production quality thing, and the iteration happens at a higher level.

                                                                              1. 1

                                                                                Got it, thanks! This made me realize that I reach for different languages in different cases for prototyping. Not yet really sure why now. But I feel that sometimes the dynamic types of Lua make me explore faster, whereas sometimes static types of Go or Nim make me explore faster.

                                                                        2. 4

                                                                          I’m going to assume you’re arguing in good faith here, but as a lurker on the go-nuts mailing list, I’ve seen too many people say “I don’t think generics are necessary” or “I haven’t heard a good enough reason for the complexity of generics”. It’s worth pointing out the Go team has collected feedback. Ian Lance Taylor (one of the current proposal’s main authors) spends a large portion of time responding to emails/questions/objections.

                                                                          I read a comment from someone who was on the Kubernetes team that part of the complexity of the API (my understanding is they have a pseudo-type system inside) is based on the fact that proto-Kubernetes was written in Java and the differences between the type systems compounded with a lack of generics created lots of complexity. (NOTE I don’t remember who said this, and I am just some rando on the net, but that sounds like a decent example of the argument for generics. Yes, you can redesign everything to be more idiomatic, but sometimes there is a compelling need to do things like transfer a code base to a different language)

                                                                          1. 1

                                                                            Ouch, I was wondering why the Kubernetes API looks so painfully like Java and not like Go. TIL that’s because it was literally a dumb translation from Java. :/ As much as I’m a pro-generics-in-Go guy, I’m afraid that’s a bad case for an argument, as I strongly believe it is a really awful and unidiomatic API from Go perspective. Thus I by default suspect that if its authors had generics at their disposal, they’d still write it Java-style and not Go-style, and probably still complain that Go generics are different from Java generics (and generally that Go is not Java).

                                                                          2. 3

                                                                            I don’t know if the author’s example was a good one to demonstrate the value of generics, but a cursory look at the diff would suggest he didn’t really gain anything from it. I always thought a huge benefit of generics was it saved you 10s or even 100s of lines of code because you could write one generic function and have it work for multiple types. He ended up adding lines. Granted, the author said it was mostly from tests, but still there doesn’t seem to be any dramatic savings here.

                                                                            1. 3

                                                                              I recommend taking more than a cursory look. The value here is very much in the new library interface. In effect, the package provides generalize channels, and before the change, that generalization meant both a complicated interface, and losing compiler-enforced type safety.

                                                                          1. 5

                                                                            I’ve seen people take DRY to completely destructive ends. It’s often a dangerous principle to work/hack by. But CARE lacks a prescriptive quality that DRY has.

                                                                            The idea of turning acronym into practice need not be a thing. Simply empathize with and care about all the inevitable readers coming after you. They don’t necessarily think like you do. Try to think like a devil’s advocate as you code. Like prose, it’s a wonderful exercise to come back to your code in 24 hours; look at it through a new lens and refine it. It’ll do wonders. Sometimes repeat yourself. Don’t worry about any acronyms.

                                                                            1. 2

                                                                              Cool idea.

                                                                              One other solution that may require less work, depending on your email hosting and mobile client application (assuming you’re willing to install one) – use rules.

                                                                              Let’s say you host your own mail and you allow literally-anything@mydomain.com land in your inbox. This is called a “catchall” or “wildcard” alias in the parlance of a provider like Fastmail. Now let’s say your email client allows the creation of rules and push notifications associated with rules.

                                                                              Create rule in email client:

                                                                              1. Trigger is to: limited-availability-foo-corp-product@yourdomain.com
                                                                              2. Action: Push Notification

                                                                              Voilá!

                                                                              1. 1

                                                                                Most smtp servers (and email providers) also allow appending “+anything” to email addresses, so might not really need a catch-all account - normal accounts should work too. So just set up a rule on “my.email+foo-corp-product@gmail.com” and it will still end up in your inbox. The only problem you can encounter is some email validation rules on some websites are incomplete/broken/RFC-not-compliant and doesn’t allow “+” characters, but I think those are a minority (I’m using such addresses with the “+” suffix to know the source of spam I’m getting ;-))

                                                                                1. 2

                                                                                  I use the catchall technique for the same reason :)

                                                                              1. 8

                                                                                It’s interesting to me that things like column width and spaces vs. tabs are considered “debates” or worthy of “controversy”. Trivially, these are matters of opinion and we’ll never agree on what’s “best”. Best for you is not best for me. And best for me is not best for you. Is it so hard to accept that our personal philosophies about code readability are not universal?

                                                                                What’s more important is that code formatting is project-idiomatic. Apply the rules of the road and never debate their application. Do debate with your teams what the rules of the road should be. Not once a week, but at some reasonably long interval, in open forum. Those debates result in linting rules and .editconfigs. The rules will not be “best” for everyone – accept that from the outset – but, they’ll probably be good enough for most people. Of course the rules won’t be perfect for everyone, and the rules may even feel hostile to some. Those folks should customize their editors to display the rules of the road in a way that’s ergonomic for them.

                                                                                1. 13

                                                                                  I don’t agree. I’ve been using Rails for 10+ years (at least 8 with some confidence), and am still actively using it on a daily basis on one project. I’ve sometimes used the standard conventions, other times I’ve modified (or rather extended) them pretty extensively. Clearly Rails has got a lot of things going for it, and many of the shiny novelties that have been touted as better alternatives weren’t. Still, I think Rails has big shortcomings and articles like this one fail to imagine how, or even that, they could be improved upon.

                                                                                  The main argument presented here seems to be:

                                                                                  With Rails, you don’t have to make any of the decisions above.

                                                                                  The author doesn’t try to argue that Rails makes good decisions, only that it’s great that we don’t have to make them ourselves.

                                                                                  The second and final point is:

                                                                                  Rails Helps Maintainability

                                                                                  The argument being that libraries tend to be maintained over long periods of time, which is true in many cases, and I agree that the ecosystem is Rails’ very strongest point. (This is mostly true for hands-on, everyday things like “connect to Stripe” or “upload to S3”. Other ecosystems are better at other things.)

                                                                                  Then the author comes back to the point about strong conventions which he claims help “fewer parts of an app to get crufty as time goes by”. I don’t agree. I think Rails’ conventions actively encourage bad practices, which harms maintainability and indeed leads to a crufty codebase.

                                                                                  These problems stem first from ActiveRecord which is a weak abstraction and almost invariably leads newcomers down the wrong path, after which they must learn a whole lot of “best practices” to implement decent database access pattern. Secondly, Rails does nothing to encourage users to isolate domain logic and keep it sanely structured. (An unstructured collection of service classes is a small but insufficient step towards rectifying this problem.) The result is that, after a short honeymoon of “getting up and running in no time”, it becomes harder to focus on the app domain and “the problems [we] need to solve”, because the domain logic tends to be spread out all over the place.

                                                                                  These arguments have been rehashed for almost as long as Rails has been around. There’s nothing remotely new in what I just wrote. People’s tastes and experiences vary. I’m reluctant to say there is no objectively assessable dimension to this issue, but on the whole we’ll do best to agree to disagree.

                                                                                  1. 7

                                                                                    I’m with you. Although I will concede that most businesses fail, and Rails does allow small teams to move quickly toward usable features for customers. Perhaps marginally improving the company’s chances of success.

                                                                                    The problems all come with success and larger teams. The monster ActiveRecord models containing business logic, without domain boundaries. The fact that dynamically typed Ruby underlies it all. The lack of established modularity patterns … These all culminate, making for inefficient, large teams after the honeymoon years of startupdom are over. All those readymade, but poor Rails decisions that made starting up a success really come back to bite you.

                                                                                    1. 4

                                                                                      What do you prefer these days?

                                                                                      1. 2

                                                                                        I am not a subOP, but I have moved from Rails to Phoenix and never looked back.

                                                                                      2. 2

                                                                                        I’m interested to hear which frameworks solve those problems for you!

                                                                                        1. 4

                                                                                          For me Phoenix with Elixir solve most of these problems. It is still mostly opinionated, but with ease you can change that behaviours, it encourages proper separation of the application logic, it uses repo-pattern instead of the ActiveRecord, etc. Of course, it is less popular, so finding hires is a little bit harder, but if you look within community (which author is strongly suggesting) then there should be no problem with finding people.

                                                                                          1. 1

                                                                                            I love Phoenix too! I need more experience with it, but as far as I’m concerned that was a great answer to my question 😄 Cheers!

                                                                                          2. 1

                                                                                            The two main problems I pointed out were AR being a weak abstraction and Rails not doing enough to encourage domain logic to be written in an isolated and structured manner.

                                                                                            For the first problem, my conclusion is that database abstractions are not worth the trouble. There are several that are better than AR, but SQL databases are actually pretty hard to abstract over, at least if you want to full advantage of what they can do. Instead, treat the database as your framework. (And by “database”, I mostly mean Postgres.) This approach to writing applications is still pretty common in large enterprises (from what I gather) and “modern” devs like to make fun of it, but I think it’s more relevant than ever. If you put PostgREST or PostGraphile on top of that to expose a REST/GraphQL API, this setup fits right into a modern stack.

                                                                                            For the second problem, I think domain-driven design goes in the right direction (although it’s been obfuscated by being lumped together with particular technologies and bloated architectures, not least microservices). I see DDD as an offshoot of the bigger field of (abstract) data modeling or concept modeling, which was to a big extent ruined by heavy UML standards, consultants, frameworks… But I think it’s essential, and I would measure a language or framework by how clearly and directly it lets you express the domain model. (Domain Modeling Made Functional is one approach to this.) Yes Rails tries to make some things more “declarative”, which is good, but again, it has little to offer when a system grows more complex.

                                                                                            I would use Erlang/Elixir (or Gleam!) if I ever had to create a system of the kind that the BEAM was meant for, but not for a regular CRUDdy web app.

                                                                                            So the short answer is: Postgres, because it helps me focus on and express the domain model!

                                                                                            (@squarism this was in answer to your question too. More concretely, my preferred current stack is PostGraphile + Elm.)

                                                                                        1. 1

                                                                                          Kudos and best of luck!

                                                                                          Speaking for your future users googling solutions to problems – in a world where search prominence is perhaps more important than domain names, I recommend a more unique name like helloOS.

                                                                                          1. 2

                                                                                            I agree wholeheartedly with the author’s opinion on explicit vs. implicit nil.

                                                                                            On the point of guard clauses we disagree.

                                                                                            Except in this case, we’re not “guarding” the rest of the method from being run. That conditional is the entire raison d’être of the class.

                                                                                            And indeed, the raison d’être (execute super when appropriate) remains the same – albeit with a ruby-idiomatic postfix conditional.

                                                                                            Conditionals need not look a certain way. They don’t exist to lend a certain visual element to your code. Furthermore, Ruby is to blame for guard clauses, not Rubocop. It’s not unreasonable for Rubocop to recommend programmers express problems more succinctly. In my opinion, guard clauses make code more readable in code bases where they’re idiomatic. That’s an important caveat. If the developers you work with regularly ignore this Rubocop rule, then guard clauses will not be idiomatic in your code base, and you should avoid them for that reason.

                                                                                            1. 2

                                                                                              I wish the example wasn’t about ‘nil’ because the author seem to imbue ‘nil’ with some magic readability that I don’t think it has. It’s pushing the behavior back to the caller and having it decide what to do and I think that’s rarely a good idea.

                                                                                              1. 1

                                                                                                Yeah, for me it isn’t about nil specifically. Sometimes things read more clearly with explicit returns.

                                                                                                1. 1

                                                                                                  The behaviour is identical in all the code examples. They all return nil under the same circumstances. The only difference is whether you can see it actually written in the code.

                                                                                                2. 2

                                                                                                  My current opinion on guard clauses is that they are appropriate in specific situations (a couple spring to mind). I think it’s a false dichotomy to either try and use them as much as possible, or not at all. I can see an argument for never using them, depending on the people in your team, but personally I’m not on those kinds of teams.

                                                                                                1. 15

                                                                                                  The problem with being so prescriptive about how people “should” write code is that everyone works and thinks differently, and what’s right for you is certainly wrong for others.

                                                                                                  1. 3

                                                                                                    Finding new rock routes to climb, mountain bike trails to ride, and trails to run. And the occasional attempt and frequent failure to catch some fish for dinner after work.

                                                                                                    1. 9

                                                                                                      seems disingenuous to keep calling things ‘alternatives to Google Analytics’ when there isn’t remotely feature parity.

                                                                                                      1. 20

                                                                                                        It might be for a lot of people. Some claim there isn’t feature parity between LibreOffice and Excel and yet a lot of people use it without bigger problems :)

                                                                                                        1. 1

                                                                                                          I’m with you here. I used Google Analytics for a few years before I finally managed to excise Google from my life (mostly) and honestly I used it for a blog and I looked at like 2 views ever, maybe 3.

                                                                                                        2. 12

                                                                                                          I’m glad of that. Many GA users only desire a subset of its features. The superset of GA’s features are powered by user privacy violation.

                                                                                                          These are indeed alternatives to GA and users can make their own choice as to whether the alternatives’ feature sets are sufficiently rich.

                                                                                                        1. 13

                                                                                                          Leaving a job because the tech is old seems very odd to me.

                                                                                                          However, 5 years is an incredibly long time to spend doing any one thing. I certainly wouldn’t stay in one job that long unless it were maybe one that let me change what I was doing every few years without leaving?

                                                                                                          1. 18

                                                                                                            Just to add to your first paragraph: It did seem that the author tried to make suggestions about which tech would be better, but didn’t get any support. It can be quite frustrating to work with legacy code and not getting listened to because your ideas doesn’t have an immediate return on investment (“Yeah, good idea, but we don’t have the time/resources/money to set your plan into action this time either”). Programming is creative, and having ideas repeatedly struck down kills the creativity and joy.

                                                                                                            1. 7

                                                                                                              That’s a very sensible thing to do IMO. If your skills are stagnating and your day-to-day work gives you no opportunity to advance them, then at some point you’ll want to update your skills. Either with something new, or something old that you’re unfamiliar with. Don’t mistake this advice for “chasing the shiny new thing”; rather an acknowledgement that new skills are important to your professional development/expanding your mind.

                                                                                                              1. 2

                                                                                                                I literally cannot stop aquiring new tech skills (or other skills, even!). My job is almost never involved in this.

                                                                                                                I understand that I’m not everyone. But that’s why I said it seems odd to me and not that it’s a bad idea. Maybe it’s a good idea for you. I don’t go to work for the tech (or I would have a very different job!)

                                                                                                              2. 2

                                                                                                                It may seem odd but I got to be in the very same position a couple of months back. I was a contractor for a company that deals with hedge funds, and some financial stuff like that, my excitement over that industry has never been really there though but the renumeration was damn great.

                                                                                                                However, we had to manage such an old codebase this company had built inhouse using Zend Framework 1! At the time, I took the job with the idea we were going to be using recent tech obviously, they had said it’s PHP + recent JS flavours (vuejs, react JS). I tried to trudge on for a while but could just not get productive. I ended up resigning because I felt so bad that I couldn’t deliver the value they sought nor was I bothered to learn outdated tech and have an obsolete skillset.

                                                                                                              1. 3

                                                                                                                I’m all for the “small web” or “indie web”, but it’s worth considering that the intersect between “people with their own servers” and “people lacking the technical knowledge to self-host a website” is quite small.

                                                                                                                Am I misunderstanding the goal of this project/foundation? Is it not targeting the two, arguably non-intersecting groups above?

                                                                                                                1. 10

                                                                                                                  I appreciate the sentiment of not trying to change a code base’s well-established and consistent style. However as a manager, the deference to more “senior” developers/managers/Apple/Microsoft in this essay is not a desirable trait in a new teammate.

                                                                                                                  Good junior engineers ask good questions that reveal blind spots that “senior” engineers and managers have long had. Thoughtfully and tactfully press issues and ask questions, junior folks. Everyone more senior than you have more blind spots than you can imagine. But also know that senior folks will often hide behind the shield of their seniority, and you should know when they’re putting it up. If possible, avoid those people. If it’s not possible, hone your tact and use a different angle to make your case. These skills that some people call “soft skills” will get you very far in your career.

                                                                                                                  1. 11

                                                                                                                    Good junior engineers ask good questions that reveal blind spots that “senior” engineers and managers have long had. Thoughtfully and tactfully press issues and ask questions, junior folks.

                                                                                                                    Good point. It’s a line to walk. You have to choose what battles to fight, however. I think, for example, questioning which data store is a good fit for a greenfield application is a better way to spend your effort (as a new dev) than tabs/spaces.

                                                                                                                    1. 1

                                                                                                                      Indeed!

                                                                                                                  1. 1

                                                                                                                    Thank you; this was really interesting.

                                                                                                                    The humor and lightheartedness were sometimes more distracting than successful in their goals, however.

                                                                                                                    1. 2

                                                                                                                      Thanks for the write up and I really like your choice in both subject matter and criteria on which to to compare the two language ecosystems. Overall I thought it was a good analysis of the two. I can’t speak for Rust, but as someone who has developed in Go, I think your write up would benefit from a more in depth look at Go Modules. Go modules are how dependency management is done in Go these days, and while not a “package manager” per se, they do convey many of the same benefits. They have the added benefit that you’ll probably never have to think of GOPATH again.

                                                                                                                      Cheers

                                                                                                                      1. 12

                                                                                                                        This is the moment I removed all snaps:

                                                                                                                        1.3G /snap/slack
                                                                                                                        1.2G /snap/spotify
                                                                                                                        1.9G /snap/vlc
                                                                                                                        

                                                                                                                        It’s difficult to understand how people are OK with this.

                                                                                                                        1. 24

                                                                                                                          You’re not looking at the on-disk footprint of the snaps. You’re peering inside (probably more than one) compressed loopback files at their contents.

                                                                                                                          -rw------- 1 root root 145M Jul 15 10:04 /var/lib/snapd/snaps/slack_25.snap
                                                                                                                          -rw------- 2 root root 164M Jun 15 00:09 /var/lib/snapd/snaps/spotify_41.snap
                                                                                                                          -rw------- 2 root root 291M Jul 31 17:23 /var/lib/snapd/snaps/vlc_1700.snap
                                                                                                                          

                                                                                                                          Granted the vlc one is pretty bit, but it’s not 1.9GB big on disk.

                                                                                                                          1. 4
                                                                                                                            $ zstdcat /var/cache/pacman/pkg/vlc-3.0.11-1-x86_64.pkg.tar.zst|wc -c
                                                                                                                            62464000
                                                                                                                            

                                                                                                                            59MB. That’s 20% the size of your snap. And that’s decompressed, compared with your compressed version. A fairer comparison of the on-disc footprint would be with per-file compression. If I extract that archive onto an fs with compression (zfs+lz4), it’s 35MB—nearly 10% of the snap.

                                                                                                                            (Slack and spotify I have no interest in installing, but I expect vlc is representative.)

                                                                                                                            1. 1

                                                                                                                              Yeah, the vlc snap could do with some oprimisation, for sure.

                                                                                                                              1. 1

                                                                                                                                The vlc snap is a similar size to the others. Is there some reason to believe that other snaps aren’t also 10x larger than they need to be?

                                                                                                                            2. 3

                                                                                                                              Ah interesting. Still pretty huge, but certainly not 1.9GB huge :)

                                                                                                                              (but still have no desire to use snaps)

                                                                                                                            3. 1

                                                                                                                              Woah, is it normal for snap to behave like this? It looks like these directories contain all old copies of apps or something?

                                                                                                                              1. 7

                                                                                                                                Snapd keeps an old version of each application around so that in the event that your update goes bad, you can snap revert and immediately go back to the previous revision. I don’t know if the OP tried this, but it would have allowed them to probably keep working a lot quicker.

                                                                                                                            1. 5

                                                                                                                              “Need” is an interesting choice in words. When someone’s non-reproducible build is driving me down the highway at 200km/h in the future, I don’t need it to keep me alive, but I’d like it to. I don’t need the digital coroner of futureland to have an exact build in their hands to analyze the crash, but I’d like them to.

                                                                                                                              Security is not the only lens through which reproducibility matters. Granted, I also argue reproducibility matters to security for the same reason it matters to correctness — diagnosis.