Hacker News new | past | comments | ask | show | jobs | submit | alfons_foobar's comments login

> Instead of relying on a single server to store all data, we can replicate it onto several computers. One common way of doing this is to have one server act as the primary, which will receive all write requests. Then 2 or more additional servers get all the data replicated to them. With the data in three places, the likelihood of losing data becomes very small.

Is my understanding correct, that this means you propagate writes asynchronously from the primary to the secondary servers (without waiting for an "ACK" from them for writes)?


For PlanetScale Metal, we use semi-sync replication. The primary need to get an ack from at least one replica before committing.


Soo... We have a network hop after all?


For writes, yes. But what if your workload is 90% reads?


It makes a lot of sense for read-heavy workloads, for sure!

I was just trying to get a better understanding of what is happening under the hood :)


Is that ack sent once the request is received or once it is stored on the remote disk?


Not even necessary, just update the DNS record pointing to your home address


True.

Also this:

"Because Animal is a Protocol, any class that defines feed() becomes an Animal"

is slightly incorrect.

By default, protocols are only relevant for static type analysis, but you _can_ enable runtime instance checking using the @runtime_checkable decorator.

(So you can do "if isinstance(foo, Animal):...", but AFAIK this decorator comes with a performance penalty)


Protocols allow you to explicitly declare a class implements them by making them a base of the class, but do not require it. Every class that implements the specification of the protocol is usable where the protocol is specified, not only those explicitly marked with it. Python didn't make c#'s doofy mistake of requiring the programmer to explicitly annotate everything. So, not every implementer of the protocol will have isinstance be true.


That is correct, but the @runtime_checkable decorator (which goes on the class that defines the protocol, e.g. "Animal" in the blog's example) makes it so that any class that implements the required methods (e.g. Rabbit) also passes the isinstance test (so isinstance(Rabbit, Animal) does actually return True, even though Rabbit is not defined as a subclass of Animal, i.e. NOT class Rabbit(Animal) !)

Whether it makes sense to use that is a different question, but it is possible :)

See https://docs.python.org/3/library/typing.html#typing.runtime...


thanks for showing me that, as I had no idea.

it looks rather gross to me, and more dangerous than useful. why bother with a half check that can only see if the methods/attributes are present, but that can't guarantee they do what you need? better to not offer such a check at all, I should think.

but I'm not a fan of a great number of things python has been doing over the last some years.

if you were going to do such a thing (perhaps to allow type-safe callbacks from untyped code), I would think a wrapper would be the proper method, that checks the incoming parameters and the outgoing return value, raising an error if those are of the wrong sorts, and possibly further wrapping if something was declared to fit a protocol.


Maybe it's a new closed-closed principle. A class should be closed to modification and extension, F U.


[flagged]


I can program in a dozen languages or so, so I'm not coming at it from some place of knowing python and complaining about C#. There's plenty to complain about in python's typing.

Having to hand annotate classes to indicate interface membership instead of just writing classes and letting the compiler perform structural analysis depending on their usage is annoying.

If f# has fixed that, good for it.


What happens when member names collide and you match an interface you shouldn’t have? It’s an issue even in Go, which, unlike Python, has a usable type system.


I suppose if you were so unfortunate as to have two interfaces name the same function with different expectations on what it does, you'd end up having to use an intermediate object to wrap around your base one, to ensure it matches the required interface, possibly adding a helper to wrap the current object for convenience at callsites.

In C#, you would instead define a method and specify the name of the interface in order to override the method it receives to be different from the base method that is experiencing the conflict.

I know this is a real issue, but I don't think this is excessively common for either language.

And the real answer for both would be to rename/prefix the names in the interfaces so that they aren't conflicting in the first place, if you have the ability to do so :-)

There are certainly always trade offs when building something.


This is a good example of a game-theoretic equilibrium :)


I might be dense, but I don't understand what that has to do with type hints...

To my eyes, the problem of choosing useful defaults for complicated types/datastructures is independent of whether I add type hints for them.

I think I am missing something...


Prometheus is not agent based though


kudos for actually looking what the problem is.

As a (former) NetEng, it bothers me to no end that so many people claim "it's the network" when their application is slow / broken, without understanding the actual problem.


This.

I often use generator expressions for the intermediate values (so I don't allocate a new list for each step), but I find this to be much more readable.


> Just write:

    if key not in table:
        return default_value
    value = table[key]
I think this could/should be shortened to

    value = table.get(key, default_value)
    ...
    return value
No?

In case you disagree, I'd be happy to hear your thoughts!


I assume you're basically referring to this quote from the article?

"Ignore fields coming from the API if you don’t need them. Keep only those that you use."

IMO this addresses only one part of the problem, namely "sanitize your inputs". But if you follow this, and therefore end up with a dict whose keys are known and always the same, using something "struct-like" (dataclasses, attrs, pydantic, ...) is just SO much more ergonomic :)


Consider applying for YC's Summer 2025 batch! Applications are open till May 13

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

Search: