Software testing

Reconozco que comencé a tomarme muy en serio el ser más estricto con el desarrollo y refactorings de las pruebas desde hace relativamente pocos años. Efectivamente, me llevó su tiempo darme cuenta de la enorme rentabilidad metodológica al pasar de una aplicación de consola para depurar (...) que tener formalizadas correctamente una completa y contundente batería de pruebas. Tanto es así, que hoy día sólo veo a través de las pruebas, quiero decir, cuando desarrollo nuevo código de producción, pocas veces entro en él en modo depuración si las pruebas correspondientes indican que todo va bien.

(Update: no en vano he publicado en 2019 un nuevo trabajo sobre todas aquellas prácticas ágiles que permiten escribir código mejor diseñado y de mejor calidad y que permite así escribir mejores tests: El Libro Práctico del Programador Ágil)

No obstante, y sin caer en la simpleza de reconocer lo fácil que es detectar en qué otros fallan, veo a menudo (muchas más veces de las que me gustaría) que el hecho de tener implantantado una arquitectura y metodología que permite y exige el crear pruebas, éstas se desarrollan como para salir del paso, en lo que se suele en llamar el happy path y que yo llamo particularmente "pruebas felices".

¿Qué es una prueba feliz?. Cuando escribimos una nueva clase o añadimos una nueva funcionalidad a código ya existente, tenemos la tendencia natural de escribir pruebas que consciente o inconscientemente sabemos que van a dar pocos problemas. Probamos entonces el mejor caso y que resuelve bien nuestro código: la prueba feliz viene a decirnos que nuestro código hace bien aquello para lo que lo hemos desarrollado. No obstante, si nos limitamos a escribir exclusivamente pruebas felices, estamos ignorando gran parte del objetivo de tener una solución respaldada por tests. Buscamos sólo pruebas felices porque en realidad percibimos el escribir pruebas como un mal que hay que asumir en lugar de un pilar fundamental y esencial en el desarrollo de un software de calidad y profesional.

El objetivo de escribir pruebas no es sólo el de tener un mecanismo por el que poder comprobar automáticamente que algo funciona ahora y seguirá funcionando en el futuro. Escribimos tests no sólo para la situación ideal (el camino feliz) sino que debemos desarrollarlos para comprobar todas aquellas situaciones incómodas en las que una funcionalidad particular se podría ver comprometida. Se nos olvida en ocasiones que los tests persiguen detectar errores, si nos quedamos con los casos más sencillos, seguramente estaremos ocultando bugs que tarde o temprano nos explotarán en las manos.

¿Cuándo es el momento más oportuno para detectar errores y problemas?, ¿cuando estamos precisamente desarrollando una nueva funcionalidad o cuando el software está ya en producción con uno o varios clientes usándolo?. La respuesta es más que obvia.

Recientemente he desarrollado un servicio de Windows para instanciar ciertos servicios web que emulan el comportamiento de un tipo de dispositivo. Se simula uno de estos dipositivos instanciando sus servicios web correspondientes en un puerto específico. Desarrollé como es lógico ciertas pruebas para garantizar que los web services se instancian bien para el puerto 8000, ¿y ya está?. Absolutamente no, ¿qué pasaría si al desplegar ese software en una máquina en producción ese puerto está ya siendo usado?. En este caso, las pruebas tienen que garantizar que somos correctamente notificados cuando se da esa circunstancia, que un error de este tipo no provoca un crash completo del servicio de Windows, etc. Si me hubiera quedado en la prueba feliz, seguramente habría terminado antes, pero con toda seguridad en el futuro habría tenido que dedicar muchísimo más tiempo a solucionar ese tipo de errores en producción y con un cliente insatisfecho...

Esto no es más que un ejemplo pero es que a veces no nos damos cuenta de la cantidad de esfuerzo y tiempo que nos podemos ahorrar detectando errores en producción sencillamente creando una batería correcta de tests en la fase de desarrollo. Pocas cosas hay que tranquilicen más en software que saber que tu producto está tan suficientemente probado que muy difícilmente se van a encontrar problemas en el despliegue del mismo.

Una ley del software viene a ser que cuanto más y mejor pruebes un software, mayor lo vas a rentabilizar, en el sentido de dedicar menos tiempo a depurar errores, el tener menos clientes reportando problemas, etc.

Tampoco es cuestión de crear el mayor número de pruebas porque sí sino de crear éstas con la calidad suficiente y cubriendo todos los posibles casos.

Este es un asunto que, me temo, solemos subestimar y es que no es trivial crear y saber desarrollar pruebas con la suficiente calidad; el problema es que en nuestra profesión muy a menudo debemos tener un carácter polifacético (lo que viene siendo tener que hacer de todo un poco); este no es un tema sencillo sino que el tester es un claro perfil de persona cualificada con ciertas aptitudes en su profesión, como bien indica este magnífico libro de Software Testing.

A veces me he planteado la pregunta de cómo evaluar un buen software de uno que no lo es tanto. Aquí entran en juego seguramente aspectos muy subjetivos; sin embargo, si intentamos llegar a algún tipo de principio del tipo de los que muestra Max Kanat en su libro Code Simplicity, existen realmente varias maneras de evaluar la calidad de un buen software.

No me gusta nada ni siquiera plantear el concepto de calidad, ya que en la mayoría de las ocasiones, los desarrolladores de software hacen lo que pueden en el contexto laboral con el que les toca lidiar; pocas veces he visto que realmente las cosas se hagan mal por pura y llana pereza mental. Sí he visto muchas a menudo que las cosas se hacen mal por ingenuidad o por la falta de un tutor que sirva de guía y ganas de traspasar su experiencia.

¿Cómo entonces distinguir una librería o trozo de software bien hecho de otro no tan bueno?.

Un error muy común que cometen muchos desarrolladores de software es escribir código de manera que es difícil crear a su alrededor las suficientes pruebas o tests que garanticen que ahora y más adelante, el software funciona.

Esto es un mantra que repito a menudo: la estructura de una solución que puede ser probada no tiene nada que ver con la estructura de otra para la que es imposible crear un conjunto de tests. Por tanto, aquí tenemos un elemento que nos puede indicar en cierta medida la calidad de una pieza de código: si se puede probar con facilidad o dificultad.

Pero, ¿qué hay del mantenimiento?, ¿no es verdad que queremos escribir software que viva muchos años y que pueda ser vendido y desplegado en el mayor número de clientes posible?. ¿Cómo vamos a hacer esto si la solución que escribimos es imposible de mantener?. Volvemos a la metáfora del coche que no se puede reparar...

Del mismo modo que antes, un buen software escrito para facilitar su mantenimiento no tiene nada que ver en su forma y estructura de otro que es imposible o muy difícil de mantener (diseño rígido), entendiendo por mantenimiento la detección fácil de pequeños bugs y la capacidad de mejorar el producto con nuevas características o mejoras de las ya existentes.

Efectivamente, con el tiempo nos damos cuenta de que el diseño, estructura y forma de un software que permite ser probado con facilidad y que puede ser mantenido con sencillez, no tiene nada que ver con el diseño, la estructura y forma de un software que ni podemos probar bien y para el que es muy complicado introducir algún cambio.

Esto es un principio de desarrollo de software inquebrantable que uno termina por aprender a lo largo de varios años después de algunas etapas de fracasos y errores.

Cuando llegamos a este tipo de conclusiones, nos damos cuenta de que programar bien no se consigue sencillamente leyendo un buen manual de C#, Ruby on Rails o lo que sea; conocer los rudimentos de cualquier tecnología no es suficiente. Existen principios, leyes, diseños, etc. que nos indican realmente cómo llegar a una solución con la suficiente calidad.

Software quality¿Qué es lo que distingue un buen profesional de una persona que se gana la vida con aquello que le ordenan hacer?. Llevo mucho tiempo preguntándome qué es lo que realmente distingue a alguien por el que las compañías se pelearían en conseguir de aquellos que nada más entregar un currículum, éste va a parar a una enorme y creciente pila. Me temo que queda muy atrás el tiempo en que bastaba con decir tu título o profesión para convertirte en candidato: los paradigmas laborales están cambiando más rápidamente de lo que nos estamos dando cuenta.

No obstante, podemos esbozar un enorme y relevante corolario de logros en nuestra pasada vida laboral, mientras que sólo podemos ser verdaderamente profesionales en aquello que hacemos en el día a día.

Programadores, desarrolladores de software, aquellos en general que trabajan creando nuevas soluciones, sólo pueden prosperar de un modo, ni títulos, ni el soporte de grandes compañías en las que uno ha trabajado y nada de todo esto: somos profesionales cuando somos capaces de realizar un trabajo igualmente profesional.

Esto no es ninguna novedad, claro está, pero lejos de una actitud complaciente y egocéntrica que nos hace considerar todo lo que hacemos como lo mejor, tenemos que reconocer una cosa: hacer un trabajo pro requiere de una disciplina diaria que no tiene todo el mundo.

Me he encontrado en muchas ocasiones en la tesitura de tener que corregir detalles y bugs de compañeros, lo cual no está mal y forma parte de nuestro trabajo. Sorprende cuántas veces he descubierto cosas que manifiestamente se podrían haber hecho mucho mejor exactamente con el mismo esfuerzo.

Si cuesta el mismo trabajo hacer una cosa regular y hacerla de manera excelente, ¿por qué elegir la primera?. En muchos casos es sencillamente por pura pereza; en otros por que para exigirnos un nivel de excelencia en todo lo que hacemos se tienen que dar una serie de condiciones en el contexto en el que trabajamos.

No termino de entender cómo sabiendo hacer algo muy bien, por qué lo dejamos con un nivel de calidad pésimo si además nos cuesta el mismo esfuerzo. Un profesional esto lo tiene muy claro y es que la única métrica por la que se nos puede medir y valorar no es otra que la calidad del trabajo realizado. No hay más.

En el lugar donde trabajo llegan frecuentemente currículums y me sorprende que la mayoría de la gente no pone en valor la calidad de los trabajos realizados: casi siempre se ensalza el dominio de tal y cual tecnología, el haber trabajado en la renombrada empresa X, cuando en realidad lo que a un responsable de recursos humanos (o al menos es lo que yo mismo aplico) le gustaría ver algo como "Desarrollo de la aplicación tal actualmente en producción con tantos usuarios", "módulo X compartido en Github con tantos usuarios", etc. etc.

No somos profesionales por lo que decimos y ni siquiera por dónde trabajamos, sino por la calidad de lo que hacemos.

Lo sorprendente es que esta calidad en muchas ocasiones se consigue sencillamente eligiendo correctamene, a pequeños pasos y creando el hábito de hacer las cosas bien, obviando la pereza de terminar de cualquier forma, sin darnos cuenta de que así vamos dejando piedras que tarde o temprano se desmoronarán encima nuestra. No necesitamos participar en grandes y subvencionados programas de I+D para realizar cosas fantásticas (...): la mejor innovación se puede hacer cualquier día en el trabajo que estamos realizando. Si conseguimos como hábito que la excelencia sea la base de todo lo que realizamos, será entonces cuando irán surgiendo nuevas ideas, oportunidades de éxito y posibilidades para mejorar nuestra carrera profesional. Hacer, por lo contrario, un trabajo cutre, posiblemente nos permitirá pagar algunas facturas más, pero irá menoscabando nuestras oportunidades tarde o temprano.

Si aquello en lo que estoy enfrascado ahora mismo lo puedo hacerlo mejor, ¿por qué no hacerlo?. Un profesional se labra con el trabajo diario de muchos años.

Es recurrente la pregunta que me hacen según la cual siempre se pone en duda la necesidad de realizar software sencillo, fácil de entender (por nosotros y por los demás) pero sobre todo, mantenible. Muchos de quienes nos dedicamos a desarrollar software profesional no tenemos claro aún ciertos conceptos esenciales, como por ejemplo que un diseño matenible no tiene nada que ver con un diseño de algo que es imposible modificar, depurar, evolucionar, etc. Aun funcionando bien, el primero nos dará un mayor rendimiento del trabajo realizado, mientras que en el segundo caso el software pasa a producción moribundo y sin apenas solución de continuidad.

No obstante, nos cuesta reconocer la relación que existe entre la sencillez y la facilidad de mantenimiento.

Mantenible (palabra mantra en el Libro Negro del Programador) no significa trivial, que un principiante sin apenas esfuerzo pueda entender a la primera, sino coherente, un diseño eficiente que facilita los cambios en el futuro y que la adaptación a nuevos requerimientos relacionados son viables (a un coste asumible).

A diferencia del autor de un best-seller que cuando publica un libro que funciona bien recoge royalties según las ventas, cuando publicamos un producto software tendremos más o menos éxito si este puede evolucionar, si puede ser cambiado y fácilmente mantenido.

En Code Simplicity (libro que recomiendo aunque no se lea ni una línea de código) se pueden leer frases auténticamente reveladoras que el autor intenta sintetizar a modo de leyes comunes que gobiernan el desarrollo de cualquier software.

Una de estas afirmaciones que sostiene el autor es que la facilidad de mantenimiento de cualquier pieza de código es proporcional a la simplicidad de sus partes individuales ("The ease of maintenance of any piece of software is proportional to the simplicity of its individual pieces").

Cuando leí esta frase pensé que cuánto tiempo había intuido esta relación pero sin embargo había sido incapaz de sintetizarla de esta manera tan magistral. Una virtud tiene ese libro: sintetiza de una manera genial auténticas verdades que aún siendo sencillas de entender no lo es tanto de aprehender e introducir en nuestro adn de programadores profesionales.

Efectivamente, parece básico pero no es tan elemental tenerlo presente en nuestro día a día.

Si queremos hacer software mantenible, la clave está en conseguir que cada una de sus partes sean sencillas. La cuestión no es contraponer sencillez versus mantenibilidad, sino que ambos conceptos están íntimamente relacionados (y además su relación es proporcional).

¿Por qué nos debemos preocupar de que lo que desarrollamos pueda ser mantenido con relativa facilidad?, por la sencilla razón de que durante la vida de cualquier producto software, sea algo que se venda bajo licencia, un desarrollo interno en nuestra compañía o incluso cualquier proyecto personal, éste va a ser mantenido durante mucho más tiempo que el que ha costado desarrollarlo. Es más, cuanto más éxito tenga, más cambios y mejoras se nos van a pedir, por lo que el ritmo de evolución de un producto puede ser considerado también como un síntoma de su éxito.

Yo siempre pongo el mismo ejemplo: ¿compraríamos un coche que es casi imposible de reparar o al que es muy difícil cambiarle el aceite?.

¿Verdaderamente tenemos esto presente cuando escribimos líneas y líneas de código?.

Estos conceptos de sencillez y facilidad de mantenimiento son fáciles de entender, pero lo que no es tan fácil es tenerlos presentes en nuestro día a día: nadie es capaz de escribir código limpio a la primera, sino que para llegar a él debemos buscar esa solución sencilla mediante refactorings, repaso continuo de lo ya realizado, etc.

Un ingenuo desarrollador simplificará cuando le venga bien, no de manera sistemática, no se preocupará de que lo que hace pueda ser matenido / depurado con facilidad (no percibe que esto le puede golpear en el rostro con efecto boomerang); un programador cándido busca exclusivamente que lo que está haciendo funcione a cualquier precio, sin tener en cuenta eso de que pan para hoy y hambre para mañana...

Si nuestro software es mantenible, estaremos poniendo los cimientos del éxito del mismo. Si no lo es, nacerá moribundo y terminará convirtiéndose en un fracaso y fuente de clientes insatisfechos. Conseguimos este objetivo de mantenibilidad cuidando de que las partes individuales de nuestro producto sean sencillas.

Hay diferentes maneras de aprender y mejorar nuestro trabajo como desarrolladores de software. El aprender una nueva tecnología (o mejorar las habilidades en aquellas que dominamos) requiere a menudo repensar cómo hacemos las cosas.

Hay quien se siente cómodo buscando en foros continuamente para resolver cualquier problema; esto para mí es algo así como aprender por prueba y error llevado al extremo. Hay quien, como yo, preferimos aproximarnos a una nueva herramienta o tecnología leyendo un buen libro de arriba abajo. Las opciones son diversas y como se suele decir cada maestro tiene su librillo.

No obstante, he visto durante mucho tiempo el que es un gran defecto de muchos programadores profesionales: cuando conocen en profundidad las herramientas, lenguajes, etc. que utilizan en el día a día, se anquilosan haciendo siempre, durante años, las mismas cosas y del mismo modo. El desarrollar software tiene un grado versatilidad y flexibilidad que difícilmente hay una única forma de hacer algo, todo lo contrario, siempre existen cientos de formas de resolver un problema; entonces, ¿por qué nos abstenemos de descubrir esos otros enfoques?.

Una manera fundamental de aprender a mejorar, conocer alternativas y producir el efecto pero-por-qué-a-mí-no-se-me-ha-ocurrido-esto es sencillamente leer el código de proyectos realizados por otros.

Desde hace muchos años soy asiduo lector de CodeProject, web colaborativa donde se puede encontrar casi de todo; igualmente, existen repositorios públicos bien conocidos donde se encuentran verdaderas joyas de programación; hablo de GitHub, CodePlex y Google Code, por poner unos ejemplos. Cualquiera quiera compartir un proyecto lo puede publicar en alguno de esos portales.

Sin embargo, lo que aquí quiero señalar es que no hay mejor manera de aprender a programar que leyendo proyectos realizados por otros. Así de sencillo. En esos repositorios públicos que apuntaba antes se encuentra verdaderamente el state-of-the-art de muchas áreas y tecnologías.

Husmear en las tripas del código de otros proyectos te permite descubrir nuevas formas de hacer, te enseña cómo otros han resuelto ciertos problemas e incluso nuevos estilos de programación.

Por mucho que dominemos ciertos lenguajes de programación, de scripts o de cualquier cosa, cada problema, solución o proyecto que tengamos que afrontar se puede resolver de muchas formas diversas; yo siempre digo lo mismo: tonto del todo no soy, o eso creo, pero seguro que hay otras mentes más privilegiadas a las que se les ha ocurrido a resolver algo de una manera más smart. Bucear en otros proyectos te lleva a ese tipo de aprendizaje que difícilmente se va a encontrar leyendo un libro.

Por poner un sólo ejemplo, he aquí una de esas joyas de desarrollo por su buen diseño e implementación: moq.

CodePlex

github

Google Code

 

En ocasiones me han preguntado por qué insisto tanto en que el código que se escriba sea lo más legible posible, que se pueda leer y entender sin que construcciones extrañas o clases de cientos de líneas te arañen la vista, por poner unos ejemplos.

Se pueden dar muchos argumentos a favor de añadir un poco de esfuerzo a nuestro trabajo para escribir código que otros puedan entender; de todos los posibles a mí me parece que hay un criterio fundamental que no siempre se tiene tan en cuenta.

Cualquier trozo de código va a ser muchas veces leído que escrito o modificado. Esto es, cualquier método, función, clase, etc. va a ser repasado y leído en más ocasiones que las veces que hay que ir a ellos para hacer una pequeña modificación. Por tanto, si a todas esas veces le añadimos un coste de tiempo por la complejidad de entender lo que leemos estamos ante un obstáculo que nos quitará tiempo para dedicarnos a tareas más productivas o creativas.

No escribimos software para nosotros sino para que otros lo entiendan. Esto es clave para conseguir soluciones mantenibles y evolucionables. A veces ignoramos que ese otro podemos ser nosotros mismos.

¿He mencionado un extra de esfuerzo?. En realidad ese esfuerzo lo tenemos que hacer explícitamente si no estamos acostumbrados a fluir con los buenos hábitos de programación que existen para este tema en particular; elemenos tan sencillos y triviales como elegir buenos nombres descriptivos para nuestros artefactos de software (¿por qué llamar a una variable _nde cuando le podemos poner _numeroDeEntidades, por ejemplo), métodos o funciones que hacen una única cosa sin más de tres o cuatro argumentos, elementos de una clase ordenados siempre de la misma manera en toda la solución y un larguísimo y extenso etcétera.

Soy de la opinión de que quien no intenta escribir legiblemente realmente no le interesa hacer un buen trabajo y está dejando piedras en el camino con el que un compañero se tropezará cuando tenga que asumir ese código.

Lo sorprendente es que muchas veces el esfuerzo de escribir algo de manera complicada ¡es el mismo que escribirla de manera simple!. Si tenemos las dos opciones, ¿por qué entonces no hacer la que supone un mejor trabajo?.

La productividad de un equipo de trabajo en ocasiones viene dada por pequeños detalles que en sí mismos pueden parecer insignificantes pero sumados marcan una gran diferencia. El Libro Negro del Programador habla intensivamente acerca de cómo desterrar malos hábitos e incorporar buenos precisamente para aumentar la productividad. En ocasiones se entiende ésta exclusivamente como echar más horas: yo digo que trabajar con productividad tiene más que ver con usar herramientas correctamente, tener un equipo de trabajo bien organizado y buenos procedimientos.

Uno de estos procedimientos que pueden ahorrar muchísimo tiempo de esfuerzo inútil es subir correctamente al repositorio de código los últimos cambios introducidos. Como en muchas ocasiones, los mejores hábitos y técnicas son precisamente los más sencillos.

¿Cuánto tiempo hemos pasado resolviendo conflictos de código introducido al mismo tiempo o después de nuestros últimos cambios?. Demasiado si se tiene en cuenta que ese es tiempo no productivo y, en ocasiones, frustrante.

La siguiente técnica busca minimizar las posibilidades de generar conflictos; cuanto mayor sea el número de desarrolladores en un equipo, más posibilidades habrá de generar este tipo de problemas.

Para reducir las posibilidades de conflicto en el código cuando vamos a introducir un nuevo cambio:

  • Obtenemos la última versión (lo que nos garantiza que no vamos a usar en ningún momento código obsoleto).
  • Introducimos los cambios o nueva funcionalidad.
  • Ejecutamos todos los tests; deben pasar el 100%.
  • Obtenemos de nuevo la última versión. De este modo vemos si nuestros cambios han introducido algún error de compilación con los cambios introducidos por otros (o al revés).
  • Antes de subir, volvemos a ejecutar todos los tests.
  • Ahora sí que subimos los cambios.

De este modo reducimos radicalmente la posibilidad de conflictos.

Hay diversas opiniones sobre la frecuencia de subir los cambios (cada X horas, cuando se termina una funcionalidad completamente, etc.). Esto dependerá de la naturaleza de cada proyecto. Personalmente me siento cómodo con subir frecuentemente (varias veces al día).

Lo mejor es acordar entre los miembros del equipo el procedimiento a seguir en este proceso (check-in process): ¡mejor uno aunque no sea el mejor que ninguno!.

Cuanto más tiempo viva tu aplicación, más probable será que tenga que cambiar; así de sencillo y contundente.

En ocasiones me han preguntado por qué parezco obsesionado por programar y diseñar de la manera más simple y legible posibles, para qué preocuparse ahora por aquello que puede o no necesitar cambiar en el futuro. La pregunta en sí ya encierra cierta candidez acerca de los artefactos que generamos en nuestra profesión.

Una de las verdades sobre nuestro trabajo, entronada a modo de ley, nos dice que cuanto más tiempo viva nuestra aplicación, programa, sistema, plugin, framework, etc. más probable será que necesite cambios, mejoras, correcciones, etc. Ley o no, lo que sí puedo decir es que ningún software en el que he participado ha permanecido inmutable más de seis meses...

¿Tenemos presente en nuestro día a día esta realidad?. ¿Nos preocupamos realmente en refactorizar y mejorar a pequeños saltos continuamente?. ¿Nos esforzamos en encontrar la solución más simple a cualquier problema?.

Es cierto que podemos dejar las cosas tal y como nos salen la primera vez que las hacemos (total, funcionan, ¿no?); sin embargo, si vamos dejando cabos sueltos, duplicidades, errores conocidos y toda una estela de debes, con el tiempo se formará una montaña que nos caerá encima inevitablemente (o enterrará el producto en el olvido).

Cualquier software va a necesitar cambios en un futuro necesariamente: cualquier producto que se lance al mercado va a morir si no se renueva con mejoras continuamente (continuous delivery), cualquier cliente consolidado que tengamos nos pedirá mejoras o cambios con toda seguridad, por mucho esfuerzo que hayamos dedicado a probar nuestro código, finalmente el cliente encontrará nuevos errores o pequeños bugs, cuando no nos encontramos con el consabido problema de haber entendido mal algún requisito en concreto. En otras ocasiones, la evolución del mercado o tipología de clientes al que se dirige nuestro software determinará el tipo de cambios a introducir.

Demasiadas razones para no programar centrando nuestro trabajo en la sencillez de las soluciones; esta casi nunca se consigue a la primera, sino que poco a poco, mediante pequeñas refactorizaciones, auscultando el trabajo con tests y a medida que la aplicación crece, vamos mejorándola en todos los aspectos. Tampoco podemos obviar que el coste de evolucionar una aplicación debe ser el mínimo posible, de lo contrario estaremos fuera del mercado antes de lo que nos gustaría.
 

"Aunque suene paradójico, programar profesionalmente significa también estar dispuesto a destruir parte del trabajo realizado ¡precisamente para mejorarlo!. Si nuestro software no puede ser modificado y mejorado fácilmente, estará perdiendo rentabilidad y oportunidades de competir."

 

En una etapa laboral anterior, sufría a menudo el típico ataque inesperado según el cual un manager o jefe de proyecto venía a pedirme a mí y a mi equipo la corrección o puesta en producción de algo que por arte de birlibirloque se había convertido ese día en crítico. A lo mejor lo tenía en el cajón olvidado hasta que le explotó en las manos.

Nada peor para un programador que tener que resolver un bug o incluir una nueva característica con la presión del tiempo, sobre todo si no estaba previsto.

Esto puede parecer a excusa, pero cuando trabajamos excesivamente presionados vamos dejando atrás las buenas prácticas, los buenos hábitos y el formalismo de probar y probar por el camino; cuando el tiempo aprieta aligeramos nuestro trabajo sin darnos cuenta de que esto tiene un precio tremendo y en ocasiones los resultados son catastróficos: se actualizan cosas que suponemos que funcionan bien y creemos que no deben dar problemas (sin imaginar algún tipo de efecto secundario), olvidamos los rigores de la gestión de versiones (claro, nos han dicho que es algo crítico) y además apenas tenemos tiempo de probar todo el sistema, por poner sólo unos ejemplos. Para resumir, cuando tenemos encima de la mesa algo crítico lo olvidamos todo y nos centramos en el problema.

La cuestión no está tanto en poder gestionar estas situaciones ocasionalmente sino cuando estas se convierten en crónicas y el modo habitual de trabajar; en ese caso el software resultante será de pésima calidad. Es tema recurrente en El Libro Negro del Programador, así que dejad que os recuerde que código de mala calidad es igual a problemas: soluciones inmantenibles, más costosas por las dificultades de introducir nuevos cambios, incapacidad de ser asumidas con facilidad por nuevos miembros del equipo y, en definitiva, programadores frutrados que dedican más tiempo a depurar que a crear código de valor.

Trabajar bajo la presión de problemas no previstos por nosotros constituye el típico escenario en el que quien presiona no tiene ni idea de software: sólo ve programadores cuyo trabajo debe ser igual que conectar cables, o están bien puestos o están mal puestos, no hay más. Personalmente considero que quien lidera un equipo de desarrolladores debe tener profundos conociemientos de software.

Siempre, y lo digo taxativamente, siempre que me he encontrado en esta situación el diagnóstico ha sido el mismo: gestores de proyecto mal planificados y con una organización pésima; el problema es que esta falta de trabajo eficaz termina trasladándose a los miembros del equipo de desarrollo. Tampoco podemos excusar a clientes que de un día para otro encuentran un bug crítico que hará temblar su organización: si se ha hecho bien el trabajo, esta situación no se debe dar.

En cualquier caso, si nos encontramos en esta tesitura y detectamos que para llegar a tiempo tenemos que dejar cabos sueltos y entrar en una zona de riesgos, debemos notificarlo adecuadamente a los managers; basta un simple correo que con sutileza pero con contundencia debemos advertir de la falta de tiempo para probar exhaustivamente o implementar los cambios solicitados (esto es una manera de delegar responsabilidades).

También es una cuestión de actitud: ¿estamos para que viertan sobre nosotros la mala organización de quienes jerárquicamente están por encima?, ¿es esto profesional?. He visto cómo algún proyecto ha fracasado no por la falta de pericia y buen hacer de los desarrolladores, sino por problemas de gestión.

El saber decir "lo siento, esto no se puede hacer de aquí a mañana" tiene efectos positivos que debemos considerar: estamos honrando nuestro trabajo (no nos pagan por trabajar, el profesional busca hacer un buen trabajo, que no es lo mismo) y, además, uno o dos noes de este tipo hará recapacitar a quien lo provoca e intentará evitarlos en el futuro (para lo que simplemente tendrá que organizarse mejor).

Este tipo de situaciones demuestra también una falta total de productividad: cuando se convierten en crónicas entonces ya sabemos en el tipo de compañía en la que trabajamos. Cuando identificamos un manager cuya idiosincrasia de trabajo es el caos, entonces la salida que nos queda es intentar cambiar de grupo de trabajo, departamento o compañía: un profesional se hace profesional precisamente haciendo un magnífico trabajo, éste es su currículum y su manera de progresar.

Como desarrolladores que nos debemos ganar la vida desde la calidad de nuestro trabajo debemos considerar como máxima que la mayor parte de nuestras actividades deben estar correctamente planificadas, debemos tener un roadmap claro aunque incluyamos un pequeño percentaje de nuestro tiempo para deviaciones e imprevistos.

Resulta sorprendente cómo pequeños pasos y hábitos consiguen con muy poco mejorar muchísimo la calidad de nuestro código; cuando hablamos de calidad entendemos también legibilidad, es decir, la facilidad o no de poder entender un pedazo de código leyéndolo tal como leemos un relato corto. Yo siempre digo que si se consigue entender de una o dos pasadas lo que hace un pedazo de código, entonces es que este apunta a estar bien hecho.

Ahora bien, ¿qué hacen por ahí esos trozos de código comentados que, lógicamente, no se van a ejecutar?.

Este es uno de los malos hábitos que debemos quitarnos de encima; el dejar rastros de código obsoleto va en contra de que este sea legible y fácil de entender.

Cualquiera que retome vuestro trabajo y se encuentre con él, lo primero que va a pensar es, ¿será esto un bug resuelto, lo habrán dejado ahí por alguna razón, será importante?. Este tipo de interrupciones en la lectura de líneas de software distraen del resto y crean dudas.

La razón por la que solemos dejar código comentado es obvia: nos cuesta mucho eliminar trabajo previo, pero es que precisamente esa labor de destrucción (eliminar algo que no está bien) y reconstrucción (re-crearlo para mejorarlo) es lo que aporta calidad a nuestro software. Entonces, ¿para qué dejar rastros de lo anterior?. Otra razón es que en ocasiones dudamos y no estamos seguros de las modificaciones que queremos introducir. Este último caso es fácil de resolver: una buena batería de tests nos deben indicar la solvencia o no de lo que cambiamos.

Por otra parte, ¿para qué está el repositorio de código?. Si modificamos algo y eliminamos un bloque, siempre lo podremos recuperar más adelante si hacemos una buena gestión en nuestro sistema de control de código fuente.

No es que haya que caer en extremismos; el desarrollar software tiene un componente lúdico y tampoco debemos ceñirnos rígidamente a las reglas, prácticas y buenos hábitos que sabemos que son necesarios para hacer un buen trabajo. Lo que indico aquí es que un software de producción y que debe ser mantenido y revisado, no debería tener bloques de código muerto.

"No dejemos código comentado: esto distrae a un futuro lector de nuestro trabajo y ensucia la solución"

Páginas

Mis libros en todas las tiendas:

Amazon
Google Play
Apple
Kobo
Barnes and Noble
Scribd
Smashwords
Payhip
Gumroad

Rafael Gómez Blanes Rafael Gómez Blanes
¿Hablamos?

 

Trabajo en...

Archivo

Mis novelas...