If there's one thing I've learned from programming is that there are clever solutions to problems, and then there are "clever" solutions to problems. One is an intelligent solution to a difficult problem that results in improved efficiency and a better way to to do something and the other will wind up on The Daily WTF, and result in headaches and pain for anyone else involved.
My question is how do you distinguish between one and the other? How do you figure out if you've over thought the solution? How do you stop yourself from throwing away truly clever solutions, thinking they were "clever"?
"Debugging is twice as hard as writing the code in the first place. Therefore, if you write the code as cleverly as possible, you are, by definition, not smart enough to debug it." –- Brian W. Kernighan
to be truly clever it must also be simple. Ask people dumber than you, if they do not understand it'll probably be a problem later (that does not exclude also asking people smarter than you or reading reference material on the subject, etc.)
There are many ways to be clever.
If it's about coding tricks, my rule of thumb is to avoid them they are mostly obfuscation.
If it's about using good algorithms and good data structures big O is here to help you decide if you are really clever (do not forget to check what kind of performance is needed in that part of code).
be very cautious of premature optimizations. Even simple tricks like doing two things at once in a loop is often a way to make program more complex, hard to maintain and make evolve, and slower in the end.
in my experience there is really very few cases where cleverness is needed. The KISS principle (Keep It Stupid and Simple) was of much more help to me. Use the most simple solution that could possibly work is one of the TDD principles.
Keep It Simple Stupid
- Nate
Keep It Simple Sexy
- Pascal Thivent
Quoting from Einstein:
Make it as simple as possible, not simpler.
Truly clever is the solution that describes the problem in the simplest and therefore most straightforward way. The more you see what is done, the clever is your solution - there more it's about how, it's "clever" (or just weird :-)).
A clever solution makes the code simple. A "Clever" solution makes the code short.
The goal I always strive for is simpler and easier to understood. My idea of a clever solution is one that introduces a major simplification. For example, if you can say, "Hey, wait a minute, we have to do all the same processing for take-out orders that we do for eat-in orders, except for this one little part about recording the tip to the waiter for tax purposes. Why is all the code written twice? Let's just write it once and call it twice." That simplifies the code and is clever. Or, "Hey, we're following the textbook formula that says to compare the cosines of the angles. But our angles are and must always be less than 90 degrees, so if cos A < cos B then B must be > A. Why don't we just compare A and B and skip the whole cosine calculation?" Etc.
"Too clever" is when you make the code harder to understand. Like when you say, "Hey, instead of this couple of IF statements that make completely clear to the reader what I am doing and why, I could just write 'x=x&0x374 + (y==1 ? 32 : 89) ^ (z-x)'. That's cool because not only is it one line instead of 4, but it looks really neat and no one will understand what it means except me!"
In real life, there are lot's of hazy cases. Well, here's one I just wrote myself recently. We had a block of code that was comparing two Java strings, but it had to consider the case where either or both were null. So the original code said this: (Apologies to those not familiar with Java. Hopefully the gist of the idea will be comprehensible).
if (s1==null && s2==null)
return true;
else if (s1==null && s2!=null)
return false;
else if (s1!=null && s2==null)
return false;
else if (s1!=null && s2!=null && s1.equals(s2))
return true;
else if (s1!=null && s2!=null && !s1.equals(s2))
return false;
else
return false;
There were some unnecessary tests in there that could certainly be eliminated. I simplfied it down to:
return s1==s2 || s1!=null && s1.equals(s2);
My version was certainly shorter and more efficient. Was it simpler or too clever? I think it's debatable. But I did it, which I guess says that I thought it was better.
Final comment: A solution that is just marginally "too clever" can be made "clever" by adding a comment that explains it.
To take a trivial example, I once worked on a program that performed a series of transformations on a matrix. It would start with matrix[0] and build matrix[1], then it would do its next transform reading matrix[1] and writing to matrix[0], etc, back and forth. So I had a couple of lines of code that said:
old=new;
new=1-old;
That could certainly be cryptic. So I included a comment that explained that this toggled us between 0 and 1. In that case, I thought a one-line comment adequate to explain to any competent programmer what I was up to.
For clever solutions there is a problem. For "clever" solutions there is often no real problem - just the solution.
Post answers to the questions here at SO and let us decide (and decide for yourself) how clever you are :)
This will get you started on the road to programming (and general problem-solving) excellence:
http://en.wikipedia.org/wiki/Occam%27s_razor
Well:
"One is an intelligent solution to a difficult problem that results in improved efficiency and a better way to to do something and the other will wind up on The Daily WTF, and result in headaches and pain for anyone else involved."
-Covar
Ask a more experienced programmer. Better yet, ask thousands of them on Stack Overflow.
If you're feeling a solution is "clever" it probably is.
The best strategy is to engineer minimalistically. Don't add stuff which is not really necessary. Don't try to accommodate in your solution for all possible scenarios that you may encounter in the next 50 years. Just for today and for tomorrow, that's enough.
When I look at code that I have written shortly after writing it and think I was clever, I have learned that I was more likely "clever" and try again.
I aim for boring and uninteresting working code.
I always start by "Doing the simplest thing that could possibly work." Then I test if the solution is correct, robust, and performant. Often, at that point I am done. I consider this to be one form of cleverness.
If your solution can be described as elegant instead of clever, then you're using the "right" kind of clever.
If your functions do too many things and have too many side-effects, then it is far too clever by half. If it is really nice and easy to read and is elegant yet efficient, then it is you who is clever!
The "cleverness" that Alex Papadimoulis refers to is best understood in the context of his Programming Sucks [1] philosophy.
Basically, his argument is that programming is not the creative art form that we all like to think of it as. It's about simply getting the job done in a simple, maintainable and human-readable manner. What you refer to as clever without quotes doesn't quite fit into Papadimoulis' view at all.
The argument is that there are good, tested, established patterns for how to solve problems in programming, and that you should stick to them. That you can't be clever - you can only work hard to learn the patterns that already exist.
The opposite of "clever" is not clever without quotes, it's not conjuring your own awesome ideas - it's reading Code Complete and Refactoring, and just sticking to the if-you-will boring fundaments of programming.
Disclaimer I'm not writing this down to advocate it, I'm just trying to explain the concept of WTF-"clever" the way I've understood it.
[1] http://thedailywtf.com/articles/programming-sucks!-or-at-least,-it-ought-to-.aspxYou just have to learn from your mistakes, and learn from others mistakes. This is about balance. Every time you seem something hacked out, or overly clever, ask yourself, put yourself in that developer's situation, and think about their thought processes.
This is about balance, and applying what we've learned to new situations. You have to be going after Wisdom, not just Knowledge. That fact that you're asking this question shows you're on the right path. It's just that there's no easy answer.
Some things to particularly keep in mind:
You have to decide if the additional benefit in being clever offsets the difficulty of the programmer coming after you understanding what you did.
You ask people smarter than you.
It's a "good clever" solution if you are clever enough to deal with the side effects of your cleverness, and "bad clever" otherwise.
A clever solution can become a great solutions if it's well tested, well documentedand well explained
You are truly clever When others call you smart or clever it does not get to your head and you are still grounded a ever.
The "Elegant" distinction is the right one, but elegance has its own problems -- some solutions aren't at all obvious because the thinking that went into the solution isn't obvious in the code or commentary. As another respondent put it, if you have to explain the code to someone else, you're being "clever".
The other thing that can blow up in your face is where you do something so elegantly that the solution can't be generalized. I had a co-worker in the late '80s, early '90s, who wrote a run-time library so that all the behaviors were driven by tables. Giant arrays of structures with fields all indicating what was supposed to be done. And when the updates to the code no longer fit that paradigm, the library was hacked to pieces. We were all very impressed when it was first written, except the code didn't last but about 8 years before it was all dumped. As an aside, the developer who did the re-write tried to be even more elegant. I re-wrote his code less than 8 years later because it was "Clever++". If you get my meaning.
Truly good code is extensible and designed to be maintained and modified, because all of those things will happen. It should read well by people who aren't intimately familiar with what you wrote. Profile your code. The 90/10 rule really does work -- 90% of execution time is spent in 10% of the code. Focus your skills making that code work properly. And remember that code lives on, long after you've completed the project -- make sure the next person can understand what you've written, can debug the problems they find, and not make a mess in the process.