Yeah, there's competing forces involved. If you push too many things together that do not belong together, then you end up with code that is hard to comprehend. Additionally, if you spread too many things apart that should otherwise be together, then you end up with code that is hard to comprehend (your point). Finally, what things belong together and what things ought to be separated will depend on the domain and even the specific constraints within the domain.
In order to objectively determine when things have gone poorly you have to factor in a lot of external details.
For example, manual memory management is a detail that should almost always be someplace else because it isn't relevant to solving the problem at hand. So we did this with garbage collectors. However, sometimes we need this detail present (high performance computing and/or constrained hardware ie video games etc).