2 ms·
The real problem is that we forget that there was a lot of bad code in the early days. When I studied books from 10 to 15 years ago, the patterns that were con
by jdw64 2mo ago
The real problem is that we forget that there was a lot of bad code in the early days.
When I studied books from 10 to 15 years ago, the patterns that were considered 'common practice' back then would be considered low-quality code today.
Our threshold has risen. People tend to forget the rings of experience embedded in community codebases and only look at the final results.
And they always claim that only the best results represent their community.
But the 'bad results' were also produced by the same community.
From that perspective, I think the floor has risen significantly. You might disagree. People with name recognition in open source usually only see the 'best' code.
But I mostly see the 'worst' code.
This is an issue of accessibility depending on your environment. I work for $15 an hour, as a freelancer doing subcontracting work in Korea, so I mostly see the worst of the worst. In that context, AI code quality feels like a huge improvement.
Because in closed source codebases, there's plenty of low quality code.
In contrast, open source projects tend to curate only the best code, driven by visibility and reputation. I think that difference is significant.
You might not agree with me. And that's fine. We all have our own value systems. I don't agree with you, and you probably don't agree with me. That's a natural consequence of us being different people.
But here's what I think: I respect you, but our views can differ. I think your point is valid in certain contexts, but I stand by mine.
- pmg101 2mo agoCan you give an example of a pattern that was considered common practice in a book 10 to 15 years ago that would be considered low-quality code today? My experience is pretty much the reverse: that we seem to just go round and round relearning the lessons that had already been learned in the past.
- ModernMech 2mo agoI feel like the industry has learned a lot of good lessons from functional programming, and that has been reflected by functional features being baked into almost every popular imperative language.
- jdw64 2mo agoRight, there were examples like Singleton and baseController. We moved from ambient/global dependency access to explicit constructor injection and Composition Root, didn't we? Application entry points use Composition Root now, but old general programming books didn't. Errors were handled differently too. In the past, you'd throw new Exception() and wrap it in try/catch at a higher level, but these days we use Result<T, E> type modeling. Of course, C# still uses try/catch, but the guidance in .NET has long been to return predictable failures as type contracts. Old .NET documentation used to encourage global access to common features and dependencies. Now it's shifted toward composition at the entry point. Node.js used to use nested error-first callbacks as a standard pattern, but that's no longer the case, right? It moved to promise/async-await, and these days, as you know, type-based modeling is trending. C# books also used to return null if something was missing, but now we use nullable reference types to express nullability more explicitly. Even inheritance—these days it's often advised to avoid inheritance, but it used to be very common. Just off the top of my head, I can think of quite a few examples. Record keywords and immutability features started appearing about 10 years ago, and Java has started adopting them too. These are all outdated patterns now, with clearly defined use cases. More precisely, the contexts in which they should be used have become much more granular. I could probably give about 30 more examples of this.
- jdw64 2mo agoAnd the 'monad' that functional programmers always talk about—same story. In C#, they encourage monadic composition by chaining errors. But about 15 years ago, that wasn't the case. Back then, if there was no value → null. Now, even the absence of a value is modeled with Option, Maybe, or nullable types. Failures are handled not with throw/try-catch but with Result, Either, or Try. Overall, we've shifted toward a style where we preserve the computation context and then compose the next computation. Instead of manually branching every time, now we use map, bind, or LINQ-style operations that define the composition rules. Things that used to be used only by a small group of people eventually become embedded into the language itself. For example, callbacks have evolved into Task, Promise, and async/await. So honestly, I don't think quality has declined at all. I think there's just more context to keep track of now. I've seen around 40 different company codebases. I have no idea about US code, but I've seen code from Korean and Chinese large corporations, and the difference between past and present code is quite significant.