Tinselcity

¡Ay, ay, ay, Agile!

Ay, ay, ay, Agile es una pequeña colección de escenas cotidianas, fragmentos de retratos de programadores. Todo es real. Ojalá tuviera imaginación para imaginar estas cosas y no las viviera en la realidad. No pretenden ser humorísticas. Tampoco pretendo humillar a nadie, ni protestar o quejarme de nada. Son simples retratos.


George recibe una tarea que consiste en añadir uno de esos tutoriales/demostraciones embebidos en la aplicación para resaltar e informar de una nueva funcionalidad. En la tarea no viene ninguna explicación sobre qué debe mostrar o decir el tutorial. Mirando en la tarea original de la funcionalidad no viene tampoco ninguna explicación sobre cómo se usa la funcionalidad o qué debería ser lo más representativo o destacable.

George pregunta a la persona que implementó la funcionalidad pero esta, aunque le explica de qué trata, tampoco le sabe decir qué debería poner en el tutorial. George se lamenta en voz alta diciendo que podrían estar un poco más definidas las tareas.

- Agile significa menos documentación - le recrimina Karen desde la mesa de enfrente.

Sorprendido, George insiste en que le parece normal saber por lo menos qué es lo que tiene que hacer.

- Agile significa documentación menos detallada y más abierta, porque la documentación no vale nada. Lo que tienes que hacer es trabajar en equipo - le corrige Karen.


Una mañana me dice Tom:

- Oye. Mira, yo intento ir mejorando las cosas que veo en los JSPs cuando tengo que modificar algo pero ya es la cuarta vez que Karen me echa la bronca por limpiar algo. Lo siento, pero no voy a seguir haciéndolo porque no quiero que me eche la bronca otra vez.

Le he dicho que no se preocupe, que no pasa nada; que no lo sienta, que ya lo siento yo.


- Bueno, esto son las promesas de jQuery. No sé si las conoces. Es para manejar la asincronía - el Arquitecto siempre asume que nadie sabe nada


- Edward, tienes un desajuste de 14 minutos en las imputaciones del mes de Septiembre. Por favor arréglalo cuanto antes. - el jefe, que algunas semanas antes aseguraba que aquí no se venía a hacer horas y que los tiempos eran simplemente informativos, para vosotros mismos.


En la reunión “explicativa” de antes de empezar el sprint donde nos cuentan lo de Agile:

- Una vez que empecemos el sprint, no se quita ninguna tarea del sprint. Repito, no se quita ninguna tarea del sprint. - dice enfáticamente Karen.

Semana y media después, en medio del sprint:

- Frank, desasígnate esta tarea porque la sacamos del sprint. - oigo a Karen decir.

- ¿Qué? Pero ¿así sin más?

- Sí. Y si ya has imputado algún tiempo a esa tarea, bórralo. - dice Karen dando la conversación por terminada.


En una reunión, dos personas que han sido contratadas explícitamente para mejorar la calidad del proyecto describen el horror que han visto en el código. Es todo tan desorganizado que no se siguen ni siquiera unos mínimos básicos de orden y limpieza, así que están proponiendo implantar un proceso de “buenas prácticas” con, al menos, unas normas simples y fundamentales para dar algo de consistencia y coherencia al código.

El Arquitecto es el responsable directo del proyecto desde su inicio. Su aportación en la reunión es:

- Yo es que como soy Fullstack no tengo problemas con las buenas prácticas. Estas cosas a mi me salen de forma natural ya. Pero es cierto que, claro, el resto del equipo igual le cuesta más.


En un cierto formulario de una sección de la aplicación, se introducen hasta 5 direcciones de correo electrónico de contacto. Estas direcciones se validan en servidor originalmente. Se envía el formulario, se valida apoyándose en la infraestructura de validación de Struts y, si hay errores, se redirige de vuelta al mismo formulario pero con un mensaje de error.

Cuando se desarrolla esto, XHR (“AJAX”) ya existe y se usa en todos sitios desde hace años. Validaciones simples hechas en cliente llevan existiendo muchísimo más tiempo, claro. Aún así, tardan 3 años en decidir que tener que hacer la petición completa, ir y volver del servidor y repintar la página entera por un error en una dirección de correo electrónico es una experiencia mejorable. Se les ocurre, ¿por qué no validar en cliente?

El Arquitecto construye una expresión regular en JavaScript y una función validarEmail. Durante los siguientes 6 años, la aplicación funciona de esta forma:

  1. Cuando el usuario ha introducido las direcciones de correo y pulsa el botón de aceptar, las direcciones de correo pasan por la función validateEmail.
  2. Si una dirección no es válida, se escribe en un campo oculto el número del campo no válido.
  3. El formulario se envía a servidor de todos modos.
  4. En servidor no se validan las direcciones de ninguna forma. Lo que se hace es mirar si el campo oculto está relleno.
  5. Si lo está, entonces se redirige de nuevo al formulario igual que se hacía antes, marcando la dirección errónea gracias al campo oculto.
  6. Sólo hay un campo oculto, así que si hay varias direcciones erróneas, solo se marca como errónea la última. Si el usuario sólo corrige esa, que es lo más natural, se vuelve a repetir todo el proceso, con petición y recarga de toda la página cada vez.
  7. Además, la expresión regular que tienen no está demasiado bien y deja pasar por buenas muchas direcciones claramente erróneas. Después de todo el proceso, aún es posible introducir direcciones malas en el formulario y que se acepten porque en servidor ya no se validan.

(Nota: Sí, al encontrar esto lo he arreglado y lo he dejado bien xD)


En una reunión sobre el funcionamiento del “equipo”, estamos la mitad del equipo. Estamos “los desarrolladores” pero no están “los analistas”. Michael, el jefe, nos aclara con mucha insistencia:

- No son “ellos” y “nosotros”. Somos un equipo. ¡Estamos todos trabajando juntos! Os tenéis que meter esto en la cabeza de una vez. Tenéis que cambiar vuestra forma de pensar.

Exactamente dos minutos después, Michael dice:

- Ya hablaré con ellos cuando sea oportuno, ahora de lo que se trata es de cómo trabajáis vosotros.

Unas horas después, según salgo hacia casa uno de los analistas me ve algo decaído y me dice:

- Mira, tienes que entender un poco la dinámica que hay aquí en este proyecto. Por un lado estamos nosotros, que estamos aquí desde el principio y tenemos una relación más o menos cordial. Luego está el otro grupo, que vinieron hace unos 8 años.


Hay un componente que permite ejecutar diferentes comandos sobre lo que haya seleccionado en un listado. Se configura pasando los varios comandos como funciones de JavaScript y el controlador este proporciona también una serie de opciones adicionales sobre su funcionamiento. En particular, podemos proporcionar una función de callback que puede interceptar el proceso antes de que se ejecute la operación y realizar tareas adicionales (por ejemplo, rellenar un campo oculto con cierto dato, o comprobar que la selección es adecuada para esa operación) y puede decidir que la operación se cancele.

Al principio del código del componente está la explicación. Hay un:

var OPC_CANCEL = true;

Y la explicación dice:

/**
 * ...
 * - preExecOpCB (opcional): callback que se ejecuta  antes de comenzar la ejecución de la operación.
 *   Este callback puede devolver return OPC_CANCEL (true) para cancelar la ejecución del execOp
 * ...
 */ 

En el código, hay alrededor de cien ocasiones donde se usa esto. En todas ellas aparece:

    return OPC_CANCEL (true);

Y obviamente en todas ellas da un error porque OPC_CANCEL no es una función. Esto ha estado así siempre, durante 10 años. Nadie se ha dado cuenta nunca. Es más, hay un punto concreto en el código donde alguien, muy optimista hace:

    return OPC_CANCEL (false);

Que tampoco funciona, claro.


- No, no, no. Te estás complicando. No hay ningún servicio para modificar. Solo hay dos servicios. El servicio de crear registro nuevo y el de anular que antes borraba pero ahora anula. Entonces si cambia el estado a anulado, tú llamas a anular. Si cambia a reactivado, tú llamas a crear uno nuevo y el de crear uno nuevo si encuentra uno existente anulado, lo reactiva. Pero si el usuario no tiene permiso para ver los anulados, cuando intenta crear uno nuevo, el de insertar lo detecta también pero no lo reactiva, le da un error. Y si mueves de fecha un registro entonces primero llamas a anular el viejo y luego a crear uno nuevo en la otra fecha. Y si hay uno anulado en esa fecha que no puedes ver, entonces te da un error, pero el otro se deja anulado también. No te compliques.

Minutos después, por e-mail, dice:

- Hay que crear el servicio de modificar fecha, que llama a baja y a insertar.

Los registros, por cierto, no tienen clave. Se buscan por fecha y se confía en que no puede haber dos registros en un mismo día. Obviamente existen registros en el mismo día.

Al día siguiente descubro que el servicio de borrar que antes borraba pero ahora anula ni borra ni anula. No se usa desde hace años y hay que hacerlo nuevo. Sin complicación, claro.


- Eso lo dirás tú. Porque yo he estado leyendo muchísimo sobre Agile últimamente y Agile dice que no documentación.


En un comentario de Hackerl News, un tipo lo llama “los Cinco Valores y Doce Principios”, así con mayúsculas. Y luego dice algo como “Esto lo dice el Primer Valor y el Séptimo Principio”. Yo no le contesto pero mi cerebro piensa que si Agile es tu religión, espero que como mínimo me hables con lenguaje bíblico con citas como “Y se acercó Martin Fowler a la serpiente y le dijo: te arrastrarás sobre tu vientre porque no te auto-organizaste bien.” o si no paso de hacerte caso.


Voy a ver a la analista…

Una pregunta muy concreta. El tema es que es estoy haciendo ConfirmarBajaCosa…
Eso ya está hecho.

Ya bueno, pero hay que rehacerlo con el cambio este.

Sí, pero ya existe. No es hacerlo; solo es modificarlo. Ya tienes el esqueleto y todo, solo es cambiar un poco.

Bueno, cambian los parámetros de entrada, cambian las validaciones, cambia que antes era un delete y ahora es un update, cambia la salida porque antes no se devolvía nada y ahora sí.

Pero ya existe, solo es una modificación.

Eh… vale… En fin, la pregunta es que cuando el estado…

Sí, eso está en la documentación.

Sí, sí, pero a eso iba. Es que lo que pone en la documentación…

Sí, es muy sencillo. Si eres gestor, se pone a 2 (propuesta_anulada) y si no a 4 (aceptado_anulado).

Eso. Pero es por confirmar, porque…

Sí, sí, pues así es como tiene que ser.

…pero estaba pensando en el caso en que eres gestor pero está en estado 3 (aceptado)…

Sí, sí, si eres gestor se pone a 2.

Lo digo porque si está en estado 3 (aceptado) pasaría a 2 (propuesta_anulada) y parecería más lógico que fuera 4 (aceptado_anulado).

… Ah, sí, en ese caso sí. Claro. ¿No está puesto así en la documentación?

No, está lo que decías antes.

Bueno, pues ahora lo corrijo, pero vamos sí, es evidente. De 1 pasa a 2 y de 3 pasa a 4.

He ido guardando algunas preguntas para Gunther, el experto en BBDD, que contrataron para ver si ponía orden en el infierno de PL/SQL. después de un par de dudas le pregunto por una práctica muy habitual en el proyecto.

- Esto, ¿hasta que punto es normal?

- Mira, yo no lo he visto nunca. Bueno, quizá alguna vez algo parecido pero así nunca.

Hay unas tablas generales. Son tablas que contienen generalmente configuraciones o valores casi-constantes. Por ejemplo provincias o tipos de comunicación con un servicio externo. Que son casi constantes porque aunque parezca que algunos pueden cambiar no han cambiado en 20 años. Hay 3 tipos de comunicación. Ya está es lo que hay. Estas tablas no tienen nombre, se llaman cosas como M123 o A77 o D154.

Ahora resulta que tienes en otra tabla una columna tipo de comunicación, algo como tipo_comunicacion_el. Y entonces es cuando aparece otra columna: tipo_comunicacion_tb a su lado. Esta columna contiene el nombre de la tabla en la que se encuentra tipo_comunicacion_el. En algunos casos esto significa que en un proceso hacen una llamada en plan “busco una cierta fila, cojo el nombre de la tabla y con eso voy a buscar en la tabla general algún dato extra sobre, en este caso, el tipo de comunicación”. Esto, en realidad, no se hace prácticamente nunca. Porque el contenido de esa columna es fijo. Es decir, tipo_comunicacion_tb es M144 para todos los registros de la tabla original. No es que pueda cambiar de unas filas a otras. Vamos, que en una tabla con 1000000 de filas, se guarda D123 un millón de veces.

¿El resultado? M144 aparece escrito a fuego en unas cuantas decenas de sitios. Nunca se lee realmente el valor de las tablas, se escribe en el código directamente. Cada vez que se escribe un registro nuevo, se acompaña con M144, a fuego, que unas veces viene en el proceso almacenado y otras viene desde la llamada externa desde Java, y así M144 también aparece a fuego unas cuantas decenas de veces más en el código Java.

No todo son desventajas1). Esta generalidad de las “tablas generales” ha permitido que se escriban ciertas utilidades de forma genérica. Esto significa exactamente esto: Que en cliente, en JavaScript pueda haber también algunos miles de códigos como M144 a fuego.

Lo peor de todo es cómo lo tienen tan asumido que se saben muchos códigos de memoria. “¿Familia de artículos? Mmm… La tabla D104.”

1)
ahemm