Your code should only talk to it's immediate collaborators
This minimizes coupling, leading to the more resilient code.
If you have to reach deep into some object that may serve as indication that there is something wrong with the level of abstraction of your code - two levels that try to interact are too far removed.
The long set of chained calls like
page.blocks.header.font can serve as an indicator that you may be reaching out too deep into the object.
At the same time there are styles of code that employ a long chain of code that are totally fine. The examples include
a.getB().getC(), then it would be difficult to change the design and architecture to interpose a Q between B and C. You’d have to find every instance of a.getB().getC() and convert it to
a.getB().getQ().getC(). This is how architectures become rigid. Too many modules know too much about the architecture.
somehow when you follow other principles, it's relatively easy to comply with this, but I've thought of this as a challenge before