It is a balance. Follow DRY while you are developing and the refactoring should occur as you develop.
Need to write something to a file, fine; just do it. Need to do it again in another class; time to extract common behavior.
You should also have an idea of what components will likely need this kind of abstracted behavior and preempt the wasted time writing something twice by just doing it the first time.
All of this comes with experience and the best way to gain experience is by doing it. Avoid trying to keep everything loosely coupled because it adds too much complexity is a great way to introduce tons of code smells and maintainability/extensibility issues.
Need to write something to a file, fine; just do it. Need to do it again in another class; time to extract common behavior.
You should also have an idea of what components will likely need this kind of abstracted behavior and preempt the wasted time writing something twice by just doing it the first time.
All of this comes with experience and the best way to gain experience is by doing it. Avoid trying to keep everything loosely coupled because it adds too much complexity is a great way to introduce tons of code smells and maintainability/extensibility issues.