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 a programmer, I find myself in the dilemma where I want make my program as abstract and as general as possible.

Doing so usually would allow me to reuse my code and have a more general solution for a problem that might (or might not) come up again.

Then this voice in my head says, just solve the problem dummy its that easy! Why spend more time than you have to?

We all have indeed faced this question where Abstraction is on your right shoulder and Solve-it-stupid sits on the left.

Which to listen to and how often? What is your strategy for this? Should you abstract everything?

share|improve this question
    
"As abstract and as general" is generally known as the programmer's hubris :) However, because of Murphy's law, the one degree of adaptation you'll need when working on the next task will be one you haven't provided. –  Matthieu M. Jan 4 '11 at 7:45
    
One of the best questions ever ! –  explorest Jan 28 '11 at 20:29
1  
You always guess wrong so seep it simple. When you have expanded the simple cases "enough times" you start to see a pattern. Until then, don't. –  user1249 Mar 8 '12 at 14:18
add comment

closed as not constructive by Walter, Yannis Rizos Mar 8 '12 at 14:15

As it currently stands, this question is not a good fit for our Q&A format. We expect answers to be supported by facts, references, or expertise, but this question will likely solicit debate, arguments, polling, or extended discussion. If you feel that this question can be improved and possibly reopened, visit the help center for guidance.If this question can be reworded to fit the rules in the help center, please edit the question.

9 Answers

up vote 26 down vote accepted

Which to listen to and how often?

Never abstract until you must.

In Java, for example, you must use interfaces. They're an abstraction.

In Python you don't have interfaces, you have Duck Typing, and you don't need towering levels of abstraction. So you just don't.

What is your strategy for this?

Don't abstract until you've written it three times.

Once is -- well -- once. Just solve it and move on.

Twice is the indication that there may be a pattern here. Or there may not. It can just be coincidence.

Thrice is the start of a pattern. Now it transcends coincidence. You can now abstract successfully.

Should you abstract everything?

No.

Indeed, you should never abstract anything until you have absolute proof that you're doing the right kind of abstraction. Without the "Rule of Three Repetitions", you'll write stuff that's uselessly abstracted in a way that's unhelpful.

Doing so usually would allow me to reuse my code

This is an assumption that's often false. Abstraction may not help at all. It can be done badly. Therefore, don't do it until you must.

share|improve this answer
1  
"Never abstract until you must." - I take it you avoid the use of classes, methods, loops, or if statements? These things are all abstractions. If you think about it, code written in high-level languages is very abstract whether you like it or not. The question isn't whether to abstract. It's which abstractions to use. –  Jason Baker Dec 31 '10 at 23:03
9  
@Jason Baker: "I take it you avoid the use of classes, methods, loops, or if statements". That does not seem to be what the question was about. Why make the absurd claim that all programming is impossible if we avoid over-abstracting our designs? –  S.Lott Dec 31 '10 at 23:21
1  
I'm reminded of the old joke where a man asks a woman if she'll sleep with him for a million dollars. When she says yes, he asks if she'll sleep with him for five dollars. When she says "What kind of woman do you take me for?" the response is "Well, we've already established that you'll sleep with someone for sex. Now we're just haggling over the price." My point is that it's never about a decision to abstract or not. It's about how much to abstract and what abstractions to choose. You can't choose to hold off on abstraction unless you're writing pure assembly. –  Jason Baker Jan 1 '11 at 3:26
9  
@Jason Baker: "You can't choose to hold off on abstraction unless you're writing pure assembly" That's trivially false. Assembly is an abstraction over machine language. Which is an abstraction over the hardware circuitry. Please stop reading too much into the answer that wasn't present in question in the first place. The question wasn't about "Abstraction" as a concept or an intellectual tool. It was about abstraction as an OO design technique -- misapplied -- too often. My answer was not that abstraction is impossible. But that "over abstraction" is bad. –  S.Lott Jan 1 '11 at 5:32
1  
@JasonBaker it is not an unheard reason for sleeping with somebody. Perhaps you were thinking of "money"? –  user1249 Mar 8 '12 at 14:19
add comment

where Abstraction is on your right shoulder and Solve-it-stupid sits on the left.

I don't agree with "solve it stupid", I thinks it can be more "solve it smart".

What's smarter:

  • Writing a complex generalised solution that has could support multiple cases
  • Writing short and effecient code that solves the problem at hand and is easy to maintain, and which can be extended in the future IF it is required.

The default choice should be the second one. Unless you can demonstrate a need for generational.

The generalised solution should only be when you known that it is something that will be used in multiple different projects/cases.

Usually I find generalised solutions are best served as "Core Library Code"

share|improve this answer
    
If you could make all the assumptions here, you wouldn't have a problem. Short and easy to maintain are mutually exclusive. If you know something will be reused, the general solution would address that. –  JeffO Jan 3 '11 at 22:16
    
@Jeff I'm not quite sure I understand your comment.. –  Darknight Jan 3 '11 at 22:39
    
You took the "Solve it Stupid" out of context. –  Bryan Harrington Jan 3 '11 at 23:19
add comment

A syllogism:

  1. Generality is expensive.

  2. You are spending other people's money.

  3. Therefore the expense of generality must be justified to the stakeholders.

Ask yourself if you are really solving the more general problem in order to save the stakeholders money later on, or if you just find it an intellectual challenge to make an unnecessarily general solution.

If generality is determined to be desirable then it should be designed and tested like any other feature. If you can't write tests that demonstrate how the generality you've implemented solves a problem required by the specification then don't bother doing it! A feature that meets no design criteria and cannot be tested is a feature that no one can rely upon.

And finally, there is no such thing as "as general as possible". Suppose you write software in C#, just for the sake of argument. Are you going to make every class implement an interface? Every class an abstract base class with every method an abstract method? That's pretty general, but it is nowhere near "as general as possible". That just allows people to change the implementation of any method through subclassing. What if they want to change the implementation of a method without subclassing? You could make every method actually a property of delegate type, with a setter so that people could change every method to something else. But what if someone wants to add more methods? Now every object has to be expandable.

At this point you should abandon C# and embrace JavaScript. But you still haven't gotten anywhere near general enough; what if someone wants to change how member lookup works for this particular object? Maybe you should write everything in Python instead.

Increasing generality often means abandoning predictability and massively increasing test costs to ensure that the implemented generality actually succeeds in meeting a real user need. Are those costs justified by their benefits to the stakeholders who are paying for it? Perhaps they are; that's up to you to discuss with the stakeholders. My stakeholders are not at all willing for me to abandon static typing in pursuit of an entirely unnecessary and extremely expensive level of generality, but perhaps yours are.

share|improve this answer
2  
+1 for useful principles, -1 for making it all about money. –  Mason Wheeler Jan 3 '11 at 17:12
4  
@Mason: It's not about money, it's about effort. Money is a practical measure of effort. Efficiency is benefits accrued per effort produced; again, profit in money is a practical measure of benefits accrued. It is simply easier to discuss the abstraction of money than to come up with some way to measure effort, cost and benefit. Would you prefer to measure effort, cost and benefit in some other way? Feel free to make a proposal of a better way. –  Eric Lippert Jan 3 '11 at 19:28
2  
I agree with @Mason Wheeler's point. I find the solution here is to not involve stakeholders in that level of a project. It obviously depends heavily on the industry, but clients do not usually see the code. Also, all these answers seem to be anti-effort, seems lazy. –  Orbling Jan 4 '11 at 0:27
2  
@Orbling: I am strongly opposed to unnecessary, expensive, wasteful effort that takes resources away from worthy and important projects. If you are suggesting that this makes me "lazy" then I submit that you are using the word "lazy" in an unusual way. –  Eric Lippert Jan 4 '11 at 3:06
1  
In my experience, other projects do not tend to go away, so it is usually worth investing as much time as needed in the current project before moving on. –  Orbling Jan 4 '11 at 5:01
add comment

I'm a big fan of the K.I.S.S. principle.

I focus on providing what I'm asked to do, and not on what is the best solution. I had to let go of perfectionism (and O.C.D.), because it made me miserable.

share|improve this answer
    
Why the dislike of perfectionism? (I did not vote you down by the way) –  Orbling Jan 4 '11 at 0:29
    
Not aiming for perfection works for me. Why? Because I know my programs will never be perfect. There is no standard definition of perfection, so I just choose to provide something that works well. –  Pablo Jan 6 '11 at 19:54
add comment

It depends on why you are coding, the purpose of your project. If the value of your code is that is solves a concrete problem, then your want to get that done and move on to the next problem. If there are quick and easy things that you can do to make things easier for future users of the code (including yourself) then by all means, make reasonable accommodations.

On the other hand, there are cases where the code you are writing serves a more generic purpose. For example, when you are writing a library for other programmers, who will be using it in a wide variety of applications. The potential users are unknown and you cannot ask them exactly what they want. But you want to make your library broadly useful. In such cases I'd spend more time trying to support the general solution.

share|improve this answer
add comment

Just to be clear, making something generalized and implementing an abstraction are two different thing entirely.

For example, consider a function that copies memory.

The function is an abstraction that hides how the the 4 bytes are copied.

int copy4Bytes(char * pSrc, char * pDest)

A generalization would be making this function copy any number of bytes.

int copyBytes(char * pSrc, char * pDest, int numBytesToCopy)

The abstraction lends itself to reuse, while the generalization just makes the abstraction useful in more cases.

More specifically related to your question, Abstraction is not only useful from a code reuse perspective. Often times if done correctly it will make your code more readable and maintainable. Using the example above, what is easier to read and understand if you are skimming through code copyBytes() or a for loop iterating through an array moving data one index at a time? Abstraction can provide a sort a self documentation that in my opinion makes the code easier to work with.

As my own rule of thumb, if I can come up with a good function name that describes exactly what I intend a piece of code to do then I write a function for it regardless of whether or not I think I will use it again.

share|improve this answer
    
+1 for making the difference between abstraction and generalization. –  Joris Meys Jan 1 '11 at 12:25
add comment

Eric Lippert points out three things that I think apply in his article future proofing a design. I think if you follow it you will be in good shape.

First: Premature generality is expensive.

Second: Represent in your model only those things which are always in the problem domain and whose class relationships are unchanging.

Third: Keep your policies away from your mechanisms.

share|improve this answer
add comment

Ah, YAGNI. The most abused concept of programming.

There's a difference between making your code generic and doing extra work. Should you spend extra time to make your code loosely coupled and easily adapted to do other things? Absolutely. Should you spend time implementing unneeded functionality? No. Should you spend time making your code work with other code that hasn't been implented yet? No.

As the saying goes "Do the simplest thing that could possibly work". The thing is that people always confuse simple with easy. Simplicity takes work. But it is worth the effort.

Can you go overboard? Of course. But my experience is that few companies need more of a "get it done now" attitude than they already have. Most companies need more people who will think things through ahead of time. Otherwise, they always end up having a self-sustaining problem where no one ever has time for anything, everyone is always in a rush, and no one gets anything done.

Think about it this way: chances are good that your code is going to be used again somehow. But you're not going to correctly predict that way. So make your code clean, abstract, and loosely coupled. But don't try to make your code work with any specific pieces of functionality that don't exist yet. Even if you know it will exist in the future.

share|improve this answer
    
Nice distinction between simple and easy! –  Matthieu M. Jan 4 '11 at 7:48
    
    
"But my experience is that few companies" - interestingly, the reverse may be true in academia. –  Steve Bennett Nov 30 '11 at 6:34
add comment

A good general rule for this kind of thing is Zero, One, Infinity. That is, if you need what you're writing more than once, you can assume you'll need it even more times and generalize. This rule implies that you don't bother with abstraction the first time you write something.

Another good reason for this rule is that the first time you write the code, you won't necessarily know what to abstract because you only have one example. Murphy's Law implies that if you write abstract code the first time, the second example will have differences that you didn't anticipate.

share|improve this answer
1  
That sounds a lot like my version of the Refactoring Rule: strike two! refactor! –  Frank Shearar Dec 31 '10 at 22:26
    
@Frank: It probably is your Refactoring Rule, but with the second paragraph added from personal experience. –  Larry Coleman Dec 31 '10 at 22:29
    
+1: I believe this is also noted fairly early on in The Pragmatic Programmer almost verbatim IIRC. –  Steve Evers Dec 31 '10 at 22:34
    
oh definitely. There's nothing to abstract with only one example: as soon as you have a second example, you can see what is common (shared) and what not, and you can abstract away! –  Frank Shearar Dec 31 '10 at 22:55
    
A sample of two is in my opinion too small to generalize for infinity. In other words, much much too early. –  user1249 Mar 8 '12 at 14:24
add comment

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