Llevo suficientes años programados cómo para acordarme de cuando había que escribir programas re-entrantes en ensamblador de 8 bits. Afortunadamente la programación ha progresado muchísimo desde entonces. No obstante, hasta las mejores herramientas pueden usarse mal, cómo cuando se pone un mono a los mandos de una excavadora. El agravante en desarrollo de software es que a la inexperiencia se suele sumar la inagotable arrogancia de muchos programadores la cual debería ser sorprendente en una profesión dónde se piensa que las opiniones son cómo los culos (todo el mundo tiene uno) hasta tal punto que es muy probable que cierren un comentario en Stackoverflow sólo por escribir «yo opino que…». Voy a enumerar algunas de las malas ideas que he ido viendo a lo largo del tiempo, no necesariamente en orden de importancia.
Errores de diseño
• Si te pones a desarrollar un sistema sin haber pensado previamente de forma concienzuda sobre su arquitectura entonces es que probablemente estás trabajando en algo que tendrás que tirar a la basura.
• Si descubres una solución nueva a un viejo problema es que probablemente no has entendido bien todas las sutilezas del problema. En esto son legendarios los desarrolladores de frameworks JavaScript todos los cuales empiezan y terminan igual: con un “¡Hola Mundo!” que parece super güay pero que a la postre muta en un amasijo críptico de comportamiento oculto ad-hoc y mal documentado.
• Los lenguajes de scripting con tipado dinámico no se inventaron para escribir sistemas de producción. Son cómo si un día se te rompe un bolígrafo y lo arreglas con pegamento. Entonces te maravillas de lo rápido y eficaz del resultado y decides que los ladrillos del nuevo tabique que estás poniendo en tu casa los vas a unir con pegamento también.
• Los frameworks no son una solución mágica, con frecuencia acaban causando más problemas de los que solucionan. Un problema de sufren muchos programadores jóvenes es que no les interesa nada que no puedan aprender en un fin de semana. Ven un tutorial de Java y cómo no se aclaran con la configuración de Tomcat entonces deciden pasarse a Node.js porque es en apariencia más sencillo. Incluso si se quedan con Java, deciden usar Spring Boot porque todavía no saben cómo levantar un Tomcat embebido en el proyecto de desarrollo. Pero estos atajos sólo son una forma de diferir una curva de aprendizaje que tendrá que ser superada igualmente más adelante.
Problemas de rendimiento
• La escalabilidad por diseño es un buen comienzo pero no se puede saber cómo de escalable es un sistema al menos hasta que se prueba un prototipo con una infraestructura y carga lo suficientemente similar a la del entorno de producción. Las pruebas de carga y rendimiento que no se pueden mapear a indicadores de negocio sirven de bien poco. En un benchmark lo que importa son las transacciones por segundo, el tiempo medio de servicio y la latencia en el peor caso.
• Que una subrutina parezca muy sencilla y elegante no implica en absoluto que se ejecute de forma eficiente. Durante años la tendencia en los lenguajes de programación ha sido hacia incrementar la diferencia entre lo que el programador escribe y lo que la máquina ejecuta realmente. Últimamente parece ser que hay un cierto retorno a aproximarse de nuevo al hardware con lenguajes como Rust o Go.
Defectos de codificación
• Ocultar la complejidad no la reduce. Si tu mando de la tele tiene 20 botones y metes 15 debajo de una tapa para que parezca más sencillo de usar, entonces no estás ayudando realmente al usuario, sólo estás haciendo que se pregunte dónde rayos está el botón que necesita. Análogamente, externalizar el comportamiento de un sistema en un fichero XML no reduce su complejidad, puede que aumente la distinción entre lo que es el algoritmo y lo que es su parametrización, lo cual es bueno, pero no simplica la solución al problema.
• Lo más difícil cuando tienes que mantener código legado es averiguar qué tenia en la cabeza el programador cuando lo escribió. El código “autodocumentado” explica lo que hace pero no por qué lo hace así. Hay un consejo de Dave Carhart en el cual recomienda escribir código cómo si el que lo fuere a mantener sea un psicópata homicida que conoce la dirección de tu casa.
• Los mejores programadores escriben código que es aburridamente narrativo. Cualquier programador puede escribir código que la máquina ejecute correctamente haciendo uso de las funcionalidades incluidas en la última version del lenguaje. Lo difícil es escribir código que un humano pueda “ejecutar” mentalmente. Hace un par de meses un programador veterano me dijo: “lo que no me gusta de los programas escritos en Java es que se componen de centenares de clases que indivicualmente no hacen prácticamente nada”.
• Los mapeadores objeto-relacional no son excusa para que no aprendas SQL. La razón es que empezarán a generar el SQL por ti y cuando salgas a producción no tendrás ni idea de lo que está haciendo tu aplicación realmente con la base de datos.
• Ponerse a refactorizar un código que no se conoce bien es un craso error. La razón es que ese horrendo código espagueti que te han asignado mantener no empezó siendo un espagueti. En realidad el programador que lo escribió originalmente era un tipo bastante capaz excepto que al principio no conocía bien los entresijos del problema, luego, según le llegaban incidencias y lo depuraba lo fue parcheando para cubrir todos los casos particulares pero nunca tuvo tiempo de refactorizarlo él mismo. Cada IF metido a capón en medio del código es una pizca de conocimiento que no figuraba en las especificaciones originales. Entonces si lo cambias de arriba a abajo por las buenas estás inexorablemente avocado a repetir todos los mismos errores que el programador que te precedió.
Fallos en las pruebas y monitorización
• Los logs son una forma paupérrima de monitoriar el funcionamiento de un sistema. La trazablidad de un sistema debe ser parte de su diseño. No es que los logs sean supérfluos, todo lo contrario. Pero volcar todo lo que va pasando en un archivo de texto te acarreará muchisimo trabajo posterior de escribir y mantener expresiones regulares para extraer la información y mover los archivos de un lado para otro.
• Ningún juego de tests puede reemplazar a la evidencia estadística de horas de funcionamiento libre de fallos en un sistema. Enhorabuena si eres un fanático del TDD, pues te ahorrarás muchas horas depurando tu propio código. Pero que un software pase un juego de pruebas no implica para nada que esté listo para ir a producción.
• Sólo el mayor de los ingénuos espera que los usuarios proporcionen las entradas correctas al sistema. Las entradas no sólo no serán correctas sino que serán literalmente cualquier mierda.
• Ninguna red es fiable. El protocolo TCP/IP está diseñado para trabajar con una tasa permanente de errores de transmisión. Si diseñas tu aplicación basándote en la premisa de que la red siempre estará en funcionamiento entonces sufrirás inexorablemente muchas desagradables e inesperadas paradas de servicio, o peor, corrupción de datos, etc.
Ideas erróneas en la gestión de proyecto
• Agile es tu peor enemigo. ¿Te parece bien que el cliente te pueda cambiar las especificaciones cada dos semanas? ¿Tener que asistir a un daily todos los dias antes de las nueve de la mañana para explicar continuamente lo que estás haciendo? ¿Que te interrumpan por Skype o por teléfono dos veces cada hora? ¿Mirar de reojo cada vez que lees una página web que no está directamente relacionada con tu tarea en curso? ¿Tener que justificar al milímetro todo lo que haces y convertirte en una trituradora humana de tickets?
• Ninguna propuesta de mejora técnica supera el filtro gerancial si no puede ser explicada cuantitativamente en términos de retorno de la inversión.
Post relacionado: Hackers vs Space Cowboys.