I've been thinking about this topic for a while.
My conclusion is - it's not a matter of quantity, but of quality and context.
For example, a proper project structure beats comments explaining where the files are located (implementation vs. intension)
Similarily, classification to clarify context beats naming (Id on a Patient -> Patient.Id).
I believe DDD has a say in good documentation - classification provides context, context creates boundaries and boundaries lead to intentional implementations (this is where this belongs, rather than it needs to exist).
Code in itself isn't good enough to be considered documentation. The problem in most cases doesn't reside in the fact that the codes' working is commented or not commented, but rather the driving force (domain logic) isn't.
We sometimes forget who's boss - if the code changes, the domain logic or reasoning shouldn't, but if the domain logic or reasoning changes the code definitely will.
Consistency is very important also - convention by itself is useless if it isn't consistent.
Design patterns aren't just 'good practice' - it's lingo us developers should understand. Telling a developer to add a new type to a Factory is better understood than to add a new type to a method (where context and consistency is weak or missing).
Half the struggle is familiarity.
On a side note, API's which seem to favor a lot of documentation are also very domain and context sensitive. Sometimes duplicating functionality isn't evil (same thing, different contexts) and should be treated as separate.
In terms of commenting, it's always good to point out the domain logic behind the reasoning.
For example, you are working in the medical industry.
In your method you write "IsPatientSecure = true;"
Now, any decent programmer can figure out that the patient is being marked as secure. But why? What are the implications?
In this case the patient is an inmate that was transferred securely to an off premises hospital. Knowing this, it is easier to imagine the events that lead up to this point (and perhaps what still needs to happen).
Maybe this post seems philosophical at best - but remember that it is 'reasoning' or 'logic' that you are writing about - not code.