Só para esclarecer, fazer algo generalizado e implementar uma abstração são duas coisas completamente diferentes.
Por exemplo, considere uma função que copia memória.
A função é uma abstração que oculta como os 4 bytes são copiados.
int copy4Bytes (char * pSrc, char * pDest)
Uma generalização faria essa função copiar qualquer número de bytes.
int copyBytes (char * pSrc, char * pDest, int numBytesToCopy)
A abstração se presta a reutilizar, enquanto a generalização apenas torna a abstração útil em mais casos.
Mais especificamente relacionado à sua pergunta, a abstração não é apenas útil da perspectiva de reutilização de código. Muitas vezes, se feito corretamente, tornará seu código mais legível e fácil de manter. Usando o exemplo acima, o que é mais fácil de ler e entender se você está percorrendo o código copyBytes () ou um loop for iterando através de uma matriz que move dados um índice por vez? A abstração pode fornecer uma espécie de documentação própria que, na minha opinião, facilita o trabalho do código.
Como regra geral, se eu puder criar um bom nome de função que descreva exatamente o que pretendo que um pedaço de código faça, escrevo uma função para ele, independentemente de achar ou não que vou usá-lo novamente.