SOLID isn't bad, but like the idea of premature optimization, it can easily lead you into the wrong direction. You know how people make fun of enterprise code all the time, that's what you get when you take SOLID too far.
In practice, it tends to lead to a proliferation of interfaces, which is not only bad for performance but also result in code that is hard to follow. When you see a call through an interface, you don't know what code will be run unless you know how the object is initialized.
The problem is that SOLID on its own does nothing for you. It's a set of (vague) rules, but not a full framework for how to design software. I would even argue that SOLID is actively harmful if used on its own.
Things like Clean Architecture and Domain-Driven Design are a lot closer to being true frameworks for software design, and a lot of their basic principles are actually really good (like the core of the application being made up of objects which perform calculations, validations and business rules with no side effects), but the complexity of those architectures is a problem in itself.
And, even aside from that, I think the industry in general reached a point where people decided that, principled object-oriented design is just not worth it. Why spend all this effort worrying about the software remaining maintainable for decades, when we could instead just throw together something that works, then IPO, then rewrite the whole thing once we have money.
I think the most important principle above all is knowing when not to stick to them.
For example if I know a piece of code is just some "dead end" in the application that almost nothing depends on then there is little point optimizing it (in an architectural and performance sense). But if I'm writing a core part of an application that will have lots of ties to the rest, it totally does make sense keeping an eye on SOLID for example.
I think the real error is taking these at face value and not factoring in the rest of your problem domain. It's way too simple to think SOLID = good, else bad.
[1] https://github.com/EnterpriseQualityCoding/FizzBuzzEnterpris...
This should be the header of the website. I think the core of all these arguments is people thinking they ARE laws that must be followed no matter what. And in that case, yeah that won't work.
SOLID approaches aren't free... beyond that keeping code closer together by task/area is another approach. I'm not a fan of premature abstraction, and definitely prefer that code that relates to a feature live closer together as opposed to by the type of class or functional domain space.
For that matter, I think it's perfectly fine for a web endpoint handler to make and return a simple database query directly without 8 layers of interfaces/classes in between.
Beyond that, there are other approaches to software development that go beyond typical OOP practices. Something, something, everything looks like a nail.
The issues that I have with SOLID/CLEAN/ONION is that they tend to lead to inscrutable code bases that take an exponentially long amount of time for anyone to come close to learning and understanding... Let alone the decades of cruft and dead code paths that nobody bothered to clean up along the way.
The longest lived applications I've ever experienced tend to be either the simplest, easiest to replace or the most byzantine complex monstrosities... and I know which I'd rather work on and support. After three decades I tend to prioritize KISS/YAGNI over anything else... not that there aren't times where certain patterns are needed, so much as that there are more times where they aren't.
I've worked on one, singular, one application in three decades where the abstractions that tend to proliferate in SOLID/CLEAN/ONION actually made sense... it was a commercial application deployed to various govt agencies that had to support MS-SQL, Oracle and DB2 backends. Every, other, time I've seen an excess of database and interface abstractions have been instances that would have been better solved in other, less performance impacting ways. If you only have a single concrete implementation of an interface, you probably don't need that interface... You can inherit/override the class directly for testing.
And don't get me started on keeping unit tests in a completely separate project... .Net actually makes it painful to put your tests with your implementation code. It's one of my few actual critiques about the framework itself, not just how it's used/abused.
Even his "critique" of Demeter is, essentially, that it focuses on an inconsequential aspect of dysfunction—method chaining—which I consider to be just one sme that leads to the larger principle which—and we, apparently, both agree on this—is interface design.
The only part of SOLID that is perhaps OO-only is Liskov Substitution.
L is still a good idea, but without object-inheritance, there's less chance of shooting yourself in the foot.
If you follow SOLID, you'll write OOP only, with always present inheritance chains, factories for everything, and no clear relation between parameters and the procedures that use them.
L and I are both pretty reasonable.
But S and D can easily be taken to excess.
And O seems to suggest OO-style polymorphism instead of ADTs.
That's how I view it. You should design your application such that extension involves little modifying of existing code as long as it's not necessary from a behavior or architectural standpoint.