Background
I am not a big fan of abstraction. I will admit that one can benefit from adaptability, portability and re-usability of interfaces etc. There is real benefit there, and I don't wish to question that, so let's ignore it.
There is the other major "benefit" of abstraction, which is to hide implementation logic and details from users of this abstraction. The argument is that you don't need to know the details, and that one should concentrate on their own logic at this point. Makes sense in theory.
However, whenever I've been maintaining large enterprise applications, I always need to know more details. It becomes a huge hassle digging deeper and deeper into the abstraction at every turn just to find out exactly what something does; i.e. having to do "open declaration" about 12 times before finding the stored procedure used.
This 'hide the details' mentality seems to just get in the way. I'm always wishing for more transparent interfaces and less abstraction. I can read high level source code and know what it does, but I'll never know how it does it, when how it does it, is what I really need to know.
What's going on here? Has every system I've ever worked on just been badly designed (from this perspective at least)?
My philosophy
When I develop software, I feel like I try to follow a philosophy I feel is closely related to the ArchLinux philosophy:

Arch Linux retains the inherent complexities of a GNU/Linux system, while keeping them well organized and transparent. Arch Linux developers and users believe that trying to hide the complexities of a system actually results in an even more complex system, and is therefore to be avoided.

And therefore, I never try to hide complexity of my software behind abstraction layers. I try to abuse abstraction, not become a slave to it.
Question at heart

Is there real value in hiding the details?
Aren't we sacrificing transparency?
Isn't this transparency valuable?


The reason for hiding the details isn't to keep the details hidden; it's to make it possible to modify the implementation without breaking dependent code.

Imagine that you've got a list of objects, and each object has a Name property and other data.  And a lot of times, you need to find an item in the list whose Name matches a certain string.

The obvious way is to loop over each item one by one, and check to see if Name matches the string.  But if you find that that's taking far too much time, (as it would if you have several thousand items in the list,) you might want to replace it with a string-object dictionary lookup.

Now if all of your lookups were done by retrieving the list and looping over it, you've got a huge amount of work to do to fix this.  It's even tougher if you're in a library and third-party users are using it; you can't go out and fix their code!

But if you had a FindByName method to encapsulate the process of the name lookup, you can simply change the way it's implemented and all the code that calls it will continue working, and get a lot faster for free.  That's the real value of abstraction and encapsulation.
