HNHacker News
TopNewBestAskShowJobs

throwitaway1123

469 karma · joined November 28, 2023

Created this account 11/23. Might throw it away at some point.
submissionscomments
throwitaway1123··on Why Gumroad Didn't Choose Htmx
> Plus in most cases showing error messages too fast is terrible UX.

The solution to that problem is to debounce or throttle your error messages. That allows you to report validation issues to the user quickly, but not overwhelmingly fast, before sending a network request potentially across the Earth and back.

throwitaway1123··on Rewriting Rust
React and react-dom are peer dependencies (npmgraph lists them but doesn't graph them visually). The actual full installation command is: `npm install next@latest react@latest react-dom@latest`[1]. Even if you include react and react-dom, the dependency graph still looks tolerable to me: https://npmgraph.js.org/?q=next%4014.2.13%2C+react%4018.3.1%...

[1] https://nextjs.org/docs/getting-started/installation#manual-...

throwitaway1123··on Rewriting Rust
> The alternative is the npm hellscape where you have a package for "isOdd" and a package for "is even" that can break the entire ecosystem if the owner is disgruntled because everything depends on them.

The is-odd and is-even packages are in no way situated to break the ecosystem. They're helper functions that their author (Jon Schlinkert) used as dependencies in one of his other packages (micromatch) 10 years ago, and consequently show up as transitive dependencies in antiquated versions of micromatch. No one actually depends on this package indirectly in 2024 (not even the author himself), and very few packages ever depended on it directly. Micromatch is largely obsolete given the fact that Node has built in globbing support now [1][2]. We have to let some of these NPM memes go.

[1] https://nodejs.org/docs/latest-v22.x/api/path.html#pathmatch...

[2] https://nodejs.org/docs/latest-v22.x/api/fs.html#fspromisesg...

throwitaway1123··on Rewriting Rust
> Look at the dependency tree for a next

Looks ok to me: https://npmgraph.js.org/?q=next

Ironically, most of the dependencies are actually Rust crates used by swc and turbopack [1][2]. Try running `cargo tree` on either of those crates, it's enlightening to say the least. And of course, Node has a built in file watcher, and even the most popular third party package for file watching (Chokidar) has a single dependency [3].

[1] https://github.com/vercel/next.js/blob/07a55e03a31b16da1d085...

[2] https://github.com/swc-project/swc/blob/b94a0e1fd2b900b05c5f...

[3] https://npmgraph.js.org/?q=chokidar

throwitaway1123··on Orion, our first true augmented reality glasses
Yeah it is surprising because it seems like a relatively obvious solution. The Watch doesn't use electromyography though [1], it looks like it currently uses "the accelerometer, gyroscope, and optical heart sensor with a new machine learning algorithm." I wonder how accurate that is compared to the EMG solution Meta is using.

[1] https://www.apple.com/newsroom/2023/10/apple-watch-double-ta...

throwitaway1123··on Orion, our first true augmented reality glasses
That was the part that stood out to me as well after watching The Verge's video: https://youtu.be/mpKKcqWnTus?t=98

The Vision Pro uses optical sensors for hand tracking, so if your hands aren't visible to the device it obviously can't track them. Electromyography solves that problem, and I could imagine Apple integrating some variant of this in a future Apple Watch, and just falling back to optical sensors if you don't own one.

throwitaway1123··on Microsoft TypeSpec
The built in DOM types for the browser's `crypto.randomUUID` function actually already use this technique to a lesser extent: https://github.com/microsoft/TypeScript/blob/121c5dd36bd87e4...
throwitaway1123··on Rio: Web apps in pure Python
> "2 or 2000..." statement is just a jab toward mathematicians.

It's a jab towards mathematicians in the context of criticizing a language proposal. He's comparing the complexity of mathematicians and their 2000 line proofs to the complexity of allowing statements in lambdas. He explicitly calls the proposal a "Rube Goldberg contraption".

> Bit of correction: no statements and a single - arbitrarily complex - expression.

I phrased it as a dichotomy between single and multiple statements because in many languages there's the concept of an 'ExpressionStatement', which is a single expression that acts as a statement. This makes the boundaries between a single statement and an expression somewhat murky. In JS for example the MDN docs have this to say about ExpressionStatements: "Apart from the dedicated statement syntaxes, you can also use almost any expression as a statement on its own." [1] GVR himself calls it "the problem of the multi-statement lambda" rather than "the problem of the statement lambda".

I don't want to get bogged down in pedantic debates about terminology though. I completely understand how it works, and said in my very first reply to you: "but it's nice to not be limited to expressions".

> End of the day, support for statements in a lambda would lead to a need for new symbols.

All it would require is a newline character. He calls this out in the blog post: "If the double colon is unpythonic, perhaps a solution could be found that uses a single colon and is still backwards compatible [...] I actually have one in mind: if there's text after the colon, it's a backwards-compatible expression lambda; if there's a newline, it's a multi-line lambda; the rest of the proposal can remain unchanged. Presto, QED, voila, etcetera."

There's absolutely nothing complex about allowing statements in lambdas from a user interface perspective (all of the complexity is in the implementation). Almost every modern language has support for this feature. Even Golang, which is perhaps the epitome of simplicity — the language that fought tooth and nail against generics, and doesn't have a ternary operator (or inline if), or string interpolation — supports defining inline callback functions with statements. There are even whitespace sensitive languages like CoffeeScript that bit the bullet and don't impose any restrictions on lambdas. The simplicity argument just feels really weak to me. At the time that blog post was written a Python user couldn't add a print statement to a lambda to debug their code. How in the world is that simple for biology students and people writing one-off projects?

[1] https://developer.mozilla.org/en-US/docs/Web/JavaScript/Refe...

throwitaway1123··on Rio: Web apps in pure Python
> You don't need to try putting words in his mouth after he specifically stated that maintaining a simple user interface is higher priority.

I'm not trying to put words in his mouth (I'm pretty sure I delineated his direct quotes with quotation marks). But I saw him write multiple paragraphs about the complexity of lexing multi-statement lambdas in Python due to its whitespace sensitivity, and then conclude that the user facing interface must necessarily be complex too, which just feels fallacious to me. If the complexity of the implementation doesn't factor into the design then why go through so much effort to communicate how difficult it is to lex? He compares the implementation to a "2000 step [...] infinite-dimensional" mathematical proof.

I just fundamentally don't buy the argument that one statement in a lambda is fine, but two is dark magic that needs to be removed from the call site and quarantined in a separate def, and I think if the implementation were simpler GVR wouldn't have been so diametrically opposed to the feature. Even if he outsourced the "puzzle solving" to an external contributor, no one enjoys the increased maintenance burden of a complex implementation.

Anyone who's ever written customer facing code knows what it's like to receive a seemingly simple feature request that's actually difficult to implement because of prior architectural decisions, and the "gut reaction" is to convince the user that the feature itself is bad. I hate to invoke comedy but this reminds me of the microservices meme: https://www.youtube.com/watch?v=y8OnoxKotPQ

throwitaway1123··on Rio: Web apps in pure Python
From the blog post you linked: "But the complexity of any proposed solution for this puzzle is immense, to me: it requires the parser (or more precisely, the lexer) to be able to switch back and forth between indent-sensitive and indent-insensitive modes, keeping a stack of previous modes and indentation level."

He's saying exactly what I said: that parsing (or more precisely lexing) makes the problem complex, because Python uses indentation semantically. He then rationalizes avoiding the implementation complexity with a gut feeling: "But none of that takes away my gut feeling".

throwitaway1123··on Rio: Web apps in pure Python
If a callback function gets really unwieldy then you should probably extract it from the call site and define it elsewhere, but that should happen because you decided to, not because the language's limitations coerced you into doing it. The lambda restrictions in Python are probably due to the complexities of parsing indentation based languages, and the clean code argument is just a helpful rationalization. I've never woken up in angst over the fact that I wrote a callback function with two statements in it.
throwitaway1123··on Rio: Web apps in pure Python
Using a list combined with the walrus operator is a clever hack, but it's nice to not be limited to expressions. In JS you can define the equivalent of a multi-line lambda function with any number of statements (which is helpful when you're passing a function as a callback e.g. in a React hook).
throwitaway1123··on Swift 6
I also disliked unqualified imports. I can never get used to languages where you can 'import foo' or 'use foo' and it just dumps a bunch of symbols into the current scope. That combined with Swift's 'implicit member expressions' makes it difficult to read code outside of an IDE (although I understand why they made that tradeoff given some of the long identifiers Swift inherited) [1].

[1] https://github.com/Quotation/LongestCocoa

throwitaway1123··on Show HN: Electrico – Electron Without Node and Chrome
It might have been confusing since there's another project operating in this space called Neutralinojs.
throwitaway1123··on Show HN: JAQT – JavaScript Queries and Transformations
Dexie supports observable queries, but it operates on IndexedDB rather than plain JS objects: https://dexie.org/docs/liveQuery()#vanilla-js
throwitaway1123··on macOS Sequoia is available today
Wow, that might be the best part of the update. System Integrity Protection shields /usr, /bin, and /sbin, so I prefer to use the system provided executables in those directories when possible.
throwitaway1123··on Show HN: JAQT – JavaScript Queries and Transformations
This is actually a pretty decent use case for something like this. You could technically convert a user provided filter function to a string to serialize it, then recreate it using the Function() constructor, but that requires adding 'unsafe-eval' to your content security policy [1][2].

[1] https://developer.mozilla.org/en-US/docs/Web/JavaScript/Refe...

[2] https://developer.mozilla.org/en-US/docs/Web/JavaScript/Refe...

throwitaway1123··on Ask HN: Anyone else hate sports with a passion?
It sounds like you have an aversion to sports because you were forced to participate in them as a child, which is completely understandable. If someone had coerced you into the school's drama program you might find theater revolting as an adult as well.

It might help to think of sports less as "people playing a simple game" and more as "a demonstration of human athleticism at the highest level". The game is just a pretext. When you watch table tennis, you're viewing people with some of the most finely honed fast twitch muscle fibers, reflexes, and hand eye coordination in the world demonstrate their skills, not just people bouncing a ball back and forth across a table.

You might also enjoy the data analysis aspect of sports. Sports are increasingly being dictated by statistics. It's somewhat cliche at this point to recommend it, but if you haven't already, it might be worth watching the movie Moneyball (or reading the book it's based on).

throwitaway1123··on iPhone 16 Pro and iPhone 16 Pro Max
They definitely could, but it would likely cost Apple more to have two sets of sensors, not to mention take up more space in the device itself. Isn't that how they justified removing the headphone jack? And of course this is Apple we're talking about — they would probably deem having two authentication methods to be too confusing for users. They only recently decided to allow things like arbitrary home screen icon re-arrangements in iOS 18.
throwitaway1123··on iPhone 16 Pro and iPhone 16 Pro Max
The rest of the industry seems to be moving towards under-screen ultrasonic fingerprint readers, which if Apple adopted, would allow them to shrink the notch by getting rid of the Face ID sensors. I think they've dug in their heels on Face ID though, so it likely won't happen (although they did reverse course on Force Touch, so anything is possible).

They likely won't end up reducing the size of the notch any further until they figure out how to either make Face ID work with just a single selfie camera (which would inevitably be less secure), or put the sensors under some sort of semi-transparent display.

Many people thought they missed an opportunity by not simply putting the fingerprint sensor under the Apple logo on the back of the iPhone, but they probably didn't like the UX of that solution.

throwitaway1123··on Htmx, Raku and Pico CSS
> Plus they only work with JS enabled, unlike React+SSR where you can progressively enhance your app.

You can SSR web components using the Declarative Shadow DOM API, which is finally supported in all of the major browsers and works without JS.

throwitaway1123··on Greppability is an underrated code metric
I personally believe that Prettier strikes a decent balance between being configurable vs being opinionated. I've used formatters that are much less opinionated than Prettier (e.g. the last time I used XCode it only handled indentation by default). ESLint also teeters on the edge between configuration vs convention quite well in my opinion, especially given the fact that browser JS and server side JS have vastly different linting requirements. I also love the extensibility of ESLint. Being able to write your own linting rules is a boon on productivity. Having access to custom framework specific linting rules is quite nice (I couldn't use React without the react-hooks/rules-of-hooks third party ESLint rules).

> Some JS, some TS

I think the JS community has done remarkably well amongst dynamically typed languages in settling on one form of gradual typing and adopting it fervently (Flow no longer has any market share at all). Whereas the last time I checked Python still had the Mypy/Pywright divide, and Ruby had the Sorbet/RBS dichotomy.

Ultimately though, most of your critique boils down to the fact that JS (unlike Rust and Go) isn't maintained by a single monolithic entity, and therefore there's no one to dictate the standards you're looking for. If Deno were the sole caretaker of JS for example, we'd have a standard linter and formatter devoid of complex configuration, but Deno doesn't control JS.

This is a consequence of JS being a collaborative product of the various browser vendors, TC39, and the server side JS runtimes that have adapted JS to run on servers. The advantage of this of course though is that JS can run natively in the browser. I think that's a decent tradeoff to make in exchange for having to wade through dependencies with different ideas about when it's appropriate to use arrow functions.

throwitaway1123··on Greppability is an underrated code metric
Since we're on the topic of higher order functions, arrow functions allow you to express function currying very succinctly (which some people prefer). This is a contrived example to illustrate the syntactical differences:

  const arrow = (a) => (b) => `${a}-${b}`
  
  function verbose(a) {
    return function (b) {
      return `${a}-${b}`
    }
  }
  
  function uncurried(a, b) {
    return `${a}-${b}`
  }
  
  const values = ['foo', 'bar', 'baz']
  values.map(arrow('qux'))
  values.map(verbose('qux'))
  values.map(uncurried.bind(null, 'qux'))
  values.map((b) => uncurried('qux', b))
throwitaway1123··on Greppability is an underrated code metric
ESLint and Prettier are the de facto default linter/formatter combo in JS. There are rules you can enable to enforce your preferred style of function [1][2].

[1] https://eslint.org/docs/latest/rules/func-style

[2] https://eslint.org/docs/latest/rules/prefer-arrow-callback

throwitaway1123··on State and time are the same thing
> code execution could be mapped to diffs between state transitions to provide rewind functionality and debugging for free.

Some of what you're saying reminds me of the JS library Immer. Using JS proxies (which can intercept and detect arbitrary object mutations), it allows you to produce a new state by mutating a "draft" copy of the current state.

The produceWithPatches function provides you with arrays of patches and inverse patches that are essentially diffs between the old state and the new state. You can then apply these patches and inverse patches (using Immer's applyPatches function) to rewind the state backwards and forwards. Elm was one of the first languages (on the frontend at least) to pioneer this concept of "time travel debugging", which was then popularized by the Redux DevTools web extension.

throwitaway1123··on Dokku: My favorite personal serverless platform
Yes, this is correct. If you're using IP address allowlists then you also have to check the Host HTTP header (Cloudflare won't allow their other customers to forge that header). Or, you can use mTLS (as another commenter pointed out), or tunnels (as I pointed out): https://news.ycombinator.com/item?id=26690388
throwitaway1123··on Dokku: My favorite personal serverless platform
Agreed. It also can't hurt to setup a firewall or EC2 Security Group that only allows ingress from Cloudflare IPs: https://www.cloudflare.com/ips/

Alternatively, you can use Cloudflare Tunnel, and then block all incoming connections.

throwitaway1123··on Show HN: Ruroco – like port knocking, but better
> It does not matter - all the ports are closed.

Yeah and I have a lock on my door. I still won't post my address on HN. It's all about defense in depth.

Another thing I forgot to mention is that port knocking only works if your hypothetical friend has a dedicated static IP. If your ISP decides to reassign your IP address then IP allowlists are useless. Many ISPs in the US run this racket where they make you pay for a "business account" to get a dedicated IP, even if you only want an IP6 address (which are plentiful).

throwitaway1123··on Show HN: Ruroco – like port knocking, but better
You are both slightly wrong, and slightly misunderstanding what I'm saying.

> TLS is not mandatory in all cases, but if you want to use it, it is not an issue having a certificate.

TLS is mandatory if you want to ensure your connection isn't being eavesdropped on or tampered with.

> And even then you do not have to open any ports, even to letsencrypt verification, since you can use DNS verification method instead (for example using Cloudflare API).

Yes this is called the ACME DNS challenge. I've used it many times, but if you want to be able to type in your server's domain name on a friend's TV and have it resolve to your server's IP address, then you'll need a public DNS record.

> Certificate itself has nothing to do with DNS beyond the verification step.

Yes it does, because most certificate authorities only sign certificates for fully qualified domain names, not IP addresses [1], so it obviously does involve the domain name system (you can view the domain name associated with a certificate in your browser, it'll be listed under the field "common name"). On a desktop computer you could get around this by editing the hosts file to map any domain name to any arbitrary IP address, but you can't do that on a TV.

> And there can be a public DNS record but it doesn't say anything about ports. And the CT transparency log doesn't say anything about ports or IP addresses.

I never said anything about ports, I said a public DNS record exposes the server's IP address. The whole point of the domain name system is to convert domain names into IP addresses, so that you can actually use the internet protocol to connect to a server's IP (internet protocol) address. Try running dig from the command line on literally any domain name and watch it expose the server's IP. Malicious bots can watch the transparency log to find out about new certificates [2], then run dig or some other tool to issue a DNS request (to determine the IP address of the server), and then start hammering the server to search for vulnerabilities or even potentially to just DDOS it. If you use a wildcard certificate it's harder for attackers to figure out which subdomain to query to find your server's IP, but with WireGuard I don't need a domain name at all.

[1] https://community.letsencrypt.org/t/ssl-on-a-ip-instead-of-d...

[2] https://community.letsencrypt.org/t/suspicious-web-traffic-a...

throwitaway1123··on Show HN: Ruroco – like port knocking, but better
Port knocking only handles authentication (it's basically a crude password). It doesn't ensure the integrity (tamper prevention) or privacy of your connection. You would need to set up SSL certificates to handle that. You also need to get the TV to accept those certificates, which would require either a public DNS record (which exposes your server's IP via the certificate transparency log to any client that can issue a DNS request), or you would need to modify your friend's router's DNS resolver (which is even more complicated than installing a VPN, and assumes the TV uses the router's DNS server). A TV isn't going to have an /etc/hosts file that you can use to point a domain at your server's IP address.

So instead I would go to my friend's house, connect to their Wifi, and accept incoming connections from computers and TVs over the local area network and forward them through WireGuard. The TV would connect to my device via plain HTTP (which is fine since it's all happening locally), and then my device would be responsible for securely connecting to the server via WireGuard. This also has the benefit of implicitly revoking access as soon as I leave their house with my device.

← PreviousPage 3 of 11Next →