What I try to do in my projects is to allow complex code (if it serves a purpose), but only in libraries and try to make it as self-contained and well documented as possible. Application code should be simple.
Complexity is all at our common libraries. So most programmers don't even need to understand our abstractions, they just work. Of course, sometimes our abstractions are not enough so you need to get your hands dirty. However I would say it works well 99% of the time.