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.

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.

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?.

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"

¿Por qué leer El Libro Negro del Programador?

Adquirir desde:
Amazon (kindle eBook / papel)
CreateSpace (papel)
PayHip (epub / mobi / pdf)

El libro negro del programador.com
Segunda Edición - 2017

Archivo

Trabajo en...

Mis novelas...