Good enough doesn't imply half-arsed or lashed together. It should concisely meet the requirements at hand, not what you think the requirements might be next week. It doesn't mean you are naive and haven't considered the big picture, nor are you lazy or stupid. It doesn't mean you are a moron if you don't use wildcard generics and don't have a fetish for multiple inheritance.The challenge is in defining what "good enough" means. I'm not going to attempt that here, but I am going to say something about what I minimally expect from code that I am supposed to take seriously.
I believe all developers should have a geek valve that prevents them from introducing overly-generic, indecipherable black magic to a codebase. In conversation you would look a bit unusual if you insisted on using flowery language to express a point that could be adequately conveyed in more standard terms. Some people may miss your point. The fact that their grasp of English isn't as advanced as yours doesn't make them stupid. It means you aren't communicating efficiently. Why can't the same logic apply to code? Favour explicit and clear over clever.
When I write code I have the following priorities:
If the code is not correct it has no reason to exist in the first place. The most convenient way to verify that the code is correct is to write proper tests. If I stumble across a piece of code that lacks tests, I am going to assume that the author either doesn't know or doesn't care if his or her code actually works.
It is not okay to skip writing tests. Yes, I know all the excuses for not writing tests so you can spare me the tedium of repeating them.
The code you write is for communicating with other people. Not for communicating with the compiler. The compiler will accept a lot of unreadable nonsense -- your coworkers will not. For your code to be understandable its intent has to be clear. Once the intent is clear you should aim for the simplest solution that will do -- the simpler a solution is the easier it will be to verify.
It is not okay to skip documenting your code. It is not okay to add layers of abstraction where none are needed.
If you have managed to demonstrate that your code is correct and understandable, you should ask yourself if it will perform adequately. In a lot of cases there will be no need to optimize your code. The first thing you need to do is to understand what your performance goal is. Then you measure. Then you optimize.
Most programmers are bad at writing correct and understandable code -- which sort of makes it irrelevant whether it is fast or not.