> When you trust the abstraction
I agree. I would also say that in cases where the abstraction doesn't make sense you have to know what's going on inside the box in order to trust it.
In your example, the file system as an abstraction makes sense because once you understand that it's a tree, you are pretty much good to go.
I remember working on some projects early in my career with a very senior developer who had a habit of making the strangest abstractions possible on a problem. For example, need to use a class to define a triangle? His constructor might take 7 arguments! The center of the triangle on the screen, and the distance from the center as well as the degrees of rotation from the center (with the bottom of the screen being 0 degrees). Oh, and actually, it didn't take 7 arguments, it took 4, but three were some special object type containing a tuple of radians plus a mishmash of other parameters and a coordinate on screen. Because he wanted to, you know, reuse that code again. So in order to build a triangle, I had to define a center point on screen (with 0,0 in the middle of course because that's how his code worked) and then calculate the coordinates of the three triangle points from the distance I wanted, then convert degrees into radians or some such....bah! I don't remember all of the details, this was a long time ago, but it was horribly obfuscated and made no intuitive sense. He explained that it was all to avoid some singular edge case that he had encountered once, and he thought it was a good trade-off because all of the new edge-cases it introduced were manageable.
When I received this code (without documentation or useful comments), he was on vacation for two weeks.
Naively, I assumed it was an easily understandable abstraction in that I could simply supply 3 coordinates in some order to the library and get a triangle. I spent a couple days trying to figure out the order I was supposed to issue the coordinates to get it to draw before giving up and just reading the code to figure it out. Worse yet, the internals were abstracted all to hell in a similar obfuscated fashion and I literally got nowhere in trying to figure it out.
I actually just waited for him to get back to walk me through the code, peppering him with question like "do we really need to define the z coordinate as 0 all the time since the display is always 2d?" before proceeding on that work. Once I understood it, I just wrote some wrapper code to translate three normal 2d coordinates into his craziness to simplify my life.
I ran into this kind of thing with his abstractions all the time. From the most insane string class you have ever seen to a home rolled virtual memory library that pickled objects onto disk, but all of your objects had to be built around a base class that was full of useless virtual functions that you had to implement.