One strategy that was on my mind today: Whenever you're writing an API start on the "consumer" side. If you had the perfect version of this interface, what would the code that's using it look like? I find that if I start on the "implementation" side I'm more likely to come up with a solution that closely reflects what was easiest/most direct to implement, whereas starting thinking from the perspective of the user of the interface tends to lead me to better abstractions.