Hacker Newsnew | past | comments | ask | show | jobs | submit | crdrost's commentslogin

We still can take it more seriously!

Here's a PDF handout from 2023 for handing to hospital admins, https://www.nerode.org/clean-air/medical%20clean%20air%20rel... . The same statistics can probably be looked up for children acquiring covid at school, because like where else do they get it. $100 HEPAs in every classroom, $40 reusable p100 masks for every teacher, ask parents to voluntarily mask their kids.

Just share stories. You see [1], go to your social media and share it, “she got COVID like 3 or 4 times and it seems to have caused chronic kidney disease, even with vaccines reducing the rate of straight up death, we need get this thing under control otherwise our generation's not going to live to see 80. Each time you get it there is another small chance of long covid, another rolling the dice hoping for no snake eyes. Masking is just saying you want to roll the dice fewer times.”

Organize or join a covid slack channel at work, there are other groups like https://publichealthactionnetwork.org/ , if BTS Army can connect over K-pop we can connect over wanting to protect others.

1. https://x.com/HollyMars2/status/1936235382816784443?t=A4RaLq...


So, there is a reason that CRDT researchers would not like this response that you have given, but down-thread from you it's not why the author jakelazaroff didn't like it, but it's worth giving this answer too.

The reason CRDT researchers don't like the sync server is, that's the very thing that CRDTs are meant to solve. CRDTs are a building-block for theoretically-correct eventual consistency: that's the goal. Which means our one source-of-truth now exists in N replicas, those replicas are getting updated separately, and now: why choose eventual consistency rather than strong consistency? You always want strong consistency if you can get it, but eventually, the cost of syncing the replicas is too high.

So now we have a sync server like you planned? Well, if we're at the scale where CRDTs make sense then presumably we have data races. Let's assume Alice and Bob both read from the sync server and it's a (synchronous, unencrypted!) last-write-wins register, both Alice and Bob pull down "v1" and Alice writes "v1a" to the register and Bob in parallel writes "v1b" as Alice disconnects and Bob wins because he happens to have the higher user-ID. Sync server acknowledged Alice's write but it got lost until she next comes online. OK so new solution, we need a compare-and-swap register, we need Bob to try to write to the server and get rejected. Well, except in the contention regime that we're anticipating, this means that we're running your sync server as a single-point-of-failure strong consistency node, and we're accepting the occasional loss of availability (CAP theorem) when we can't reach the server.

Even worse, such a sync server _forces_ you into strong consistency even if you're like "well the replicas can lose connection to the sync server and I'll still let them do stuff, I'll just put up a warning sign that says they're not synced yet." Why? Because they use the sync server as if it is one monolithic thing, but under contention we have to internally scale the sync server to contain multiple replicas so that we can survive crashes etc. ... if the stuff happening inside the sync server is not linearizable (aka strongly consistent) then external systems cannot pretend it is one monolithic thing!

So it's like, the sync server is basically a sort of GitHub, right? It's operating at a massive scale and so internally it presumably needs to have many Git-clones of the data so that if the primary replica goes down then we can still serve your repo to you and merge a pull request and whatever else. But then it absolutely sucks to merge a PR and find out that afterwards, it's not merged, so you go into panic mode and try to fix things, only for 5 minutes later to discover that the PR is now merged. And if you've got a really active eventually consistent CRDT system that has a lot of buggy potential.

For the CRDT researcher the idea of "we'll solve this all with a sync server" is a misunderstanding that takes you out of eventual-consistency-land. The CRDT equivalent that lacks this misunderstanding is, "a quorum of nodes will always remain online (or at least will eventually sync up) to make sure that everything eventually gets shared," and your "sync server" is actually just another replica that happens to remain online, but isn't doing anything fundamentally different from any of the other peers in the swarm.


"When data subjects exercise one of their rights, the controller must respond within one month. If the request is too complex and more time is needed to answer, then your organisation may extend the time limit by two further months, provided that the data subject is informed within one month after receiving the request."

Backup retention policy 60 days, respond within a week or two telling someone that you have purged their data from the main database but that these backups exist and cannot be changed, but that they will be automatically deleted in 60 days.

The only real difficulty is if those backups are actually restored, then the user deletion needs to be replayed, which is something that would be easy to forget.


Upvoted for the cute proof- without-words geometrical diagram of the Legendre transform, but the fact that you defined the inverse map as (x, y) to (\hat y, \hat x) I found impossible to keep my head straight. Probably it's easy if I slow down and stop skimming the article.

IMO the easier derivation — may just be personal tastes as someone more on the engineering side — is just another integration by parts.

So with f(g(x)) = g(f(x)) = x, define y = g(x) for U-substitution with x = f(y):

    ∫ g(x) dx = ∫ g(f(y)) f'(y) dy
              = ∫ y f'(y) dy
              = y f(y) – ∫ f(y) dy
              = g(x) x – F(g(x)) + C
The more interesting thing is that this is a really basic integration by parts which means that this diagram of yours that I like, is more universal than it appears at first? I'd have to think about that a bit more, how you can maybe graphically teach integration by parts that way, is there always a u substitution so that you can get u f(u) or so and get this nice pretty rectangle in a rectangle... hmm.


Yes, there's a similar diagram on the Wikipedia page for Integration by Parts.


And it links to the more specific page on Integral of inverse functions:

https://en.wikipedia.org/wiki/Integral_of_inverse_functions


I also got confused until I read your feedback.


So for example the capital O on license plates in California is only distinguished from the zero by being slightly more squarish, the capital G is mostly distinguished from six by six being slightly more smooth and diagonal in its top arc. I and one are a bit further visually, as are B and 8, but it would probably fool a traffic camera that was taking down plates automatically.

In addition, all-numbers-plates, I believe, are reserved by California exempt plates (emergency vehicles, police), and vanity plates are absolutely a thing, much more likely to start and/or end on a letter, so that's why you see numbers at the beginning and end. Like you can kinda see “6EIC023” and say “oh yeah my car looks like an ad for Geico” but because the start and end are numbers it doesn't occur to most people.


All-numbers would be worse not better? That's only 10^7, even if they kept the first one 1-9 and did 26^7,they'd have billions, seems like the obvious solution, but I take it there must be some limitations that make it hard to go there.


The DV (Disabled Veteran) plates are notably all-numerical. They are also issued in order of application.

That’s the primary way you can differentiate them at a glance from the DP (Disabled Person) plates.

Just a little odd fact; I know you meant the more standard plates.


The DMV considers the "DP" at the end of a DV plate to be part of the identifier. So DV123DP, in their database.


I think the DV and DP have implicit prefixes (DV and DP respectively) for when they are referenced or recorded.

I may be wrong, but that’s what get when I see them.


The enum idea is often wise; also: for just an example that has probably occurred a hundred thousand times across the world in various businesses...

Original design: store a row that needs to be reported to someone, with an is_reported column that is boolean.

Problem: one day for whatever reason the ReporterService turns out to need to run two of these in parallel. Maybe it's that the reporting is the last step after ingestion in a single service and we need to ingest in parallel. Maybe it's that there are too many reports to different people and the reports themselves are parallelizable (grab 5 clients, grab unreported rows that foreign key to them, report those rows... whoops sometimes two processes choose the same client!)... Maybe it's just that these are run in Kubernetes and if the report happens when you're rolling pods then the request gets retried by both the dying pod and the new pod.

Alternative to boolean: unreported and reported records both live in the `foo` table and then a trigger puts a row for any new Foos into the `foo_unreported` table. This table can now store a lock timestamp, a locker UUID, and denormalize any columns you need (client_id) to select them. The reporter UPDATEs a bunch of rows reserving them, SELECTs whatever it has successfully reserved, reports them, then DELETEs them. It reserves rows where the lock timestamp IS NULL or is less than now minus 5 minutes, and the Reporter itself runs with a 5 minute timeout. The DB will do the barest amount of locking to make sure that two UPDATES don't conflict, there is no risk of deadlock, and the Boolean has turned into whether something exists in a set or not.

A similar trick is used in the classic Python talk “Stop Writing Classes” by @jackdied where a version of The Game of Life is optimized by saying that instead of holding a big 2D array of true/false booleans on a finite gameboard, we'll hold an infinite gameboard with a set of (x,y) pairs of living cells which will internally be backed by a hashmap.


I believe _Algernon_ was making a joke about how you could take this problem and make the code even worse, not proposing a solution to the problem.

It's also not even a problem with slow computers or insufficient memory, __init__ does I/O here, it connects to ZeroMQ, so it could have arbitrary latency in various circumstances exceeding the 100 milliseconds that we would be sleeping for. So the joke is, this fixes the problem in your test environment where everything is squeaky clean and you know that ZeroMQ is reachable, and now you have bugs in prod still.


I don't think it's totally crazy to, say, open a DB connection in __init__() even though that's not an instantaneous operation. That's not a hill I would die on, you can just say “open a connection and hand it to me as an argument,” but it just looks a little cleaner to me if the lifecycle of the connection is being handled inside this DB-operations class. (You can also defer creating the connection until it is actually used, or require an explicit call to connect it, but then you are also writing a bunch of boilerplate to make the type checker happy for cases where the class is having its methods called before it was properly connected.)


It's not totally crazy in that I see it all the time, but it's one of the two most common things I've found make Python code difficult to reason about.[0] After all, if you open a DB connection in __init__() -- how do you close it? This isn't C++ where we can tie that to a destructor. I've run into so many Python codebases that do this and have tons of unclosed connections as a result.

A much cleaner way (IMO) to do this is use context managers that have explicit lifecycles, so something like this:

    @contextmanager
    def create_db_client(host: str, port: int) -> Generator[_DbClient, None, None]:
        try:
            connection = mydblib.connect(host, port)
            client = _DbClient(connection)
            yield client
        finally:
            connection.close()


    class _DbClient:
        def __init__(self, connection):
           self._connection = connection
        
        def do_thing_that_requires_connection(...):
           ...
Which lets you write client code that looks like

    with create_db_client('localhost', 5432) as db_client:  # port 3306 if you're a degenerate
        db_client.do_thing_that_requires_connection(...)
This gives you type safety, connection safety, has minimal boilerplate for client code, and ensures the connection is created and disposed of properly. Obviously in larger codebases there's some more nuances, and you might want to implement a `typing.Protocol` for `_DbClient` that lets you pass it around, but IMO the general idea is much better than initializing a connection to a DB, ZeroMQ socket, gRPC client, etc in __init__.

[0] The second is performing "heavy", potentially failing operations outside of functions and classes, which can cause failures when importing modules.


I get the points everyone is making and they make sense, but sometimes you need persistent connections. Open and closing constantly like can cause issues


There's nothing about the contextmanager approach that says you're open and closing any more or less frequently than a __init__ approach with a separate `close()` method. You're just statically ensuring 1) the close method gets called, and 2) database operations can only happen on an open connection. (or, notably, a connection that we expect to be open, as something external the system may have closed it in the meantime.)

Besides, persistent connections are a bit orthogonal since you should be using a connection pool in practice, which most Python DB libs provide out of the box. In either case, the semantics are the same, open/close becomes lease from/return to pool.


> This isn't C++ where we can tie that to a destructor

`def __del__`


> def __del__

Nope, do not ever do this, it will not do what you want. You have no idea _when_ it will be called. It can get called at shutdown where the entire runtime environment is in the process of being torn down, meaning that nothing actually works anymore.


C++ destructors are deterministic. Relying on a nondeterministic GC call to run __del__ is not good code.

Also worth noting that the Python spec does not say __del__ must be called, only that it may be called after all references are deleted. So, no, you can't tie it to __del__.


So in this case that would be, a FooBarWidget is not a subclass of FooWidget but maybe still a subclass of AbstractWidget above that. It contains a thread and config as its state variables. That thread instantiates a FooWidget with the saved config, and runs it, and finally closes its queue.

The problem still occurs, because you have to define what it means to close a FooBarWidget and I don't think python Thread has a “throw an exception into this thread” method. Just setting the should_exit property, has the same problem as the post! The thread might still be initing the object and any attempt to tweak across threads could sometimes tweak before init is complete because init does I/O. But once you are there, this is just a tweak of the FooWidget code. FooWidget could respond to a lock, a semaphore, a queue of requests, any number of things, to be told to shut down.

In fact, Python has a nice built-in module called asyncio, which implements tasks, and tasks can be canceled and other such things like that, probably you just wanted to move the foowidget code into a task. (See @jackdied's great talk “Stop Writing Classes” for more on this general approach. It's not about asyncio specifically, rather it's just about how the moment we start throwing classes into our code, we start to think about things that are not just solving the problem in front of us, and solving the problem in front of us could be done with just simple structures from the standard library.)


So when you've got an interval you usually mean two sounds that are separated in time. So like the iconic Jaws Melody dun-dan-dun-dan-dun-dan, those notes are separated by an interval that could be called one semitone, 100 cents, or a minor second, depending on who is talking.

Or in “Oh when the Saints Go Marching In,” the ‘Oh-when’ interval is two tones (four semitones), 400¢, or a major third, the ‘when-the’ interval is another minor second, and the ‘the-Saints’ interval is one tone or a major second. Adding those up we find out that “oh-Saints,” if you just omit the other words, is 700¢ or a “perfect fifth”, so “saints-Go” is a descending perfect fifth, -700¢.

Now you can play all four notes at the same time and you would still refer to these distances between the notes as intervals, but nobody is likely to describe this sound as a bunch of intervals. It is a “I(add 4) chord” in that context and the +100¢ interval between the major third and the perfect fourth is what gives it its spiciness.

So then you have to clarify whether you mean that we are playing one note first and then two notes together second, or are we playing all three notes at the same time, or are we playing all three notes separately.

If it's one and then two, or two then one, the higher note of the dyad will sound like the melody usually, and you'll reckon the interval between those two. People who have really well trained musical ears, instead hear the shift on the lowest note, but it requires training.

If you mean that all three are separated by time, then it's a melody. In this case these first four notes of “Oh When the Saints Go Marching In” would perhaps be described maybe as an arpeggiated major chord with a passing tone, same as I said earlier as “I(add 4).” I'm not actually 100% sure if that's the right use of the term passing tone or whether passing tones have to lie outside your scale or something.

If the three notes are played at the same time, that's a chord, specifically it's a triad chord. You might talk about the stacked intervals in that chord, a major chord stacks a minor third on a major third, a minor chord stacks a major third on a minor third, stacking major on major is augmented, stacking minor on minor is diminished, and there are suspended chords where you don't play either third, so sus2 stacks a fourth atop a second and sus4 stacks a second atop a fourth. So a lot of those have their own names, and some of those names get weird (like to stack a fourth on a fourth you might say “Csus4/G,” which treats the lowest note G as if it were the highest note but someone decided to drop it down an octave).


> So like the iconic Jaws Melody dun-dan-dun-dan-dun-dan, those notes are separated by an interval that could be called one semitone, 100 cents, or a minor second, depending on who is talking.

For what it's worth, I would call that a "half step".


Consider applying for YC's Fall 2025 batch! Applications are open till Aug 4

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: