I make software and climb mountains. Currently building Profit, a portfolio performance tracker / trading journal app for macOS and iOS over at @codefreeze
I really believed a whole generation of developers, who only know open source from npm and pypi, miss how open source actually used to work.
When Debian or a Linux distribution ships a dependency they take responsibility of it. If there is a security issue and it’s not fixed by the developer upstream, they fix it for their users.
Debian and others basically vendor every thing they distribute. They honor the license and they maintain patches. Most of the stuff that you get from your Linux distribution is basically a (small) fork.
The same is true for Apple, Microsoft and others. The open source software they ship, they carry that responsibility.
That doesn’t mean that security fixes are not upstreamed, but Apple or Debian or anyone else won’t jump in Twitter to shame a developer into compliance with their ways. They are not dependent on the health of a packaging infrastructure. They own their software including all the things it depends on.
I want that thinking back. Because it fundamentally makes people feel more responsibility and it shares the burden of issues. It also does not put so much focus and attention on the one overworked developer who just happened to have too much of the world depend on their library. Remember: they carry a responsibility they never signed up to and they never got compensated for.
Complexity is a beast. Even when paying attention to keep things simple, you end up with complexity at some point. You constantly have to take a step back, reevaluate your decisions, and trim.
@seriengruender Ich bin tendenziell auch gegen eine Wegzugsteuer in der jetzigen Form, aber ganz von der Hand zu weisen ist die Grundidee ja nicht. Warum sollte man stille Reserven, die in Deutschland geschaffen wurden, nicht auch hier versteuern?
Don't use `additionalProperties: true` in your LLM tool schema definition. It doesn't work uniformly across providers. OpenAI handles it, OpenRouter collapses it into an empty {} object. If you want arbitrary JSON as parameter, you better send it marshaled as a string.
@godbout It boggles my mind how an application built with native frameworks can be so much laggier than a browser window rendering a complex website. SwiftUI on macOS is a disaster. I’m experiencing this with my own app and am in the process of going back to AppKit for non-trivial views.
Man schimpft gerne über die deutsche Bürokratie und die fehlende Digitalisierung, aber es gibt auch Positives zu berichten.
Am Dienstag habe ich ein neues Fahrzeug online via i-Kfz zugelassen. Login über Elster, ein paar Daten eingegeben, mit Kreditkarte bezahlt, fertig. Hat wahrscheinlich keine 5 Minuten gedauert.
Eine halbe Stunde später kam die Nachricht, dass die Unterlagen verschickt wurden (ZB I+II und Plaketten), und 2 Tage später hatte ich sie im Briefkasten.
Um Längen angenehmer und stressfreier als das Aufsuchen der örtlichen Zulassungsstelle.
If your origin servers and most of your users are in Germany, it’s probably not a good idea to use Cloudflare Free. Not because Cloudflare is bad, but because Deutsche Telekom is being a dick when it comes to peering.
Liquid Glass is a design cancer.
It consumes and overwhelms everything it touches by adding intense distortions, drop shadows, lighting effects, and unnatural spacing to controls and UI in ways that make them harder to see and understand.
It is pretty, and seductive, but it makes every interface it touches worse by prioritizing fun effects over common sense design principles like contrast, uniformity, readability, and sane information density.
Liquid Glass is the antithesis of great UI design: it is fashion. Form over function.
Great design “isn’t just what it looks like, it’s how it works”. And Liquid Glass makes nearly everything it touches look pretty, but work worse.
@jakereszturi@mani_bono@dhh Resolved. The screen was only blank during the encryption password prompt. Enter it blindly, hit enter, then it just works.
My homie Jediah is paging the Systems Performance Hotline with a very interesting question: does a single sequence counter _really_ bottleneck the whole system? Isn’t it all just a read and an increment?
Well, yes and no. Incrementing a counter atomically in-memory can be very cheap: a single instruction in most architectures. Even when contending on the same cache line with other threads, a modern CPU can do this 20 million times per second. That’s a lot! But this counter we’re talking about is not in-memory; it’s a row in a relational database! This suddenly makes the problem much more complex, and much more expensive.
For starters: in InnoDB, the storage engine that MySQL uses by default, all access to data (whether reading or writing) must happen through a transaction. Even when it’s a single statement with `AUTOCOMMIT`, the transaction is implicit, but it does exist. The performance costs associated with each transaction are very significant, particularly since these transactions have ACID semantics, and some very tough requirements!
The toughest, by far, is that by the time the transaction is committed, the database must be able to crash without losing the data we’ve just updated. That means the data must be written to disk (!!!) before our transaction is committed. In InnoDB, like in the vast majority of databases, we use a write-ahead-log (called the Redo log), where the update operation itself is serialized, instead of serializing the actual leaves of the B-Tree where the row lives. How fast can we write this WAL? Modern NVME drives can take a lot of throughput if we’re efficient when writing, but we’re *not* efficient here, because we need to do a lot of very small writes; we’ll never saturate the block queue.
A top-of-the-line NVMe drive as provided in EC2 can do 1.6M IOPS with a 4k block size, and your average WAL entry takes at least two blocks. So the very best we can do here is gonna be 800k updates per second, assuming there’s no contention on the underlying database rows.
In a real world scenario, since all these updates are hitting *the exact same row in the database*, the performance is dominated by the row lock that is acquired on each update. You’d be lucky to hit 100k updates per second with a VERY beefy CPU. And that’s not a lot!
But wait a second! As I explained yesterday, after scaling up our unsharded keyspace, our PlanetScale cluster hit 3 MILLION queries per second, with more than 80% of these being inserts.
So, hmm, these numbers don’t add up! How can you insert 2.4M rows per second if every insert needs to generate a sequence ID from the unsharded keyspace?
Here’s the trick: Vitess is cheating here (a little bit, but don’t worry, it’s the good kind of performance cheating). It’s not incrementing the sequence counter every time you insert a new row into the cluster. When an `INSERT` with an auto-increment column arrives to a VTGate (the routing proxy that plans the queries and forwards them to the actual MySQL shards), the VTGate increases the sequence counter in the unsharded keyspace… but not by one! It increases the counter by a very large number (usually at least 1000), so that then it can assign 1000 sequence numbers to the incoming rows directly from memory, without having to increment the counter again for each request. The worst thing that can happen is that the VTGate crashes before finishing the sequence chunk, in which case a gap will be left in the underlying shards, but no data corruption can occur.
So in summary: increasing a counter in a relational database is actually super expensive, and most definitely a bottleneck. In fact, it’s so expensive that Vitess needs to cheat to not do it that often!
@novikoff I like the layout changes they did (tab bar, toolbar, corner radius, etc), but Liquid Glass is bad. Serves no purpose, is distracting, and just feels out of place.
The positive side of this is that I learn not to get too attached to the OS I use. It’s just a tool after all. If I don’t like it, I can always move on. Hello Linux, long time no see.