The Pragmatic Programmer by Andy Hunt and Dave Thomas
There is no such thing as a best solution, be it a tool, a language, or an operating system. There can only be systems that are more appropriate in a particular set of circumstances.
You shouldn't be wedded to any particular technology, but have a broad enough background and experience base to allow you to choose good solutions in particular situations.
Never run on auto-pilot. Constantly be thinking, critiquing your work in real time.
"Kaizen" is a Japanese term that captures the concept of continuously making many small improvements.
Instead of excuses, provide options.
Don't leave "broken windows" (bad designs, wrong decisions, or poor code) unrepaired. Fix each one as soon as it is discovered. If there is insufficient time to fix it properly, then board it up. Perhaps you can comment out the offending code, or display a "Not Implemented" message, or substitute dummy data instead. Take some action to prevent further damage and to show that you're on top of the situation.
It's time to bring out the stones. Work out what you can reasonably ask for. Develop it well. Once you've got it, show people, and let them marvel. Then say "of course, it would be better if we added...." Pretend it's not important. Sit back and wait for them to start asking you to add the functionality you originally wanted. People find it easier to join an ongoing success.
Keep an eye on the big picture. Constantly review what's happening around you, not just what you personally are doing.
The phrase "good enough" does not imply sloppy or poorly produced code. All systems must meet their users' requirements to be successful. We are simply advocating that users be given an opportunity to participate in the process of deciding when what you've produced is good enough.
Great software today is often preferable to perfect software tomorrow. If you give your users something to play with early, their feedback will often lead you to a better eventual solution
Don't spoil a perfectly good program by overembellishment and over-refinement.
The mistake lies in assuming that any decision is cast in stone—and in not preparing for the contingencies that might occur.
All software becomes legacy as soon as it's written.