No detengas tu progreso como programador. Keep it simple
En este artículo quiero hablar de la importancia de escribir código simple para favorecer su mantenimiento y su reutilización
Hace años bromeaba con un amigo mío sobre cómo muchas veces tendemos a complicar las cosas cuando programamos. Buscamos soluciones rebuscadas, sobreoptimizadas y tan excesivamente complejas que su posterior mantenimiento (por no hablar de su reutilización) es literalmente imposible.
Muchas veces esto se debe al desconocimiento de técnicas y características de las herramientas que estamos usando. Otras veces es el sobreexceso de información que los programadores “soportamos” en el día a día: la aparición de nuevas tendencias, librerías y frameworks añaden una prisa muchas veces innecesaria para adoptarlos. Y sí, también creo que hay cierto orgullo en encontrar soluciones de las que podamos sentirnos orgullos al enseñar, como si lo complejo fuera siempre mejor.
Frente a eso en este artículo me gustaría reivindicar justamente lo contrario:
Keep it simple
¿Qué significa simple?
Lo primero será definir qué entendemos por simple. Creo que es un concepto tan abierto que es posible que cada uno tenga su propia opinión. Sin embargo, creo que podemos estar de acuerdo en que simple es algo fácil de entender, usar, reusar y extender.
🧐 Escribe código fácil de entender
Si aceptamos esas características de un código simple, hay una conclusión inmediata que podemos extraer: la mejor forma de conseguir la simplicidad en el código que escribamos es “obligarnos” a que las cosas realicen una única tarea. Dicho de otro modo, huir del código espagueti donde los conceptos y responsabilidades se entremezclan para abrazar la simplicidad en cada parte que lo compone.
El concepto de responsabilidad única, que aparece enunciado como un principio SOLID, nos permitirá encapsular funcionalidad en trozos muy pequeños que podremos ir mejorando con el tiempo sin recurrir a refactorizaciones tediosas y cuyo mantenimiento será mucho más fácil y agradable: ya sabes, no es lo mismo leer un archivo de 1.000 líneas que uno de 50.
Pónselo fácil a tu yo del futuro
Por tanto, acostúmbrate a que las funciones, métodos y clases hagan una única sola.
Emplea las variables de modo que no vayan modificando su significado a lo largo del tiempo (la típica variable foo
que acaba terminando en un cajón “desastre”.
Evita siempre que sea posible los efectos secundarios del código. Por ejemplo, si la declaración de una función es esta:
const result = analyzeProducts(products)
Asegúrate de que el argumento products
no es también modificado internamente, lo cual, además de provocar la sorpresa del desarrollador que use la función, añadirá complejidad extra al no poder saber qué hace la función con tan solo mirar su declaración.
O si por ejemplo tenemos esta otra función:
const total = calculateTotal(products)
Trata de que el resultado siempre sea el mismo independientemente del momento de invocar la función. Si una función depende de valores externos pásalos como argumentos de modo que quede reflejado todo lo que necesita la función para hacer su trabajo.
En definitiva, asegúrate de escribir un código consistente que exprese aquello que lleva a cabo.
🥳 Escribe código fácil de usar
Haz que el código que escribes hable por sí mismo. Escoge nombres adecuados para variables, funciones y clases.
Evita funciones sobrecargadas cuyo comportamiento varía en función de los argumentos que recibe (esto tiene un nombre de esos que nos gusta emplear a los programadores para mostrar todo lo que sabemos: ad-hoc polymorphism, algo de lo que librerías antiguas abusaban enormemente).
Expón tan sólo aquellas partes que quieres que sean públicas y haz privadas todas aquellas variables y funciones que no quieres que otros modifiquen. Y no, no es necesario para ello recurrir a las clases y su keyword private. Algunos lenguajes como Javascript nos permiten realizar closures sobre variables y funciones de modo que podamos ocultar determinados detalles de implementación a la vez que exponemos las partes que queremos que sean públicas:
const counter = function createCounter() {
let count = 0;
return {
getCount() {
return count;
},
setCount(value) {
count = value;
return this;
},
increment() {
count = count + 1;
return this;
}
};
};
♻️ Escribe código que sea fácil de reutilizar
Si te acostumbras a escribir funciones cada vez más cortas que hagan una única cosa, este paso será practicamente inmediato, ya que te resultará sencillo crear pequeños módulos que puedas importar en otras partes del programa de modo que aproveches esa lógica en distintas partes.
De este modo así cumplirás con otro concepto tan importante como es el de Don’t repeat your self. ¿A quién no le ha pasado tener que reemplazar el mismo código en distintas partes de la aplicación por no haber sacado al principio algo de tiempo para extraerlo a un módulo?
Además, cuanto más “puras” sean tus funciones (es decir, no lleven a cabo efectos secundarios, no dependan del estado externo, etc.) más fácil te resultará extraerlas a micro módulos para volverlas a reutilizar.
🚲 Escribe código fácil de extender
Por ultimo dedica tiempo a escribir clases y funciones a las que posteriormente puedas añadir nueva funcionalidad sin tener que modificar su estructura interna. Esta es la base del principio SOLID open-closed y es la idea que subyace tras numerosos patrones de diseño.
Aprovecha el uso de interfaces, haz que tus funciones sean fáciles de componer, familiarízate con técnicas como el currying de funciones, etc.
Acostúmbrate a trabajar con DTO’s u objetos para pasar múltiples argumentos de una función, de modo que acabes con código mucho más autoexplicativo:
❓const result = calculateTotal(subtotal, null, null, giftCard);🔆const result = calculateTotal({ subtotal, giftCard });
En este ejemplo hay dos argumentos que reciben null pero cuyo significado no podemos ver a simple vista, obligándonos a revisar la declaración de la función para averiguar lo que hacen. En el segundo caso, todo queda mucho más claro.
Y sí, haz que funcione
Hacer código simple muchas veces no basta. Al menos no si no conseguimos que funcione y haga lo que esperamos que tenga que hacer.
Para ello, creo que metodologías como TDD son muy interesantes, aunque las apliquemos de una forma más laxa de lo que proponen. Si antes de lanzarnos a programar nos acostumbramos como mínimo a escribir micro-tests que validen que las funciones y métodos funcionan correctamente (aunque nos olvidemos de casos frontera y de todos los errores posibles que pueden suceder), estaremos ganando una seguridad y robustez en nuestro código que a larga nos resultará increíblemente valiosa.
Por tanto, podemos seguir un patrón de desarrollo en cada cosa que hagamos que sin caer en la complejidad de metodologías como la ya mencionada Test Driven Development nos ayuden a evolucionar de forma segura y tener un código que es a la vez simple y que hace aquello que se espera de él:
- Primero haz que funcione.
- Reescríbelo para hacerlo cada vez mejor.
- Optimízalo.
Esta simple iteración la podemos llevar a cabo todas las veces que queramos con la seguridad de que siempre que pasemos por la “casilla de salida” tendremos nuestro micro test de respaldo para saber que funciona bien al menos para sus casos más generales.
Nota. ¿Por qué estoy hablando de micro tests y no de suites completas? Bien. Creo que es engañarse pensando que en todos los proyectos hay la posibilidad de crear una suite de pruebas robusta donde se contemplen no sólo los casos más generales, sino aquellos que viven en la frontera y resultan más conflictivos. Muchas veces el tiempo es el que es ( y el dinero ), y resulta inviable llevar a cabo la metodología TDD en el más estricto sentido. Pero sin embargo, sí que veo factible asegurar unos mínimos de calidad implementando estos tests que al menos, en el comportamiento general, aseguren la validez del código que escribimos.
Conclusiones
Muchas veces cuando escribo esta clase de artículos me resulta muy difícil no caer en las “verdades del barquero”, es decir, realizar una enumeración de cosas que parecen evidentes y que por ser de sentido común no deberían repetirse tan a menudo.
Sin embargo la experiencia me ha enseñado en que por muy presentes que se hallen en nuestro subconsciente, en el día a día las tendemos a olvidarnos de ellas por todos los factores que comentaba al principio.
Es por eso que de vez en cuando viene bien leer (y escribir) un artículo como este.
¿Quieres recibir más artículos como este?
Si te ha gustado este artículo te animo a que te suscribas a la newsletter que envío cada domingo con publicaciones similares a esta y más contenido recomendado: 👇👇👇