mmillin
As a benign example, eating food with your hands rather than utensils. In some cultures this is rarely ever tolerated, in others it depends on the food item, and in others still you might always eat with your hands. These will be at odds and you have to decide what is OK to shame and what isn’t.
I think we as a society bias against shaming in seeking inclusivity, but some things can be lost along the way as well. To use the eating example again, eating with your hands instead of utensils may be more likely to spread disease (or maybe it needs to be coupled with a stronger shame against _not_ washing hands). I don’t know what the right approach is to strike a balance here in a multicultural society.
While the connectedness of our world allows for great ideas to be spread and shared, there’s a huge reduction in actual variety. I don’t know what the solution is.
When it comes to assumptions about the input, ideally model them in the type system. If you can’t, explicit checks and throws are OK in my book. But don’t check-and-hide any errors. You’ll be hard pressed to debug the issues they’ll cause down the road, since it will usually be far from the implementation that you see the impact.
This is something I’ve struggled to fight against in many PR reviews. Especially once already written, convincing someone that their excessive null checking is harmful is an uphill battle. Short of better modeling (and languages that allow for sum types to enable it), I haven’t been able to come up with a universally convincing argument against this kind of “shotgun parsing.”
Maybe it really just isn’t that big of a deal? But when actually reading through and refactoring a codebase I’ve always found it frustrating to manage these unnecessary checks. Sometimes they’re nearly impossible to delete safely once present without first adding some kind of logging or broad investigation.
While software engineering certainly deals with different constraints, I don’t think this is a fair comparison. When stakes are low (as they are for most software engineering), different precautions are appropriate. The aerospace or financial software engineering worlds might be more comparable here, and the engineering for those systems looks quite different as a result.
See also: https://www.jerf.org/iri/post/2026/programming_is_engineerin...
I’ve seen two separate engineers implement a “generic idempotent operation” library which used separate transactions to store the idempotency details without realizing the issues it had. That was in an organization of less than 100 engineers less than 5 years apart.
One other thing I would augment this with is Antithesis’ Definite vs Indefinite error definition (https://antithesis.com/docs/resources/reliability_glossary/#...). It helps to classify your failures in this way when considering replay behavior.
[0] Distributed Systems Programming Has Stalled: https://news.ycombinator.com/item?id=43195702
[1] Choreographic Programming: https://en.wikipedia.org/wiki/Choreographic_programming
Learning about the more advanced machines, even the manual ones, is fascinating. If computers weren’t around, I’m sure I’d be doing something with knitting professionally instead of programming.
Let me slop that for you
I’m looking forward to reading this.
This is one of the key reasons why I’ve ingrained the “You Ain’t Gonna Need It” principle into my development philosophy. Many times I see engineers build a system that can support a dozen different use cases, but only two are used in practice. A few years down the road when several other new features have been added and the codebase needs a refactor, the extra complexity of those ten unused features become hurdles. And anyone who knows better has moved on or been reorg’d away. I’ve lost too many hours bending over backwards to support a feature that I learn much later was never used.
Note that this applies to features that increase complexity. Sometimes you can support more with less complexity through a simpler abstraction, which I’m all in favor of.
A recent example: an engineer wrote a custom caching layer for a service call, then called the service wrapper every time the data was needed, relying on caching to avoid hitting our dependency too often. I suggested fetching the data once and passing it around, but the engineer pushed back, citing the feature’s launch deadline and the effort required to update multiple interfaces. Their solution ultimately has more failure modes and is harder to test (requiring mocking of the service wrapper in several places), but it isn’t terrible and we probably won’t encounter cache overflow issues.
Another persistent example is function parameter length. Inevitably, there’s always “just one more argument” needed until we hit our configured linter limit. About 70% of the time, engineers add a suppression and push the change through as-is. Refactoring to reduce parameters can require significant work (and simply stuffing them into a parameter object doesn’t solve the underlying problem).
I could respond to these patterns by expanding our coding standards guide. It could document that caching shouldn’t be relied upon within a single request’s scope, or reinforce that functions should have fewer than 7 parameters (already enforced by our linter). But in my experience, these guidelines are rarely consulted before contributing. As the parameter example shows, people often push for exceptions rather than follow standards rigidly.
I do think standards guides can work well for open source projects, where contributions should never block someone from delivering value. Contributors always have the option to fork and use their changes as-is, which undermines arguments for “just getting something in.” Internal service codebases don’t have that luxury. When you’re changing a service to launch your feature before a major sales event, delays have real costs, and there’s no “I’ll fork this and maintain it myself” alternative.
This one really rings true. Every individual change you don’t push back on makes things slowly, incrementally worse until you end up with a pile of garbage. But do you really want to block someone’s change because they wrote some awkward, hacky code? After all, they’ve solved some problem for the business and it might only take an hour to clean up later.
Later never comes. Hacks get built on top of other hacks and that one hour improvement would now be a week long refactor. No one can justify that.
After few rounds of this you start to become the type of person who blocks changes for code clarity and things others view as nitpicks. Now you’re the asshole stopping people from getting work done. You ask yourself if it’s really so bad to let it slide this one time.
Repeat.
Am I missing something with this analysis? It seems like 2025 is on pace for fewer workers laid off, not more.
Most BNPL plans are not reported to credit agencies and therefore don’t build credit. But “financing” by paying with a credit card and paying the balance in full would build your credit, still with no interest.
Couldn’t this also be evidence that money is the issue? i.e. you can’t get to that millionaire CEO spot if you have a lot of kids you need to pay for. Instead the successful are those having fewer kids.
Calendaring and Scheduling Developer's Wiki
Additionally, as machine-generated content proliferates, I think having services use something like the web of trust concept for membership would be super powerful. The problem is, of course, the terrible UX of cryptographic signatures. But I think there's a lot of opportunity for the group that makes it easy to use.