Bjarne Stroustrup the creator of the C++ programming language is quoted as saying,
"C makes it easy to shoot yourself in the foot; C++ makes it harder, but when you do it blows your whole leg off."
I think the point he was making is that a good programming language provides a flexible and powerful tool chest for developers to work with but its equally as easy to create a monster then to create a beautiful elegant piece of software.
An important part of working effectively in any language is to be able to chose the right tool for the job, we don't always need the power tools, sometimes a hammer and some nails will do a perfectly good job.
Lets look at some examples of where trying to be too clever might result in problems.
Tying Yourself Up In Threads
There should always be a healthy amount of scepticism whenever anyone says "we need this to be multi-threaded".
Lets be clear threading itself is not actually that complicated, what can very quickly become incredibly confusing is trying to manage access to data and resource once you have multiple threads of execution.
By using multiple threads you open up a whole new potential stream of defects whilst also simultaneously making your code harder to debug.
Using multiple threads is sometimes seen as the only way to increase performance, this is a slightly skewed way of looking at the problem.
Inefficient code is still inefficient when run in multiple threads and few things are less performant than a deadlocked application.
There are obviously occasions when a multi-threaded environment is necessary but this shouldn't be the default position whenever we encounter a performance problem.
On Reflection That Wasn't Clever
Reflection is a very cool thing, and quite often once a developer gets a taste for it they see it as the answer to all sorts of questions.
But reflection is quite often inefficient and can have a large negative impact of readability.
Bad use of reflection can be seen when we implement marker interfaces (interfaces with no methods) or when we are told to extend a certain class but not to add or implement any methods.
This leads to code without a clear purpose where readers will ask themselves questions like "what does that mean?", "why are we doing that?"
The type of meta-programming that reflection allows can be incredibly useful but it shouldn't be used to the detriment of well structured code with clear purpose.
Extending The Problem
Many languages provide the capability to add functionality to existing classes, whether it be categories in objective-c or extension methods in C#.
This can sometimes be very useful to avoid constant copy pasting of some utility function but can also encourage bad practice.
Its very easy when using this kind of feature to create a class with an eclectic mix of functionality with the same class being repeatedly modified to do a job it was never intended to do.
This can lead to a class with an inconsistent API lacking cohesion providing poor abstraction.
If your writing a large number of these methods for a class consider whether you can create a new class more suitable to your needs by using composition, this will lead to greater control of not only the API of the class but the also the internal workings.
The point with all three of these examples is not that any of these aspects of programming are evil more that the scale and complexity of a solution should be in proportion to the size of the problem.
We don't need to always open up the whole toolbox at our disposal, within agile their is the concept of the "simplest thing that could possibly work", this not only produces code that is more easily readable and maintainable but ensures time isn't wasted on premature optimisation or gold plating.
Part of the skill of a craftsmen is in being able to achieve wondrous things with everyday tools by applying hard earned skill and experience, this is just as true in software.
Always start off thinking how do we solve this problem using basic constructs, prefer simplicity before reaching for the industrial strength solutions and make sure your not always looking for an excuse to use that new cool feature.