"El lado humano del software"

Soluciones al código para un SCRUM Radical

Años leyendo y aprendiendo sobre patrones de diseño de programación, para hacer un código elitista, reusable, ampliable, refactorizable, de calidad, y de pronto llegas a trabajar a una empresa que te impone el más puro estilo de “a saco” y “¡yeaaaaaah!” todo lo aprendido a la basura, a hacer ¿código bazofia?

Se te rompen todos los esquemas, pero ni tiempo para reflexionar, los encargos se amontonan, hay que terminar como sea, y el cliente final “Donde dije digo, digo Diego”. Te cambian el funcionamiento de la aplicación a tontas y locas. Ellos lo llaman “puro ágil” cualquier programador lo llamaría “pura mierda” … pero es lo que hay, es lo que se siente cuando después de tanto esfuerzo en lograr ciertas metas de pronto no valen nada y a modificar una montaña de código. Pero esa montaña de código implica una estructura lógica y modificarla es un esfuerzo que termina en dolor físico y mental y por supuesto costes.

Para bien o para mal, hay que producir deprisa, barato y ser flexible cambiando los funcionamientos dinámicamente. Es el mundo en el que estamos.

Pero… “¿cómo diablos vamos a producir así? Es una locura, el código no es flexible, ¡no se puede hacer esto!” se pregunta uno.

Ante esto tienes dos posibilidades, sufrir o adaptarte. Yo prefiero esto último ¿no crees?

Aquí voy a explicar un nuevo patrón de diseño, nacido a raíz del sufrimiento esfuerzo de estar refactorizando código cientos de veces.

A los elitistas les van a doler los ojos, pensando que son un conjunto de barbaridades, pero creédme, esto es lo mejor para la locura de un SCRUM a lo bestia que tanto aman los clientes modernos

El patrón de diseño WuaUP para SCRUM  rompe todas las reglas, todas las buenas prácticas de programación.

El patrón WuaUP para SCRUM no debe ser empleado en un software que precise de una alta fiabilidad y performance. OJO sólo sirve para proyectos pequeños o medianos pequeños, y con un programador (tú) o un máximo de 3 programadores con una integración y comunicación plenas. JAMAS debe emplearse para proyectos grandes, ni en los que la planificación pueda hacerse.

Por desgracia, es un patrón util que sirve para más del 80% de la producción moderna del software actual dada la obsesión imperiosa a unas entregas rápidas y cambios bruscos.

En la mayor parte del software, no se necesita ni de tanta fiabilidad ni de tanto performance, sólo resultados.

El patrón WuaUP para SCRUM busca refactorizaciones del comportamiento funcional lo más rápido posible partiendo del más puro caos en el diseño (cuando no hay diseño), ese es su objetivo principal, ninguno más.

Veremos algunos ejemplos de código; como hay un montón de lenguajes pero quizás el más general conocido por todos sea JavaScript lo pondremos en este lenguaje. Para los que apenas lo conozcan voy a poner un JavaScript a nivel casi elemental, fácilmente adaptable a otras lenguas.

Empezamos con la fiesta:

 

Instrucciones Simples.

No uses instrucciones que requieran a un especialista en el lenguaje o pensar para entenderlas. No importa que pierdas performance. Tampoco uses las instrucciones recién salidas que no entiende casi nadie. Créeme lo importante es que entiendas el código lo más rápido posible. En el SCRUM radical lo mismo estás con una cosa que con otra, y lo mismo de un día para otro te ponen a alguien a ayudarte que ni sabe el lenguaje en el que estás. Simplifica, ¡lo importante es el volumen! Claro que, como todo, tampoco se trata de hacer un algoritmo que sea de cálculo exponencial, todo en su medida.

 

Líneas Simples.

Haz líneas de código simples y cortas, muy cortas. Si necesitas una línea larga rómpela, si tienes que por ello crear variables temporales úsalas, el performance es terciario (excepto si es un bucle crítico). En el patrón el programador orgulloso no presume de líneas de código maestras o eficientes, presume de líneas simples y cortas, contra más para tontos mejor.

 

Pocos Comentarios.

No hagas apenas comentarios, el código debe ser simple por sí mismo, si necesita comentarios es que está mal escrito. Como siempre esta regla no debe ser extrema, se deben comentar ciertos comportamientos extraños o distintos a lo habitual y por supuesto lo que es tendente al olvido. Pero poca cosa más.

 

Booleanos Prohibidos.

¡No los uses! A partir de este momento están muertos. Ni en bases de datos ni en tu código. En su lugar usa enteros. ¿Qué gastas más memoria absurdamente? ¡Y qué más da! Ya es muy barata. ¡Estamos ante un SCRUM radical! En los booleanos existe sólo 2 estados posibles, ¿y si al día siguiente te sacan que el comportamiento de cierta funcionalidad necesita otro estado más? recuerda que es cambiante puro. Si usas un booleano en el momento que te añadan más estados perderás el tiempo refactorizando por culpa del tipo definido, incluso en la BBDD. Tocar definiciones en producción de la BBDD es molesto. En el momento que tengas más de 3 estados te aconsejo que uses una enumeración (ya sabes eso que se usa para ponerle un nombre a los números en tiempo de programación).

 

Minimiza en lo posible las capas de objetos.

Emplea los objetos lo menos posible. Increíble yo diciendo esto, con lo que a mí me han gustado siempre, y también las capas. Cierto software complejo resulta hasta difícil de concebir sin los mismos. La capacidad de abstracción caracteriza a los buenos programadores. Evidentemente no debemos de caer en duplicar código, pero tampoco en perder excesivo tiempo en evitar que algunos patrones se repitan. Ya comenté que el código reutilizable usa objetos, pero con el SCRUM Radical la reusabilidad suele importar más bien poco. Lo único que suelen querer es ver resultados rápidos, aunque a la larga pueda costar más cara la producción. En lugar de objetos usa funciones.  No hay tiempo para concebir estructuras lógicas complejas ni diferentes funcionamientos según los estados en diferentes capas. Las funciones son más predecibles. Esto recuerda a los lenguajes funcionales, pero yo hablo de funciones simples, sin más.

 

Maximiza numéricamente las funciones.

Usa funciones por todos lados, no por necesidades del código, sólo porque te lo diga la intuición, por defecto siempre de más, escribiendo de forma natural todo lo que puedas en funciones. El código eficiente y correctamente escrito según la metodología tradicional usa las funciones justas, el patrón WuaUP usa muchas funciones de más. El uso de muchas funciones ayuda a atomizar y vectorizar el código, ideal para las refactorizaciones. Una función nunca debe ser mayor de una página de texto.

 

Atomízalo todo.

En el patrón WuaUP para SCRUM tenemos micro sprints por horas. Haz un poco de código, testéalo, haz otro poco vuélvelo a testear. Produce una sensación muy frustrante cuando haces mucho código y lo pruebas, después te mueres de asco por la pérdida de tiempo y encima desgasta mentalmente muchísimo, es horrible. El software debe ser construido muy poquito a poquito en incrementos diminutos como pelotas de tenis ¿He dicho pelotas de tenis? Mejor incluso más pequeño, granos de arroz (5 ó 7 líneas).

 

Agrupa las variables en listas.

No uses variables globales, pero tampoco locales excepto en los casos claros, en su lugar agrupa las variables en colecciones genéricas, y créate unas cuantas colecciones que forman contextos. Con esto evitarás el tedio de refactorizaciones difíciles del SCRUM Radical al cambiarte el comportamiento de la aplicación.

Es típico que de pronto veas que no puedes acceder a ciertos valores que se encuentran encapsulados por la programación tradicional y que de repente pasas a necesitar. Esto provoca refactorizaciones difíciles y dolorosas.

Las agrupaciones parten de ser variables globales que contienen muchas variables dentro. Cada agrupación debe responder a un contexto, permitiendo un cierto encapsulamiento sin llegar a la basura extrema de las globales, siendo rápidas de refactorizar.

En un momento dado, puesto que las agrupaciones llevan valores objeto en su interior, puedes llegar a programar cierto comportamiento en alguno de ellos.

Nota: en el lado cliente, es más fácil de entender. En el lado servidor hay dos tipos de agrupaciones, las globales puras que afectan a todos los usuarios, y las agrupaciones del contexto del propio usuario que en un momento dado está haciendo cualquier petición, por ejemplo una transacción por un web service, o la descarga de una página. En dicho caso metes en la sesión una única variable que es una lista dinámica de propiedades.

Así ahorramos tener que estar con el lío de tener que estar pasando valores, que según los contextos es difícil a veces porque sencillamente no tienes un valor que te hace falta. Y no es tan chapucero como variables globales puras, es como decir, un intermedio entre lo bien realizado y la porquería pura, con la ventaja que obtienes la velocidad de creación/refactorización de la porquería pura.

 

Usa variables genéricas.

Procura usar variables de tipado genérico excepto en los casos muy claros. Que si, que definir el tipado en el compilador tiene muchas ventajas cuando programas una aplicación clásica, pero cuando estas con ante SCRUM Radical el tipado es un atraso. Entrega, entrega y entrega y ahora el cliente te pide cambios, cámbialo todo, no espera, vuélvelo a cambiar ¿no te has enterado de qué va la historia? Este es el modelo que quieren los clientes, entiéndelo. No vas a código perfecto, sólo a entregas rápidas y con un grado de que no se cuelgue del 99,99% olvida ese 0,01% restante, es imposible.

 

Envía a las funciones listas.

Usa listas de propiedades genéricas: muerte a las variables simples. Usa lo menos posible las variables normales de toda la vida (excepto en contextos muy localizados), usa en su lugar listaa de propiedades (según cada idioma se le denomina de una forma). No pases un parámetro a una función envía listas completas (no es lento, técnicamente el ordenador envía el puntero). Usa listas prácticamente siempre, aunque aparentemente sólo vas a enviar un valor, nunca se sabe, luego las refactorizaciones son terribles. Que sí, que hay magnificas herramientas que hacen refactorizaciones, pero al final siempre hay dolor. ¿hace falta que repita que entrega, entrega y ahora cámbialo todo y vuélvelo a cambiar?

 

Cada vez que te digan ahora debes añadir no sé qué variable más, la añades a la lista:

Y ahora en el código cada vez que necesites ese nuevo valor  “Brutal” comprueba que existe (que no es nulo) antes de tratar con el mismo, ya que ha podido ser añadido meses después en la realización de la primera versión del producto.

De este modo, podrás tener muchísimo código que se refiera a miCliente3 pero sin añadirle referencias a “Brutal” y seguirá funcionando perfectamente. Siendo por tanto un código que se adapta a los datos que le puedan venir. Puedes tener muchas funciones que ataquen a un mismo tipo de lista. Veamos el ejemplo completo:

Por supuesto puedes hacer cascada, metiendo valores en valores, es decir:

Ojo al consumir estos valores, debes de primero comprobar existe la raíz:

La aplicación cada vez que consuma una nueva propiedad que se añade tiempo después, debe validar antes que exista, de este modo podrá funcionar en producción con estados distintos. Fíjate que hablo de estados distintos, no de rango de valores disparatados de una variable que es lo que se suele hablar en los libros de textos o en las academias. Yo hablo de que una variable puede venir o no, y otra cosa es que si su rango de valores es correcto. Se trata de hacer la aplicación flexible en la medida de lo posible a los cambios locos. De este modo se proporciona soporte a estados en la memoria completamente disparatados porque nunca se sabe lo que va a venir en el siguiente sprint de SCRUM.

Podemos invocar a mil funciones distintas enviando la lista y sólo en las funciones que lo implementen soportará los nuevos campos.

Debemos tener cuidado con una cosa, si invocamos una función con un valor simple, el valor se duplica, es decir:

Escribirá en la consola de JavaScript un 2 y un 1. El 1 es porque el valor de la variable a no cambia, se duplica al invocar a la función.

Por el contrario, al enviar la lista, se pasa un puntero, una referencia, con lo que el valor cambia:

Retorna:

2
Object {valor: 2}

console.log(decir2(lista)) retorna el valor dado que así se encuentra en la función decir2

console.log(lista) restorna eel objeto. En cualqquier caso el valor en ambos casos es el 2. Demostración que la función cambia el valor del puntero.

Este efecto puede ser bueno o malo según las necesidades, pero imaginemos que no lo queremos. Que no queremos modificar el valor del original dentro de la función, un ejemplo de mal funcinamiento:

Escribe 10 veces en la consola, el valor 10. Porque f.valor++; está siempre cambiando el valor a la misma variable, y el temporizador hace que se ejecute la salida más tarde cuando está el valor a 10.

Ahora vamos a arreglar el problema:

Escribe los valores del 1 al 10 en la consola.

El truco está que lista3 se redefine a cada iteraación del bucle, con lo que rompemos el puntero.

Si hicieramos lista3=null nos estaríamos cargando el valor, el truco es redefinir la varable para romper punteros.

Para romper punteros despues de pasar una lista a una función debemos definir  esa variable de nuevo y ¡listo!

 

Conclusiones

La parte estática de los lenguajes me encanta, es más lo prefiero cuando diseño algo bien, es una sensación de control y de perfección, pero la realidad se impone en muchas empresas por su tipos de clientes.

¿Aumento de bugs? ¿código impredecible? No, si algo tiene el SCRUM radical es que estas continuamente subiendo a entornos con lo que la aplicación está más que probada y rodada, llegándose a subir incluso casi diariamente.

Lo que obtienes es un código flexible que se va comiendo casi de todo a medida que avanzas, las nuevas propiedades le son invisibles a la parte del código que no las acepta. Cuando tengo que pasar más valores añado una propiedad a la lista.

Tú puedes decir, que sólo necesitas pasar un valor a una función, eso de momento, puede ser que en SCRUM al día siguiente pases 3 o 4, e incluso cascadas de valores, y así no tienes que estar redefiniendo los métodos.

En resumen, encapsula todas las variables en listas antes de llamar a las funciones y rompe los punteros cuando haga falta. Curiosamente los lenguajes dinámicos están de moda (léase por ejemplo Phyton). En definitiva es ir a un código super dinámico, la pérdida de parte del intellisense y otras virtudes son despreciables en comparación con lo que se gana cuando estas escribiendo código sin parar que conoces a la perfección y refactorizándolo continuamente.

Deja un comentario

Compartir
Twittear
Compartir
+1
Pin