A lot of comments are code smells—an indicator that the code is too complicated or a method or class needs a more intention-revealing name.
But, in the last year or so, I've started writing comments to explain the thinking behind designs and possible future directions that I think I'll forget or that others will find useful. I've found it really helps. I've got a brain like a sieve and I was finding that I frequently ended up rewriting code I'd previously written because I couldn't remember the direction the design was going in. A real waste of time. The comments have almost completely stopped that, but they can cause a new problem: I have to resist the temptation to start implementing the design I'm explaining in the comment.
I prepend the tag "FUTURE" to comments that describe ideas about future directions to distinguish them from "TODO"s which mean "needs cleaning up". I try to keep TODOs to a minimum (zero). Whereas FUTUREs are fine and about possible future directions, rather than the health of the design.
Not everything needs to be beautifully designed
Sometimes I use FUTURE instead of TODO for something that could be cleaned up but that I don't feel is worth the effort at the moment. I personally don't think all code needs to be beautifully designed.
Design is an activity that takes time. It's an investment of time. Your time is limited, so you should invest it wisely and where it has the biggest impact, e.g. published APIs and high-level interfaces. High quality design everywhere is like highly optimized code everywhere—very wasteful.
In case it's not clear, I'm not advocating poor quality, misleading or unreadable code. I'm assuming a high base level of quality. What I'm talking about is where to spend valuable design time beyond that.
For me, writing procedural code is significantly faster than writing object-oriented code. My object-oriented code tends to be more flexible, but takes me longer to write as I have to think carefully about domain concepts, spend time coming up with the right vocabulary and do lots of refactoring to find a good partitioning of responsibilities.
When you use interfaces you can mix procedural and object-oriented code. You can have a clean object-oriented core and have relatively procedural implementations behind those interfaces. It's possible to write clear procedural code—i.e. have classes that "do too much" from a strict object-oriented point of view (i.e. that don't always obey SOLID principles—particularly S and O) but are still easy to understand and maintain.
When you get to the stage where those classes are starting to become unwieldy, you can rearchitect / refactor into a more object-oriented design.
Perhaps some people really do "think in objects" and can quickly and easily come up with an object architecture and the right names for classes and objects. If you can't (and I can't—it takes me significant time and effort) then forcing everything to be SOLID and OO is akin to premature optimization. It's better to invest that energy where it will make a real difference such as the core business model, the higher-level interfaces and public and published APIs.