Abstracciones prematuras

Cuando empecé a programar, cuando aprendía un nuevo patrón de diseño no tardaba mucho en encontrar en donde aplicarlo. Mis proyectos rápidamente tenían varias clases que representaban cada abstracción del patrón que quería aplicar. Lo mismo pasaba con arquitecturas y formas de organizar mis proyectos. Hubo un tiempo donde creaba tres capas al iniciar mi proyecto (presentación, reglas de negocio y acceso a datos), hubo otra época en que creaba una capa de servicios al iniciar el proyecto y otra de repositorios; en otro tiempo creaba interfaces para casi todas las clases con la idea de poder cambiar las implementaciones sin afectar el resto del proyecto.

Con el tiempo fui descubriendo que el tener muchas abstracciones tiene un precio. Aunque siempre digo que las clases son gratis y no debes tener miedo de crear una más. No pienso lo mismo cuando se trata de agregar una nueva capa de abstracción. Esas sí me van a costar si me lleno de clases o interfaces que no hacen otra cosa más que abstraer la implementación de algo que puede ser simplemente una clase concreta.

Ahora mi regla es: si solo hay una implementación entonces no se necesita una interfaz. Las implementaciones que solo se usan para los tests no cuentan, me refiero a implementaciones de código real. Si después descubrimos que habrá otra implementación, es entonces cuando se hace un refactoring del código para introducir la interfaz; pero no antes. Debemos resistir la tentación de la capitis y solo agregar abstracciones cuando sea necesario. Si encontramos una abstracción con una sola implementación concreta entonces se trata de una abstracción prematura.



Por ejemplo:

Supongamos que tenemos una lista de clientes y nos piden que la exportemos a un archivo CSV. Es posible que hagamos una clase CustomerExporter con el método Export; de momento con eso es suficiente.

Sabemos que quizás en un futuro nos pidan que también se pueda exportar a otro formato; pero de momento no es parte del alcance del proyecto y quizás nunca sea necesario otro formato. Si introducimos una interfaz ICustomerExporter y la única implementación CustomerCsvExporter tendremos complejidad innecesaria y una abstracción prematura.

Es hasta que tengamos el requerimiento o necesidad de poder exportar clientes en otro formato que debemos realizar el refactoring e introducir la abstracción para las dos o más implementaciones.


Comentarios