How can you make software reusable? The prevailing design fashion is to anticipate changes in the way that software will be used, then try to provide mechanisms for accommodating these imaginary uses. This approach would work, if you could predict the future.
The root cause of the drive to build reusable software is that the circumstances under which software is used change, ergo software needs to be changed to accommodate those circumstances. Seen this way, the concept of "building for reusability" is nonsensical. The solution is to go to the source of the problem and make software easier to change. Stop wasting time trying to design for reusability, start investing time in continuous refactoring.
One way reusability is achieved is through abstraction. All successful software libraries (graphics, algorithms, etc.) set out to solve problems in a particular domain. This is not "designing for reusability," this is designing software to address a particular domain broad enough to be useful for a wide variety of applications.
Platonic software design would consist of composing these domain libraries together using engineering techniques of abstraction, the outside ones building on the inside ones, like the layers of an onion. Two problems preventing this from being reality are leaky abstractions, and domain mismatch, making techniques such as Open Implementation necessary.
The only code reusability technique that is somewhat successful is the strategy pattern, but that is because the strategy pattern is just first-class functions and polymorphic types.