There's a really great metaphor for how to manage complexity in abstraction.
We're all familiar with spaghetti code--you know, functional flow that winds its way through the source files and ends up in a big tangle.
"Aha!" we say, "This is awful, let's fix it."
So, we build all these layers of abstraction, with the hope that we can swap out any layer at random and things will be fine. This is lasagna code, and ends up being a gooey mess whenever you try to change a layer--you can always add layers, mind you, but actually removing one in the middle can prove to be quite messy.
The fix is ravioli code: Little self-contained bits of code with small, well-defined boundaries and implementations well-isolated from the outside world only communicating through messages.
~
The author does make a valid point, though: debugging through lots of abstractions is kind of a pain in the neck, and depending on the app a bunch of custom concrete code can be a lot simpler to maintain.
That's the siren song, though...that code is much easier to deal with until it isn't and then you're screwed.