Para ser claros, hacer algo generalizado e implementar una abstracción son dos cosas completamente diferentes.
Por ejemplo, considere una función que copia la memoria.
La función es una abstracción que oculta cómo se copian los 4 bytes.
int copy4Bytes (char * pSrc, char * pDest)
Una generalización sería hacer que esta función copie cualquier número de bytes.
int copyBytes (char * pSrc, char * pDest, int numBytesToCopy)
La abstracción se presta para su reutilización, mientras que la generalización solo hace que la abstracción sea útil en más casos.
Más específicamente relacionado con su pregunta, la abstracción no solo es útil desde una perspectiva de reutilización de código. Muchas veces, si se hace correctamente, hará que su código sea más legible y fácil de mantener. Usando el ejemplo anterior, ¿qué es más fácil de leer y entender si está hojeando el código copyBytes () o un bucle for iterando a través de un conjunto de datos en movimiento índice por índice? La abstracción puede proporcionar una especie de auto documentación que, en mi opinión, hace que el código sea más fácil de trabajar.
Como regla general, si puedo encontrar un buen nombre de función que describa exactamente lo que pretendo que haga un fragmento de código, entonces escribo una función para él, independientemente de si creo que lo volveré a usar o no.