glyph
Again, it's tough to talk about this while constantly emphasizing that the CVE at best a tiny little data point, not anywhere close to a confirmation bullseye, but my model of this process would account for it. And the way it accounts for it is in what I guess I need to coin a term for, "vigilance decay". Sort of like alert fatigue, except there are no alerts, or hedonic adaptation, for when you're not actually happy. You need to keep doing the same kinds of checks, over and over, at the same level of intensity forever to use one of these tools, and humans are super bad at that; so, at some point in your list, you developed the learned behavior "hey, this thing is actually getting most of this stuff right, I am going to be a little less careful". Resisting this is nigh impossible. The reason it's less of a problem with human code review is that as the human seems to be getting better at not making the mistakes you've spotted before, they actually are getting better at not making those mistakes, so your relaxed vigilance is warranted.
I was deliberately vague about my direct experiences because I didn't want anyone to do… well, basically this exact reply, "but you didn't try my preferred XYZ workflow, if you did, you'd like it".
What I saw reflected in your repo history was the same unpleasantness that I'd experienced previously, scaled up into a production workflow to be even more unpleasant than I would have predicted. I'd assumed that the "agentic" stuff I keep hearing about would have reduced this sort of "no you screwed up" back-and-forth. Made particularly jarring was that it was from someone for whom I have a lot of respect (I was a BIG fan of Sandstorm, and really appreciated the design aesthetic of Cap'n Proto, although I've never used it).
As a brutally ironic coda about the capacity of these tools for automated self-delusion at scale, I believed the line "Every line was thoroughly reviewed and cross-referenced with relevant RFCs, by security experts with previous experience with those RFCs.", and in the post, I accepted the premise that it worked. You're not a novice here, you're on a short list of folks with world-class appsec chops that I would select for a dream team in that area. And yet, as others pointed out to me post-publication, CVE-2025-4143 and CVE-2025-4144 call into question the efficacy of "thorough review" as a mechanism to spot the sort of common errors likely to be generated by this sort of workflow, that 0xabad1dea called out 4 years ago now: https://gist.github.com/0xabad1dea/be18e11beb2e12433d93475d7...
Having hand-crafted a few embarrassing CVEs myself with no help from an LLM, I want to be sure to contextualize the degree to which this is a "gotcha" that proves anything. The main thrust of the post is that it is grindingly tedious to conclusively prove anything at all in this field right now. And even experts make dumb mistakes, this is why the CVE system exists. But it does very little to disprove my general model of the likely consequences of scaled-up LLM use for coding, either.
Let me restate that: it is not free to continue supporting PGP. It has a tremendous cost both in its own maintenance and its opportunity cost. Every moment spent attempting to mitigate its fundamentally broken design is a moment that could instead be put into designing something new, that works properly and doesn't require dragging around the massively bloated corpse of 1999-era cryptographic engineering.
> I'm not writing an eq method or a repr method in most cases, so it just doesn't add much for the cost.
That's part of the appeal. With vanilla classes, `__repr__`, `__eq__`, `__hash__` et. al. are each an independent, complex choice that you have to intentionally make every time. It's a lot of cognitive overhead. If you ignore it, the class might be fit for purpose for your immediate needs, but later when debugging, inspecting logs, etc, you will frequently have to incrementally add these features to your data structures, often in a haphazard way. Quick, what are the invariants you have to verify to ensure that your `__eq__`, `__ne__`, `__gt__`, `__le__`, `__lt__`, `__ge__` and `__hash__` methods are compatible with each other? How do you verify that an object is correctly usable as a hash key? The testing burden for all of this stuff is massive if you want to do it correctly, so most libraries that try to eventually add all these methods after the fact for easier debugging and REPL usage usually end up screwing it up in a few places and having a nasty backwards compatibility mess to clean up.
With `attrs`, not only do you get this stuff "for free" in a convenient way, you also get it implemented in a way which is very consistent, which is correct by default, and which also provides an API that allows you to do things like enumerate fields on your value types, serialize them in ways that are much more reliable and predictable than e.g. Pickle, emit schemas for interoperation with other programming languages, automatically provide documentation, provide type hints for IDEs, etc.
Fundamentally attrs is far less code for far more correct and useful behavior.
Supply chain attacks are a complex and nuanced topic so there are plenty of reasons to be thoughtful about adopting new dependencies, but it's definitely not as simple as "just use the stdlib for everything".
Python can be used quite successfully in high-performance environments if you are judicious about how you use it; set performance budgets, measure continuously, make sure to have vectorized interfaces, and have a tool on hand, like PyO3, Cython, or mypyc (you should probably NOT be using C these days, even if "rewrite in C" is the way this advice was phrased historically) ready to push very hot loops into something with higher performance when necessary. But if you redundantly validate everything's type on every invocation at runtime, it does eventually become untenable for anything but slow batch jobs if you have any significant volume of data.
Even in the cases where the truth really is somewhere in the middle between two opposing camps, reading a sequence of side A #1, side B #1, side A #2, side B #2, in disconnected stories gives you a very skewed view subject to recency bias. For example you can’t easily check the history to see if a claim B is making in their second story was already debunked by A in their first one, and it’s a huge waste of time and energy for A to have to spend all their media budget just refuting that claim over and over because B keeps bringing it up every time there’s no fact checker right in front of them to call them on it (and even sometimes if there is).
In other words the current media environment rewards being loud, wrong, simple and repetitive far over and above even the normal human bias for such things. It reinforces our worst cognitive habits.
Having had this experience now it’s much easier to appreciate the practical benefits of systems like Rust and Haskell, where the type checker is doing real work.
That said, if you care about the performance improvements that typing can give you with Mypy, you might want to look here:
https://github.com/mypyc/mypyc-benchmark-results/blob/master...
It won't be going toe to toe with Rust any time soon, but a 4x to 17x speedup is nothing to sneeze at.
The solution is just to avoid inheritance. It’s full of terrible pitfalls in most languages, but Python more than most.
The OP should have dropped it because it's unmaintained, and a maintained replacement has existed for a long time: https://cryptography.io/
This is an especially important consideration for security-critical libraries like cryptographic libraries.
- "def" instead of "define"
- "cls" instead of "Class"
- "sys" instead of "system"
- "os" instead of "operating_system_facilities"
- "ntpath" instead of "windows_path_names"
- "abc" instead of "abstract_base_classes"
Python aggressively abbreviates almost everything in common use. If it were in the stdlib, perhaps it would be the built-in names "attrs" and "attrib" rather than having dots in them, but the names would indubitably still be very short.
I understand that spooky action-at-a-distance magic can really ruin a codebase's maintainability. But what you've developed here is not a judicious appreciation of its danger and its power, but a blanket aversion to both its risks and its benefits.
An apt metaphor would be, let's say: toast. If you try to make some toast, but accidentally burn your house down, it's understandable that you might want to have your bread un-toasted for a while. But it doesn't make sense to switch your diet to be entirely raw as a result, especially if you eat a lot of chicken.
In python, metaprogramming is like fire. People who haven't seen it before are fascinated before it, and try to touch it. This always goes badly. But that doesn't mean it's useless or we shouldn't have it. There are many things it's good for, if it's carefully and thoughtfully applied.
attrs goes out of its way to avoid any behind-the-scenes effects. It even generates Python code, rather than using setattr(), so that if any error happens in the constructor, you can step through it normally in the debugger, and see it in the traceback. Its semantics are clear and direct. It doesn't have these problems.
if you have a dict, it maps something to something else. You should be able to add and remove values.
Objects, on the other hand, are supposed to have specific fields of specific types, because their methods have strong expectations of what those fields and types are.
attrs lets you be specific about those expectations; a dictionary does not. It gives you a named entity (the class) in your code, which lets you explain in other places whether you take a parameter of that class or return a value of that class.
>>> import attr
>>>
>>> @attr.s
... class Thing(object):
... a = attr.ib()
... b = attr.ib()
...
...
>>> @attr.s
... class Many(object):
... things = attr.ib()
...
...
>>> many = Many([Thing(1, 2), Thing(3, 4)])
>>> many
Many(things=[Thing(a=1, b=2), Thing(a=3, b=4)])
>>> attr.asdict(many)
{'things': [{'a': 1, 'b': 2}, {'a': 3, 'b': 4}]}
>>> import pickle
>>> pickle.dumps(many)
"ccopy_reg\n_reconstructor\np0\n(c__main__\nMany\np1\nc__builtin__\nobject\np2\n
Ntp3\nRp4\n(dp5\nS'things'\np6\n(lp7\ng0\n(c__main__\nThing\np8\ng2\nNtp9\nRp10\
n(dp11\nS'a'\np12\nI1\nsS'b'\np13\nI2\nsbag0\n(g8\ng2\nNtp14\nRp15\n(dp16\ng12\n
I3\nsg13\nI4\nsbasb."
>>> import json
>>> json.dumps(attr.asdict(many))
'{"things": [{"a": 1, "b": 2}, {"a": 3, "b": 4}]}'
>>>> Research shows that shorter work weeks are just as effective.
John Carmack:
> I feel like longer work weeks are more effective.
Does anyone else see the problem with this?
Of course, pop-sci writing is often terrible. Of course, headlines can wildly misrepresent the research they're covering. Of course, there may be issues at stake (such as, in this case, personal freedom) beyond the simple phenomenon being described.
However, if you have an issue with the research's methodology, explain it. It might even be a little interesting to hear a new conflicting hypothesis from your own anecdotal experiences.
As it happens, regarding the quality of pop-sci journalism, on this particular issue, the research on the starkly diminishing returns of overtime and the negative impact it has on work (especially creative work) is all pretty consistent. For those who do not have the luxury of working in cushy chair-sitting industries like Mr. Carmack and myself, overtime is strongly correlated with an increase in industrial accidents, both fatal and otherwise.
I really wish that high-status people in the software industry would stop thinking that their success exempts them from cognitive bias and the need to make a rational argument, or that their experience writing software somehow transfers, with no particular education, to social science or management.
The problem with this opinion is neatly summed up by this statement:
> Given two equally talented people, the one that pursues a goal obsessively, for well over 40 hours a week, is going to achieve more.
which has been all but proven wrong by repeated scientific studies. In the general case, it is not true. In the specific cases of outliers where it appears to be true, my understanding of the research indicates that the "People with the psychological makeup that allows them to productively pursue a goal obsessively for well over 40 hours a week will tend to be extremely successful". But this attribute is highly unusual, and it may not be something you can cultivate; people who are taller also tend to do better in life, but that does not mean that the average person should torture themselves on the rack for 80 hours a week in the hopes of getting taller, either.
So, there are outliers, which is what I think you mean by "10x atheletes", but those outliers are just that: outliers. And we do not have good metrics for determining who they are in the software industry, currently.
(Thank you for your kind words.)