"Refactoring: Improving the design of existing code" by Martin Fowler, Kent Beck, John Brant, William Opdyke and Dan Roberts.
This book serves both as a tutorial and a reference. It's a tutorial on the topic of "refactoring" - changing existing code for the sake of better design/code, without affecting its external behavior. It's also a reference of this subject, more than half the book being a catalog of "refactorings" - common ways to modify code to make it better/simple/more robust. It somewhat resembles "Design patterns" presenting techniques in a dictionary-like matter.
I only skimmed through the reference part, as one should do on the first reading (it's mostly for later, if you want to apply some refactoring to your code and want some guidance), but I read the tutorial part thoroughly, and really enjoyed it.
It appears that one of my philosophies in programming is, in fact, refactoring. Taking working code and applying changes to it only for the sake of making it better code (without any visible change to the user/customer) is something I do a lot, both to my code and to code of others. It is, IMHO, the best way to program, and it's reassuring to know that a whole book was written on the subject by experienced programmers.
Refactoring is a way to assure that "it's okay not to be perfect". When people design something, say, a computer program, they will do their best to design it correctly from the start, but this doesn't always work out. In fact, with requirements changing and deadlines pushing, it mostly doesn't work out from the first time. But should it ? Should we expect perfection right away? This is un-human and unnatural for a design process. Refactoring allows us to reassess an existing design, gradually improving upon it as changes come on the way. It is a far more natural way to design. Make your best, but know that there is place for improvement later. This way, you aren't afraid to change, to improve, which is very important. Design conducted this way will always stay up to date, fitting best its current requirements. I don't want to go too far idealizing, because ideals don't exist, but refactoring helps us to somewhat approximate them.
I liked many things in the book, but especially enjoyed the part on automatic testing. It is a very important factor in refactoring and in programming as a whole.
A programmer likes to be confident about the changes he applies, especially to complex unknown code. Small tests that can be always run to verify correctness can really save a few gray hairs :-)
By all means, read this book if you're into serious programming.