You want your code to consist of small pieces that you can test and understand separately.
Each small part should do one thing and do it well, regardless of whether this part is a function, and a method, or a class.
You want to be able to assemble large pieces of functionality from these small pieces so that each composition, no matter how complex internally, remains simple at the level of abstraction of that functionality.
In other words, even at a high level, we should still be able to describe complex internal elements in simple external models.
This is what Andrew Koenig says when he says: "Abstraction is selective ignorance." By deliberately abandoning the knowledge of how something wmay works inside, we may not consider how it works, but what it does.
Let's give a brief example. At the top end, we could say: "this class will find the smallest int in some data structure." This tells us what he does, not how he does it, and at this high level of abstraction, that we all care.
We have something that does something, and its modular, we can replace it with something else that does the same, no matter how it is done. It has an open interface.
Now at a lower level, it may happen that this is due to the fact that inside it is a heap, or a priority queue, or something else.
And these things can be implemented in terms of trees or self-balancing trees or even (under the optimal) linked list. The linked list will be a suboptimal implementation, but until he did the same, we would not be a cafe, because if suboptimality came back enough to slow down our program, we could exchange it for a better implementation with the same interface.
And these things are implemented in terms of traversing the tree (pre-order: always go in the order on the left, parent, right). And these things are implemented in terms of simple operations on nodes.
And here is the important part: since the rest of the application has nothing to do with the internal or side effects of this module, the swap is from a worse implementation, since the best of them does not change any of our other codes, it simply speeds up the work.
Each level is associated only with layers located directly above and below it, so that each layer can be replaced. Visually, it looks like circles inside circles inside circles, and not like overlapping Venn diagrams.
If you need to rely on intuition, it means that your code has side effects, or that it has too wide interfaces for other modules, or that instead of interfaces in general, instead of code created by stand-alone, disjoint modules, you have overlaps and intersections and fragile code. That you do not have it broken into pieces is simple enough to understand.
(Shit, late, and I'm afraid that I might break this explanation better. I will come back to edit this.)