- Test features, not units (the time spent vs time saved is meh). So when something breaks, you can take it from there. Start digging.
- Build features
- Fix bugs by first writing a test, and then getting green
- Never go over-fancy with inheritance and whatnot. Readable longer functions are preferred over smaller once that break up the logic. Keep the poor soul in mind that has to go through your code in 3 years time. That could be you yourself ;-)
- Comment the "why"
That's it really. For web applications. Seems to work perfectly well for a code base that's over 10 years old and has seen many a developer come and go. Yes there's a bunch of legacy, but not a single part of it that's hard to reverse engineer with some effort.