I finally tracked down an aphorism that's been stuck in my brain for a while:
"All problems in computer science can be solved by another level of indirection."(I was having a hard time tracking it down as I'd heard the version with "abstraction" substitutued for "indirection".)
It was stated by some guy I hadn't heard of named Butler Lampson, who it turns out (1) is wickedly smart, (2) was amazingly influential (e.g. the Xerox Alto) and (3) also works at Microsoft now (over in MSR).
I recall that when I first heard it I was taken aback, possibly having worked on one too many projects that got horribly bogged down in trying to be too abstract and failing to deliver anything concrete. Now, however, I'm seeing it as part of the innovation race. The more levels of abstraction you have the more nimble you are and the more you enable that you hadn't thought of. If you're not adding levels of abstraction and flexibility to a project, you're doing the wrong thing.
On the hobby game I'm working on I spend most of my (mental) time struggling with where to draw the dividing lines. For example, if I have already coded up a concept of Vehicles (things you can drive) and Weapons (things you can carry and shoot with), should a Vehicle's permanently mounted armaments be Weapons too (demanding that Weapon be restructured to accomodate both held and mounted weapons) or are they a facet of the Vehicle?
The right answer is probably to add the level of indirection between "thing you can shoot with" and where it lives (vehicle; something you can carry). This means ripping apart the Weapon functionality which risks adding bugs. But the end result is that there will be no duplicated code. And then it's going to be just a few lines of code to enable the ability to rip the chain gun off a jeep and carry it with you, or attach your portable rocket launcher to a jetski.
(I should note that since it's strictly a hobby project, I'm coding as I go, with no advance planning. I approach each 1-2 hour block thinking "I'm going to add one little feature" and see where it takes me. This means a lot of code gets rewritten, which is sometimes frustrating, but if I was planning everything ahead of time I'd never actually do any of it, and it wouldn't be nearly as stimulating or relaxing.)