Embedding your assets like this isn't always an improvement. For example, I work on a site with a Go server and static content pages, and I like that I can update one of the pages and see the change instantly without having to re-compile the entire server binary just to get the new files included.
> Why do you prefer having an app running (and owning the sole menu bar) when it has no GUI on screen?
Here's a story from when I was using Windows for work after using Macs for ages. I had one folder in Sublime Text open, and I wanted to close that window and then open another one. So I hit the [X] button in the corner, which closed the window, and then I instinctively went to the global menu bar at the top of the screen to go to 'File › Open' to open my new window. But of course, it wasn't there, because closing the window also got rid of my ability to access the menu bar.
And then I opened Sublime Text again, and it re-opened with the old window I wanted to get rid of.
This is why, like others in this thread, I've grown to really like the application-vs-window separation. Having a menu bar on each window, and having programs close themselves when they get down to zero windows, means I have to do my operations in a certain order (I have to open my second window before I can close the first one, I can't do it in either order) and use a UI hierarchy that I don't think makes sense (I have to use the menu bar of an existing window to open a new window, even though that operation has nothing to do with that window's contents).
> The standard net/http server violates this advice and recovers panics from request handlers. Consensus among experienced Go engineers is that this was a historical mistake. If you sample server logs from application servers in other languages, it is common to find large stacktraces that are left unhandled. Avoid this pitfall in your servers.
I don't think I've ever seen a server library — HTTP or otherwise — that didn't have a top-level "catch all exceptions" or "recover from panic" step in place, so that if there's a problem, it can return 500 (or the Internal Server Error equivalent) to the user and then carry on serving other requests.
My reasoning is that any panic-worthy programming error is almost certainly going to be in the "business logic" part of the server, rather than the protocol-parsing "deal with the network" part, and thus, recoving from a panic caused by processing a request is "safe". One incoming request could cause a panic, but the next request may touch completely unrelated parts of the program, and still be processed as normal. Furthermore, returning a 500 error but having nobody read the stacktrace is bad, yes, but it's way, way, way better than having your server crash meaning nobody can use it ever.
Oh wait, is the assumption here that your service is being run under Borg and has another 1000 instances running ready to jump in and take the crashed one's place? Is this another case of Google forgetting that people use Go outside of Google, or am I reading too much into this?
As a sidenote to your sidenote: I've noticed that the term "syntax" seems to have two different meanings nowadays. There's the technical meaning, namely "the rules that govern how characters are parsed into abstract syntax tree nodes", which in your example, would cover whether Rust shoud use `.` or `::` as a namespace separator, whether to use `[]` or `<>` for generics, that sort of thing. (Both of which have trade-offs in constraining how other parts of the language can be designed.)
But I think sometimes, people use "syntax" in a blanket "how the language looks" way — that is, whether it's symbol-heavy, whether it's word-based, whether it's information-light or information-dense, and so on. This makes it more a function of which features of expressivity the language chooses to expose, than the individual syntactic choices that determine which characters we use and for what. Again in Rust's case, it has attributes, it has namespace separators, it has the zero-tuple, it has generics, and it has lifetimes, all of which need some way to be expressed.
Don't get me wrong, you're allowed to not use a language if you don't like the way it looks visually. Or maybe it makes good use of a certain character that's hard to type on your particular keyboard layout. That's fine. I also can't decree that either of these uses of the term "syntax" are wrong. But when we're talking about language syntax, it's important to remember when you're talking about syntax, and when you're instead talking about language features. If you don't like the way lifetimes look, that's one thing; if you don't like the way lifetimes make you change the way you write code, that's another.
So I have to ask: of those four code snippets, how would you prefer to write them? What would you change? And can you get away with making those changes without breaking anything else?
Looks like the application requires macOS v12, which is only a year old. What features does it require that means it can't be backwards-compatible? Is it a SwiftUI thing?
> Programming is a means to an end, and the cost of using Rust (hiring, increased development time) is often not worth it.
I agree with this. I learnt Rust before Go, and using Go makes me feel like The Oatmeal piracy guy[1]:
"I'm not sure if I should use Go to write this HTTP service. I'd lose immutability tracking, I'd lose compiler-enforced thread safety, I'd lose the powerful type system, I'd lose the comprehensive error handling, I'd suffer from a million little papercuts, I'd have to use the weird date formatting system, I'd have to check nil pointers, I'd...
...oh, it's seven days later and I've already accomplished more writing networking servers and clients in Go than I ever have in years with Rust."
This isn't to say the points raised about Go aren't true. They are true, and if a better language were available, I wouldn't stand my ground and argue their benefits, I'd switch to it. The last comment I happened to post on this website is about how Go is insufficient without its army of linting tools [2]! Yes, I'm incredibly happy to have learnt both Go and Rust as their combination has expanded my skillset and the range of programs I'm willing to write tremendously. But if someone said to me "you should just use Rust instead of Go for your production services", I'd think the "just" was doing some incredibly heavy lifting.
An article that I'd like to see is one comparing the two languages for this niche (networking servers and clients), contrasting not just the language pitfalls but the third-party libraries necessary, the iteration speed, and the choices you'll have to make up-front. My guess is that the languages would be judged more closely together.
Like many things with Go, its approach seems reasonable and simple at first, but allows you to accidentally write code that looks right but is very, very wrong. For example, what do you think this code will do?
Now I insist on using the durationcheck lint to guard against this (https://github.com/charithe/durationcheck). It found a flaw in some exponential-backoff code I had refactored but couldn’t easily fully test that looked right but was wrong, and now I don’t think Go’s approach is reasonable anymore.
Serious question: how do you square your third paragraph with your first? That is, if you're using Obsidian's features like [[square bracket link syntax]], or #tags, or inline images, aren't you effectively locked in to editors that support the same set of features?
> Just a reminder to everybody that Fastmail is an Australian company, and is therefore subject to Australia's TOLA / Assistance And Access. [...] Having your e-mail provider compelled to work against your interests is no joke and you may not want to be in that situation.
This is not quite true.
The TOLA bill does allow the Australian government to compel an employee to break their product's encryption — which, yes, is dumb as hell. But Fastmail does not offer end-to-end encryption. As an Australian company, they already have had to comply with a court warrant asking them to surrender data; in other words, law enforcement does not need them to install a backdoor when they already have a front door. Your comment implies that TOLA made Fastmail less secure somehow, but this has been the case long before TOLA; the existence of that bill changes nothing.
I feel like it's important to point this out, not for the sake of pedantry, but to say that if you want truly secure encrypted e-mail, you must be in control of the encryption and decryption step, rather that having a company do that for you — you can't assume you'll be safe just because your provider isn't based in Australia. It's been a while since I've looked, but I think it would be very hard to find an e-mail provider that explicitly says it won't hand over data when presented with a valid warrant.
I use cURL a ton too, for when I want to make a one-off request, examine the response, and then throw it away. Here are some reasons why I'd reach for a tool like this:
• I want the history of every request and response to be saved by default, so if I ever need to look back to one I know it's available
• I'm sending several similar requests and I want them to share a set of variables, or, I want something in the response of one request to be used as a parameter when sending another
• I want to set a URL parameter with a bunch of symbols in without worrying about quoting
• I have so many types of requests that I'd like to organise them in a tree
• The JSON returned in a response is absolutely massive and I'd like to expand/collapse subtrees instead of viewing the whole thing as unhighlighted text
EDIT: I just tried the latest beta, and I'm happy to say that scrolling the list is now much faster! On the other hand, the blurry fonts, the lack of overscroll, the non-native dropdown menus, the inability to view your vault with the Preferences window open, and the lag when resizing the window are all still there. This does not fill me with hope that the final released version is going to be any better.
If you're using Make as a command runner or a "standard entry point" to a project, instead of using it as a build system that tracks dependencies between files, I highly recommend using `just` instead: https://github.com/casey/just
It has this functionality built-in, and avoids a lot of Make's idiosyncrasies. (Not affiliated, just a fan.)
> My (limited) exposure to Java was quite painful because I had to deal with layers and layer of inheritance and abstractions that at some point made it very difficult to do what I needed to do.
Hey — could you go into more detail about some of the times when inheritance and abstraction in Java were a problem, or when you had to deal with the gorilla issue?
I promise I'm not trying to catch you out or start a language war; as someone who lived in the Java world for a long time, I'm interested in which parts of it people who visited briefly have found annoying or painful to deal with.
I set up a non-public-facing IPv6-only web server last night, so the issues are fresh in my mind! I'm fortunate enough to have an IPv6-capable home connection, and the hosting provider I use (Scaleway) charges extra for assigning IPv4 addresses to machines, so I thought I'd see how easy it would be to save a bit of money and make this machine IPv6-only. I've IP-filtered the host to only my home and my other servers, so having IPv4 support should be a waste.
The machine is now running fine, but I had a few roadblocks setting it up:
• My provisioning scripts download a release of 'dry'[0] from GitHub, which does not support IPv6. I ended up assigning my new machine a temporary IPv4 address and removing it later.
• The scripts also import a key from 'keyserver.ubuntu.com'[1], which, again, does not support IPv6. Attempting to connect just timed out, and if I hadn't just solved the other issue, I would have assumed the host was down.
• There seems to be a bug in Scaleway's cloud firewall (the things it calls Security Groups), where you cannot allow inbound ICMPv6, only standard ICMP (for IPv4). This meant my pings never responded and I thought the machine wasn't up when it was up.
Basically, what I want you to take away from this post is that if you disable IPv6, it's still the case that during maintenance, things are going to break, often mysteriously and with bad error messages, but outside of maintenance, things will likely run smoothly. My machine runs Sentry, and after the problems I had setting it up, I didn't dare run the Sentry './install.sh' script with IPv4 disabled as I didn't trust it to handle that case correctly — and even if the script reported no errors, I wouldn't have trusted there to actually be no errors. Since then, though, it's been running fine, so having an IPv6-only server is certainly possible, even if you have to give in and assign it an IPv4 address at the start, then take it away again later.
I'd be really happy with that! Building the functionality of errcheck[1] and ineffassign[2] into the compiler — or at the very least, into govet — would go a long way to allay my worries with Go.
I think the reason they don't do this is that it's a slight (albeit a very tiny one) against Go's philosophy of errors being values, just like any other. While the `error` type is standard and used throughout Go source code, it still just has a simple three-line definition[3] and is not treated as a special case anywhere else; there is nothing stopping you from returning your own error type if you wish. A third-party linter could simply check for the `error` type specifically, but the first-party tools should not, and there's nothing like Rust's `#[must_use]` attribute that could be used instead. I respect Go's philosophy, but I feel like pragmatism must win in this case.
I like Go. It's useful for the things I need it for since it compiles fast into a single binary and has networking utilities in its standard library. I was used to Rust's error handling when I started, but I liked how simple Go's design was in comparison, so I stuck with it to get a proper feel for the language.
After a while, I tried using the Goland IDE, and its static analysis tool found a dozen places where I wasn't handling errors correctly: I was calling functions that return errors (such as `io.ReadCloser.Close` or `http.ResponseWriter.Write`) without assigning their results to variables, so any errors produced by them would simply be ignored. My code was compiler-error-free, go-vet warning free, and still, I was shipping buggy code.
A few months later, I try using the golangci-lint suite of linters, and again, it found even more places where I wasn't handling errors correctly: I was assigning to `err` and then, later, re-assigning to `err` without checking if there was an error in between. My code was still compiler-error-free, go-vet warning free, and now IDE-warning free — and I was still shipping buggy code.
I don't see how anyone can see this as anything other than a big ugly wart on the face of the language. It's not because it's repetitive, it's because it's fragile. Even with code I was looking at and editing regularly, it was far too easy to get wrong. I'm going to continue using Go because it still fits my purposes well, but I'm only running it on my servers, so any mistakes I make are on my head, rather than on anybody else's.
I also don't think Go's design is really amenable to things like the Option and Result types people are writing — yes, I would never have had these problems in Rust, but code written using them in Go is clunky and looks out-of-place and doesn't feel like it's the right thing to write. I wouldn't ever use the `Optional` type in the article. But it's definitely not a solution in search of a problem. There's a huge problem.
• It's huge. If I run `docker-compose ps`, it lists thirty entries, one of which seems to have failed and exited.
• With that hugeness comes CPU and RAM requirements. Sentry's installer complains if you give it anything under 8 GB of memory and 4 cores.
• The UI comes with an obnoxious amount of JavaScript, and is just generally slow and clunky. I see spinning wheels a lot.
Errorpush looks like a fantastic alternative for my needs, especially if I'm able to use the Rollbar Terraform provider to configure it, as well as if there are suitable integrations for all the programming languages my services are written in.