I find as a general rule, the more that my application tries to abstract and protect the user from the "technical" nature of the platform the more code I have to write.
For example I produced a CMS that was intended to be used by content writers who were not technical.
However as the complexity of the website increased (more dynamic content on pages etc) I had to write a lot of code because there were a lot of exceptional cases "I want this side bar to appear on all of these types of pages apart from these 3 because of condition X and this other one because of condition Y". This means that my code ends up being an enormous pile of if statements with a huge number of database flags at the backend and checkboxes on the front end.
In the end it proved more effort efficient to produce a simple tag language for the front end and expose that to the designers and content writers, this took a lot of complexity out of the back end which could then concentrate on providing the primitives for the tag language.
You do move some complexity to the front end here for sure, but people are often better at specifying what it is they mean if they can actually generate and tweak it to some extent themselves and show the result rather than trying to explain everything in an email.
Another great example of this is Unix command line utilities , the basic interface for many of these has remained relatively unchanged since the 80s whereas GUI applications seem to be continuously redesigned.
Part of the zen of Python is "Flat is better than nested". Until recently, I always thought of this at a code block/function level. Recently I realized that this is also important when modularizing and adding layers of abstraction. The more layers of abstraction (from foo.bar.baz import Baz) you add, the more code you write and have to "keep in your mind". This presentation by Jack Diederich at PyCon 2012 really opened my eyes to the potential problems of adding layers of abstraction via modules and classes: http://pyvideo.org/video/880/stop-writing-classes
Interesting you say that; I would argue (and have) the exact opposite. Good abstractions, by their very nature, reduce the amount of moving parts you have to keep in your head at any one time. When the number of "moving parts" created by your abstractions outnumbers the actual bits its abstracting, then you know your design took the wrong turn somewhere.
> When the number of "moving parts" created by your abstractions outnumbers the actual bits its abstracting, then you know your design took the wrong turn somewhere.
This is an interesting point which I agree with and is usually where I end up. In the past I've started from the opposite end, creating multiple modules, class hierarchies, etc. This future proofing has made things harder for me to follow/understand when reading at a later date. It has become tiresome and now I consciously start at the other end, making the simplest thing that could work. Layers of abstraction then come naturally as needed.
This is the best approach , but it is best combined with fairly comprehensive re factoring otherwise you end up in a situation I have been in a few times where you have new code that runs with a nice abstraction and old code that works with less abstraction.
At that point you can introduce bugs because somebody modifies the old code in a way which would not be allowed under the new abstraction and then the new code ends up reading data produced by the old code leading to a cascade of failure.
For example I produced a CMS that was intended to be used by content writers who were not technical. However as the complexity of the website increased (more dynamic content on pages etc) I had to write a lot of code because there were a lot of exceptional cases "I want this side bar to appear on all of these types of pages apart from these 3 because of condition X and this other one because of condition Y". This means that my code ends up being an enormous pile of if statements with a huge number of database flags at the backend and checkboxes on the front end.
In the end it proved more effort efficient to produce a simple tag language for the front end and expose that to the designers and content writers, this took a lot of complexity out of the back end which could then concentrate on providing the primitives for the tag language.
You do move some complexity to the front end here for sure, but people are often better at specifying what it is they mean if they can actually generate and tweak it to some extent themselves and show the result rather than trying to explain everything in an email.
Another great example of this is Unix command line utilities , the basic interface for many of these has remained relatively unchanged since the 80s whereas GUI applications seem to be continuously redesigned.