Take the 2-minute tour ×
Programmers Stack Exchange is a question and answer site for professional programmers interested in conceptual questions about software development. It's 100% free, no registration required.

As programmers I feel that our goal is to provide good abstractions on the given domain model and business logic. But where should this abstraction stop? How to make the trade-off between abstraction and all it's benefits (flexibility, ease of changing etc.) and ease of understanding the code and all it's benefits.

I believe I tend to write code overly abstracted and I don't know how good is it; I often tend to write it like it is some kind of a micro-framework, which consists of two parts:

  1. Micro-Modules which are hooked up in the micro-framework: these modules are easy to be understood, developed and maintained as single units. This code basically represents the code that actually does the functional stuff, described in requirements.
  2. Connecting code; now here I believe stands the problem. This code tends to be complicated because it is sometimes very abstracted and is hard to be understood at the beginning; this arises due to the fact that it is only pure abstraction, the base in reality and business logic being performed in the code presented 1; from this reason this code is not expected to be changed once tested.

Is this a good approach at programming? That it, having changing code very fragmented in many modules and very easy to be understood and non-changing code very complex from the abstraction POV? Should all the code be uniformly complex (that is code 1 more complex and interlinked and code 2 more simple) so that anybody looking through it can understand it in a reasonable amount of time but change is expensive or the solution presented above is good, where "changing code" is very easy to be understood, debugged, changed and "linking code" is kind of difficult.

Note: this is not about code readability! Both code at 1 and 2 is readable, but code at 2 comes with more complex abstractions while code 1 comes with simple abstractions.

share|improve this question
Comments and clear names are invented to hasten the time needed to understand complex code. It's perfectly fine for your lower-level code to be more complex; at some level, you're almost certainly calling a far-more complex and far-lower level anyway. –  DougM Jun 23 '13 at 23:31
“Too much” is bad by definition. –  Jon Purdy Jun 24 '13 at 4:22
@JimmyHoffa: Gotta keep those types in their place. And don’t be jealous—I don’t get to write Haskell all day. It’s mostly PHP, JavaScript, and OCaml actually. –  Jon Purdy Jun 24 '13 at 14:52
add comment

4 Answers

up vote 58 down vote accepted

The very first words of TC++PL4:

All problems in computer science can be solved by another level of indirection, except for the problem of too many layers of indirection. – David J. Wheeler

(David Wheeler was my thesis advisor. The quote without the important last line is sometimes called "The first law of Computer Science.")

share|improve this answer
And how do you know when you have too many levels of indirection? I would tend to say it comes with experience, but a more experienced programmer easily understands more indirection hence doesn't see a problem with too many levels. –  m3th0dman Jun 24 '13 at 7:30
@m3th0dman - you have the right level of abstraction when it becomes easy to make changes future. Of course, you can also ask how you know when that will occur which merely repeats the question cycle in a different manner. –  GlenH7 Jun 24 '13 at 10:54
add comment

Yes, definitely. The thing is, no abstraction is perfect. All of the details of the layer that abstractions sit atop are there for a reason, and it can simplify a lot of things, but if that complexity wasn't necessary at some point, it probably wouldn't be there in the first place. And that means that at some point, every abstraction is going to leak in some way.

And that's where the real problem lies. When abstractions fail, the more of them you have layered in between the code you wrote and what's actually going on, the harder it is to figure out the problem and fix it, because there are more places where the problem might be. And the more layers there are, the more you have to know in order to track it down.

share|improve this answer
"And that means that at some point, every abstraction is going to leak in some way.": True. A better abstraction is one that leaks less often. –  Giorgio Jun 23 '13 at 21:28
In light of Bjarne's answer (and referencing David Wheeler's wiki page), perhaps you can change your quote attribution? :) –  congusbongus Jun 24 '13 at 0:01
@CongXu: While David Wheeler may often be quoted as saying that, do you know for a fact that he was the first to utter this? Or is it possible that Bjarne Stroustrup said it first? And please don't use wikipedia to convince my or anyone else. While it often is right, it just as often is wrong. –  Marjan Venema Jun 24 '13 at 18:29
@CongXu: Btw I have gone at it from the other end: googling for "Bjarne Stroustrup quotes" and have not found a single reference of Bjarne having uttered the "adding another layer of indirection" phrase... Not conclusive of course but does make it highly unlikely he was the first to utter it. –  Marjan Venema Jun 25 '13 at 9:20
I've once naively taken the advise of a senior to add an abstraction where it wasn't needed. It was never used beyond what i wanted to do in the first place. –  Cees Timmerman Aug 13 '13 at 12:26
show 3 more comments

I feel that our goal is to provide good abstractions on the given domain model and business logic.

I have a different view: our goal is to solve a business problem. Abstractions are just a technique to organize a solution. Another answer uses the analogy of a tailor making clothes. I have another analogy I like to think of: a skeleton. The code is like a skeleton, and abstractions are the joints between bones. If you have no joints, then you just wind up with a single bone that cannot move at all and is useless. But if you have too many joints, you wind up with a pile of sloppy jelly that can't stand up on its own. The trick is to find the right balance -- enough joints to allow for movement, but not so much that there's no actual defined shape or structure.

share|improve this answer
add comment

Yes absolutely.

The analogy I like to use to explain programming is that of a Tailor. When making a suit, a good Tailor will always leave a small amount of fabric at strategic locations within the garment to allow the garment to be taken in, or out, without changing its overall shape or structure.

Good Tailor's don't leave reams of fabric at each seam just incase you happen to grow a third arm, or become pregnant. Too much material in the wrong places will make for an ill fitting, and ill wearing garment, the extra fabric simply gets in the way of normal use. To little fabric and the garment is prone to tears and will not be able to be altered to cope with minor changes to the physique of its wearer, effecting the way garment sits.

Perhaps one day, our Good Tailor will be tasked to make a dress so tight he has to sew its wearing into it. And perhaps our Good Tailor is asked to make maternity wear, where style and fit are second to comfort and expand-ability. But before undertaking either of those special jobs a good Tailor would be wise enough to make everyone aware of the compromises that are being made to achieve those goals.

Sometimes these compromises are the correct route to take, and people are willing to accept their consequences. But in most cases, the approach of leave a little where it counts the most will outweigh any perceived benefits.

So, relating this back to abstraction. Its absolutely possibly to have way too many layers of abstraction, just like its possible to have way to little. The true art of the programmer, like the our tailor friends, is to leave a little where it counts the most.

Getting back on topic.

The problem with code is usually not abstraction, but dependencies. As you've pointed out, its the code which connects discrete objects that's an issue, because there's an implicit dependency between them. At some point communication between things just needs to be concrete, but judging where that point is usually requires some guesswork.

That being said "Micro" anything is usually an indication that you've overgranulized your object layout, and are probably using Type as a synonym for what should be Data. Having less things also means less dependencies needed to communicate between them.

I'm a big fan of asynchronous messaging between systems for this reason. You end up with two systems dependent on the message, rather than each other. Giving you less tight coupling between communicating systems. At that point, if you need to have a dependency between systems you need to consider whether you've got the bits that are dependent in the right place(s). And its often the case that you dont.

Finally, complicated code is going to be complicated. There's often no way around that. But code which has less dependencies is far easier to understand than one which relies on various external states.

share|improve this answer
+1 for "Good Tailor's don't leave reams of fabric at each seam just incase you happen to grow a third arm, or become pregnant". We often tend to design software this way, sadly. –  Kemoda Jun 28 '13 at 11:22
Along with understandability, one can also find abstraction useful when bending a curved line into a straight one. Meaning you're reducing complexity and/or entropy with the abstraction. Perhaps something like a Curry type data-handler where the fat you shave is still useful later on. –  Cody Feb 18 at 21:28
add comment

Your Answer


By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.