HN user

Lukasa

333 karma

My name is Cory. I build networking software. I work on open source Python projects. I write about networking and about Python. See https://lukasa.co.uk for, you know, me.

Posts5
Comments81
View on HN
Linux 5.19 4 years ago

Quoting directly from the text:

It's the third time I'm using Apple hardware for Linux development

No mention of ARM64 there.

Re configurable TLS: TLS 1.3 allows services to perfectly pin certs and reject your custom root CA. It breaks the flow you are talking about that has worked up to 1.2. The answer is to not build a myopic protocol/technology that only cares about 1 dimension of usage.

No it doesn't. I have no idea what technology you think this is (maybe HPKP?), but installing a local root CA absolutely continues to work in all browsers with TLS 1.3.

The same is true of Swift, and Swift can also call into C whenever it likes. The difference is that Swift can do the same for Objective-C at full fidelity, including support the full Objective-C feature set (ARC, arbitrary selectors, interfaces, properties, you name it).

You can definitely default on a negative rate mortgage, by not paying your monthly payment. You cannot pay nothing each month. Instead, the principal reduces each month by more than the amount you paid. You still have a term over which you have to pay the mortgage off. No-one is offering (or will offer) a negative interest rate _interest only_ mortgage.

Negative interest rates make sense if you consider them as a lender trading current cash-on-hand for future cash flow. That is, the bank has $200k today, but it would rather see that broken up into payments over 10 years, even if it has to pay you to do it.

When viewed through this lens, it becomes clear that the factor driving this is likely that the bank is being disincentivised from storing the cash directly.

`some Shape` is literally identical to `impl Shape`, including the semantics you discuss above. The compile-time return value of a function returning `some Shape` must be the same on all execution paths. It just avoids expressing to the caller what it is.

Incidentally, this in principle allows the optimiser to specialise the caller to the return type of this function, avoiding the existential altogether.

Have you read the memo? By saying "stop saying that women are worse at coding" you are putting words in his mouth, as the memo states a very, very different thing i.e. that women are less likely to choose coding for various reasons, including biological ones. There's a world of difference between these two arguments.

I wasn't replying to the memo, I was replying to bluecalm, and bluecalm said this:

Now I say: women are in general less likely to be interested in tech and less likely to become good programmers because they are, on average, less competitive and less likely to devote themselves to solitude practice which is often necessary to become a very good coder.

Note "less likely to become good programmers". I feel pretty comfortable with my response given that.

and expressing all kinds of possible viewpoints should be facilitated.

I disagree. Many kinds of possible viewpoints construct hostile work environments, and should be forbidden. It is simply not necessary to allow a workplace to tolerate all views. We don't allow people to cover their cube in swastikas, walk around greeting all their colleagues with "heil hitler", and to push for the dismissal of all their Jewish colleagues in an attempt to reduce the influence of the hidden Jewish conspiracy running the world.

If Mr Google had wanted to write this on his personal blog I wouldn't have cared at all. But he didn't do that: he wrote it at work, in his professional capacity, and posted it for his co-workers to see. Guess what: speech at work is something that can get you fired. See Colin Kaepernick for evidence.

I mean, come on, this is a pretty obvious point - and I'm starting to believe that it takes intent to misread it like you did.

I...don't think I did misread it? I said "he cannot mean this", and you appear to agree with me: due to the facts on the ground, he cannot have intended to mean that. Therefore, I have to assume he did not mean that.

So if he believes that Google employs discriminatory hiring practices, then he presumably believes that some of his colleagues are not the best possible choice for their role, and do not deserve to be there. That seems like a straightforward reading of his text. Am I wrong?

Should white NBA players be offended by that statement? The answer is obvious: they shouldn't as that only means they were the ones on the tail of the genetic distribution and made it anyway or maybe even they overcome disadvantages to get there.

I don't know: I'm not an NBA player and have no idea what the experience of becoming one is like. But there is a difference in kind here. He didn't say "Men are better suited to be Google employees", he said "Men are better suited to be programmers". The closer analogy here is to say that "Black people are better basketball players than white people", and here it might well be fair for white NBA players to be offended. There is a distinction between saying "More of X are good enough to pass this bar", and "X is better than Y". People who can pass the bar are unlikely to be offended for themselves (though they may be offended for others who don't attempt to cross that bar), but they may be offended for themselves if the suggestion is that they are worse than their colleagues.

But if you said, in addition, "The NBA currently employs discriminatory hiring practices that favour white athletes at the expense of black ones", then they should be offended. At that point you are saying "I believe that group X is better than group Y, and many of group Y are here despite there being better members of group X". That is offensive.

We can however do something with this information: we can try changing tech world to be more welcoming to women.

I have a suggestion as to how to do that: stop saying that women are worse at coding. Just don't even bring it up. This goes doubly because there is no evidence for that at all.

You can make the tech world more welcoming to women by welcoming more women, and then give them the opportunity to succeed. Writing think pieces about how women are so ill-suited to coding doesn't just display a stunning lack of understanding about how the industry got started, it also makes it clear that right now you think women don't belong.

But if the view is that "software work as it is today is just not women's work, so we should make it more like women's work", then I'm sorry but you've already lost.

He was very clear that he was talking about the group not any individuals.

Since when does that excuse anything? If he'd written "Jews are, in general, hateful monsters. Not the Jews who work here, they're great, but most of the rest" does that statement become acceptable?

More importantly, Mr Damore does not know all the women at Google personally. He cannot. So when he says "In general, women are less suited to/interested in programming careers", he cannot possibly implicitly mean "but clearly that does not apply to every woman currently employed at Google, who were all hired because they are the best in the world at their jobs". Damore asserts that Google practices discriminatory hiring practices. For this to be true, Google must have at least once hired a woman where a better male candidate was available, and more importantly must do so more often than they do the reverse.

If you are going to make general statements about a group of people, then you should not be surprised when individuals in that group assume you mean that statement to apply to them.

I can't speak to consultants, but as an experienced conference speaker I can tell you that it vastly improves my employability.

I cannot stress enough how much some modicum of "fame" in a community greases the wheels of employment. You don't need to be at the Guido van Rossum level of famous to get this benefit: just being known and respected by enough of the "right people" helps enormously.

Software engineers often underestimate how much of our industry is built on "who respects you". If respected people trust you to know what you're talking about and to do good work, it makes it much easier to find good jobs and get well paid.

(For those who hate public speaking, similar benefits accrue to those who write great blogs or notable, innovative OSS projects.)

It's the same as if you blamed the TLS/SSL RFC for being responsible for the heartbleed bug in OpenSSL - It makes no sense.

It makes some sense.

Features are attack surface. Each extra feature or option your protocol enables is more code you need to manage. So careful decisions need to be made: just because you can easily specify a feature for many use-cases in your protocol doesn't mean you should, because once you spec it people might just use it.

For heartbleed, for example, why was the TLS Heartbeat extension ever specified for TLS over reliable protocols? It serves no purpose: TCP has TCP_KEEPALIVE if that's a thing you need. But it was specified, and because it was specified it was implemented, and then it became attack surface that needed to be protected. It wasn't. So I guarantee to you that if RFC 6520 had been more restricted in scope, the Heartbleed attack would not have happened (or would have been a much more minor story, I can't remember if Heartbleed affected only the TLS and not the DTLS implementation).

It's worth noting that the iOS and macOS keychains are very different. In fact, if you check the design docs you'll find they share only four functions between them. Essentially, as far as I could tell, the iOS keychain participates in the sandboxing of apps, while the macOS one does not.

Requests cannot throw errors from urllib because Requests does not ever invoke urllib code.

Any error that does not inherit from our top-level exception is a bug: please let us know so we can fix it.

The problem isn't Python, it's OpenSSL.

OpenSSL got TLSv1.2 support in version 1.0.1. Any older version of OpenSSL doesn't support TLSv1.2. That affects a number of platforms:

- the system Python on macOS, which link against the system OpenSSL (an anaemic 0.9.8zh)

- most of the older (pre-3.6) python.org releases on macOS, which have the same problem

- any Python on a Linux operating system with an older OpenSSL

So the backport needed is to backport a newer OpenSSL to the platform.

I Am Not A Legal Scholar, but:

It is not clear to me that any of the constitutional documents in the UK enshrine a right to silence. The Right to Silence in the U.K. is generally built up on common law, not statue. Every essay I have ever found on this topic refers to the right to silence in the UK as predicated on common law, not on statute, let alone on a critical constitutional document that would require explicit repeal.

So yes, Parliament cannot implicitly repeal some documents. But I don't think that the Right to Silence is in any of those. Of course, citations to the contrary would be welcome!

EDIT: And in fact the law has been challenged, all the way to the ECHR. The challenge failed: https://www.theguardian.com/uk/2007/jun/29/transport.eu

That's not how the Westminster system works. Parliament has the right to legislate more or less as it pleases, and is not bound by any superior authority, including the courts. The courts in the U.K. cannot strike down Acts of Parliament.

In this case, there is an Act of Parliament (Section 172 of the Road Traffic Act 1988, as amended by Section 21 of the Road Traffic Act 1991) that makes it an offence to withhold this information. That is the end of the story: Parliament has said it, therefore it is so.

(Note that in the U.K. there is currently a way out: the ECHR. I don't think they cover the right to not self-incriminate, but if they do that would be a possible challenge.)

Remember: in the U.K., Parliament governs by wielding the power of the monarch. That power is formally unbounded and absolute.

Sorry, let me be clearer.

The reason that just having an in-memory Reader or Writer doesn't solve the problem is that the failure modes don't match up. An in-memory reader/writer has basically no failure modes beyond ENOMEM. That's why in the no-I/O implementation, this is exactly what we use: write to an in-memory buffer.

Real I/O on the other hand has many failure modes. For an example, consider timeouts. If your parser does I/O, you need to test timeouts at every location that your parser does I/O. You need to confirm it handles those timeouts appropriately. And you need to decide what "appropriately" means here: do you retry? Do you abort? Do you attempt to unwind that state transition?

All of these are expansions of your state space. This means your protocol parser has to handle this combinatorial explosion of possible outcomes: at every point you have a Read/Write you need to be ready and prepared to handle all possible error conditions that can come out of that.

If your parser does no I/O, though, and only writes to buffers, this problem does not exist. That allows you to have two totally isolated sections of code: one part manipulates bytes in memory (the parser), and another bit is responsible for getting those bytes to and from the network. Each can be tested separately. If we need `n` tests for the no-I/O parser, and `m` tests for the I/O without parser, then to achieve equivalent test coverage your combined code requires `n * m` tests to achieve equivalent logical coverage of the possibility space.

Small, isolated components are good.

Yeah, so that's very reasonable.

In Python-land this is all pretty easy. For example, HTTP/2 is a protocol of the first kind ("variable-length data structures with length prefixes") at the framing layer, which is implemented in a Python packager called hyperframe. This uses a combination of the `struct` module and bytestring operations to achieve its results. A similar approach works for the second kind as well.

Basically, in Python this is almost always much easier because struct sizing and memory allocation isn't a concern like it is in a C-like language (though even there, dynamically sized structures and pointers are your friends).

But I agree, there is a lack of good discussion about "how do I actually do this?" I'd like to elaborate on that at some point for sure, because the reality is that it's remarkably simple.

I think that's a tempting conclusion to draw, but it's not quite right. The standard interfaces of Go reduce the pain, but the design principle ("Don't do I/O in parser or state machines") remains solid.

The reason for this is basically that I/O and protocol logic are separate concerns, and whenever they start influencing each other too much they impose costs on each other.

The best example is actually testing. If your protocol code includes calls to Golang's `Reader`/`Writer` interface methods, it causes a few problems.

The easiest thing to see is that it causes testing problems. For example, for each call to `Reader`/`Writer` methods, in addition to testing all possible reads/writes (a protocol concern), you need to test all possible I/O failures (timeouts, closed connections, weird kernel problems) in order to actually cover the complete failure space.

However, if your code doesn't have reads/writes mixed in with protocol logic, your testing scenarios are much easier. Bytes just come in and go out. Reading/writing problems aren't an issue.

This is just basic separation of concerns stuff, but it really does help, even in languages with "blessed" I/O mechanisms.

Hi, I'm the linked PyCon speaker!

It'd be good to know what additional information you'd like on the "how". I think at a high level I addressed that in my talk, but if it didn't make it across or you needed more information I'd love to know what you need. Ideally I'll turn this into a blog post at some point so it'd be great to have an idea of what extra info is needed.

It turns out TLS isn't that bad.

OpenSSL exposes a "memory BIO", which is basically exactly this. You send in writes, and then emit data when you can, and in the meantime it buffers.

It's a bit more limited than that, but generally speaking it's not too bad.

We're working on a draft that will allow clients to signal what resources are already in their cache. This should allow us to reduce the bandwidth risk of unnecessary pushes.

This is a real worry, but as with all things the actual behaviour of H2 on lossy networks is more complex than that.

TCP's congestion control algorithms don't work that well when you have many TCP streams competing for the same bandwidth. This is because while packet loss is a property of the link, not an individual TCP stream, each packet loss event necessarily only affects one TCP stream. This means the others don't get the true feedback about the lossiness of the connection. This behaviour can lead to a situation where all of your TCP streams try to over-ramp.

A single stream generally behaves better on such a link: it's getting a much more complete picture of the world.

However, your HOL blocking concern is real. This is why QUIC is being worked on. In QUIC, each HTTP request/response is streamed independently over UDP, which gets the behaviour you're talking about here, while also maintaining an overall view of packet loss for rate limiting purposes.

Yeah, I agree that for constrained devices this is somewhat problematic, though I'd say the only big concern there is header table size. Even that can be coped with, worst-case by just enforcing the lower-limit from the get-go and GOAWAYing if the client violates it.

But yes, nginx's HTTP/2 implementation is really quite strange to me.

This is because nginx has some interesting assumptions about the HTTP/2 preamble works. See this mailing list thread[0] for discussion about it. See also the nginx bug[1].

The TL;DR is that nginx wants to do some weird stuff with flow control to avoid the need to do internal buffering. nginx is definitely outside the RFC here: what the client is doing is entirely acceptable.

[0] https://lists.w3.org/Archives/Public/ietf-http-wg/2016AprJun... [1]: https://trac.nginx.org/nginx/ticket/959

You wouldn't.

What I was respond to was this specific sentiment: "With Go it doesn't matter if an operation is blocking or non blocking, that fact can totally be abstracted from the client code." My argument was that that is simply not true. Client code must know the difference between blocking and non-blocking code because it affects the flow of information around the program.

It is not categorically different.

As I said above, green threading has advantages over OS threading, but they behave exactly the same in terms of design patterns and potential bugs.

This is what I was getting at when I said "not that different": compared to the difference between event-loop concurrency and threaded concurrency, M:N green threading is basically just a subcategory of threading.