Unpopular opinions: software development edition

A lo largo del tiempo he ido escribiendo bastantes posts en los que intentaba analizar desde un punto de vista (más o menos) racional varios aspectos relacionados con el desarrollo de software. En este post aprovecharé para repasar algunos de ellos. En realidad, nada es ni tan blanco ni tan negro y en los posts enlazados podréis ver un poco mejor la gama de grises.

Quizá no sean exactamente opiniones impopulares. Más bien podríamos decir que son opiniones controvertidas sobre temas que pueden ser examinados con cierto detalle y en los que podemos (y debemos) replantearnos nuestro punto de vista periódicamente.

Veamos algunas.

Utilizar métodos estáticos está bien

En los diseños orientados a objetos se tiende a demonizar su uso, pero los métodos estáticos no son más que funciones, y como tales son muy útiles. Bien utilizados ofrecen alternativas interesantes a la hora de diseñar y pueden simplificar muchos escenarios de testing (en contra de lo que se suele pensar).

Utilizar tipos primitivos ayuda a escribir código más mantenible

Evitar modelar todo con strings o decimals es una cosa, pero introducir tipos específicos para cada concepto que te encuentras provoca que tengas que reimplementar muchas operaciones básicas que están disponibles para los tipos estándar.

Es preferible evitar utilizar clases

Si tu lenguaje lo permite, es mejor intentar diseñar utilizando estructuras más simples (valores, funciones o módulos) antes que empezar a pensar en clases. Los objetos acoplan estado y operaciones, pero además tienen un ciclo de vida que hay considerar. Si no vas a necesitar varias instancias de una clase, probablemente no necesites una clase.

No pasa nada porque (algunas) clases sean grandes

Partir la funcionalidad de un sistema en una miríada de pequeñas clases muy focalizadas y (supuestamente) reutilizables está muy bien, pero puede hacer más difícil entender como funciona todo que tener un código más líneal (y procedural) empaquetado en menos clases. Además, si necesitas garantizar que se mantienen ciertos invariantes en partes críticas de una aplicación, a veces sólo te quedan las clases como mecanismo para encapsular información y evitar usos indebidos de la misma.

En muchos casos utilizar TDD no tiene sentido

Pese a que suene a anatema en determinados ámbitos, hay muchas situaciones en las que utilizar TDD no ayuda a mejorar el diseño ni el proceso de desarrollo. Ni siquiera tener tests automatizados debería ser algo a perseguir sin pararse a pensar antes qué pretendes obtener con los tests.

La inyección de dependencias no debe ser la opción por defecto

Diseñar un sistema para permitir realizar inyección de dependencias en todos los puntos posibles añade una complejidad a la hora de utilizarlo que, sencillamente, no compensa si al final vas a tener una única implementación de cada dependencia. Refactoriza el código para usar inyección de dependencias cuando lo necesites, pero no lo hagas de forma especulativa.

Los ORMs son muy útiles (y no por evitarte escribir SQL)

Los ORMs tienen muchos detractores e implican varios sacrificios (curva de aprendizaje, abstracciones incompletas, …). Pese a todo ofrecen muchas ventajas a la hora de modelar, especialmente gracias a cosas como el Identity Map, la persistencia por alcance o el polimorfismo, que van mucho más allá de evitarte escribir SQL (algo de lo que nunca te puedes pretender aislar por completo).

Los repositorios son importantes (aunque utilices un ORM)

Cuando se utiliza un ORM existe cierta tendencia a despreciar el uso de repositorios por considerarlos una parte «ya cubierta» por el propio ORM. Utilizar repositorios es más que encapsular llamadas a una capa de persitencia. Utilizar repositorios permite establecer un lenguaje común sobre el tipo de operaciones que es pueden realizar sobre cada entidad y ayudar así a proteger los invariantes de tu dominio.

Dejar ficheros en una carpeta es un mecanismo de integración válido

Es indudable que se trata de un sistema prehistórico y con muchos inconvenientes frente a utilizar alternativas más modernas como APIs Web o colas de mensajes. Sin embargo, la facilidad para implementarlo, usarlo y comprobar los datos que se mueven cuando hay errores son ventajas que no hay despreciar.

Hay que comentar el código

El código limpio de los auténticos artesanos ágiles es completamente autoexplicativo y con un nivel de abstracción tal que permite leerlo como si fuese una novela. Sí, vale, me lo creo. Pero lo que no puede leerse es la mente de quien lo programó para saber por qué tomó unas deciciones y no otras. Puedes llevar esa documentación fuera del código (mensajes de commits, pull requests, etc.), pero documentar el porqué de las cosas junto al propio código hace que sea más sencillo consultarlo.

Asumir deuda técnica es algo perfectamente razonable

«Como clean-coder quiero que mi código sea limpio y mantenible para que así…» Todo eso está muy bien, pero nunca hay que olvidar que el código hasta que no está en producción no sirve para nada. Saber gestionar la deuda técnica, ser consciente de cuándo hay que asumirla y de cuándo hay que empezar a pagarla es clave para el desarrollo de software.

Subir las dependencias al repositorio de código es la mejor forma de crear compilaciones reproducibles

Incluir dentro del repositorio de código fuente las dependencias de terceros está considerado una mala práctica en muchos entornos, pero te permite independizarte por completo de servicios de terceros durante el proceso de compilación y garantizar que las compilaciones son realmente reproducibles.

Menos despliegue continuo y más despliegue de calidad

Queda muy bien presumir de que puedes hacer 400 despliegues en producción diarios y que tu tiempo para resolver una incidencia es menor de 4 minutos desde que la implementas hasta que llega a los usuarios, pero como usuario preferiría no haberme encontrado con la incidencia directamente. Hace falta dedicar más tiempo a diseñar y probar antes de empezar a utilizar a tus usuarios como testers gratuitos.

Conclusión

En el fondo, no hay tantas cosas en el desarrollo de software que sean realmente tan opinables.

No es cuestión de «yo tengo derecho a opinar como quiera y toda opinión es respetable». Es cuestión de analizar los pros y los contras de todo sin empezar a dar por sentado cosas sólo porque estén consideras buenas prácticas o las llevemos haciendo toda la vida.

Estos análisis no pueden realizarse de forma completamente abstracta y generalista y, ahí sí, entra en juego el contexto (personal, tecnológico, de equipo, de negocio, …) en el que nos encontramos a la hora de tomar decisiones.