Thanks for your comment! I should have defined it better; I work with tons of people who view that as good code. More objects, more code, more everything. Then it's good code. It's a super-OOP methodology that I think many of them couldn't get out of. So if they look at a class of mine that doesn't make use of a ton of objects, that's 'bad code'. The definition of 'good code' in this article strictly pertains to those people who view it that way. By the title, I meant if you think tons of objects and extra stuff is good code, then stop writing good code, and focus on the software, the end result for the user.
While I appreciate the intent of your article, I think the title is regrettable and obscures the real distinction you were going for. There should never be a distinction between "good code" and "good software."
The Software Craftsmanship movement has been having this discussion for a while, i.e., assessing the costs of bad code and making those costs visible to the stakeholders. You might find it worthwhile to engage that conversation.
I think the issue is many engineers value things like tests, short functions, interfaces, dependency injection, pure functions, comments, DRY, etc. To them, these things are qualities of "good code", and they spend all their time on this stuff instead of the bigger picture objectives. When you get out of that mindset, then I think "good code" can be equal to "good software".
It sounds like you're talking about over-engineered code, not "good code". When people solve problems that aren't there, or prematurely optimize, or make solutions needlessly general at the expense of readability, they're making the code worse.
Code is like regulation. Everyone agrees that we need laws and regulations, and that some complexity is needed to get it right, but a 7500-page code is strictly worse than a 25-page code that achieves the same end.
OOP is an interesting paradigm. The original vision of it (seen in Smalltalk, Ruby, and with a completely different approach, Scala) was a middle ground between imperative and functional programming that can capitalize on the benefits of each, and that looked a lot like the message-passing paradigm we see in Erlang. Unfortunately, what's now called OOP is absurd scaffolding and misuse of "design patterns" that makes solutions much more complex than the problems they exist to solve.
A major problem occurs when OOP is expected to fill needs better-suited by functional approaches, as in C++ and Java. It's not that OOP is evil. It's that when you start seeing FooFactoryFactory classes, you should really have been using higher-order functions a long time ago.