Threads for rtpg

  1. 8

    :( this looks too much like vs code to me

    1. 6

      Presumably intentionally so; VSCode w/ language-server driven intellisense has taken over the editor market in a big way, and I gather they’re trying to make the sales pitch of “pay us money for our product instead” a little easier by softening the UI changes for anyone who they can convince to switch.

      Not ideal for people who love the current JetBrains IDE UI paradigm, I suppose.

      1.  

        I feel like that goes both ways though. If there’s less difference, why am I paying?

        I am not an absolutionist in terms of redesigns, but as someone who likes using Jetbrains software for working in Enterprise Software, moving towards this “you can barely have two files open at once” design makes me a bit sad (I’m 100% sure I can mess around with the configuration/layout to get what I want of course)

        1. 8

          I feel like that goes both ways though. If there’s less difference, why am I paying?

          I mean it’s hard to say (I’m neither a vscode nor much of a jetbrains guy), but in my limited experience with CLion I walked away with the impression that one buys it for the features (some of which are advantages over rust-analyzer), and merely tolerates the UI. Not that there’s anything completely wrong with the UI, but the current mostly bog-standard “bag of icons” IDE paradigm can’t really be selling many licenses on its strength alone, can it?

          “We’ve got these features but a UI familiar to you” is probably an easier sell than “we’ve got these features and a UI familiar to a VB6 dev” to the newer generation of JS/python/Ruby/Go devs they’re increasingly trying to target, who’ve mostly come up on the textmate/sublime/atom/vscode evolution of editors, is my basic read. The Visual Studio proper / Eclipse school of IDE design is probably slowly going away as it’s becoming increasingly unfamiliar to younger devs.

          1.  

            For me, the biggest value of JetBrains is their unified framework for parsing and manipulating code, which allows for a reasonably consistent experience across languages in their IDEs. For single-language usage, I‘m not that sure.

      1. 2

        Was expecting a rant but this is just a legit article talking about some cool advances for multi page app tech.

        Having rich interactivity is super nice, and there’s a lot of places where SPA-y frameworks just work nicer, but there’s definitely this feeling that the MPA design space isn’t fully explored (htmx for me is the big one. PJAX of course existed before but htmx has a lot of niceties about it).

        Figma isn’t going to become a multi-page app, but I do get this feeling that at least MPAs kinda default to a certain kind of statelessness that reduces weird stuff from breaking.

        1. 8

          I have always wanted to write the text on mathematical reasoning for impatient people. I think TLA+ is very interesting, but even some fairly bog-standard case disjunction ideas and “advanced” laws of excluded middle are very powerful.

          I think the challenge is that people understand these concepts. They understand that something is true or false. But often what is missing is an understanding that what they are looking at is actually a situation where these ideas apply.

          In a way, it’s like design patterns: people might understand that patterns exist, but the value comes from identifying that the real world problem abstracts to the pattern (or identifying that it doesn’t abstract to it, or abstracts for a subset of cases…).

          Given how people tend to figure this stuff out from seeing a lot of things in context, I don’t know how you tackle this issue. But I think there’s potential for such a text to instantly make the lives of a lot of more junior engineers much better.

          1. 2

            I was working on this a bit last year. It’d just cover classical logic, no combinatorics or graph theory or anything, and devote a lot of space to examples and applications. I think it’d also dip into second order logic- it’s okay for programmers to use a non-absolute framework for reasoning because they’re unlikely to run into the problems that causes.

          1. 30

            its release philosophy is supposed to avoid what I call “the problem with Python”: your code stops working if you don’t actively keep up with the latest version of the language.

            This is a very real problem with the Python and Node ecosystems.

            1. 16

              I’m going to be grumpy and ask what this “problem” is supposed to mean, exactly. I can deploy, say, a Python application on a particular version of Python and a particular operating system today, and then walk away for years, and as long as I pay the hosting bill there is no technical reason why it would suddenly stop working. There’s no secret kill switch in Python that will say “ah-ha, it’s been too long since we made you upgrade, now the interpreter will refuse to start!”

              So what people always actually mean when they say things like this is that they want to keep actively developing their code but have everybody else stand still forever, so that they can permanently avoid platform upgrades but also the language and ecosystem will never leave them behind. So the real “problem” is that one day nobody else will be willing to provide further bug and security fixes (free or perhaps even paid) for the specific combination of language/libraries/operating system I initially chose to build my app with, and on that day I have to choose between upgrading to a new combination, or doing that maintenance myself, or going without such maintenance entirely.

              And although I’ve seen a lot of claims, I’ve seen no evidence as yet that Rust has actually solved this problem — the editions system is still young enough that the Rust community has not yet begun to feel the pain and cost of what it committed them to. “Stability without stagnation” is a nice slogan but historically has ranged from extremely difficult to downright impossible to achieve.

              1. 16

                “Stability without stagnation” is a nice slogan but historically has ranged from extremely difficult to downright impossible to achieve.

                You just don’t make breaking changes. Add new APIs but don’t take away old ones. Go 1 has been stable for 10 years now. That means there are some ugly APIs in the standard library and some otherwise redundant bits, but it’s been fine. It hasn’t stopped them from adding major new features. Similarly, JavaScript in the browser only rolls forward and is great. Again, some APIs suck, but you can just ignore them for the most part and use the good versions. I’m not as familiar with the Linux kernel, but my impression there is that Linus’s law is you don’t break userland.

                Most breaking changes are gratuitous. They make things a little nicer for the core developers and shove the work of repair out to everyone who uses their work. I understand why it happens, but I reserve the right to be grumpy about it, especially because I have the experience of working in ecosystems (Go, the browser) that don’t break, so I am very annoyed by ecosystems that do (NPM, Python).

                1. 15

                  I’ll be up-front. My stance on breaking changes is that there are two types of projects:

                  1. Those which have decided to accept they are an inevitable fact of software development, and so have committed to the process of handling them, and
                  2. Those which haven’t yet.

                  And remember that we are talking not just about core language/standard library, but also ecosystems. Go has already effectively broken on this — the “rename your module to include /v2” hack is an admission of defeat, and allows the previous version to lapse into a non-maintained status. Which in turn means that sooner or later you will have to make the choice I talked about (upgrade, or do maintenance yourself, or go without maintenance).

                  And Rust has had breaking changes built into the ecosystem from the beginning. The Cargo/crates ecosystem isn’t built around every crate having to maintain eternal backwards-compatibility, it’s built on semantic versioning. If I publish version 1.0 of a crate today, I can publish 2.0 with breaking changes any time I want and stop maintaining the 1.x series, leaving users of it stranded.

                  So even if Rust editions succeed as a way of preserving compatibility of the core language with no ecosystem splits and no “stagnation”, which I strongly doubt in the long term, the ecosystem has already given up, and in fact gave up basically immediately. It has “the Python problem” already, and the only real option is to learn how to manage and adapt to change, not to insist that change is never permitted.

                  (and of course my own experience is that the “problem” is wildly exaggerated compared to how it tends to impact projects in actual practice, but that’s another debate)

                  1. 5

                    I think it’s hard to talk about this rigorously because there’s definitely some selection bias at play — we don’t have information about all the internal projects out there that might be bogged down by breaking changes between interpreter versions, and they’re likely motivated by very different incentives than the ones that govern open source projects — and there’s likely survivorship bias at play too, in that we don’t hear about the projects that got burnt out on the maintenance burden those breaking changes induce.

                    My anecdotal evidence is that I’ve worked at places with numerous Python projects bound to different, sometimes quite old, interpreter versions, and there just aren’t enough person-hours available to keep them all up to date, and updating them in the cases where it was truly necessary made for some real hassle. Even if you chalk that up to bad resource management, it’s still a pretty common situation for an organization to find itself in, and it’s reasonable to expect your tools to not punish you for having less than perfect operational discipline. In light of that, I think understanding it in this binary frame of either making breaking changes or not isn’t the most fruitful approach, because as you note it’s not realistic to expect that they never happen. But when they do happen, they cost, and I don’t think it’s unreasonable for an organization to weigh that total cost against their resources and decide against investing in the Python ecosystem. It’s not unreasonable to make the opposite choice either! I just don’t think that cost is trivial.

                    1. 7

                      Even if you chalk that up to bad resource management, it’s still a pretty common situation for an organization to find itself in and it’s reasonable to expect your tools to not punish you for having less than perfect operational discipline.

                      Imagine 20 years ago saying this about a project that suffered because they lost some crucial files and it turned out they weren’t using any kind of version control system.

                      Because that’s basically how I feel about it. Regularly keeping dependencies, including language tooling/platform, up-to-date, needs to become table stakes for software-producing entities the way that version control has. I’ve seen this as a theme now at four different companies across more than a decade, and the solution is never to switch and pray that the next platform won’t change. The solution is always to make change an expected part of the process. It can be done, it can be done in a way that minimizes the overhead, and it produces much better results. I know because I have done it.

                      1. 3

                        Because that’s basically how I feel about it. Regularly keeping dependencies, including language tooling/platform, up-to-date, needs to become table stakes for software-producing entities the way that version control has.

                        I don’t believe this is what’s being disputed: it’s that this being a fact is precisely why it’s important for the platform to facilitate ease of maintenance to the best of its ability in that regard. Doing so allows even under-resourced teams to stay on top of the upgrade treadmill, which is more of my point in the bit you quoted: tools that induce less overhead are more resilient to the practical exigencies that organizations face. I guess we’ll have to agree to disagree about where the Python ecosystem sits on that spectrum.

                        1. 2

                          This sounds like the “don’t write bugs” school of thought to me. Yes, ideally anything that’s an operational concern will get ongoing maintenance. In the real world… 

                          More anecedata: my coworker built a small Python scraper that runs as a cron job to download some stuff from the web and upload it to an S3 bucket. My coworker left and I inherited the project. The cron job was no longer a high priority for the company, but we didn’t want to shut it off either. I couldn’t get it to run on my machine for a while because of the Python version problem. Eventually I got to the point where I could get it to run by using Python 3.6, IIRC, so that’s what it’s using to this day. Ideally, if I had time and resources I could have figured out why it was stuck and unstick it. (Something to do with Numpy, I think?) But things aren’t always ideal.

                          If someone has to have discipline and try to stick closer to the “don’t write bugs” school, who should it be: language creators or end developers? It’s easy for me to say language creators, but there are also more of us (end developers) than them (language creators). :-) ISTM that being an upstream brings a lot of responsibility, and one of those should be the knowledge that your choices multiply out by all the people depending on you: if you impose a 1 hour upgrade burden on the 1 million teams who depend on you, that’s 1 million hours, etc.

                          1. 1

                            Generalizing from anecdata and my own experience, the killer is any amount of falling behind. If something is not being actively maintained with dependency updates on at least a monthly and ideally a weekly cadence, it is a time bomb. In any language, on any platform. Because the longer you go without updating things, the more the pending updates pile up and the more work there will be to do once you do finally sit down and update (which for many projects, unfortunately, tends to be only when they are absolutely forced to start doing updates and not a moment sooner).

                            At my last employer I put in a lot of work on making the (Python) dependency management workflow as solid as I could manage with only the standard packaging tooling (which I believe you may have read about). But the other part of that was setting up dependabot to file PRs for all updates, not just security, to do so on a weekly basis, and to automate creation of Jira tickets every Monday to tell the team that owned a repository to go look at and apply their dependabot PRs. When you’re doing it on that kind of cadence it averages very little time to review and apply the updates, you find out immediately from CI on the dependabot PRs if something does have a breaking change so you can scope out the work to deal with it right then and there, and you never wind up in a situation where applying the one critical update you actually cared about takes weeks or months because of how much other stuff you let pile up in the meantime.

                            Meanwhile I still don’t think Python or its ecosystem are uniquely bad in terms of breaking changes. I also don’t think Go or Rust are anywhere near as good as the claims made for them. And the fact that this thread went so quickly from absolutist “no breaking changes ever” claims to basically people’s personal opinions that one language’s or ecosystem’s breaking changes are justified and tolerable while another’s aren’t really shows that the initial framing was bad and was more or less flamebait, and probably should not be used again.

                            1. 5

                              No, I still think you’re wrong. :-)

                              I agree that for a Python or Node project it is recommended to set up dependabot to keep up to date or else you have a ticking time bomb. However, a) that isn’t always practical and b) it doesn’t have to be like that. I routinely leave my Go projects unattended for years at a time, come back, upgrade the dependencies, and have zero problems with it.

                              Here is a small project last touched in 2017 that uses Go and Node: https://github.com/baltimore-sun-data/track-changes

                              Here is the full Terminal output of me getting it to build again with the most recent version of Go:

                              (Fri, May 20  08:56:09 PM) (master|✔)
                              $ go build .
                              go: cannot find main module, but found Gopkg.lock in /var/folders/p7/jc4qc9n94r3f6ylg0ssh1rq00000gs/T/tmp.S6ZYg4FX/track-changes
                                      to create a module there, run:
                                      go mod init
                              # status: 1 #
                              (Fri, May 20  08:56:27 PM) (master|✔)
                              $ go mod init github.com/baltimore-sun-data/track-changes
                              go: creating new go.mod: module github.com/baltimore-sun-data/track-changes
                              go: copying requirements from Gopkg.lock
                              go: to add module requirements and sums:
                                      go mod tidy
                              (Fri, May 20  08:57:00 PM) (master|…)
                              $ go mod tidy -v
                              go: finding module for package github.com/stretchr/testify/assert
                              go: finding module for package golang.org/x/text/unicode/norm
                              go: finding module for package golang.org/x/text/secure/bidirule
                              go: finding module for package golang.org/x/text/unicode/bidi
                              go: finding module for package golang.org/x/sync/errgroup
                              go: finding module for package github.com/stretchr/testify/suite
                              go: downloading golang.org/x/sync v0.0.0-20220513210516-0976fa681c29
                              go: found github.com/stretchr/testify/assert in github.com/stretchr/testify v1.7.1
                              go: found github.com/stretchr/testify/suite in github.com/stretchr/testify v1.7.1
                              go: found golang.org/x/text/secure/bidirule in golang.org/x/text v0.3.7
                              go: found golang.org/x/text/unicode/bidi in golang.org/x/text v0.3.7
                              go: found golang.org/x/text/unicode/norm in golang.org/x/text v0.3.7
                              go: found golang.org/x/sync/errgroup in golang.org/x/sync v0.0.0-20220513210516-0976fa681c29
                              (Fri, May 20  08:57:10 PM) (master|…)
                              $ go build .
                              (Fri, May 20  08:57:18 PM) (master|…)
                              $ 
                              

                              As you can see, it took about a minute for me to get it building again. Note that this package predates the introduction of Go modules.

                              Let’s upgrade some packages:

                              (Fri, May 20  09:02:07 PM) (master|…)
                              $ go get -v -u ./...
                              go: downloading golang.org/x/net v0.0.0-20220520000938-2e3eb7b945c2
                              go: downloading cloud.google.com/go v0.101.1
                              go: downloading gopkg.in/Iwark/spreadsheet.v2 v2.0.0-20220412131121-41eea1483964
                              go: upgraded cloud.google.com/go v0.16.0 => v0.100.2
                              go: added cloud.google.com/go/compute v1.6.1
                              go: upgraded github.com/ChimeraCoder/anaconda v1.0.0 => v2.0.0+incompatible
                              go: upgraded github.com/andybalholm/cascadia v0.0.0-20161224141413-349dd0209470 => v1.3.1
                              go: upgraded github.com/garyburd/go-oauth v0.0.0-20171004151416-4cff9ef7b700 => v0.0.0-20180319155456-bca2e7f09a17
                              go: upgraded github.com/go-chi/chi v3.3.1+incompatible => v4.1.2+incompatible
                              go: upgraded github.com/golang/protobuf v0.0.0-20171113180720-1e59b77b52bf => v1.5.2
                              go: upgraded github.com/pkg/errors v0.8.0 => v0.9.1
                              go: upgraded golang.org/x/net v0.0.0-20171107184841-a337091b0525 => v0.0.0-20220520000938-2e3eb7b945c2
                              go: upgraded golang.org/x/oauth2 v0.0.0-20171117235251-f95fa95eaa93 => v0.0.0-20220411215720-9780585627b5
                              go: upgraded google.golang.org/appengine v1.0.0 => v1.6.7
                              go: added google.golang.org/protobuf v1.28.0
                              go: upgraded gopkg.in/Iwark/spreadsheet.v2 v2.0.0-20171026120407-29680c88e31d => v2.0.0-20220412131121-41eea1483964
                              (Fri, May 20  09:02:52 PM) (master|…)
                              $ go build .
                              # github.com/baltimore-sun-data/track-changes
                              ./handler.go:28:14: undefined: middleware.DefaultCompress
                              # status: 2 #
                              (Fri, May 20  09:02:58 PM) (master|…)
                              $ go doc middleware
                              package middleware // import "github.com/go-chi/chi/middleware"
                              
                              // snip
                              
                              (Fri, May 20  09:03:12 PM) (master|…)
                              $ go doc middleware.Compress
                              package middleware // import "github.com/go-chi/chi/middleware"
                              
                              func Compress(level int, types ...string) func(next http.Handler) http.Handler
                                  Compress is a middleware that compresses response body of a given content
                                  types to a data format based on Accept-Encoding request header. It uses a
                                  given compression level.
                              
                                  NOTE: make sure to set the Content-Type header on your response otherwise
                                  this middleware will not compress the response body. For ex, in your handler
                                  you should set w.Header().Set("Content-Type",
                                  http.DetectContentType(yourBody)) or set it manually.
                              
                                  Passing a compression level of 5 is sensible value
                              
                              (Fri, May 20  09:03:32 PM) (master|…)
                              $ subl .
                              (Fri, May 20  09:04:12 PM) (master|…)
                              $ go build .
                              (Fri, May 20  09:04:59 PM) (master|✚1…)
                              $
                              

                              Took about 3 minutes to upgrade the packages and fix the broken dependency (they renamed a middleware). Bear in mind that the upgrade I did deliberately did not try to upgrade past semantic version changes in its dependencies. Probably it would take another half hour or more if I wanted to chase down whatever breaking changes happened there.

                              Suffice it to say, yarn cannot even install its packages, and the last time I tried this stunt a couple of years ago, I got past that and then ran into a problem with webpack that I couldn’t easily solve.

                              Go is just a much more stable ecosystem than Node or Python. It’s not as stable as say browser JS, where one can reasonably expect working code to work until civilization collapses, but it’s fairly stable. And it’s not magic. If there were a communal expectation of this level of stability, it could exist everywhere. It’s a social value to keep things working in the Go ecosystem, and it’s not elsewhere.

                              1. 2

                                The other day I returned to a Python package I hadn’t touched in about a year. The actual Python dependencies portion of updating it was done in a few minutes: I updated the supported versions of Python to those currently supported by upstream, did the same for the supported versions of Django, and then had to change a whopping four lines of code, all in a unit-test file, to deal with a deprecation in Django that had finally been removed.

                                The entire remainder of getting it ready for a new release was fighting with CI — updating from v1 to v3 of the GitHub Actions tasks for Python, which I mostly did by copy/pasting from a package by someone else who I trust.

                                I mention this because while you have anecdotes about Go projects updating more or less seamlessly, I have just as many about Python projects, and other people in this thread have anecdotes about Go projects breaking in ways they found annoying.

                                All of which is to say that you should stop trying to extrapolate from your anecdata to “Go is stable and values stability, while Python is not and does not”, because it just ends up looking silly when other people show up with their anecdata. Python is not uniquely “unstable” and neither Go nor Rust are uniquely “stable”. At best, some projects are sometimes lucky enough that they can give the false impression of stability in the language/ecosystem, despite the fact that the language/ecosystem is always moving on. And that’s why I have said, over and over, that the thing to do is embrace and accept change and build processes around it. Otherwise, you’re likely to wake up one day to find out that what you thought was stable and unchanging was neither, and that you are in for a lot of trouble.

                                1. 3

                                  When I get a chance, I thought of an equivalently old Python package for me to try updating. I’ll try to do it this weekend or next week.

                                  But I just don’t buy this:

                                  Python is not uniquely “unstable” and neither Go nor Rust are uniquely “stable”.

                                  I don’t have experience with Rust, so I have no idea there. I do have years of working in Python, JavaScript, and Go and my experience is uniform: Python and JavaScript routinely have problems that make installing/updating take a workday, and Go does not. I’ve already given a lot of concrete examples, and I’m sure I could dig through my git history and find more. At a certain point, all I can say is this is my experience and if it’s not yours, great.

                                  1. 2

                                    You’re still missing the point I’m trying to make, though, because you keep diving for anecdotes to support your case, and I keep trying to remind you that if we allow generalizing from anecdotes then your own claims will get contradicted, because there are people who can bring similar anecdotes about languages like Go that you think don’t have this “problem”.

                                    My stance here is and always has been that no language or ecosystem is free of the need to keep up with dependencies and no language or ecosystem is free from breaking changes. People in this comment thread have posted experiences with Go breaking on them and you’ve mostly just ignored that or disallowed generalizations from them, while insisting that your own anecdotes support generalizations, about the objective state of particular languages/ecosystems.

                                    That is what I’m trying to get you to see, and trying to break you out of. No number of anecdotes one way or another will make your case for you, because the issue is not an insufficient number of presented anecdotes.

                                    At a certain point, all I can say is this is my experience and if it’s not yours, great.

                                    This is very close to where I’m trying to lead you, but

                                    • You never actually just say that and stop — you always feel a need to throw on another anecdote and then insist that your experience generalizes to objective statements about particular languages/ecosystems, and that’s where it goes off the rails.
                                    • You never really accept other people having experiences that don’t match yours, and thus disputing your generalizations. I don’t have the kinds of problems you do with Python. You don’t have the kinds of problems other people have had with Go. But I’m doing my best to acknowledge experiences other than my own when I say that no language/ecosystem is free of this issue: I expect that there will be people who do run into it in Python, and also in Go, and also in Rust, and also in every other language/ecosystem. You seem to be trying to erase the experiences of people who run into it in languages that you subjectively don’t believe have this problem, because it doesn’t fit the “this language has it, that language doesn’t” generalization you want to make.
                                    1. 2

                                      your own claims will get contradicted, because there are people who can bring similar anecdotes about languages like Go that you think don’t have this “problem”.

                                      I have given a ton of anecdotes and done two experiments in support of my view. On the other side, there is your a priori assertion that all ecosystems have the same problems (but is it of the same magnitude?) and an unreadably long article by a pro-Rust troll. If other people have anecdotes about Go being hard to upgrade, I’m happy to read them (assuming they can get to a point in less than 10,000 words) and theorize about why someone else might have that problem when I don’t. But that hasn’t happened in this thread.

                                      1. 3

                                        Well, right here in this thread someone mentioned problems with upgrading in Go. But the way you and another user were trampling all criticism of Go with insults — “troll”, “clickbait”, and so on — literally drove that person out of the thread.

                                        I honestly don’t know what else to tell you. It seems very clear that you’re not prepared to hear anything that contradicts the narrative you’ve got going, so I guess I’ll bow out too since it’s pointless to continue trying to get you to acknowledge stuff that was literally right in front of you.

                                        1. 1

                                          I could never tell what the actual problems were based on the links posted by m0th were. They linked to long pieces with no summaries, so while I would love to comment, I cannot. Maybe it’s because they felt targeted by ad hominem. I have a different theory for why, which is that the criticisms were scattershot and not serious. Again, if they want to come back and provide a useable summary, great.

                                          1. 1

                                            And yet I’d bet anything that if you’d been given short concise statements of problems you’d dismiss them as being trivial or minor on those grounds. Like someone else already said, I simply cannot assume that you’re actually trying in good faith to engage with criticism of a thing you like; instead all I’ve seen you do is smear and deflect and dismiss without argument.

                                            1. 1

                                              If you call this “without argument” I don’t know what to say. I really feel that the “without argument” side is yours, and it is very frustrating to me, because you’re a writer whose work I respect which makes it very hard for me to let this go. But when you write things like “anecdotes don’t count”… What is a personal dev blog but anecdotes? I agree that supporters of language X can be vociferous and annoying, and Go is one such X. In that case of Go, the vociferous attitude comes from having been attacked as using a “bad language” by people like fasterthanlime and our own experience of initially thinking things like the v2 are dumb and then slowly seeing the benefits and defending them. I agree that my initial claim was a bit too glib in its characterization, but I stand by a less inflammatory version of the same idea. I don’t agree that anecdotes aren’t the data of software engineering, and I don’t agree it’s somehow impossible to characterize software ecosystems with the understanding that any generalization will always be at best partial and incomplete but nevertheless it’s better to have the generalization than not.

                                              1. 2

                                                People brought up criticism of Go. You didn’t engage with it or argue with the points made — you ignored them, or dismissed them as too long to be worth your time to read, or just outright insulted the author of one piece of Go criticism.

                                                It’s hard for me to see a way to take this as good faith. It appears that you like Go, which is fine! Same with Python: if you don’t like it, then don’t like it — that’s fine!

                                                What’s not fine is the double-standard “my anecdotes are generalizable to broad claims about the language/ecosystem as a whole, but other people’s anecdotes are not”. Which is basically what you’re doing. If your anecdotes about Python generalize, then so do mine and so do other people’s anecdotes about Go. Which would then contradict the claims you want to make, which is probably why you’re being so cagey about not allowing others’ anecdotes to generalize while insisting that yours do. But again it’s going to be, at least, extremely difficult to take that as a good-faith argument.

                                                1. 1

                                                  When I engage with the criticism, I’m just dismissing it. If I don’t engage because I don’t have enough detail (or drowning in irrelevant details so I can’t tell why monotonic time is supposedly bad), I’m ignoring it. It’s no win.

                                                  1. 2

                                                    As far as I can tell the only “engagement” you’ve given to criticism of Go was the second paragraph in this comment, and I think that’s being charitable since it’s also possible to read as a “well, this breaking change didn’t count, and it just means Go is great instead of the greatest”. If I said Python’s stability guarantees are good but just “don’t go far enough”, I doubt you’d view it charitably.

                                                    You have, on the other hand, repeatedly dismissed critiques both by users in this thread and linked to on other sites as being too long or too “scattershot” or “fair to handwave … away”. Again: if I tried pulling that sort of thing in defense of Python you would, I hope, call me on it. You’re doing it here in defense of Go. I’m calling you on it.

                                                    1.  

                                                      I wrote a long reply, decided to sleep on it, and I give up. You haven’t conceded any points. You’ve repeatedly accused me of bad faith. You’ve decided Python is as good as it gets and by definition nothing else can be better in some ways but not others. All I can say is I didn’t invent the phrase “the problem with Python”. Other people feel this way too. Maybe we’re wrong, and everything has the same problem to the same degree. I don’t think so though.

                                      2. 1

                                        You seem to be simultaneously saying there is nothing especially broken with python while defending the culture of constantly breaking changes and saying it is inevitable. I think your attitude sums up the problem, there are a lot of enablers.

                                        1. 3

                                          This thread started out with an accusation that there is a problem that uniquely exists in certain languages, and does not exist at all in others. People were very confidently stating not that the breaking changes in Go are less frequent, or less annoying, or more justified — people were very confidently stating that breaking changes simply do not exist at all in Go.

                                          Don’t believe me? Here, and a lot of the rest of this sub-thread is people trying to quibble about “oh well that was just a change to (thing that shouldn’t count)” or explain “well these changes were justified and tolerable while those other languages’ changes aren’t” in order to somehow cling to the notion that Go is a bastion of perfect stable compatibility, even in the face of solid evidence that it isn’t.

                                          And I’m sorry if people don’t like to hear it, but I’ve just gotta call bullshit on that. Every language and ecosystem has breaking changes. There is no magic in Go that makes it somehow unchanging and perfectly compatible forever, nor is there any magic in the ecosystem that somehow makes all maintainers good stewards who never ever make unjustified changes.

                                          Still, people seem to be wildly exaggerating both the frequency of breaking changes in the languages they want to criticize, while minimizing for the languages they want to praise. It’s very human and very subjective, and very not a good way to have a reasoned discussion about this.

                                          Especially when it’s coupled with very obvious bad-faith tactics like the way critics of Go keep being dismissed or even smeared in this thread.

                                          If you dislike Python, then by all means dislike it. There are things I dislike about it. But there’s way too much in this thread, and in our industry, of people being unable to handle anything other than extremes — something is either 100% good or 0%, either completely perfectly backwards-compatible always or never — and of very clearly contradicting themselves and making really bad arguments to try to justify their subjective dislikes. Just come out and say you don’t like a thing and move on. You don’t also have to prove that it’s the worst in order to justify your dislike.

                                          1. 2

                                            I don’t know if python is especially bad. I personally found npm projects I have tried break when updating dependencies a few years later, and I have not had that experience in Go. Maybe I am just lucky.

                                            1. 1

                                              It seems to me that the disconnect here is about the scope of what constitutes “breaking changes” in a language. There certainly isn’t an objective definition! Some people consider only the core language and it’s standard library, and others include everything out to its tooling.

                                        2. 1

                                          Okay, I tried this with a Datasette project from around the same time. (It was actually deployed again in early 2020, so it’s a bit fresher than the Go project, but whatever, close enough.) Again, Node didn’t work. I think the issue with that is that libsass is dead and doesn’t compile anymore, so you need to switch to dart-sass instead. In all likelihood, the fastest solution to the Node issues is to drop all of the dependencies and just start over from scratch with only my user code, since the dependencies were just there to build a Vue project.

                                          On the Python side, it wouldn’t work with Python 3.9, but when I used Python 3.7, I got it to run again. Terminal output is below. It only took 15 minutes to get it going, but compare this to Go, which works with the current version of Go even though the package predates modules (which caused a lot of breakage not covered by the Go 1 guarantee) and I got the dependencies upgraded in a total of 5 minutes. By contrast, the Python installations all took long enough that they break flow: since the installation is going to take a while, I switch away from my Terminal, which is chance for me to get distracted and lose my place. I think this project did pretty well because it used your recommended pattern of having a requirements-freeze.txt file and it had a Bash script to automate the actual install commands. But the error when UVLoop was broken was pretty demoralizing: I have no idea how I would fix it, so getting up to Python 3.9 or 3.10 would probably involve a lot more Googling than I’m willing to do for an internet comments example. Again, the simplest fix might be to just blow away what I have now and start from scratch. I think Datasette has been relatively stable in spite of being <1.0, so I suspect that it wouldn’t be that hard to get it working, but again, it’s more than I want to do for an example. A nice thing about Go is that most dependencies don’t use C, so when something does go wrong, like that middleware that was broken in the other project, you aren’t confronted with errors in a language you don’t know using a build system you don’t understand. In general, it’s just much less intimidating to get a Go project back up to speed.

                                          So this is fairly reflective of my lived experience: Node projects, especially those that use Webpack, break in ways that are more or less unfixable and need to be restarted from scratch; Python projects can be kept running if you are willing to pin old versions of Python but give a lot of scary compiler errors and don’t have clear paths forward; Go projects can typically be upgraded by typing go get -u ./... and maybe reading some release notes somewhere. Go isn’t perfect and there are still problems, but the quantity of problems is so much less than it creates a qualitative difference in feeling.

                                          $ gh repo clone baltimore-sun-data/salaries-datasette
                                          Cloning into 'salaries-datasette'...
                                          remote: Enumerating objects: 1017, done.
                                          remote: Counting objects: 100% (94/94), done.
                                          remote: Compressing objects: 100% (72/72), done.
                                          remote: Total 1017 (delta 63), reused 23 (delta 20), pack-reused 923
                                          Receiving objects: 100% (1017/1017), 53.78 MiB | 4.25 MiB/s, done.
                                          Resolving deltas: 100% (568/568), done.
                                          Updating files: 100% (74/74), done.
                                          (Sat, May 21  12:45:40 PM)
                                          $ cd salaries-datasette/
                                          (Sat, May 21  12:45:54 PM) (master|✔)
                                          $ more README.md
                                          # salaries-datasette
                                          Public salary data acquired by the Baltimore Sun. Currently, we just have data from the state of Maryland for 2017.
                                          
                                          ## Usage
                                          
                                          Run `./run.sh setup` to install locally. The script assumes you have either Python 3 or Homebrew for Mac installed. Run `./run.sh setup-frontend` to install front end dependencies.
                                          
                                          Run `./run.sh create-db` to create a SQLite database out of the provided CSVs.
                                          
                                          Run `./run.sh` or `./run.sh serve` to run server at http://localhost:9001.
                                          
                                          Run the JS/CSS frontend server in another tab with `./run.sh frontend`.
                                          
                                          `./run.sh format` will format Python and Javascript code according to the coding standards of the project.
                                          
                                          `Dockerfile` is also provided for running/deploying with Docker. The image can be built with `./run.sh docker-build` and tested with `./run.sh docker`. The server only responds to correct hostnames (not localhost), so edit `/etc/hosts` to add `127.0.0.1   local.salaries.news.baltimoresun.com` and then test http://local.salaries.news.baltimoresun.com in the browser.
                                          (Sat, May 21  12:46:06 PM) (master|✔)
                                          $ ./run.sh setup
                                          
                                          snip a ton of output from installing things including a lot of scary errors
                                          
                                          × Encountered error while trying to install package.
                                          ╰─> uvloop
                                          
                                          note: This is an issue with the package mentioned above, not pip.
                                          hint: See above for output from the failure.
                                          # status: 1 #
                                          (Sat, May 21  12:49:40 PM) (master|✔)
                                          $ # by reading the DOCKERFILE, I learn that this used Python 3.7 when it was made
                                          (Sat, May 21  12:51:16 PM) (master|✔)
                                          $ pyenv install 3.7.13
                                          python-build: use openssl@1.1 from homebrew
                                          python-build: use readline from homebrew
                                          Downloading Python-3.7.13.tar.xz...
                                          -> https://www.python.org/ftp/python/3.7.13/Python-3.7.13.tar.xz
                                          Installing Python-3.7.13...
                                          (Stripping trailing CRs from patch.)
                                          patching file Doc/library/ctypes.rst
                                          (Stripping trailing CRs from patch.)
                                          patching file Lib/test/test_unicode.py
                                          (Stripping trailing CRs from patch.)
                                          patching file Modules/_ctypes/_ctypes.c
                                          (Stripping trailing CRs from patch.)
                                          patching file Modules/_ctypes/callproc.c
                                          (Stripping trailing CRs from patch.)
                                          patching file Modules/_ctypes/ctypes.h
                                          (Stripping trailing CRs from patch.)
                                          patching file setup.py
                                          (Stripping trailing CRs from patch.)
                                          patching file 'Misc/NEWS.d/next/Core and Builtins/2020-06-30-04-44-29.bpo-41100.PJwA6F.rst'
                                          (Stripping trailing CRs from patch.)
                                          patching file Modules/_decimal/libmpdec/mpdecimal.h
                                          (Stripping trailing CRs from patch.)
                                          patching file setup.py
                                          python-build: use tcl-tk from homebrew
                                          python-build: use readline from homebrew
                                          python-build: use zlib from xcode sdk
                                          Installed Python-3.7.13 to /Users/adhoc/.pyenv/versions/3.7.13
                                          
                                          (Sat, May 21  12:55:00 PM) (master|✔)
                                          $ ./run.sh setup
                                          
                                          snip
                                          
                                          × Encountered error while trying to install package.
                                          ╰─> uvloop
                                          
                                          note: This is an issue with the package mentioned above, not pip.
                                          hint: See above for output from the failure.
                                          # status: 1 #
                                          (Sat, May 21  12:57:08 PM) (master|✔)
                                          $ # I become worried that maybe Pyenv didn't activate for some reason, so I try explicitly adding it to my PATH
                                          (Sat, May 21  12:59:30 PM) (master|✔)
                                          $ PATH=$HOME/.pyenv/versions/3.7.13/bin/:$PATH ./run.sh setup
                                          
                                          snip
                                          
                                          success!
                                          
                                          (Sat, May 21  01:01:58 PM) (master|✔)
                                          $ 
                                          
                            2. 3

                              This thread has grown a lot overnight while I was sleeping! I still haven’t caught up, but here is my top of head takeaway:

                              I think it’s fair to complain that the Go 1 stability guarantee doesn’t go far enough, but it seems like some people elsewhere in the thread are trying to claim that adding monotonic time somehow breaks the guarantee, which makes no sense to me. At this point, someone citing Fasterthanlime basically means they don’t know anything about Go, IMO because he has been so egregious in his misrepresentation of the language. Just recently, I had to pin a specific subversion of Go 1.18 in my tests because I needed a particular behavior for the Go tool. I don’t consider that to have been the Go team breaking the stability guarantee, just an example of how you can run into the limits of it when you’re talking about the tooling.

                              Obviously, it’s going to be impossible to never break anything. (Which is what I take from your points 1 and 2.) If nothing else, security problems can force breaking changes. Certainly, you need to get to a point where you’re happy enough to commit to a design before you stabilize it: Go was not stable at all before version 1. JavaScript wasn’t stable before ECMA etc.

                              But the question to me is whether the upstream developers take breaking changes seriously or commit them wantonly. To rephrase your points:

                              1. Projects which accept that breaking changes are fact of software development, so they do it whenever it’s convenient.

                              2. Projects which accept that breaking changes are fact of software development, so they do it as little as possible.

                              I was being a bit too flip when I wrote “You ‘just’ don’t make breaking changes.” That’s like saying, you just don’t write bugs. It is unavoidable sometimes. But there is a qualitative difference as an end developer in relying on a project which attempts to avoid breaking changes and one which does not.

                              In Node, I routinely run into software that will not run on the latest versions of Node. When a new version of Node comes out, I don’t think “Oh great, more speed, more features!” I think, “Ugh, crap, what’s going to break this time?” I had a hard to diagnose break in Babel (a very popular library!) that was caused not by a major version jump in Node, but a minor version bump. It was a waste of a day of development time for me for no reason. You wrote “as long as I pay the hosting bill there is no technical reason why it would suddenly stop working.” But in this case, there wasn’t anything I did intentionally which broke my setup. I just hadn’t pinned my version of Node, Homebrew moved up by a minor version because of some other thing, and suddenly I lost a workday. It also broke production because prod was only pinned to the major version not the minor or patch.

                              A similar example was that I had an Amazon ECS server using a Docker image to serve some Python app, and one day it just stopped working in prod. The problem was that when the Dockerfile was written, it didn’t specify the version of Python, and then the version where async went from a semi-keyword to a full keyword came out and broke the dependencies I was using. It wouldn’t have mattered if the Docker image had been already baked, but the way this project was setup, the Docker image would be periodically rebuilt from the Dockerfile whenever things would restart or something. That at least was relatively easy to track down and fix because the change of Python versions was noticeable once I started debugging it.

                              You call the /v2 thing a “hack” and it is ugly and inelegant, but it does solve this problem: when you make a breaking change, let users upgrade at their own pace, instead of having them accidentally get moved onto the new thing without being aware of it. (In browser JS, "strict mode" and type="module" also have the effect of being opt-in upgrades!) That’s really the core of the so-called “Python problem” to me. Just let me decide when to work through the breaking changes. I’m not expecting eternal support or whatever. I just want something that works today to work tomorrow unless I press the big red “attempt upgrade” button.

                              1. 5

                                At this point, someone citing Fasterthanlime basically means they don’t know anything about Go, IMO because he has been so egregious in his misrepresentation of the language.

                                I’m the one who cited the monotonic time issue. I’m having trouble seeing good faith in this statement, so I’ll bow out of this thread after this. But just so you understand that this is adamantly not the case: I’ve written Go since before 1.0, contributing to some of the largest projects in the ecosystem, and as a manager moved several teams over to using it (from Python, no less.) I also don’t think those credentials should be necessary for a critique.

                                I had a hard to diagnose break in Babel (a very popular library!) that was caused not by a major version jump in Node, but a minor version bump.

                                To reiterate, this has happened to me with minor version bumps in Go, due to both modules and stdlib changes. This is even worse because it was Go itself, not a third-party library.

                                You call the /v2 thing a “hack” and it is ugly and inelegant, but it does solve this problem: when you make a breaking change, let users upgrade at their own pace

                                This actually touches on a major reason why Go’s ecosystem could be so unstable before modules: you could either vendor which had its own can of worms, or rely on authors using this hack. Both patterns emerged as common practice only after years of Go devs experiencing breaking changes in libraries. You could argue that those instabilities don’t apply to Go itself, which I suppose is fair, but that applies to your argument about Babel as well.

                            3. 13

                              Go makes breaking changes all of the time. The last one that bit me was when modules were enabled by default. Suddenly packages starting behaving differently depending on a variety of factors, including the version number of the package: https://stackoverflow.com/questions/57355929/what-does-incompatible-in-go-mod-mean-will-it-cause-harm/57372286#57372286

                              Python at least had the sense to bundle up all the breakages in a major version change, which was released 15 years ago.

                              1. 8

                                Eh no. Python does not follow semantic versioning and makes intentionally breaking changes between minor versions. In fact Python 3.x releases come with documentation titled “Porting to Python 3.x” which lists all breaking changes made intentionally.

                                1. 6

                                  Python makes breaking stdlib changes in minor version releases. Not even remotely the same as a tooling change.

                                  1. 3

                                    I’ve never been affected by stdlib changes in python in a minor release. I have by go, where it suddenly stopped respecting system DNS settings. Or there were the backwards-incompatible changes to time, maybe best summarized here.

                                    1. 4

                                      I believe you, but you are lucky. With search I found things like https://github.com/wazuh/wazuh/issues/13365 which matches my experience.

                                      1. 2

                                        I know this isn’t likely to change anyone’s mind, but the thing you linked is an example of something that had been deprecated and raising deprecation warnings for years. Here’s an example warning I get from a Python 3.7 install I had lying around (oldest I could find, I tend not to keep EOL’d Pythons on my personal laptop):

                                        DeprecationWarning: Using or importing the ABCs from ‘collections’ instead of from ‘collections.abc’ is deprecated since Python 3.3,and in 3.9 it will stop working

                                        And it appears they actually held off and didn’t finally remove that until 3.10. That’s at least four years after Python 3.7 (which issued that warning). It’s nearly ten years after Python 3.3.

                                        Python does use a rolling deprecation cycle, yes. So do some major Python projects like Django. This means you should ensure you’re bubbling up deprecation warnings in your CI, and probably read release notes when new versions come out, yes.

                                        But these things don’t just come surprise out of nowhere; they’re documented, they raise warnings, they’re incorporated into the release cycles. Knowing how Python’s deprecation cycles work is, for a Python user, the same kind of table stakes as knowing how semantic versioning works is for a Rust/cargo/crates user – if you updated a crate across a major version bump and it broke your code, everyone would tell you that you could have seen that coming.

                                      2. 2

                                        It happens, no doubt, but IME Python’s changes are much more egregious than Go’s few changes over the years. Where Go does make changes, they are typically as solutions to bugs, not gratuitous API changes.

                                        Also, speaking personally, I try to be as objective as possible and fasterthanli.me is not an objective source in any sense. It’s clickbait. There’s no pretence of objectivity.

                                        1. 13

                                          I’d like to point out that this thread has gone from a claim that Go has maintained backwards compatibility to, now, a claim that Go’s backwards-incompatible changes just aren’t as “egregious” as Python’s, and to what’s basically an ad hominem attack on someone who criticized Go.

                                          Which is kind of a microcosm of this whole framing of “Python problem” or “Node problem”. What it’s really about is not some magical language and ecosystem that never has backwards-incompatible changes, what it’s about is subjective taste. You think Go’s breaking changes are not as “egregious” and are “solutions to bugs” while Python’s are “gratuitous”. But that’s a subjective judgment based on your tastes and opinions. Someone else can have an opposite and equally-valid subjective opinion.

                                          Or, more bluntly: “No breaking changes” nearly always turns out to actually mean “Breaking changes, but only ones I personally think are justified/tolerable, and I don’t think yours are”. Which is where this thread predictably went within the space of just a few replies.

                                          Getting back to my original claim: change is inevitable. Entities which produce software can adapt to it and make it a normal and expected part of their processes, or they can suffer the consequences of not doing so. There is no third option for “all external change stops”. Nothing that lives does so changelessly.

                                          1. 3

                                            Or, more bluntly: “No breaking changes” nearly always turns out to actually mean “Breaking changes, but only ones I personally think are justified/tolerable, and I don’t think yours are”. Which is where this thread predictably went within the space of just a few replies.

                                            No I don’t think so. It has nothing to do with opinion and everything to do with experience. What someone sees directly is how they perceive reality. I’m expressing my perception of reality as someone who has experience of both Python and Go, and m0th is expressing their experience.

                                            I’m not minimising m0th’s view, which is why I phrased it as “in my experience”.

                                            Getting back to my original claim: change is inevitable. Entities which produce software can adapt to it and make it a normal and expected part of their processes, or they can suffer the consequences of not doing so. There is no third option for “all external change stops”. Nothing that lives does so changelessly.

                                            Change is inevitable, I agree, but I do think the degree matters. Python makes breaking changes often, removing APIs, etc. Go does not and only with very good reason.

                                            1. 3

                                              Change is inevitable, I agree, but I do think the degree matters. Python makes breaking changes often, removing APIs, etc. Go does not and only with very good reason.

                                              Again, the original claim at the start was that there are languages which don’t have breaking changes, and Go was specifically named as an example. That has now been walked back to the kinds of statements you are making. And your statements are, effectively, just that in your opinion one language’s (Go) breaking changes are justified and not too frequent, while another language’s (Python) breaking changes are not justified and too frequent. Which is just you stating your own personal tastes and opinions. And it’s fine as long as you are willing to admit that. It is not so fine to present one’s personal tastes and opinions as if they are objective facts. It also is not so fine to engage in the kind of ad hominem you did about criticism of Go.

                                              1. 3

                                                Again, the original claim at the start was that there are languages which don’t have breaking changes, and Go was specifically named as an example.

                                                I didn’t make that claim, so I’m not sure why you’re arguing with me about it.

                                                Which is just you stating your own personal tastes and opinions. And it’s fine as long as you are willing to admit that.

                                                I did? I explicitly said “In My Experience”. I’m not sure how I can be any clearer.

                                                It is not so fine to present one’s personal tastes and opinions as if they are objective facts. It also is not so fine to engage in the kind of ad hominem you did about criticism of Go.

                                                What are you even talking about? I legitimately can’t even understand what you’re referring to. Where’s the “ad hominem” comment I made? I think the most controversial thing I said was

                                                “Python makes breaking stdlib changes in minor version releases.”

                                                Which is objectively true as mentioned by other commenters. I made no judgement about whether it was justified or not. It’s also not “ad hominem”, which would require Python to have a position on this.

                                                Anyway, I think you’re taking this way too personally for some reason. I like Python, I have used it for many years. But I’m out.

                                                1. 3

                                                  Where’s the “ad hominem” comment I made?

                                                  IIUC, ubernostrum is referring to you explaining that fasterthanli.me is not a reliable source of information. That’s not an ad hominem though. His attacks are so scattershot that if someone cites them, it’s totally fair to just handwave it away.

                                                  1. 3

                                                    Where’s the “ad hominem” comment I made?

                                                    It’s this:

                                                    Also, speaking personally, I try to be as objective as possible and fasterthanli.me is not an objective source in any sense. It’s clickbait. There’s no pretence of objectivity.

                                                    You don’t bother to engage with the content, just brush off the author with a quick smear and then move on. Which is a problem, because the content is reasonably well-argued, from my perspective as someone who has a bit of Go experience and initially couldn’t quite describe why it rubbed me the wrong way. Putting into words the way that Go (which is not unique in this, but is a prominent example of it) likes to pretend complex things are simple, rather than just admitting they’re complex and dealing with it, was extremely useful for me, both for giving me a way to talk about what bugged me in Go and because it relates to things I’ve ranted about in the Python world previously (most notably why Python 3’s string changes were the right thing to do).

                                                  2. 2

                                                    Go the language doesn’t have breaking changes, in the sense that code written against a 1.0 language spec will — generally— continue to compile and run the same way against any 1.x language spec compiler. This isn’t an absolute statement of fact, but it’s a design principle that’s taken very seriously and is violated very rarely. The tooling doesn’t necessarily abide the same rules.

                                                    1. 1

                                                      Your comment is a bit of a roller coaster.

                                                      • Starts with “doesn’t have breaking changes”
                                                      • Immediately qualifies with “in the sense that…”
                                                      • Then walks it back with “This isn’t an absolute statement of fact”
                                                      • Then walks it back even further with “is violated very rarely”
                                                      • Then throws it all out the window with “The tooling doesn’t necessarily abide the same rules”

                                                      I’m not even sure what that’s trying to say.

                                      3. 9

                                        Go 1 has been stable for 10 years now.

                                        If you just ignore all those breaking changes they made..

                                        1. 1

                                          I only remember Modules. After Modules landed I never experienced any breaking build when updating to a new Go version. A whole different story was updating Java versions and the dozens of subtle ways they can break your service, especially at run-time (caused by some Spring DI magic).

                                          1. 1

                                            What breaking language changes have been made?

                                            1. 3

                                              Modules seems like the biggest change.

                                              1. 3

                                                I mean, Go module is not part of Go 1 stability guarantee. In my opinion, this shows how limited Go’s stability guarantee is. Go 1 is stable, but Go is not, at least if you are using “go build” to build your Go code.

                                                1. 2

                                                  I agree but that’s not a language change, and the impact is not as significant as random language changes. I can still use and build a package from 8 years ago with no issue. And whatever tool they happened to use to manage dependencies 8 years ago will still work fine (probably).

                                                  1. 3

                                                    I saw some breaking changes in one of our old projects. Written in the Go v1.4 era, IIRC. I checked it with a Go v1.14 release, and boom, it doesn’t compile due to the module changes.

                                                    Yes, it wasn’t that hard to fix (it only took a few minutes of Internet searching), but I still count that as a breaking change.

                                        2. 2

                                          When was there ever a breaking change in a new version of ecmascript? Node is not a language.

                                          1. 4

                                            There’s a bunch of things that vary in stability.

                                            • V8 the interpreter breaks working JS code very seldom
                                            • The libraries that come with Node break JS code a little more often, but still IME not very often.
                                            • V8 breaks native extensions very often. The NodeJS ecosystem discourages writing them because of this.
                                            • Some add-on packages from npm break their consumers all the time.

                                            Many packages are extremely careful not to break consumers. Others are less so. The experience you have with backwards compatibility tends to track the backwards compatibility stance of the worst thing in your entire dependency tree. When you have tens of thousands of transitive dependencies, you usually end up seeing 99.99%-ile bad behaviour somewhere in there at least once.

                                            1. 1

                                              The core problem is that a handful of “core” packages break, and nodes ecosystem is way too much about plugins, so many things that you use have 3 layers to them (all maintained by different people)

                                              The ecosystem would be a lot more stable if we were vendoring in packages more

                                            2. 2

                                              Node is a development target. The pure abstract notion of a “language” doesn’t really matter here, because people write code for Node specifically.

                                              And Node does make breaking changes. It literally makes semver-major releases, with backwards-incompatible changes that can break existing npm packages (mainly due to changes in the native API, but there also have been changes to Node’s standard library).

                                              For example, I can’t build any projects that used Gulp v3. Node broke packages that it depends on, and I either have to run deprecated/unsupported/outdated version of Node, or rewrite my build scripts. OTOH a Rust/Cargo project I’ve developed at the same time still works with the latest version of Rust/Cargo released yesterday.

                                              1. 2

                                                Yes, that’s why I said “Node ecosystem” which breaks all the damn time and not “browser ECMAScript” which has not broken since standardization.

                                                1. 2

                                                  The quote you posted says language, not ecosystem. Your comparison was a false equivalency.

                                                2. 1

                                                  ecmascript itself is a language but not a language implementation, so while you can write a lot of code in ecmascript, at the end of the day the ecmascript specification can’t run it, so you’ll need to run it using an implementation, that’s why people are talking about the Node ecosystem, the language didn’t break the ecosystem did

                                              1. 3

                                                I was going to make a joke comment about using Jepsen here, but seems this is already part of the test suite! This is super impressive, and I’m sure a very cool learning project

                                                1. 1

                                                  Are they? The readme says the opposite:

                                                  Jepsen tests, or similar system-wide correctness and reliability tests, are desirable but not yet implemented.

                                                  1. 1

                                                    Yes you’re right! I seem to have failed a bit at reading comprehension….

                                                1. 22

                                                  I have this great book, the book of mathematical counterexamples. It’s filled with things like “functions that are continuous without being integrable” and the like. Very helpful to re-confirm that, indeed, some implication does not go the other way.

                                                  But it’s also kind of interesting because you start thinking about the edges of the statement. For example, JSON is not a YAML subset, but is JSON through %yaml 1.2 ------- prepending program a YAML subset? What qualities are missing to make it a subset?

                                                  One might consider this to not matter on the ground, but this is applicable in loads of places! Maybe some database operations are susceptible to race conditions, but you can carve out specific ways of doing things to make them no longer susceptible. Skylark is “Python but without infinite loops”, meaning that you can write “python” that actually is guaranteed to terminate!

                                                  We could defnitely use the book of computer science counterexamples.

                                                  1. 7

                                                    Tangential aside on a good comment: continuity does imply that a function is integrable! It’s the converse that doesn’t hold: not every integrable function is continuous, and maybe more interestingly, not every integrable function is the derivative of some other function.

                                                  1. 2

                                                    So… no QA?

                                                    1. 13

                                                      QA is a much broader topic than “gating deployments on manual testing” which is what you seem to imply. If you do many of the other things right, you might find that gating on manual testing no longer catches enough defects to be worth it.

                                                      In fact, gating on manual testing actually works counter to many other good QA practises – some of which are described in TFA, like small batches.

                                                      1. 2

                                                        This. Sometimes you need to gate this way, but it’s a sign of a problem, not a feature to bring everywhere.

                                                      2. 10

                                                        QA is integrated into development in the form of full tests.

                                                        Having QA be an extra few month process is a sign of less than ideal development practices.

                                                        1. 8

                                                          Hopefully more companies take this approach, it is easier to compete with companies that don’t have QA.

                                                          1. 13

                                                            Honestly I’ve never worked anywhere where I felt like a QA organization added much value. They would automate tests for product requirements which were usually covered by product-dev test suites anyway, except the QA tests would take longer to run, they’d be far flakier, and they would take much longer to identify the cause of failure. Moreover, the additional manual testing they would perform in-band of releases rarely turns up issues that would reasonably block a release (they aren’t usually the ones finding the security issues, for example). It really feels like QA is something that needs to be absorbed into product/dev much like the devops philosophy regarding infrastructure–basically, developers should just learn to write automated tests and think about failure modes during development (perhaps via a design review process if necessary).

                                                            It seems like the thinking behind QA orgs is something like “these well-paid devs spend all of this time writing tests! let’s just hire some dev bootcamp grads for a fraction of the cost of a developer and have them write the tests!”. Unfortunately, writing good tests depends on an intimate understanding of the product requirements and the source code under test as well as strong automation skills, and the QA orgs I’ve worked with rarely tick any of these boxes (once in a while you get a QA engineer who ticks one or more of these boxes, but they’re quickly promoted out of QA).

                                                            1. 2

                                                              I have had an experience where the QA team found a showstopper “go back and fix before our customers get broken” bug.

                                                              Sometimes a long QA cycle can really help, but it’s not something you want to need.

                                                              1. 1

                                                                I don’t doubt that these happen, but plausibly a company without a QA org might’ve done more diligence and caught it early rather than throwing it over the wall to QA. Moreover, even if the QA org caught this one, it must be weighed against the overall inefficiency that the org introduces. Is one show stopper really worth being consistently late to market? In some orgs the answer might be “yes” but in most it probably isn’t (unless “show stopper” means “a bug so serious it sinks the company” by definition).

                                                            2. 6

                                                              As it turns out, not always (e.g. https://spectrum.ieee.org/yahoos-engineers-move-to-coding-without-a-net)

                                                              I have worked at companies with long QA cycles for good reasons - among other things we shipped software on physical device and things like iOS apps where you cannot fix a mistake instantly because of validation. But at a Web-based software company I would also say it is probably not always a good trade-off.

                                                              1. 2

                                                                FWIW, Monzo is mostly accessed through apps on your phone. When they launched the bank you couldn’t even login on their website. Their apps do seem like they’re mostly just browsers accessing some private site, though.

                                                          2. 2

                                                            fast deploys and QA aren’t incompatible. The classic way of handling this is to write code behind feature flags so that code can be integrated into production-esque environments (like a staging env) and handle at various paces.

                                                            This has the added benefit of making it easy to roll out refactors and other pieces of code without having long-running branches that accumulate a lot of stuff. And you can do stuff like release features for a subset of users, do betas, roll back feature releases, all mostly decoupled from the code writing.

                                                            And of course 100 deploys to prod per day in a full CI/CD system is likely a lot of tiny deploys that are just like…. version bumps of libaries for some random service and the like.

                                                            1. 1

                                                              We do QA! This is not something I’m very involved with, so I’ll struggled to give you details. I’d recommend you check out this recent blog post on our approach to QA.

                                                            1. 9

                                                              Ruby does this right “open do..”. Python does it right, “with … do”. Any reasonably wrapped smart resource will catch this at compile time; we used to do this for memory and files in the ’80s. ‘defer’ is just a way to make mistakes.

                                                              1. 10

                                                                Don’t these still require you to opt-in to the correct behavior? You can just forget to use those constructs too.

                                                                1. 2

                                                                  open is the classic example where not using with will still allow you to do your work. But most libs will do with thing() as actual_object: ... . If you do actual_object = thing() then you’re not getting the object you want but just a manager object.

                                                                  The way to get around using with is doing actual_object = thing().__enter__(), which is a bit unwieldy.

                                                              1. 22

                                                                RAII is far from perfect… here are a few complaints:

                                                                1. Drop without error checking is also wrong by default. It may not be a big issue for closing files, but in the truly general case of external resources to-be-freed, you definitely need to handle errors. Consider if you wanted to use RAII for cloud resources, for which you need to use CRUD APIs to create/destroy. If you fail to destroy a resource, you need to remember that so that you can try again or alert.

                                                                2. High-performance resource management utilizes arenas and other bulk acquisition and release patterns. When you bundle a deconstructor/dispose/drop/whatever into some structure, you have to bend over backwards to decouple it later if you wish to avoid the overhead of piecemeal freeing as things go out of scope.

                                                                3. The Unix file API is a terrible example. Entire categories of usage of that API amount to open/write/close and could trivially be replaced by a bulk-write API that is correct-by-default regardless of whether it uses RAII internally. But beyond the common, trivial bulk case, most consumers of the file API actually care about file paths, not file descriptors. Using a descriptor is essentially an optimization to avoid path resolution. Considering the overhead of kernel calls, file system access, etc, this optimization is rarely valuable & can be minimized with a simple TTL cache on the kernel side. Unlike a descriptor-based API, a path-based API doesn’t need a close operation at all – save for some cases where files are being abused as locks or other abstractions that would be better served by their own interfaces.

                                                                4. It encourages bad design in which too many types get tangled up with resource management. To be fair, this is still a cultural problem in Go. I see a lot of func NewFoo() (*Foo, error) which then of course is followed by an error check and potentially a .Close() call. Much more often than not, Foo has no need to manage its resources and could instead have those passed in: foo := &Foo{SomeService: svc} and now you never need to init or cleanup the Foo, nor check any initialization errors. I’ve worked on several services where I have systematically made this change and the result was a substantial reduction in code, ultimately centralizing all resource acquisition and release into essentially one main place where it’s pretty obvious whether or not cleanup is happening.

                                                                1. 3

                                                                  This is super informative, thanks! Probably worth it to turn this comment into a post of its own.

                                                                  1. 3

                                                                    The error handling question for RAII is a very good point! This is honestly where I’m pretty glad with Python’s exception story (is there a bad error? Just blow up! And there’s a good-enough error handling story that you can wrap up your top level to alert nicely). As the code writer, you have no excuse to, at least, just throw an exception if there’s an issue that the user really needs to handle.

                                                                    I’ll quibble with 2 though. I don’t think RAII and arenas conflict too much? So many libraries are actually handlers to managed memory elsewhere, so you don’t have to release memory the instant you destruct your object if you don’t want to. Classically, reference counted references could just decrement a number by 1! I think there’s a a lot of case-by-case analysis here but I feel like common patterns don’t conflict with RAII that much?

                                                                    EDIT: sorry, I guess your point was more about decoupling entirely. I know there are libs that parametrize by allocator, but maybe you meant something even a bit more general

                                                                    1. 2

                                                                      It may not be a big issue for closing files

                                                                      from open(2):

                                                                      A careful programmer will check the return value of close(), since it is quite possible that errors on a previous write(2) operation are reported only on the final close() that releases the open file description. Failing to check the return value when closing a file may lead to silent loss of data. This can especially be observed with NFS and with disk quota.

                                                                      so it’s actually quite important to handle errors from close!

                                                                      The reason for this is that (AFAIK) write is just a request to do an actual write at some later time. This lets Linux coalesce writes/reschedule them without making your code block. As I understand it this is important for performance (and OSs have a long history of lying to applications about when data is written). A path-based API without close would make it difficult to add these kinds of optimizations.

                                                                      1. 1

                                                                        My comment about close not being a big issue is with respect to disposing of the file descriptor resource. The actual contents of the file is another matter entirely.

                                                                        Failing to check the return value when closing a file may lead to silent loss of data.

                                                                        Is that still true if you call fsync first?

                                                                        A path-based API without close would make it difficult to add these kinds of optimizations.

                                                                        Again, I think fsync is relevant. The errors returned from write calls (to either paths or file descriptors) are about things like whether or not you have access to a file that actually exists, not whether or not the transfer to disk was successful.

                                                                        This is also related to a more general set of problems with distributed systems (which includes kernel vs userland) that can be addressed with something like Promise Pipelining.

                                                                      2. 1
                                                                        1. Note that in the context of comparison with defer, it doesn’t improve the defaults that much. The common pattern of defer file.close() doesn’t handle errors either. You’d need to manually set up a bit of shared mutable state to replace the outer return value in the defer callback before the outer function returns. OTOH you could throw from a destructor by default.

                                                                        2. I disagree about “bend over backwards”, because destructors are called automatically, so you have no extra code to refactor. It’s even less work than finding and changing all relevant defers that were releasing resources piecemeal. When resources are owned by a pool, its use looks like your fourth point, and the pool can release them in bulk.

                                                                        3/4 are general API/architecture concerns about resource management, which may be valid, but not really specific to RAII vs defer, which from perspective of these issues are just an implementation detail.

                                                                        1. 1

                                                                          I disagree about “bend over backwards”, because destructors are called automatically, so you have no extra code to refactor

                                                                          You’re assuming you control the library that provides the RAII-based resource. Forget refactoring, thinking only about the initial code being written: If you don’t control the resource providing library, you need to do something unsavory in order to prevent deconstructors from running.

                                                                          1. 1

                                                                            Rust has a ManuallyDrop type wrapper if you need it. It prevents destructors from running on any type, without changing it.

                                                                            Additionally, using types via references never runs destructors when the reference goes out of scope, so if you refactor T to be &T coming from a pool, it just works.

                                                                          2. 1

                                                                            The common pattern of defer doesn’t handle errors either.

                                                                            In Zig you have to handle errors or explicitly discard them, in defer and everywhere else.

                                                                          3. 1

                                                                            Using a descriptor is essentially an optimization to avoid path resolution.

                                                                            I believe it also the point at which permissions are validated.

                                                                            Entire categories of usage of that API amount to open/write/close and could trivially be replaced by a bulk-write API

                                                                            Not quite sure I understand what you mean… Something like Ruby IO.write()? https://ruby-doc.org/core-3.1.2/IO.html#method-c-write

                                                                            1. 3

                                                                              also the point at which permissions are validated

                                                                              I think that’s right, though the same “essentially an optimization” comment applies, although the TTL cache option solution is less applicable.

                                                                              Something like Ruby IO.write()

                                                                              Yeah, pretty much.

                                                                          1. 8

                                                                            Reading through those issues, there seems to be a lot of really surprising issues! And a lot of them, when digging into the fix, seem to be related to code that is trying to be performant.

                                                                            This sort of culture difference is something I’ve seen a lot. In general I try to write correct, easy to review code (at the expense of performance/work duplication). I don’t always succeed (far from it!) but I at least think I have a sense for stuff that is easier or harder to get right.

                                                                            Here, for example, the way Julia tries to figure out the day of the year is through this builtin lookup table. While this feels like the right/most performant solution (and despite leap years being a constant thing, it is easy to forget about them), my dumb first pass at this kind of problem would be to instead do something like start_of_quarter = quarterstart(date); (date-start_of_quarter).days. Definitely less performant! But I’m way more confident in it being correct.

                                                                            I think Python might have an advantage here because it has a lot of non-performant helpers that are fun to write with, so you’re incentivised to write correct (if slower) code.

                                                                            “Code shouldn’t rely on bit twiddling” feels like a hard sell in a language where performance is one of the selling points of the language, but “bugs are very bad! Let’s try to write code that’s as obviously correct as possible” feels like a decent strategy to me.

                                                                            1. 14

                                                                              I gotta say that a big difficulty for trying to do a completely self-hosted setup is just the drudgery of setting up clean A/B deploys and running scripts cleanly, as well as having nice dashboards to see the status of deploys.

                                                                              Lots of this is mostly fixed costs, and it’s not super duper hard, but Heroku offers it out of the box, and for tinier projects it’s great, cuz you can actually get to work super quickly!

                                                                              But what would be awesome is to have a very straightforward “LAMP Stack 2.0” that works well with Git-based deploy cycles. I’m sure there are Heroku-likes that I can self run, and would love to see a run down of the state of the art for this space.

                                                                              1. 5

                                                                                For static sites, it’s very nice to deploy to Netlify because it’s all Git-based, with automatic deploy previews, and you can also do Lambda functions with Netlify for dynamic stuff, but performance suffers if you try to run a dynamic site off of it, because of the cold start times.

                                                                                1. 2

                                                                                  Agree - Netlify is really the Heroku of static sites. If you can’t be bothered to set up the Git integration they even have a “drag and drop” file uploader - it feels like I’m back in 1998 again and updating my website with CuteFTP!

                                                                              1. 1

                                                                                Mypyc is, of course, used or mypy and, I believe now, black.

                                                                                In 2021 I had tried to compile some stuff with mypyc and hit several nasty bugs with it, though. It was application code, not library code, but it was still a bit of an indicator to me that I need to be careful.

                                                                                I think it’s a very good, pragmatic tool. Ultimately I think that the “real” thing that would make sense is … for libraries to be written in systems languages when reasonable. Think about how much stuff goes into an attribute access in python… and then imagine your editor running your Python buffers through that all the time. But this is a great stopgap, and it will only get better IMO.

                                                                                1. 1

                                                                                  for libraries to be written in systems languages when reasonable

                                                                                  Agreed. But we need something richer than C for defining memory-safe APIs with a stable ABI and auto-generated language bindings. I think Microsoft was onto something with COM, but of course it wasn’t perfect, and when they tried to improve on it with WinRT, the industry at large mostly didn’t pay attention.

                                                                                  I’m particularly interested in what the Rust community is starting to do in this area. Rust’s metaprogramming is powerful enough that, at least in theory, one can define a rich API in some subset of Rust, perhaps with the addition of some macros and/or attributes, then auto-generate language bindings from that.

                                                                                1. 24

                                                                                  Am I the only one being completely tired of these rants/language flamewars? Just use whatever works for you, who cares

                                                                                  1. 11

                                                                                    You’re welcome to use whatever language you like, but others (e.g. me) do want to see debates on programming language design, and watch the field advance.

                                                                                    1. 6

                                                                                      Do debates in blogs and internets comments meaningfully advance language design compared to, say, researchers and engineers exploring and experimenting and holding conferences and publishing their findings? I think @thiht was talking about the former.

                                                                                      1. 2

                                                                                        I’m idling in at least four IRC channels on Libera Chat right now with researchers who regularly publish. Two of those channels are dedicated to programming language theory, design, and implementation. One of these channels is regularly filled with the sort of aggressive discussion that folks are tired of reading. I don’t know whether the flamewars help advance the state of the art, but they seem to be common among some research communities.

                                                                                        1. 5

                                                                                          Do you find that the researchers, who publish, are partaking in the aggressive discussions? I used to hang out in a couple Plan 9/9front-related channels, and something interesting I noticed is that among the small percentage of people there who made regular contributions (by which I mean code) to 9front, they participated in aggressive, flamey discussion less often than those that didn’t make contributions, and the one who seemed to contribute the most to 9front was also one of the most level-headed people there.

                                                                                          1. 2

                                                                                            It’s been a while since I’ve been in academia (I was focusing on the intersection of PLT and networking), and when I was there none of the researchers bothered with this sort of quotidian language politics. Most of them were focused around the languages/concepts/papers they were working with and many of them didn’t actually use their languages/ideas in real-world situations (nor should they, the job of a researcher is to research not to engineer.) There was plenty of drama in academia but not about who was using which programming language. It had more to do with grant applications and conference politics. I remember only encountering this sort of angryposting about programming languages in online non-academic discussions on PLT.

                                                                                            Now this may have changed. I haven’t been in academia in about a decade now. The lines between “researcher” and “practitioner” may have even become more porous. But I found academics much more focused on the task at hand than the culture around programming languages among non-academics. To some extent academics can’t be too critical because the creator of an academic language may be a reviewer for an academic’s paper submission at a conference.

                                                                                            1. 2

                                                                                              I’d say that about half of the aggressive folks have published programming languages or PLT/PLD research. I know what you’re saying — the empty cans rattle the most.

                                                                                      2. 8

                                                                                        You are definitely not the only one. The hide button is our friend.

                                                                                        1. 2

                                                                                          So I was initially keen on Go when it first came out. But have since switched to Rust for a number of different reasons, correctness and elegance among them.

                                                                                          But I don’t ever say “you shouldn’t use X” (where ‘X’ is Go, Java, etc.). I think it is best to promote neat projects in my favorite language. Or spending a little time to write more introductory material to make it easier for people interested to get started in Rust.

                                                                                          1. 2

                                                                                            I would go further, filtering for rant, meta and law makes Lobsters much better.

                                                                                            rant is basically the community saying an article is just flamebait, but short of outright removing it. You can choose to remove it.

                                                                                          2. 5

                                                                                            I think this debate is still meaningful because we cannot always decide what we use.

                                                                                            If there are technical or institutional barriers, you can ignore $LANG, such as if you’re writing Android apps, where you will use a JVM language (either Kotlin or Java) but if you are writing backend services, outside forces may compel you to adopt Go, despite its shortcomings detailed in this post (and others by the author).

                                                                                            Every post of this kind helps those who find themselves facing a future where they must write Go to articulate their misgivings.

                                                                                          1. 11

                                                                                            The Firefox snap does not support the NativeMessaging protocol 25 yet but this feature is planned to be added soon.

                                                                                            This means that the 1Password extension cannot be unlocked by the desktop application and vice-versa. It’s been broken since they introduced the snap and I’m disappointed they’re shipping another major version with this still broken.

                                                                                            1. 3

                                                                                              Similarly Firefox snap edition will often crash due to font issues (at least with Japanese fonts) and it makes fonts unload and FF kinda unusable in this state

                                                                                              There are workarounds but snap is still pretty rough around the edges…. I get the value of snaps but would not mind if the sandboxing was toned down a bit so that applications could work.

                                                                                              1. 2

                                                                                                I’d guess thus the keepassxc integration is also broken?

                                                                                                1. 1

                                                                                                  yep, it’s broken now..

                                                                                              1. 5

                                                                                                We were very early adopters of mypy, and I’m happy for it overall. It’s like a linter on steroids, for lack of a better term.

                                                                                                A frustrating issue is that because of how Any works and with stuff like third party deps, you end up with weird situations where entire functions just don’t get really type checked, and changing some part of the code in one file suddenly makes a seemingly unrelated function be type checked.

                                                                                                It’s good that errors show up, but it’s frustrating that you end up having to clean up “other people’s changes”.

                                                                                                My “project to do if I had infinite time” would be to fork the typescript type checker to support Python. structural subtying, very good union type resolution…. typescript’s just way better at answering a lot of the questions I have about types for my “standard enterprise app”. That being said mypy is a serious project and I think people are going to be adding types over time, if only because they are at least halfway-good documentation.

                                                                                                Yeah, Python isn’t going to check the types for you. There’s still a lot of value. By labeling the types, you are at least expressing intent. So it’s not “well what is the right thing to pass in”, but “I am passing in the wrong thing”, or “the type annotation is in fact wrong”. Which sounds equivalent, but is a bit more restricted and easier to think about.

                                                                                                1. 3

                                                                                                  TypeScript is the same, a developer puts an any in some place “just for now” and it spreads out tendrils into otherwise correct code, turning off typechecking and turning solid typedefs into lies at runtime.

                                                                                                  I’m still not sure what the answer is, although allowing unknown to be used in places where you want to say “I don’t know” rather than any meaning “anything goes, do as you please” seems to be a good start.

                                                                                                  1. 4

                                                                                                    I know typescript has a variant of this issue, but there’s something incidental (I believe) happening with mypy that makes this problem worse. It’s very weird but frequent in the large codebase I work on.

                                                                                                    There is also a practical thing; the typescript type system captures more patterns than the mypy type system, so less stuff falls back to any.

                                                                                                    In any case I am glad gradual typing exists overall.

                                                                                                    1. 1

                                                                                                      IIRC TypeScript defaults to being way more aggressive with warning about “any”, and pretty much forces you to coerce “any” to a concrete type as soon as you see it.

                                                                                                      IMHO this is a good idea, but the downside is that you may end up writing incorrect or incomplete types (coming up with the correct signature might require reading through half the code base) instead of being forthright about not knowing the type.

                                                                                                1. 3

                                                                                                  Oof those if statements in the lower snippet. So much C code happens within the condition of a conditional branch, it can be hard to grok. Especially if you get used to less “line-noisy” language like Python.

                                                                                                  There’s a part of me which is like “please just make your code flatter”. But another part of me understands the value of making your code not too long, vertically (for readability). You do end up having to be really good at designing APIs in some languages to get readable code. I’m happy that I get to use languages where mediocre APIs are still pretty readable.

                                                                                                  1. 11

                                                                                                    People get the browsers they deserve.

                                                                                                    We’d see more competition in this space, but developers have voted with their feet every time Google or whoever implements a feature and dangles it out. Developers wanted a more complex web and more complicated services–well guess what that means for browser complexity? Webshits played themselves. Don’t complain about browser monocultures enabling spying at the same time you support endless feature creep and evergreen standards.

                                                                                                    We’d see better privacy, but consumers flocked to hand over their digital everything to anybody willing to dangle a blinking cat picture or whatever in their face. People who don’t take responsibility for behaviors that, by construction, undermine their freedom and privacy shouldn’t act surprised when they lose either.

                                                                                                    1. 8

                                                                                                      The domination of Chrome came way before “stuff only works in Chrome” things started becoming the norm. Chrome got popular cuz it was super fast and had a smooth UI.

                                                                                                      I do understand that an expensive-to-implement standard plays into the lock-in effect… I do think it’s not super cut and dry, though. Flash existed, plugins existed… maybe the web shouldn’t have any of those either, but lots of people wanted them. And I’m honestly glad I don’t have to download “the netflix application”.

                                                                                                      I don’t know how you square the circle of “people want to use interactive applications in a low friction way” with “we should not make web browsers turing machines” , without the gaps being filled by stuff that could be worse. I don’t have a good solution though

                                                                                                      1. 6

                                                                                                        Do you really think developer preferences played a large role in Chrome’s dominance of the market? Seems to me that Google created their market share through PR and advertising, especially on their own sites, and from their control of the default apps on Android.

                                                                                                        1. 4

                                                                                                          This is where the glib “nobody actually cares about privacy” rejoinder comes from. When it comes down to it, consumers don’t actually seem to care about privacy. I don’t know if it’s an education thing (“hey look your personal data is being sold to target ads to you”) or maybe people really don’t care and it’s odd folks like us that do. These days I genuinely believe that data privacy is a niche interest and the average user doesn’t care as long as they can connect with their friends and loved ones.

                                                                                                          At the very least GDPR style disclosures of what data is being collected can help folks who are willing understand what data they are giving up.

                                                                                                          1. 12

                                                                                                            This comic tried to address it near the end but I think the big problem is that most consumers don’t really understand what it means to lose something as nebulous as ‘privacy’. If you asked if they want a webcam in their bedroom streaming data to Google / Amazon / Facebook, that’s one thing, but having one of these companies track everything that you do on the web? It’s much harder to understand why that’s bad. As the comic explains, the real harm comes from aggregation and correlation signals. Even then, most of the harm isn’t done directly to the individual who is giving up their privacy.

                                                                                                            Bruce Schneier had a nice example attack. If people see ‘I have voted’ badges on their friends social media things, then they are around 5-10% more likely to vote. If you track browsing habits, especially which news sites people visit, then you can get a very good estimate of someone’s voting intention. You can easily correlate that with other signals to get address. In a constituency with a fairly narrow margin (a lot of them in states with effectively two-party systems) then you can identify the people most likely to vote for candidates A and B. If you hide ‘I’ve voted’ badges from the social media UIs for people who lean towards B and show them for people who lean towards A then you have a very good chance of swinging the election.

                                                                                                            That said, the fact that a person using Chrome / Facebook / WhatsApp / whatever is giving that company a hundred-millionth of the power that they need to control the government in their country is probably not a compelling reason for most people to switch. Individually, it doesn’t make much of a difference whether you use these services or not.

                                                                                                            Unless you’re a member of a minority, of course. Then you have to worry about things like the pizza-voucher attack (demonstrated a few years ago, you can place an ad with Google targeting gay 20-somethings in a particular demographic with a voucher that they can claim for discounted pizza delivery. Now you have the names and addresses of a bunch of victims for your next hate crime spree).

                                                                                                            1. 9

                                                                                                              I think the 2 main reasons people don’t care about privacy are that

                                                                                                              • it simply doesn’t make a huge difference in their lives whether their right to privacy is respected or not. Most people simply have bigger fish to fry and don’t have the cycles to spare on things that may be bad but aren’t actively causing them harm.
                                                                                                              • technology companies like Google, Meta, etc. have done a great job of presenting their software as “free”. I think most people think of signing up for Gmail or Instagram like they would getting a driver’s license or library card; they’re just signing up for some public service. These companies do the most to avoid framing this for what it is: an exchange of value, just like any other. You’re paying with your data, and you’re getting access to their service in exchange for that data. As long as using “free” software isn’t understood by consumers as a value exchange, they will never demand protection of their right to privacy and data dignity.

                                                                                                              As someone who works in the data privacy and governance space, it’s encouraging to see growing awareness of these issues at the consumer and government regulation level. Hopefully with enough movement from the government and private sector, we can keep fighting “Big Tech’s” deceptive narratives around data and their software.

                                                                                                          1. 36

                                                                                                            The core problem is the only entities currently paying for web browser development have mixed motives. The EU should just buy out Mozilla and make Firefox into the browser for the people instead of waiting around for Google to stop breaking their laws.

                                                                                                            1. 9

                                                                                                              What’s to buy? It’s open source. They can contribute to it or fork it if Mozilla Corp doesn’t like their changes.

                                                                                                              1. 21

                                                                                                                The Mozilla organization, including the expertise necessary to develop and maintain Firefox. It would probably cost more to build an independent organization capable of doing the same thing.

                                                                                                                1. 3

                                                                                                                  Which Mozilla organization? The non-profit Mozilla Foundation or the for-profit Mozilla Corporation?

                                                                                                                  1. 7

                                                                                                                    I’m not sure, what do you think?

                                                                                                                    1. 5

                                                                                                                      The Mozilla Corporation is owned in its entirety by the Mozilla Foundation. Even if somehow the Foundation were convinced to sell the Corporation, the Foundation is the one that owns the key intellectual property and is the actual steward of the things people think of as “Mozilla”. The Corporation’s purpose is to be an entity that pays taxes and thus can have types of revenue and business deals that are forbidden to a non-profit.

                                                                                                                      1. 1

                                                                                                                        The employees who work on Firefox and everything that encompasses work for the Corporation. It has more of a purpose than “taxes”.

                                                                                                                        1. 3

                                                                                                                          I am a former employee of the Mozilla Corporation, so I am aware of what the MoCo employees do.

                                                                                                                          1. 1

                                                                                                                            MoCo gets all of the revenue that’s generated by Firefox and employs most of the developers. All but one of the members of the Firefox Technical Leadership team work for Mozilla Corp - the one that doesn’t did until relatively recently: https://wiki.mozilla.org/Modules/Firefox_Technical_Leadership

                                                                                                                            While the Foundation technically owns the IP the Corporation controls the direction of the product and collects all of the revenue generated by the work of both their employees and contributions from the community.

                                                                                                                  2. 9

                                                                                                                    Declare Firefox a public infrastructure and fund Mozilla or another entity to upkeep and enhance that infrastructure.

                                                                                                                  3. 11

                                                                                                                    No thanks, I’ve had enough cookie popups for one day.

                                                                                                                    1. 55

                                                                                                                      The GDPR is specific about cookie banners not being obtrusive, and that rejecting tracking is as easy as accepting.

                                                                                                                      The only compliant banner I regularly see is from gov.uk, and I find it doesn’t annoy me at all.

                                                                                                                      The popups are as obnoxious as possible to make us hate the GDPR. Can’t we oppose the tracking instead of the law telling us when it’s happening?

                                                                                                                      1. 8

                                                                                                                        And of course the core thing is you don’t need the cookie popups if you’re not doing random tracking of people!

                                                                                                                        Every cookie popup is an announcement that the site has some automated trackers set up. If you are just using cookies for things like handling sessions you do not need the cookies.

                                                                                                                        1. 8

                                                                                                                          Absolutely. The options are either make your tracking opt-in through genuinely informed consent, or don’t track at all.

                                                                                                                          Companies found the secret third option, which is just ignore the law and dark pattern your users into agreeing to anything.

                                                                                                                          Banners say things like “we need cookies for this site to work” and pretend they need your permission to use them. Ironically they only need permission for the cookies that aren’t essential to make the site work.

                                                                                                                          Hiding things away under “legitimate interest” makes things even more confusing. Are the other things illegitimate interests?

                                                                                                                          1. 2

                                                                                                                            Can someone explain to me what “legitimate interest” actually means?

                                                                                                                          2. 2

                                                                                                                            …you do not need the cookies.

                                                                                                                            Do you mean the cookies or the popups? I’m not familiar with how the GDPR treats non-cookie based things like JWT in local storage and sent with every request.

                                                                                                                            1. 2

                                                                                                                              The same. You require consent to store any data on user computer. However it do not require some “essential” cookies - for example cookie with preferences for dark/light theme do not require consent if it is direct action on website, cookie containing session ID do not require consent, etc. That applies for local cookies only though.

                                                                                                                        2. 11

                                                                                                                          Same. I really wish companies would stop choosing to add them to their websites.

                                                                                                                          1. 4

                                                                                                                            If you already block tracking by any mean, you can get rid of those banners using something like https://addons.mozilla.org/en-GB/firefox/addon/i-dont-care-about-cookies/.

                                                                                                                            1. 3

                                                                                                                              Yeah, the EU’s heart was in the right place, but implementation has been a disaster. It’s like passing a law that murder is okay as long you say “I am going to murder you” as you take out the knife.

                                                                                                                              1. 27

                                                                                                                                What the EU did was basically passing a law that makes murder illegal. Companies/Murderers just ignore it and go around saying “anyone that doesn’t want to be murdered please answer by saying your name within of the next millisecond. Guess no one answered, so you’ve just consented to murder!”

                                                                                                                                GDPR explicitly bans all the annoying dark patterns of cookie banners. A GDPR-compliant cookie banner would ask you once whether you consent to tracking. It’d have one huge no button (but no easily accessible yes button). If you ever click no, it’d have to remember as long as possible and close itself immediately. If you click yes, you’d have to go through a handful of options to specifically choose which tracking methods to allow.

                                                                                                                                1. 10

                                                                                                                                  So, basically the polar opposite of many cookie popups today, which have a big “I ACCEPT” button and a “More options” button that you have to click to manually turn off all tracking…

                                                                                                                                2. 3

                                                                                                                                  Except large Internet companies are much more powerful and accountable to public pressure than murderers, so they should face at least as much public scorn as the lawmakers.

                                                                                                                                  1. 2

                                                                                                                                    There’s a saying, that road to hell is paved with good intentions.

                                                                                                                                    That often means that if someone’s is not sure how to help, then proceeding with helping can create more problems than resolve anything.

                                                                                                                                    1. 2

                                                                                                                                      That’s better than having no law against murder. Then we can move away from all the people saying “I am going to murder you.”

                                                                                                                                    2. 2

                                                                                                                                      Umm… we’ve just today decided to instruct Matomo not to use cookies rather then implement cookie banner for our new Wagtail-based websites. I think it’s working?

                                                                                                                                      1. 1

                                                                                                                                        Cookie popups on websites linked to by Google?

                                                                                                                                    1. 6

                                                                                                                                      I don’t know fish very well but, pardon my asking, why?

                                                                                                                                      There’s a commonly held belief that one should at least think long and hard about using a more established programming language rather than trying to code in the shell. This feels like an even longer slide down a slippery slope.

                                                                                                                                      Or am I missing something about fish shell’s magical-ness?

                                                                                                                                      1. 13

                                                                                                                                        Yeah, the only reason anyone ever writes scripts in shell is that it’s guaranteed to already be installed, which isn’t true of fish.

                                                                                                                                        Plus the I in fish stands for “interactive”; like … that’s very clearly what it’s designed for.

                                                                                                                                        1. 4

                                                                                                                                          [T]he only reason anyone ever writes scripts in shell is that it’s guaranteed to already be installed

                                                                                                                                          This right here.

                                                                                                                                          Fish is very much something I would install on my personal laptop, but on the environments where I run a lot of shell scripts, it’s either bash or a higher level language like Python depending on the complexity.

                                                                                                                                          1. 2

                                                                                                                                            Personally another reason I use shell scripts is cuz there are nice primitives. Every machine I use has Python 3 installed, but subprocess.Popen isn’t the funnest interface.

                                                                                                                                            I would love to have a shell script language that is fun to use and isn’t Powershell

                                                                                                                                            1. 1

                                                                                                                                              Yes, process management in your average language sucks compared to bash. That’s why you can find libraries for $YOUR_LANGUAGE that do it significantly better than the standard library of that language. In your case, google for “python shell scripting library”.

                                                                                                                                              If you are like me and believe that if something is too frequent it should get its own syntax and in general prefer a language built ground up for this type of scripting, you are welcome to try Next Generation Shell (I’m the author).

                                                                                                                                            2. 1

                                                                                                                                              Yeah, the only reason anyone ever writes scripts in shell is that it’s guaranteed to already be installed, which isn’t true of fish.

                                                                                                                                              I don’t really understand what the problem is here. OK I do not work with servers in my daily job but I’m pretty sure that most people do install some software first on those machines. Why not add fish to the list of web servers/JS packages/Python packages/etc…? I mean who runs their system bone stock (except on OpenBSD ;) ) so what’s the problem with installing fish?

                                                                                                                                              1. 3

                                                                                                                                                It’s not that there’s a problem with installing fish; it’s that if you’re going to bother with having prerequisites, you’ve just discarded the one advantage shell programming has over regular programming languages.

                                                                                                                                                1. 3

                                                                                                                                                  There is a spectrum, but with four important points:

                                                                                                                                                  • Installed everywhere (in the default install). This basically means POSIX shell for *NIX systems.
                                                                                                                                                  • Almost always installed, not necessarily by default, and small. Things like bash are in this list.
                                                                                                                                                  • Not always installed but a simple package with no dependencies and so low friction to install. Something like Lua is a good example here.
                                                                                                                                                  • Not always installed and brings in a messy load of stuff with versioning problems. Python is the common example here.

                                                                                                                                                  Each step in this list adds some potential friction and so should come with some benefit. There are some nice bashisms that make shell scripting easier and bash is pretty easy to install on any system that has a POSIX shell, so it’s often worth using !#/usr/bin/env bash instead of !#/bin/sh for your shell scripts. Using a real programming language such as Lua has some bigger benefits but means that users probably need to install it.

                                                                                                                                                  Something like fish or zsh is in an interesting place because it’s as much effort as installing a programming language such as Lua or Go (easier than one like Python or Ruby), but generally the uplift in functionality relative to POSIX shell or bash are fairly small.

                                                                                                                                                  If your scripts are really scripts (i.e. mostly running other programs) then a shell scripting language may be a better fit than a programming language, but now you need to think about how much easier fish is than POSIX shell or bash and whether the benefit outweighs the additional friction for users.

                                                                                                                                                  Note that the friction also implies to security audits. If someone is deploying your software in a container and it depends at run time on a scripting language, then that language implementation is now part of your attack surface. Things like Shellshock showed that bash isn’t always a great choice here, but it’s probably already in the attack surface for other things and so will be on the list of evaluated risks already. The same is true of something popular like Lua or Python (though that may not be a good thing as it may already be flagged as high risk). Something like fish will likely trigger extra compliance processes.

                                                                                                                                                  1. 2

                                                                                                                                                    Bit of a chicken and egg problem though, you have to install those interpreters and what would you install it with?

                                                                                                                                                    At some point you’re interacting with the OS primitives. The most elegant thing at that level is sh so you’re already using it.

                                                                                                                                                    1. 1

                                                                                                                                                      But is it really the most elegant? Or just lazily more convenient?

                                                                                                                                                      1. 1

                                                                                                                                                        Usually those are the same thing.

                                                                                                                                                        Ultimately there will always be some shell running. The only way to get around that is ansible (and some kind of priming system) or — well arguably it can get a lot more more complicated to do very simple things.

                                                                                                                                                        Maybe someone should make a Linux distro with fish under the hood?

                                                                                                                                                      2. 1

                                                                                                                                                        At some point you’re interacting with the OS primitives. The most elegant thing at that level is sh so you’re already using it.

                                                                                                                                                        Huh? In POSIX systems, the system libc function invokes a shell, but [v,pd]fork / clone + execve doesn’t go anywhere near the shell and these expose things that the shell does not. Any higher-level language that exposes the process-creation system calls directly will give you more control than the shell and will not depend on the shell for anything.

                                                                                                                                                        Unlike VMS or DOS, the shell is not in any way special on a *NIX system, it’s just a program that talks to a terminal (or something else) and does some system calls. This is why things like fish can exist: the program that you use for sitting between you and the operating system’s terminal facilities can be anything that you want.

                                                                                                                                                  2. 12

                                                                                                                                                    I wouldn’t say fish is magical, it just seems like a small, sane shell language with fewer thermo-nuclear footguns. On paper it should be an ideal candidate for project automation and general scripting.

                                                                                                                                                    EDIT: I guess my point is that we often treat perl/ruby/python as “a better bash”, while it seems to me that fish should be a candidate for the same role.

                                                                                                                                                    1. 2

                                                                                                                                                      From a strictly technical standpoint I can see where you’re coming from, but think about this in terms of commercial viability.

                                                                                                                                                      You do what you’re suggesting and create a pile of snowflake Fish shell code to run the company.

                                                                                                                                                      You then leave a year later for greener pa$$tures, and the next person inherits a technically superior codebase which sadly resolves into a perfect black hole of sadness and despair because NO-ONE anywhere uses this tool this way and NewPerson is totally, UTTERLY alone.

                                                                                                                                                      1. 2

                                                                                                                                                        Yes. Easier to use correctly. If bash is a quoting hell where the right thing to do – using arrays – is awkward, fish trivializes both: Compare "${array[@]}" (bash) with $array (fish): Every variable is an array and you don’t need to quote it.

                                                                                                                                                        1. 1

                                                                                                                                                          Being not POSIX compatible, fish shell scripts and bash scripts are not compatible.

                                                                                                                                                          This was a deliberate choice to be better for interactive use, which makes fish an immature and non appropriate choice for a shebang.

                                                                                                                                                      1. 4

                                                                                                                                                        I remember trying Clojure a bit, and being super interested in a lot of the ideas of the language.

                                                                                                                                                        There is the universal quibbles about syntax (and honestly I do kinda agree that f(x, y) and (f x y) are not really much different, and I like the removal of commas). But trying to write some non-trivial programs in Clojure/script made me realize that my quibble with lisps and some functional languages is name bindings.

                                                                                                                                                        The fact that name bindings require indentation really messes with readability. I understand the sort of… theoretical underpinning of this, and some people will argue that it’s better, but when you’re working with a relatively iterative process, being able to reserve indentation for loops and other blocks (instead of “OK from this point forward this value is named foo”) is nice!

                                                                                                                                                        It feels silly but I think it’s important, because people already are pretty lazy about giving things good names, so any added friction is going to make written code harder to read.

                                                                                                                                                        (Clojure-specific whine: something about all the clojure tooling feels super brittle. Lots of inscrutable errors for beginners that could probably be mangled into something nicer. I of course hit these and also didn’t fix them, though…)

                                                                                                                                                        EDIT: OTOH Clojure-specific stuff for data types is very very nice. Really love the readability improvements from there

                                                                                                                                                        1. 5

                                                                                                                                                          Interesting to hear this–indentation to indicate binding scope is one of the things I really miss when I’m using a non-Lisp. I feel like the mental overhead of trying to figure out where something is bound and where it’s not is much higher.

                                                                                                                                                          (I strongly agree on the state of Clojure tooling.)

                                                                                                                                                          1. 1

                                                                                                                                                            I think that racket solves this:

                                                                                                                                                            (define (f x)
                                                                                                                                                                (define y (* 10 x))
                                                                                                                                                                (printf "~a ~a\n" y x))
                                                                                                                                                            (f 42)