whenever possible i try to follow a pure TDD approach:
- write the unit tests for the feature being developed; this forces me to decide on the public interface(s)
- code the feature ASAP (as simple as possible, but not simpler)
- correct/refactor/retest
- additional tests if required for better coverage, exceptional paths, etc. [rare but worth consideration]
- repeat with next feature
it is easy to get excited and start coding the feature first, but this often means that you will not think through all of the public interfaces in advance.
EDIT: note that if you write the code first, it is easy to unintentionally write the test to conform to the code, instead of the other way 'round!