First a story
Early in my first job, another fresh out of school co-worker and I decided that we were going to rewrite this one library we used to make it more reusable for all of the upcoming projects. When we asked for advice from a more experienced developer, he basically told us not to bother, because we were going to fail. We scoffed at his cynicism, knowing that our design skills and knowledge of the requirements were going to result in this awesome library.
Fast forward a year and the "reusable" library that we spent so much time and effort on still had to go through considerable customizations to handle cases that we hadn't even envisioned when we started.
Did we fail because of incompetence? While our skills probably weren't quite as good as we thought at the time, no. We failed because it required the unknowable - knowing what the future would bring. The Agile premise of YAGNI summarizes this.
I summarize this experience with the title to this post, don't try to write reusable software.
I can hear your CS hearts shudder at this.
How can this be? Isn't writing reusable software what is taught in our programming classes? You can't really be saying that we should be cutting and pasting code all over the place. Besides there are plenty of successful reusable libraries out there, like printf or java.util.*. This must be a false premise!
Again, I say, "Don't try to write reusable software!"
But...but...that goes against everything I learned.
The Real Moral - Discover Reusable Software
Don't try to write reusable software, discover it instead.
Obviously you shouldn't be cutting and pasting code. Obviously you should still be using methods and classes. The DRY principle is a good one and it implies reusable code. However, reusable code is the means, not the goal.
Let me repeat that, because it is important. Writing code that is reusable (methods, classes, etc.) is the means to achieving the goal of a clean design. But your goal isn't the reusability, your goal is to only specify everything once. Only write your algorithm once. Only specify a value once. Only put your business logic on one place. If you strive to achieve those goals, you will end up with reusable components.
Even better, you will end up with code that is maintainable and written in a timely manner.