views:

323

answers:

6

I tried asking this and it got closed very quickly for being too long. (Which it was.) But I think it's a genuine question that needs to be discussed, so here's a much shorter version:

Abstractions are supposed to simplify your code. But in my experience maintaining other people's code, I consistently find that the trade-off for making code easier to write is making it harder to read, understand, and debug, especially if it's someone else doing the reading and debugging. In a lot of cases, it doesn't really reduce complexity; it just hides it or makes it someone else's problem.

Does anyone have any good principles or guidelines as to when to introduce new layers of abstraction and, more importantly, when not to?

+3  A: 

Read up on the SOLID principles.

First, the "Dependency Inversion Principle" says that abstraction is important.

Second, the "Open Closed Principle" can separate good abstraction from dumb abstraction.

S.Lott
why was this voted down? It seems to bee a good reference, and a valid point.
Kelden Cowan
Nice stuff. Well-thought-out and well-presented. But where's the principle that tells you when to quit?
Mason Wheeler
+1  A: 

The (extremely unscientific) rule of thumb I try to follow is this:

When writing a function if I find myself doing an operation whose details are not relevant to the function at hand, it can be abstracted away into a suitably named function that describes what is being done (but not how). More often than not this makes my function more readable since then it reads almost like pseudo-code. This is especially true if said operation involves more than 2 lines of code.

If it can be done in 2-3 lines and that operation is not generic enough to be used by someone else, i'll keep it inline and add a comment (if necessary).

Adnan
+4  A: 

Jim Coplien often says "Abstraction is evil"... and he isn't just trying to be controversial.

That said, if an abstraction leads towards the implementation looking like it is written in a DSL then it will aid comprehension. (It's worth browing Bob Martins recent book "Clean Code", which gets to the heart of readable, understandable software.)

Almost all abstractions, in almost all popular languages, don't give enough information up front to allow clients to really understand the services and constraints that apply (c.f. Design By Contract & Eiffel).

So, the primary purpose of implementation level abstractions are to manage complexity and insulate against change, and if used without thinking about those who come after us, lead to unreadable code.

Seb Rose
+1. Very nice. Who's Jim Coplien, BTW?
Mason Wheeler
Jim Coplien used to work at Bell Labs and is now a consultant in Scandinavia (http://www.gertrudandcope.com-a.googlepages.com/jimcoplien). He was a founder member of the Hillside Group who pioneered the patterns movement. He's also the author of a number of books (Advanced C++ Styles Multiparadigm Design for C++; Organizational Patterns of Agile Software Development)He wears sandals, likes beer, enjoys animated discussions and is a regular speaker at conferences. He often attends the ACCU conference in Oxford, England (www.accu.org)
Seb Rose
Here's an article by Coplien in where he mentions the "abstractions are evil" : http://www.artima.com/weblogs/viewpost.jsp?thread=6771
Andreas Grech
+1  A: 

Proof that there's not a simple answer to this can be seen in all of the different "code smell" pointers, which in a way can be thought of as different ways of deciding when things are too tightly entangled (yes, I know I'm oversimplifying, and some code smells are unrelated). e.g Methods too long/Too many variables/Code duplication, and many others, can be seen as pointers to inappropriate levels of abstraction.

If abstraction is the physical separation of functionally, rather than logically separate things, then "too much" abstraction is abstraction that only adds theoretical separation (e.g. a class hierarchy chain with only one concrete subclass).

Steve B.
A: 

This is my copied answer I did on the closed question. It was closed while I was writing the answer. I hope it still fits somehow.

Hmm, this is a heavy question and heavy to answer. And the truth lies somewhere in the middle. No abstraction leads to spaghetti code and is hard to understand and difficult to debug. But too much abstraction raises complexity, is hard to understand and is propably also difficult to debug. If you take the perspective of a programmer that wants to use your code they again are more or less equal because it is hard to use.

From the OOP perspective you can't gain much if you don't abstract things to some extent. The general approach for me is to focus at first on design patterns to structure my code (I do only the GoF patterns). That gives a basic structure and if you name the classes/functions after the pattern your intentions are easy to get for others.

If you start to do more and more abstractions you need a stop sign to not overreact :) Mine back then was YAGNI principle of the XP guys. YAGNI stands for "You aren't gonna need it". It means that you should not implement features that might someone in the far future maybe will find useful. Concentrate on your actual problem. If you take this problem there are already several parameters that define the problem. This might be it needs to paramterized, exchangable, transparent or whatever. If you focus to find a nice (not the perfect) abstraction you might be on a good path already. If requirements change (and they do) you need to redo some of the work anyway. So take it easy!

So to summarize. Think about abstractions but not too far. The best rule is that you can't find a good abstraction without solving the problem more than once. If you try to do it apriori you will face that at a later point your abstraction doesn't fit and that is worse than having less abstraction in the first place.

This text is also very abstract as the topic. So I hope this gives some helpful insights

Norbert Hartl
A: 

When the difference between thought and expression becomes acceptable ( whatever your definition of acceptable is ). For example , write code in assembly might be considered unacceptable ( thus need for more abstraction) , because there is a huge gap between thought and expression .

Surya