Threads for dathagerty

  1. 1

    It’s quite pretty, but the choice of “#” to mark headings strikes me as odd. Is it an attempt to appeal to Markdown fans?

    For actual book mode and reading of long form text I’d also love to have non-proportional fonts.

    1. 1

      That’s also the character for indicating a line of text is a heading in Org’s markup.

      1. 2

        It is not. Headings in Org mode are indicated with *, cf https://orgmode.org/manual/Headlines.html

    1. 10

      This is all about laptops. I understand a lot of people really need a portable computer, but I think it is worth considering what it is asking to ask for a computer that you can take everywhere with you and it still lasts for 50 years. The desktop hardware I currently have will probably last decades if looked after, some minor parts might fail and need to be replaced but the big expensive components should last a good long time. It also does not suffer from many of the drawbacks mentioned here.

      A laptop has to handle impacts, being dropped, being sat on, getting wet, getting hot, getting cold, in 50 years of constant use all of these will happen. Don’t get me wrong I would love to see a ruggedised laptop on the market that could last 50 years but I probably wouldn’t rush out to buy it. The extra cost and weight would probably be significant, and I would want it to be constructed according to the principles of ‘right to repair’ and upgradeable in a modular way which is a whole other layer of problems.

      In short, while I agree with pretty much everything in the article, it sounds like a description of a desktop pc running open source software, written in a parallel universe where no such thing exists.

      1. 6

        Man, remember netbooks? One of those, a wireless hotspot and a VPN/tunnel of some sort to a home desktop used to be my dream computing setup. I get the unbridled compute of a desktop-class processor with a super-portable method of access.

        Granted, this would not have been great from the perspective of screen real estate, but I’m kind of sad there don’t seem to be any devices like that any more.

        1. 7

          The ones I had experience with had really crappy hardware. Awful trackpads, mushy keyboards, dingy displays. And they broke a lot.

          Get an iPad and an attached keyboard, install an SSH terminal, and you’ve basically got what you’re asking for.

          1. 3

            It’s still an option. You can still buy tiny laptops for less than £100 or connect a keyboard to your smartphone or tablet.

        1. 8

          I haven’t watched the video yet, but the answer is fmt.Errorf("custom message goes here: %w", err). The %w allows the error to be unwrapped using errors.Unwrap, but you also get to add your own context if you want/need it.

          1. 3

            in small systems, this is definitely all you need, larger more complex applications definitely benefit more from structured errors and structured logging.

            1. 1

              That is one good approach. But there are reasons for others, too.

            1. 7

              While I understand that any private entity can choose its customers and change its terms at any time, I think more thought should be put into these kinds of decisions…

              While I completely agree that any “threatening or harassing” or any other kind of illegal activity or content should be dealt with, I don’t think blockchain and crypto-currency related source code falls under any of these categories. Sure, many blockchain and crypto-currency “projects” might actually be financial ponzi schemes and detrimental to both the society and the environment, but banning all such related projects is quite an overreaction…

              For example, on an unrelated project I’ve searched for some technical solutions and found two outcomes of crypto-currency projects that are just extremely original and useful even outside the crypto-currency context: https://github.com/BlockchainCommons/LifeHash and Bech32 encoding. Would the code for such projects be banned from SourceHut? (Perhaps not if hosted individually outside a blockchain or crypto-currency repository, but who knows, their main purpose is for crypto-currencies.)

              Moreover it creates a precedent… If the owners of SourceHut tomorrow decide they don’t like say AI-based image generation projects will they ban those next? Or perhaps (open-source) projects that when run display ads? Where does the banning stops once it gets started?

              While I don’t use (pay for) SourceHut myself (thus I perhaps shouldn’t have an opinion about these changes) I did keep a close eye on SourceHut developments as an alternative to GitHub, but this change in their terms made me think twice about possibly moving there…

              As said in the beginning, it’s their company thus it’s their decision…

              1. 16

                The precedent to ban projects already exists across providers. They generally have terms of service that excludes certain kinds of content. Take the child abuse example from the post. This isn’t as slippery of a slope as you make it seem, and as you already pointed out they can choose their customers and their terms. It just sounds like this choice is one you disagree with.

                1. 2

                  Look what happened when the media industry got mad at youtube-dl for “assisting piracy” or whatever–when it covers so many use cases. Meanwhile, piracy is often the best archival system we have for digital media as those corps let it rot.

                2. 5

                  Drew definitely had put thought into it. I participated in the chat on IRC.

                  1. 4

                    I am curios what the thought process was? Which were the highlighted advantages and disadvantages of such a decision (both for the SourceHut business and for the development community at large)? How much good would banning any crypto-currency and block-chain related project achieve? (Are there many such projects hosted on SourceHut?)

                    The only reasoning behind this decision is given in the beginning of the article:

                    These domains are strongly associated with fraudulent activities and high-risk investments which take advantage of people who are suffering from economic hardship and growing global wealth inequality. Few to no legitimate use-cases for this technology have been found; instead it is mostly used for fraudulent “get rich quick” schemes and to facilitate criminal activity, such as ransomware, illicit trade, and sanctions evasion. These projects often encourage large-scale energy waste and electronics waste, which contributes to the declining health of Earth’s environment. The presence of these projects on SourceHut exposes new victims to these scams and is harmful to the reputation of SourceHut and its community.

                    Not to mention the following suggestion:

                    Projects which seek out cryptocurrency donations are strongly discouraged from doing so, but will not be affected by this change.

                    Getting back to the listed reasons:

                    • “to facilitate criminal activity” – Tor is especially useful in such scenarios; will SourceHut ban the Tor project (or other similar onion-routing projects)? also especially useful are the many “end-to-end encrypted” chat applications; should we ban them?
                    • “often encourage large-scale energy waste” – hell, the whole AI/ML landscape is another prime example of technologies that just waste energy for trivial reasons such as image generation; perhaps we should ban also this category?
                    • “electronics waste” – how about the gaming industry, which push users to continuously upgrade their good-enough hardware; should we start banning games that require newer hardware?
                    • “illicit trade” – anything actually can be used facilitate such purposes;
                    • “sanctions evasion” – and in the end, any open-source project that can be used by anyone in a sanctioned country, just allowed that country (in some manner) to evade sanctions by using the labor of the open-source developers in the sanctioning countries; should we start banning access from such sanctioned countries?
                    1. 5

                      I don’t know anything more about SourceHut’s reasoning than you - I’ve just read the same announcement - but it seems to me that it isn’t being banned because of the uses you mentioned, it’s because those are (nearly) the only uses. So the fact that other technologies can also be used for those purposes isn’t really relevant.

                      1. 2

                        I don’t want to misrepresent Drew’s position, I think it’s best if you ask him personally by e-mail.

                    2. 4

                      We will exercise discretion when applying this rule. If you believe that your use-case for cryptocurrency or blockchain is not plagued by these social problems, you may ask for permission to host it on SourceHut, or appeal its removal, by contacting support.

                      I think this is more than fair and also answers your question. They are specifically mentioning the exact target of these terms, and they are the projects which you call ’“threatening or harassing” or any other kind of illegal activity or content ’.

                      1. 2

                        He makes exceptions, like for example my project, see: https://news.ycombinator.com/item?id=33404815

                        1. 2

                          I could see those two projects being “unbanned” or whatever if they filed an appeal with Drew. I know in the past they (Sourcehut) had issues with crypto-related repositories using their CI service to mine, and ended up removing access to CI for non-paying members.

                          I pretty much agree with the decision they made, because if something is going to be negative 99% of the time, I’m just going to automate around most cases being negative while providing an out for the 1% chance it’s positive.

                        1. 31

                          Regardless of how someone feels about these changes, they seem to be well implemented and alternatives readily provided through the use of standard formats. It’s nice to see these sorts of changes being communicated clearly and with plenty of time.

                          1. 30

                            I especially like the “and if you don’t like it, here’s how you can take all your data with you when you go”

                            1. 14

                              This kind of grown-up attitude & approach is alone sufficient in significantly raising my interest in the platform.

                              1. 4

                                It’s a really nice platform. I use it exclusively for personal projects now, and I’m loving it. I haven’t done much collaboration on the platform, so I can’t say much about that, but otherwise it’s great.

                                I know Drew kind of built a reputation for himself, and think what you want of him, but he’s doing right by FOSS with Sourcehut, I feel.

                          1. 2

                            This is really timely - I’ve been wanting to set up a Nomad cluster for my personal servers, and it’ll be nice to have this to reference alongside my own research and Hashicorp’s own documentation.

                            Edit: now that I’ve had time to read the full article, it’s definitely something I’ll use as a guide. Hashicorp’s documentation has been hard to sift through for actually setting all of their services up together, so it’s really helpful to see this basically say “start with Consul, then Nomad, and then Vault”.

                            1. 2

                              Depends on what you want - performance, go for a 16” M1 MacBook Pro. Anything else, go for an M2 MacBook Air.

                              1. 4

                                IMO, it is a bit more clouded than that. I love the Air for its low weight. But the 14/16” Pros have other nice benefits over the Air. You absolutely need the Pro if you need (besides more performance):

                                • Hook up more than one external screen.
                                • Need more than 24GB RAM.

                                Besides that the Pro 14”/16” have other benefits:

                                • 3 Thunderbolt ports, including one on the right-hand side, which can be handy when docking the MacBook besides a display.
                                • Much better display.
                                • HDMI/SD card slot.

                                Also, the price difference between the 8 CPU core/10 GPU core Air M2 and the baseline MacBook Pro 14” is very small (especially because many stores have discounts on the 14” now).

                                I’d get the Air if you prefer the lower weight and passive cooling over anything else.

                              1. 4

                                Oh man, that bit on Vault Sidecar Injector hit hard. My team uses Vault (self-hosted, so you can guess where this is going), and it’s basically a glorified key-value store. We talk about using the value-adds that Vault brings, but never make progress because instead of letting one person dive deep and become an expert, we shuffle ticket assignments around and let someone learn just enough to say “yeah, this is feasible but I don’t know how to get us there”.

                                1. 1

                                  Not super interesting I reckon. But the ones I use the most.

                                  ..='cd ..'
                                  ip='ip -br -c'
                                  home='git --work-tree=/home/fox --git-dir=/home/fox/.config/home.git'
                                  
                                  i3conf='vim ~/.config/i3/config'
                                  zshrc='vim ~/.config/zsh/.zshrc && source ~/.config/zsh/.zshrc'|
                                  

                                  I don’t really have a lot of super useful aliases. Most of the time is spent making git config aliases and vim stuff.

                                  1. 1

                                    Is that BSD or a mac? My ip doesn’t know either flag.

                                    1. 2

                                      That is iproute2. The goal is to have ip be brief by default because I simply do not care about all the information.

                                      λ ~ » /usr/bin/ip a
                                      1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
                                          link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
                                          inet 127.0.0.1/8 scope host lo
                                             valid_lft forever preferred_lft forever
                                          inet6 ::1/128 scope host
                                             valid_lft forever preferred_lft forever
                                      2: wlp0s20f3: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000
                                          link/ether 10:3d:1c:e9:f5:cf brd ff:ff:ff:ff:ff:ff
                                          inet 192.168.1.11/24 brd 192.168.1.255 scope global dynamic noprefixroute wlp0s20f3
                                             valid_lft 78751sec preferred_lft 78751sec
                                          inet6 fe80::9f2c:5a98:d8ef:b06e/64 scope link noprefixroute
                                             valid_lft forever preferred_lft forever
                                      3: enp0s31f6: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc fq_codel state DOWN group default qlen 1000
                                          link/ether 90:2e:16:5e:1a:b5 brd ff:ff:ff:ff:ff:ff
                                      14: enp36s0u1: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc fq_codel state DOWN group default qlen 1000
                                          link/ether 00:50:b6:9f:fe:25 brd ff:ff:ff:ff:ff:ff
                                      
                                      λ ~ » ip a
                                      lo               UNKNOWN        127.0.0.1/8 ::1/128
                                      wlp0s20f3        UP             192.168.1.11/24 fe80::9f2c:5a98:d8ef:b06e/64
                                      enp0s31f6        DOWN
                                      enp36s0u1        DOWN
                                      
                                      1. 1

                                        Thanks, but that’s why I was asking:

                                        ii  iproute2                              5.5.0-1ubuntu1
                                        

                                        ip -br doesn’t work and neither does ip -c or ip -br -c.

                                        And now I finally grasped that it would output the same as 'ip' - so it is -brief -color. Sorry, brainfart (ofc I searched before I asked that last question..) :P

                                        Apparently I have never used either flag and didn’t notice them in the manual. – signed, someone gowing up with ifconfig

                                        1. 1

                                          Yeah I found the documentation for these commands a bit lacking when I started utilizing them initially.

                                    2. 1

                                      ..='cd ..'

                                      I was going to post this as my most useful, because I just it all the time.

                                      I also have ...="cd ../.." and so on for going up more levels. Probably not useful beyond four or five levels due to how quickly can you count how deep you are in the CWD.

                                      Edit: Just to be clear, I’m talking about me visually counting up how many levels deep I am in the directory tree. Beyond three or four, I tend to just go up that much, and then look and see where I am and maybe do it again, with my finger hovering over the ‘.’ key. I don’t have a problem rapidly tapping out the ‘.’ nine times to go up 8 levels, the difficulty (for me) is determining that I want to go up 8, vs. 7 or 9 levels.

                                      1. 1

                                        Don’t want to keep posting it so I’ll link to the reply i made to the parent:

                                        https://lobste.rs/s/qgqssl/what_are_most_useful_aliases_your_bashrc#c_fqu7jd

                                        You might like to use it too!

                                      2. 1

                                        You (and others) might be interested in the one from my post to this:

                                        function up() {
                                          local d=""
                                          limit=$1
                                          for ((i=1 ; i <= limit ; i++))
                                            do
                                              d=$d/..
                                            done
                                          d=$(echo $d | sed 's/^\///')
                                          if [ -z "$d" ]; then
                                            d=..
                                          fi
                                          cd $d
                                        }
                                        

                                        Allows you to just do up 4 to get cd ../../../..

                                        LIFE-saver.

                                        1. 2

                                          Even more fun (only works in zsh, as far as I know):

                                          function rationalize-dot {
                                              if [[ $LBUFFER = *... ]]; then
                                                  LBUFFER=${LBUFFER[1,-2]}
                                                  LBUFFER+=/..
                                              else
                                                  LBUFFER+=.
                                              fi
                                           }
                                           zle -N rationalize-dot
                                           bindkey . rationalize-dot
                                          

                                          You can make this even better by adding setopt auto_cd to your config, so that if you type a directory path zsh automatically changes to that directory.

                                          1. 1

                                            I tend to use https://github.com/wting/autojump for smart CDing, personally!

                                          2. 2
                                            alias .="cd .."
                                            alias ..="cd ../.."
                                            alias ...="cd ../../.."
                                            alias ....="cd ../../../.."
                                            
                                            1. 1

                                              Interesting. I’ve never tried to install / use those “smart” cd replacements, where you can type “cd foobar” and it looks at your recent working directories to find a “foobar” and go there.

                                              I was thinking about a variant of your up function that does something like that, where I can type “up foo” in the current directory:

                                              /home/username/foobar/one/two/three/four/
                                              

                                              And so it just looks into successive parent directories for anything matching “foo”, and the first one it finds is the destination.

                                              1. 2

                                                oh man – just use Autojump https://github.com/wting/autojump. I use it on every machine i own and it’s a GODSEND.

                                                1. 1

                                                  That was what I was talking about. I’ll have to give it or maybe zoxide a try and see if I stick with it.

                                          1. 22

                                            I really like how Go’s Duration time handles this, letting us do time.Sleep(5 * time.Second)

                                            1. 14

                                              Unfortunately Duration is not a type, but an alias for an integer, so this mistake compiles:

                                              time.Sleep(5);
                                              
                                              1. 10

                                                Your point stands about the mistake, but just to clarify the terminology: Duration is a defined type, not an alias (alias is specific Go terminology which means it behaves exactly the same as that type). The reason this mistake compiles is because literals in Go are “untyped constants” and are automatically converted to the defined type. However, these will fail, because s and t take on the concrete type int when they’re defined:

                                                var s int
                                                s = 5
                                                time.Sleep(s)
                                                
                                                t := 5
                                                time.Sleep(t)
                                                
                                                1. 2

                                                  My understanding is that Duration*Duration is also allowed?

                                              2. 8

                                                The thing I dislike the most about Go’s Duration type is that you can’t multiply an int by a Duration:

                                                To convert an integer number of units to a Duration, multiply:

                                                seconds := 10
                                                fmt.Print(time.Duration(seconds)*time.Second) // prints 10s
                                                

                                                In the example above, the intent is somewhat clear due to the seconds variable name, but if you just want to have something like this:

                                                some_multiplier := ...
                                                delay := some_multiplier * (1 * time.Second) // won't work
                                                

                                                You have to convert some_multuplier to time.Duration, which doesn’t make sense!

                                                1. 2

                                                  Can’t you just overload the * operator?

                                                  1. 3

                                                    Go doesn’t allow for operator overloading, which I’m kind of okay with. It tends to add complexity for (what I personally consider to be) little benefit.

                                                    1. 3

                                                      On the other hand, this is the kind of case that really makes the argument for operator overloading. Having to use a bunch of alternate specific-to-the-type function implementations to do common operations gets tiresome pretty quickly.

                                                      1. 2

                                                        So Go has different operators for adding floats and for adding integers? I have seen that in some languages, but it’s nevertheless quite unusual. OTOH, I can see that it reduces complexity.

                                                        1. 1

                                                          Go has built-in overloads for operators, but user code can’t make new ones.

                                                          It’s similar to maps (especially pre-1.18) that are generic, but user code is unable to make another type like map.

                                                      2. 2

                                                        Go doesn’t have operator overloading

                                                      3. 1

                                                        I agree it is annoying. Would a ‘fix’ be to alter/improve the type inference (assuming that some_multiplier is only used for this purpose in the function) so that it prefers time.Duration to int for the type inferred in the assignment?

                                                        I’m not sure it would be an incompatible change - I think it would just make some incorrect programs correct. Even if it was incompatible, maybe go2?

                                                        1. 1

                                                          While I do think Go could do more to work with underlying types instead of declared types (time.Duration is really just an alias for int64, as a time.Duration is just a count of nanoseconds), it does make sense to me to get types to align if I want to do arithmetic with them.

                                                          My perfect world would be if you have an arbitrary variable with the same underlying type as another type, you could have them interact without typecasting. So

                                                          var multiplier int64 = 10
                                                          delay := multiplier * time.Second
                                                          

                                                          would be valid Go. I get why this will probably never happen, but it would be nice.

                                                          1. 3

                                                            That’s how C-based languages have worked, and it’s a disaster. No one can keep track of the conversion rules. See https://go.dev/blog/constants for a better solution.

                                                          2. 1

                                                            If you define some_multiplier as a constant, it will be an untyped number, so it will work as a multiplier. Constants are deliberately exempted from the Go type system.

                                                        1. 1

                                                          I’m hoping to do a lot of digital housecleaning this week - I want to migrate my self-hosted email to Fastmail (unless there’s some compelling reason to go somewhere else). I want to finally figure out my org-mode setup. I’m also going to start rewriting my blog using Remix for learning purposes. It’s built using Hugo right now, and I’m just not a fan of how Hugo works (really I’ve just struggled to get my site to look the way I want and if I build my own I will hopefully be able to do that better).

                                                          On a personal fitness note, last Thursday I did my first toes-to-bar, and I’m going to continue practicing that.

                                                          1. 3

                                                            Fastmail is phenomenal. I’ve been a customer for ~3 years now and am happy as a clam. Plus it just keeps getting better and better.

                                                          1. 4

                                                            I mean, their docs are surprisingly good. They’re all I’ve really needed. To start, I’d suggest reading up on IAM, ECS, and probably S3. From there, just read the docs on whatever you need as you realize you need it.

                                                            EDIT: Since you’ve mentioned wanting a course, they offer courses you can take at your own pace: https://explore.skillbuilder.aws/learn

                                                            1. 26

                                                              I find the complaints about Go sort of tedious. What is the difference between using go vet to statically catch errors and using the compiler to statically catch errors? For some reason, the author finds the first unacceptable but the second laudable, but practically speaking, why would I care? I write Go programs by stubbing stuff to the point that I can write a test, and then the tests automatically invoke both the compiler and go vet. Whether an error is caught by the one or the other is of theoretical interest only.

                                                              Also, the premise of the article is that the compiler rejecting programs is good, but then the author complains that the compiler rejects programs that confuse uint64 with int.

                                                              In general, the article is good and informative, but the anti-Go commentary is pretty tedious. The author is actually fairly kind to JavaScript (which is good!), but doesn’t have the same sense of “these design decisions make sense for a particular niche” when it comes to Go.

                                                              1. 35

                                                                What is the difference between using go vet to statically catch errors and using the compiler to statically catch errors?

                                                                A big part of our recommendation of Rust over modern C++ for security boiled down to one simple thing: it is incredibly easy to persuade developers to not commit (or, failing that, to quickly revert) code that does not compile. It is much harder to persuade them to not commit code where static analysis tooling tells them is wrong. It’s easy for a programmer to say ‘this is a false positive, I’m just going to silence the warning’, it’s very difficult to patch the compiler to accept code that doesn’t type check.

                                                                1. 34

                                                                  What is the difference between using go vet to statically catch errors and using the compiler to statically catch errors?

                                                                  One is optional, the other one is in your face. It’s similar to C situation. You have asan, ubsan, valgrind, fuzzers, libcheck, pvs and many other things which raise the quality is C code significantly when used on every compilation or even commit. Yet, if I choose a C project at random, I’d bet none of those are used. We’ll be lucky if there are any tests as well.

                                                                  Being an optional addition that you need to spend time to engage with makes a huge difference in how often the tool is used. Even if it’s just one command.

                                                                  (According to the docs only a subset of the vet suite is used when running “go test”, not all of them - “high-confidence subset”)

                                                                  1. 15

                                                                    When go vet automatically runs on go test, it’s hard to call it optional. I don’t even know how to turn if off unless I dig into the documentation, and I’ve been doing Go for 12+ years now. Technically gofmt is optional too, yet it’s as pervasive as it can be in the Go ecosystem. Tooling ergonomics and conventions matter, as well as first party (go vet) vs 3rd party tooling (valgrind).

                                                                    1. 21

                                                                      That means people who don’t have tests need to run it explicitly. I know we should have tests - but many projects don’t and that means they have to run vet explicitly and in practice they just miss out on the warnings.

                                                                      1. 2

                                                                        Even in projects where I don’t have tests, I still run go test ./... when I want to check if the code compiles. If I used go build I would have an executable that I would need to throw away. Being lazy, I do go test instead.

                                                                    2. 13

                                                                      Separating the vet checks from the compilation procedure exempts those checks from Go’s compatibility promise, so they could evolve over time without breaking compilation of existing code. New vet checks have been introduced in almost every Go release.

                                                                      Compiler warnings are handy when you’re compiling a program on your own computer. But when you’re developing a more complex project, the compilation is more likely to happen in a remote CI environment and making sure that all the warnings are bubbled up is tedious and in practice usually overlooked. It is thus much simpler to just have separate workflows for compilation and (optional) checks. With compiler warnings you can certainly have a workflow that does -Werror; but once you treat CI to be as important as local development, the separate-workflow design is the simpler one - especially considering that most checks don’t need to perform a full compilation and is much faster that way.

                                                                      Being an optional addition that you need to spend time to engage with makes a huge difference in how often the tool is used. Even if it’s just one command.

                                                                      I feel that the Go team cares more about enabling organizational processes, rather than encouraging individual habits. The norm for well-run Go projects is definitely to have vet checks (and likely more optional linting, like staticcheck) as part of CI, so that’s perhaps good enough (for the Go team).

                                                                      All of this is quite consistent with Go’s design goal of facilitating maintenance of large codebases.

                                                                      1. 5

                                                                        Subjecting warnings to compatibility guarantees is something that C is coming to regret (prior discussion).

                                                                        And for a language with as… let’s politely call it opinionated a stance as Go, it feels a bit odd to take the approach of “oh yeah, tons of unsafe things you shouldn’t do, oh well, up to you to figure out how to catch them and if you don’t we’ll just say it was your fault for running your project badly”.

                                                                      2. 4

                                                                        The difference is one language brings the auditing into the tooling. In C, it’s all strapped on from outside.

                                                                        1. 19

                                                                          Yeah, “similar” is doing some heavy lifting there. The scale is more like: default - included - separate - missing. But I stand by my position - Rust is more to the left the than Go and that’s a better place to be. The less friction, the more likely people will notice/fix issues.

                                                                        2. 2

                                                                          I’ll be honest, I get this complaint about it being an extra command to run, but I haven’t ever run go vet explicitly because I use gopls. Maybe I’m in a small subset going the LSP route, but as far as I can tell gopls by default has good overlap with go vet.

                                                                          But I tend to use LSPs whenever they’re available for the language I’m using. I’ve been pretty impressed with rust-analyzer too.

                                                                        3. 12

                                                                          On the thing about maps not being goroutine safe, it would be weird for the spec to specify that maps are unsafe. Everything is unsafe except for channels, mutxes, and atomics. It’s the TL;DR at the top of the memory model: https://go.dev/ref/mem

                                                                          1. 6

                                                                            Agreed. Whenever people complain about the Rust community being toxic, this author is who I think they’re referring to. These posts are flame bait and do a disservice to the Rust community. They’re like the tabloid news of programming, focusing on the titillating bits that inflame division.

                                                                            1. 5

                                                                              I don’t know if I would use the word “toxic” which is very loaded, but just to complain a little more :-) this passage:

                                                                                go log.Println(http.ListenAndServe("localhost:6060", nil))
                                                                              

                                                                              Jeeze, I keep making so many mistakes with such a simple language, I must really be dense or something.

                                                                              Let’s see… ah! We have to wrap it all in a closure, otherwise it waits for http.ListenAndServe to return, so it can then spawn log.Println on its own goroutine.

                                                                               go func() {
                                                                                   log.Println(http.ListenAndServe("localhost:6060", nil))
                                                                               }()
                                                                              

                                                                              There are approximately 10,000 things in Rust that are subtler than this. Yes, it’s an easy mistake to make as a newcomer to Go. No, it doesn’t reflect even the slightest shortcoming in the language. It’s a very simple design: the go statement takes a function and its arguments. The arguments are evaluated in the current gorountine. Once evaluated, a new goroutine is created with the evaluated parameters passed into the function. Yes, that is slightly subtler than just evaluating the whole line in a new goroutine, but if you think about it for one second, you realize that evaluating the whole line in a new goroutine would be a race condition nightmare and no one would actually want it to work like that.

                                                                              Like, I get it, it sucks that you made this mistake when you were working in a language you don’t normally use, but there’s no need for sarcasm or negativity. This is in fact a very “simple” design, and you just made a mistake because even simple things actually need to be learned before you can do them correctly.

                                                                              1. 3

                                                                                In practice, about 99% of uses of the go keyword are in the form go func() {}(). Maybe we should optimize for the more common case?

                                                                                1. 1

                                                                                  I did a search of my code repo, and it was ⅔ go func() {}(), so you’re right that it’s the common case, but it’s not the 99% case.

                                                                                2. 2

                                                                                  I agree that the article’s tone isn’t helpful. (Also, many of the things that the author finds questionable in Go can also be found in many other languages, so why pick on Go specifically?)

                                                                                  But could you elaborate on this?

                                                                                  evaluating the whole line in a new goroutine would be a race condition nightmare and no one would actually want it to work like that.

                                                                                  IMO this is less surprising than what Go does. The beautiful thing about “the evaluation of the whole expression is deferred” is precisely that you don’t need to remember a more complicated arbitrary rule for deciding which subexpressions are deferred (all of them are!), and you don’t need ugly tricks like wrapping the whole expression in a closure which is the applied to the empty argument list.

                                                                                  Go’s design makes sense in context, though. Go’s authors are culturally C programmers. In idiomatic C code, you don’t nest function calls within a single expression. Instead, you store the results of function calls into temporary variables and only then pass those variables to the next function call. Go’s design doesn’t cause problems if you don’t nest function calls.

                                                                              2. 3

                                                                                At least they mention go vet so even people like me without knowing it can arrive at similar conclusions. And they also mention that he is somewhat biased.

                                                                                But I think they should just calmly state without ceremony like “And yet there are no compiler warnings” that this is the compiler output and this is the output of go vet.

                                                                                This also seems unnecessary:

                                                                                Why we need to move it into a separate package to make that happen, or why the visibility of symbols is tied to the casing of their identifiers… your guess is as good as mine.

                                                                                Subjectively, this reads as unnecessarily dismissive. There are more instances similar to this, so I get why you are annoyed. It makes their often valid criticism weaker.

                                                                                I think it comes as a reaction to people valid agreeing that golang is so simple but in their (biased but true) experience it is full of little traps.

                                                                                Somewhat related: What I also dislike is that they use loops for creating the tasks in golang, discuss a resulting problem and then not use loops in rust - probably to keep the code simple

                                                                                All in all, it is a good article though and mostly not ranty. I think we are setting the bar for fairness pretty high. I mean we are talking about a language fan…

                                                                                1. 5

                                                                                  This also seems unnecessary: […]

                                                                                  Agree. The frustrating thing here is that there are cases where Rust does something not obvious, the response is “If we look at the docs, we find the rationale: …” but when Go does something that is not obvious, “your guess is as good as mine.” Doesn’t feel like a very generous take.

                                                                                  1. 6

                                                                                    the author has years of Go experience. He doesn’t want to be generous, he has an axe to grind.

                                                                                    1. 3

                                                                                      So where’s the relevant docs for why

                                                                                      we need to move it into a separate package to make that happen

                                                                                      or

                                                                                      the visibility of symbols is tied to the casing of their identifiers

                                                                                      1. 3

                                                                                        we need to move it into a separate package to make that happen

                                                                                        This is simply not true. I’m not sure why the author claims it is.

                                                                                        the visibility of symbols is tied to the casing of their identifiers

                                                                                        This is Go fundamental knowledge.

                                                                                        1. 3

                                                                                          This is Go fundamental knowledge.

                                                                                          Yes, I’m talking about the rationale.

                                                                                          1. 3

                                                                                            https://go.dev/tour/basics/3

                                                                                            In Go, a name is exported if it begins with a capital letter.

                                                                                            1. 1

                                                                                              rationale, n.
                                                                                              a set of reasons or a logical basis for a course of action or belief

                                                                                            2. 2

                                                                                              Why func and not fn? Why are declarations var type identifier and not var identifier type? It’s just a design decision, I think.

                                                                                      2. 1

                                                                                        The information is useful but the tone is unhelpful. The difference in what’s checked/checkable and what’s not is an important difference between these platforms – as is the level of integration of the correctness guarantees are with the language definition. Although a static analysis tool for JavaScript could, theoretically, find all the bugs that rustc does, this is not really how things play out. The article demonstrates bugs which go vet can not find which are precluded by Rust’s language definition – that is real and substantive information.

                                                                                        There is more to Go than just some design decisions that make sense for a particular niche. It has a peculiar, iconoclastic design. There are Go evangelists who, much more strenuously than this author and with much less foundation, criticize JavaScript, Python, Rust, &c, as not really good for anything. The author is too keen to poke fun at the Go design and philosophy; but the examples stand on their own.

                                                                                      1. 3

                                                                                        Spacemacs is a popular alternative Emacs framework.

                                                                                        A week ago, I tried to research the difference between Doom and Spacemacs, but I didn’t learn of any fundamental differences. Both frameworks support either Emacs or Vim keybindings. Both define systems of keybindings starting with the Space key, though I imagine some specific key bindings might be different. And both of them come with optional modules/layers of configuration that you can supplement with your own Elisp.

                                                                                        After my exploration a week ago, I ended up sticking with my existing Spacemacs config because I couldn’t even install Doom on my work computer – the install command dumped a five-page Elisp stack trace about a nil somewhere. However, that error may have only happened because I was using a corporate proxy with network issues.

                                                                                        1. 3

                                                                                          spacemacs, in my experience was a little too abstracted from the emacs base and you had to point to the dev branch which was wildly unstable. I hope it has gotten better

                                                                                          1. 3

                                                                                            Can confirm this; we get a lot of questions in the #emacs channel on libera from people who are confused about the basics and no one can answer them because they’ve seemingly-arbitrarily gone and changed a bunch of stuff from the normal Emacs way without really explaining how.

                                                                                            1. 2

                                                                                              I’m not sure what you mean by confused users having “seemingly-arbitrarily gone and changed a bunch of stuff”. Do you mean that they just installed Spacemacs, which itself makes changes that seem arbitrary to vanilla Emacs users, or are you saying that Spacemacs users are more likely to make seemingly-arbitrary changes on top of Spacemacs (which they would probably do by editing their .spacemacs file)? Is your comment framework-agnostic – do you also hear from confused Doom users in that channel?

                                                                                              1. 3

                                                                                                I mean the first one.

                                                                                                We get confused Doom users but not as many; I think Doom learned from the mistakes of Spacemacs and either didn’t diverge in config as drastically, or documented things better.

                                                                                                1. 2

                                                                                                  Anecdata, as a vim user, I tried spacemacs twice (months or years between) and was kinda completely lost and the second time nothing worked out of the box, not even the install instructions.

                                                                                                  That day I installed doom and it was kinda nice. I didn’t stick with it, but the experience was so much better,

                                                                                            2. 1

                                                                                              I can’t comment on Spacemacs’s level of abstraction relative to Doom, but it is still true that with Spacemacs you have to point to the unstable develop branch to use recent features. For comparison, the develop branch has had 1,488 commits since February 2020, while the master branch has had only one commit (and it’s tiny).

                                                                                              That’s not as unstable as it sounds, though: Spacemacs won’t update itself automatically on the develop branch even if you set dotspacemacs-check-for-update to t. Your configuration will only update when you choose to run git pull in your ~/.emacs.d. (Spacemacs might update your packages – I forget if it does that automatically – but it lets you roll the package updates back if you think they broke anything.)

                                                                                            3. 2

                                                                                              The biggest difference for me was kinda silly, but with Doom I was able to figure out how to set my preferred theme in ~5min, whereas after almost an hour of reading Spacemacs’ documentation, I couldn’t figure out where I could set my preferred theme so that it would load on startup. Small and silly, but it just kept going from there: I was able to grok Doom and how to configure it much more quickly than Spacemacs.

                                                                                            1. 4

                                                                                              Including version control info in the binary is a great feature!

                                                                                              1. 1

                                                                                                I’m excited - my team has been encoding this in our binaries using linker flags, it’s going to be nice to get this for free!

                                                                                                1. 0

                                                                                                  I’m actually not that impressed with this feature. It makes tracking down the source of a dev build (i.e. go build) a bit easier, but I feel like it’s duplicating existing feature.

                                                                                                  It could have bridged the gap between go install and go build outputs (the latter previously did not have access to VCS information and therefore main module version). We use go install at $work because it embeds module version information and builds are reproducible (as long as everyone is on the same Go version that does not come from nixpkgs). The only downside is that the code should be pushed upstream before running go install.

                                                                                                  Now we get a few more flags to set in addition to -trimpath should someone use the new VCS information to finally implement main module versions for go build output since the extended VCS build information is not (yet, hopefully) set in go install output. Other than that, it’s nice to have an extensible Settings field in build info.

                                                                                              1. 14

                                                                                                Love the corrections, and I agree that it is weird that this tutorial uses Gin of all libraries to show of writing APIs with Go - Gin doesn’t even conform to the standard library’s net/http interfaces, you have to wrap any middleware that does conform.

                                                                                                One small nit-pick around the IDs, and it’s not even your improvements, but when you’re writing an API you should never (seriously can’t think of one reason why you should) let the user set record IDs. Ideally that should all be in the database (which is why using an in-memory database is an…odd choice).

                                                                                                Overall, Russ’s comments about the tutorial irk me a bit - if you want something narrow in scope, don’t choose to do something like a full-on RESTful API. Sure, it’s basic and common like spaghetti and meatballs, but like spaghetti and meatballs it takes a lot of work and a surprising amount of complexity to make it truly good. Like, auth is integral to how APIs work, interacting with a database is a key part of the API. Either give a disclaimer that those parts are going to be glossed over, or change the tutorial title to reflect that you’re focusing on RESTful endpoints or something.

                                                                                                I’m probably coming off overly grumpy about this, but I really love Go and I think we can do better when it comes to teaching aspects of the language. The rest of the documentation and (official) tutorials are incredibly good, no reason this can’t be as well.

                                                                                                1. 6

                                                                                                  These comments resonate with me – thanks.

                                                                                                  I agree about the caller not having to generate the ID: I should have made that change too. :-) I’ve added a comment pointing this out and linking here at the bottom of the Unique album IDs section.

                                                                                                  1. 2

                                                                                                    I’ve been quite happy with using chi.

                                                                                                    1. 2

                                                                                                      Me too. All new Go work I’ve done that justifies using something beyond the standard library has used Chi.

                                                                                                  1. 1

                                                                                                    I’m of the mind a mix of both is good. The first programming class I took used Python, which made it easy to translate my thoughts into a working program. Then, pretty early on in my CS track one of my classes had several assignments where we had to interpret assembly (I forget the instruction set). That got me to “think like a computer” and understand how my programs worked more than any other class I’ve taken.

                                                                                                    1. 3

                                                                                                      Scany adds some quality-of-life improvement on top of pgx by eliminating the need to scan into every field of a struct. However, the desired field names must still be listed out in a SELECT … statement, so it only reduces boilerplate by half.

                                                                                                      I personally don’t feel like that counts as boilerplate. But maybe someone with more expertise in SQL queries can tell me why using a SELECT * would be better than listing the fields. Or maybe I just don’t mind taking a little extra time to be explicit because I prefer it.

                                                                                                      And I don’t see the difference between writing the SQL statements in my Go code as strings and writing them in a SQL file and using code generation to generate Go code with the queries in…a string. I dunno, maybe I’m more allergic to code generation than the author.

                                                                                                      1. 3

                                                                                                        SELECT * means you’re getting an unbounded mess of all the columns, while listing them individually means you’ll both only get what you need, and your query will break if the table structure changes. It’s generally better according to the SQL book I read recently.

                                                                                                      1. 0

                                                                                                        In other words, use common sense. Who would have thought?

                                                                                                        1. 37

                                                                                                          Appeals to common sense only work for intuitive and empirical phenomena. Nothing about programming is intuitive, though, and most programming methodology is non-scientific.

                                                                                                          In this particular example, I have heard people use “common sense” as a justification for YAGNI, a polar opposite position, which suggests that there’s nothing common or sensed about the opinion.

                                                                                                          1. 9

                                                                                                            Considering how dogmatic some developers can be, stuff like this needs to be said more often than you’d think.

                                                                                                            1. 7

                                                                                                              Saying “use common sense” isn’t useful or informative to most people.

                                                                                                              1. 4

                                                                                                                Common sense is not as common as you’d think.

                                                                                                              1. 6

                                                                                                                I wish this included some explanation of why these are useful or explanations of why they are. Like, why use zerolog over logrus/zap/whatever? Why use gorilla/mux over gin or go-chi or the standard library? Why have that overly-complex unique code thing to determine where a logged error is thrown instead of making sure your errors have stack traces?

                                                                                                                1. 4

                                                                                                                  I’m not the author of the post, but I can try to answer some questions:

                                                                                                                  Like, why use zerolog over logrus/zap/whatever?

                                                                                                                  zerolog and zap is what the author of logrus admit he would write if he wrote logrus/v2. zerolog claims to be a “better” version of zap (there are claims of performance improvement on other people’s computers)

                                                                                                                  Why use gorilla/mux over gin or go-chi or the standard library?

                                                                                                                  gorilla/mux is much lightweight as opposed to gin which has renderers, etc… Also, there are claims of very high performance on other people’s computers. With gorlla/mux you can plug your own json de-/serialization library which is faster than gin’s.

                                                                                                                  Why have that overly-complex unique code thing to determine where a logged error is thrown instead of making sure your errors have stack traces?

                                                                                                                  ¯\(ツ)/¯ No idea… The unique code approach feels very hacky and brittle to me.

                                                                                                                  1. 3

                                                                                                                    I would even suggest “httprouter” as a more lightweight alternative to gorilla/mux.

                                                                                                                    1. 2

                                                                                                                      Most “higher level” Go routers are probably based on it anyways.

                                                                                                                    2. 1

                                                                                                                      We use unique logging codes for our logs, and it makes it easier to locate a particular statement in either the logs, or the source code. Now, we generate the unique code by hand, but it’s not a horrendous issue for us (we have a separate document that records each logging statement).

                                                                                                                    3. 1

                                                                                                                      I’d be curious to know the best practices for annotating errors with stack traces. Any good library suggestions?

                                                                                                                      1. 3

                                                                                                                        github.com/pkg/errors has some nice helpers, as described in its documentation. The issue is that it requires changing your code to using errors.Errorf() instead of fmt.Errorf().

                                                                                                                        Go2 will do it differently, but natively

                                                                                                                        1. 3

                                                                                                                          Also, errors.Wrapf is very useful when handling errors from packages which don’t use errors.

                                                                                                                          1. 2

                                                                                                                            You can wrap errors using fmt.Errorf() and the %w verb, and then later deal with them using errors.Is() or errors.As() and friends.

                                                                                                                            1. 1

                                                                                                                              That doesn’t give you stack traces though, correct?

                                                                                                                          2. 2

                                                                                                                            YES. This is probably my biggest issue with supporting production Go code. Errors are still too hard to locate.

                                                                                                                            1. 1

                                                                                                                              I personally use this to manage all that. If you use the errors.Wrap() function to wrap errors, it’ll add stack traces. And if you want to make a new error, the errors.New() function will also add a stack track where it was called. Then when you’re logging the error make sure it’s being logged in a way that will not just print the message. Most loggers should have a way to do that (I know zerolog and logrus do).

                                                                                                                              1. 1

                                                                                                                                Shameless plug for my errors library: https://pkg.go.dev/github.com/zeebo/errs/v2

                                                                                                                                • captures stack traces, but only once even if wrapped multiple times
                                                                                                                                • plays nicely with standard library errors package with errors.Is and errors.As
                                                                                                                                • has a “tag” feature to let you associate and query tags with errors
                                                                                                                                • helper to keep track of groups of errors