El asesino paradójico

En este momento ya te habrás dado cuenta que asesinos hay por cientos y que es casi imposible evitarlos a todos y que, ademas te ha tocado vivir alguno que otro. En mi caso, me han tocado todos en diferentes momentos.

Si bien todos son peligrosos, este afecta directamente a la empresa y puede llegar a matarla por completo. Si bien los anteriores afectaban a las personas (Principalmente) este puede marcar la diferencia entre una empresa que sigue en pié y otra que simplemente se estanca y desaparece.

Alguna vez viste alguna empresa que lleva años en el medio y nunca crece? Empresas que son consideradas solo “de paso”. Todo esto, claro, independientemente de las situaciones del mercado que, incluso, es lo contrario. Muchas veces son empresas con un nicho marcado o en situación en la que no existe competencia directa, pero así y todo, no se mueven.

En estas empresas (Claro, no en todas) arremete este asesino que me gusta llamar “paradójico“: Internamente se hacen mal las cosas, pero gracias al nicho, todo sale relativamente bien.

No es que se escriban mal las líneas de código y por arte de un fantasma en los circuitos, todo compile y ande perfectamente. En realidad el código, los procesos y procedimientos se hacen mal, y salen mal, pero al ser los únicos en el mercado o no contar con competencia directa y real, entonces sus clientes aceptan los resultados tales como les son presentados.

Dentro de mi tránsito por diferentes empresas me han tocado estar en dos, memorables, con este problema. Algunas de las costumbres destacables en estas compañías eran:

  • No entender su producto ni la materia prima con la que trabajaban.
  • Considerar que tener un proceso productivo atentaba contra la empresa.
  • No saber cómo y qué cobrarle a sus clientes.
  • No entender las capacidades de sus empleados.
  • Esperar que todo se haga espontáneamente sin anticipar ningún movimiento (No capacitar, no minimizar riesgos, no aprender).

Imaginemos por un momento un lugar donde el producto se realiza de tal forma que va contramano de cualquier buena práctica conocida. No porque se haya descubierto una mejor forma sino porque se desconocen estas prácticas. Un lugar en donde, sabiendo que existen necesidades puntuales de capacitación y actualizaciones, se opta por esperar que los empleados sepan usar la diferentes herramientas, solo porque un proyecto lo demanda.

Los proyectos suelen dejar un margen de utilidad muy ajustado o, incluso, generar pérdidas. La empresa fluctúa entre estos dos extremos y flota, se mantiene.

Pero, todos cometemos errores, por lo que equivocarse es parte del proceso de aprendizaje. Estas empresas, por el contrario, carecen de esta capacidad, la de aprender. Y ese es núcleo del problema: La incapacidad de aprender.

Esta incapacidad se combina con otros factores, ya que, dándole un respiro a la idea, algo que considero de lo más difícil es saber lo que no se sabe. O mejor dicho: Cómo saber lo que no sé que no sé?

Con esto quiero decir que si uno desconoce algo, en su totalidad, es imposible que sepa que lo desconoce. En este caso, estos lugares se niegan a quitar ese velo y prefieren mantener el Statu Quo.

Tal vez, llevados de la mano por alguna extraña incomodidad o por sugerencia de un tercero, contrarán a alguien externo con el objetivo de generar el cambio. El externo, al ver esta situación intentará romper con estas conductas, pero como la misma empresa quiere mantener todo estático terminará forzándolo a adaptarse a las prácticas ya establecidas o, en su defecto, llevarlo hacia la puerta de salida más próxima.

Como decía, el problema está en la incapacidad de aprender o querer hacerlo. Es la máxima en la zona de confort. Estas empresas suelen darse de cabeza cuando salen fuera de su capullo e intentan ir más lejos de su propio mercado. En ese momento, con mucha suerte, con el golpe, terminarán generando el cambio. Las que no, simplemente dejarán de existir.

Anuncios

Máquinas de estado

Ayer me preguntaban cómo solucionar un problema de flujos de datos y procesos. Lo primero que se me vino a la cabeza fue: Eso es una máquina de estados!

Imaginemos por un momento un diagrama de flujos clásicos. Donde tenemos flechas que indican dirección y conectan diferentes elementos. Estos elementos representan acciones y, desde el inicio al final, los datos fluyen dejando que cada uno de esas acciones hagan algo sobre los mismos antes de pasarlos al siguiente componente.

Adicionalmente, era necesario saber que elemento estaba realizando qué y que dicho elemento conociera cualquier otro elemento que pudiese estar conectado a este para poder enviar los datos hacia ellos.

Por supuesto, hay muchas formas de implementar una máquina de estados. Un simple switch y algunas líneas de código ya son una máquina de estados pero, por supuesto, hay que hacerlo un poco más difícil 🙂

Si aún te preguntas dónde se usan estas máquinas de estado… bueno, son comunes en el desarrollo de videojuegos. Por ejemplo, cuando un personaje está realizando una acción, lo normal es que esa acción sea un estado del personaje. Saltar, correr, caminar, son estados del objeto y solo uno puede ejecutarse en un momento particular. Luego, solo se puede ir de caminar a correr como posible flujo y no de correr a agacharse sin primero caminar (Por dar un ejemplo).

El código

El código necesitaba hacerse en JavaScript (Lenguaje que amo) y debía contemplarse la posibilidad de no tener clases base. Esto quiere decir que, por ejemplo, para un nodo de la máquina de estado pueda conocer un nodo anterior o un nodo siguiente, lo lógico sería tener una clase base que implementase estos métodos y así reusarlos en cada nueva instancia de un nodo.

La máquina

    var stateMachine = {
        currentState: null,
        next: function() {
            if (this.currentState._next !== null) {
                this.currentState = this.currentState._next;
                this.currentState.process.call(this);    
            }
        },
        prev: function() {
            if (this.currentState._prev !== null) {
                this.currentState = this.currentState._prev;
                this.currentState.process.call(this);    
            }
        }
    };

La maquina de estados solo conoce el nodo o acción actual y provee dos funciones para poder moverse hacia adelante o hacia atrás (Más movimientos dependerán de nuestras necesidades).

El nodo

    var step = (function() {

        var s = function (configuration) {
            this._configuration = configuration;
            this._next = null;
            this._prev = null;
        };

        s.prototype.process = function () { };

        return s;
    }());

Una definición de “clase” clásica. Teniendo un constructor y una función que se usará para ejecutar las acciones del nodo.

Las acciones

    var firstStepFunction = function() {
        console.log(this.currentState._configuration.text);
        this.next();
    }

    var secondStepFunction = function() {
        console.log(this.currentState._configuration.text);
        this.next();
    }

    var lastStepFunction = function() {
        console.log(this.currentState._configuration.text);
        this.next();
    }

Cada función representa una acción particular para un nodo particular.

Uniendo todo

    var step1 = new step({text: "step 1"});
    step1.process = firstStepFunction;

    var step2 = new step({text: "step 2"});
    step2.process = secondStepFunction;

    var step3 = new step({text: "step 3"});
    step3.process = lastStepFunction;

    step1._next = step2;
    step2._prev = step1;
    step2._next = step3;
    step3._prev = step2;

    stateMachine.currentState = step1;
    step1.process.call(stateMachine);

En este caso, se puede crear un nuevo nodo, asociarle una acción en particular y sus siguientes o previos nodos en la cadena de ejecución.

La línea final dispara la ejecución del primer nodo, el cual se encargará de llamar a sus siguiente nodo y ejecutar todo el flujo.

En resumen. Este tipo de máquinas nos pueden ser de mucha utilidad ahorrándonos condificiones anidades y código poco mantenible. También, poder conocer el estado de un proceso. Aislar los mismos en diferentes unidades especializadas, entre otros beneficios varios.


Modas… Ese problema en sistemas

Leía en un grupo de desarrolladores local (De Argentina) un hilo sobre el uso de EF y cómo este ha ido en desmedro de muchas aplicaciones al agregar una capa muy gruesa de procesos al código y su ejecución. Haciendo las aplicaciones lentas innecesariamente.

Dentro de esta conversación también se sugería que el nuevo EF para .Net Core es “más mejor” y no hace la cosas como el viejo EF. Aunque en lo personal piense que el nuevo EF hace las cosas como lo hacia el viejo EF cuando recién había llegado a nuestros códigos.

El punto es que cuando EF apareció la discusión era si debíamos usar EF o Nhibernate. Y que el que seguía usando Datasets no entendía nada (aunque tal vez aquí si se estaba en lo correcto. Hay un post en este blog, en algún lugar, que muestro el veneno que eran los DS).

Pero el post no es sobre lo absurdo de usar un ORM para una aplicación (Estaba escribiendo el tipo de aplicación en la que no se debería usar… Pero no se me ocurre una en la que sí se debería).

No, el post es sobre modas. Algo que creo que ya comenté alguna vez pero que no está de más volver a reiterar. Justamente encontré este post en el blog, de hace 5 años atrás, donde destacaba lo absurdo e inecesariamente complicado de las configuraciones de Unity para inyectar dependencias. Incluso esbozaba una idea de automatización solo por código (Curiosa cosa que hoy se consigue en .Net Core… Microsoft quiero mi dinero por copyrights).

Entonces, a que se debe que todo el mundo hable de X implementación o producto y quiera usarlo en sus desarrollos aunque no tengan sentido alguno? La respuesta es simple: Modas.

Sí. No importa si tu trabajo está detrás del teclado y no leas la “Para Ti”. Igual eres victima de las modas en tu rubro e igual que el lector de revistas del corazón, tu comprarás cualquier cosa que te pongan delante.

Este problema lo vemos todo el tiempo. Desde la aparición de jQuery (ojo, que me sigue pareciendo uno de los mejores a pesar de que podría ser más liviano) hasta su defenestración por los consumidores de Angular, para que estos sean defenestrados por los de React, y estos nuevamente por los de Angular + TypeScript. Ah! Y los de ES5 por los de ES6 + Babel, los que fueron abucheados por los de TypeScript a secas y los de ES6 + WebPack + Babel (aunque muchos no sepan que Babel está allí).

Más allá de la paranoia de este viejo loco. La realidad de la moda existe, y parte de la misma se debe a las empresas que la producen. Muchas de estas están en la necesidad de sacar cosas nuevas para mantenerse en las primeras planas. Muchas de estas cosas nuevas sí son mejoras, no se mal entienda, pero un gran puñado no es más que basura propuesta como una bala de plata salvadora que ha venido a revolucionar el mercado.

La otra parte de la responsabilidad está en nosotros. Los que le pegamos a las teclas. Es nuestra culpa por no darnos el tiempo para analizar el verdadero impacto de la nueva tecnología o herramienta propuesta. De tener el valor de decir “no” si la misma causará más daño. Es nuestra responsabilidad mantenernos actualizados y saber sobre lo que usamos y no aceptar algo solo porque un grupo de personas está haciendo algo de ruido.

Hace muchos años atras, en los cuarteles generales de una empresa que todos conocemos, alguien quería vendernos la idea de WPF. Desde el público una voz (no la mía claro) dijo: tengo cajeros de supermercado que usan terminales unix… Vos me estás diciendo que debo decirle a la gerencia que cambie todo el parque de computadoras solo para hacer una animación en un formulario de Windows?

Este comentario no hacia referencia a no querer progresar, no querer cambiar. Hacía referencia al sinsentido de algo que se quería, en aquel momento, imponer por moda.

En la charla sobre EF un amigo que admiro, además de por su amistad por sus conocimientos, dijo que en definitiva todo vuelve a simples mapeadores entre objetos y tablas. Algo que hemos hecho desde tiempos inmemoriables y que vuelve a resurgir en .Net Core.

Como en este ejemplo que escribía hace 7 años atrás o como este otro (Microsoft, segundo copyrights que me debés) intentando romper con la idea de pesados ORMs e inclinar la balanza a los mapeadores.

En resumen, somos víctimas de las modas y por lo tanto es importante que sepamos darnos el tiempo de analizar aquello que adoptamos para nuestros proyecto. Solo porque está haciendo ruido no quiere decir que sirva.


Asesino codename: el nido

Y acá estamos con otro de estos destructores de equipos y morales individuales.

El nido es un tipo de asesino que se caracteriza por la similitud que tiene con el comportamiento de los pájaros cuando estan cuidando a sus recién nacidos.

Estos presentan un comportamiento heredado de piar lo más fuerte posible para que, al llegar sus padres al nido con el alimento, tengan mayores posibilidades de ser alimentados. Y por supuesto, con mayor alimento más fuerte se vuelve por lo que produce más los gritos obteniendo, así, mayores recompensas alimenticias. Todo esto, claro, en desmedro del que no fue cuidado.

En las empresas pasa algo similar. En especial cuando uno ocupa cargos jerárquicos altos y pierde contacto con los diferentes equipos de trabajo.

Como los pájaros progenitores, un jefe o gerente tratará de visitar con cierta frecuencia a sus polluelos. Pero su desconexión con el grupo lo llevará a comportarse de similar forma que estas aves y sus crías: solo verán aquellos que hacen ruido.

Se acuerdan de ese que no se podía callar y que siempre tenía una opinión aunque no tuviese valor alguno? Bueno, ese es el pájaro chillón que tú (Si eres el jefe), como ave proveedora visitando el nido, escuchará y te hará creer que es el mejor del grupo.

Lamentablemente el alejamiento de las trincheras del desarrollo y tu larga estadía detras de hojas de cálculos y diagramas de Gantt hicieron que ya no tengas la capacidad de entender el dialecto técnico y los intrincados vericuetos del día a día del equipo, por lo que la reacción natural será premiar a aquel que quede resonando más en tus oídos.

Por otro lado, como miembro del nido, puedes convertirte en ese pajarraco gritón y aprovecharte de tu jefe adormilado. Pero esto minará el equipo, desmoralizará a tus pares. Recuerda que, en definitiva, el software se construye de a muchos.

De cualquier manera y como decía, este gerente puede llegar aún más lejos. Por ejemplo, sin entender lo cotidiano del equipo, llamarle la atención a aquel que no pía (Sólo porque no lo hace) aunque este polluelo sea una pieza fundamental en el equipo.

Recordemos que este comportamiento no es más que la expresión de inseguridad de aquel que no está involucrado en un equipl pero que, al mismo tiempo, tiene que responder por sus acciones. El ruidoso le da seguridad a este inseguro administrador, y como decía, incluso si lo que diga no tiene sentido.

De esta forma el esfuerzo individual para con el equipo se diluye y aquel que no ha gritado no recibe los beneficios de su superior e, incluso, puede llegar a recibir sus castigos.

Esto genera en aquel que está acostumbrado a trabajar en equipo un cortocircuito entre sus acciones (Corectas, pro equipo) y los “castigos” recibidos.

Imaginemos una persona haciendo todo correctamente pero que, tras cada paso dado, se le dice que está equivocado. Tarde o temprano esta persona se encontrará dudando de cada acción a tomar, no sabiendo si lo que hace es correcto o no para finalmente dejar de hacerlo.

En este momento el micromanagement se hará más frecuente y, con este, una validación del pensamiento original de ese jefe. O sea, esté comenzará a darse la razón sobre haber pensado que el no gritón no era un buen empleado.

Entonces, si estás a cargo de equipos de desarrollo, lo mejor que puedes hacer es mantenerte actualizado. No hace falta que sepas escribir código, pero por lo menos trata de entender que estás produciendo. En definitva saber sobre lo que produces es parte de considerar que eres competente en tu trabajo.


Otro asesino… silencioso

Sí, hay infinidad de asesinos de equipos, proyectos y, porqué no, empresas.

Entre estos asesinos, tal vez aquel que suele ser uno de los más comunes, pero que curiosamente es el que menos resalta, es el silencio. El silencio no en sentido de quedarse callado. Cerrar la boca y escuchar es bueno, muy bueno. De hecho ayuda a entender otros puntos de vista, a aprender.

No les ha pasado que trabajan con alguien que no puede dejar de hablar? Que siempre tiene algo para decir aunque no tenga ningún sentido lo que está diciendo? Alguien que siempre tiene un bocadillo por más estúpido que sea?

Bueno, ese no puede callarse, y es parte de otro mal, no necesariamente de este, así que ya hablaré de ese personaje.

En todo caso e intentando volver a la idea, el silencio al que me refiero es aquel que llamamos “problemas de comunicación”. Suele aparecer mucho en las retrospectivas (Si es que haces algo así) y, en nuestro rubro es común encontrarlo con frecuencia cuando un hispanohablante trabaja con gente de habla inglesa.

Y es en este momento, en esta particular ecuación en la que se suele confundir un problema profundo con algo tan superficial con no hablar bien otro idioma.

No. El problema de comunicación no está en el idioma usado, si no en la forma en como la comunicación fluye entre los miembros del equipo y nada o poco tienen que ver con el idioma.

Es más, todo esto no está asociado a trabajar con equipos con diferencias lingüísticas. Esto pasa dentro de equipos culturalmente idénticos, sentados todod juntos en el mismo espacio oficinesco.

La comunicación es un problema cuando se forman pequeños grupos dentro de los equipos en los que la información es retenida. Cuando no todos están al tanto de lo que pasa. Cuando no todos tienen voz en las decisiones que los afectarán.

Un caso obvio es cuando un grupo hace una estimación de producto, se lo vende al cliente y luego espera que un grupo diferente cumpla con lo pactado.

Te has encontrado en situación en la que llevas meses en una empresa y nadie te dijo quien es esa persona que te manda mails? O descubres que había un release a producción del que nadie te informó pero que resultas ser el responsable de llevarlo adelante? O te invitan a una reunión en la que el título de la misma hacía referencia a que conversaría sobre algún análisis de productos nuevos y cuando llegas a la misma todos, excepto tú, ya han tenido esa conversación y la reunión se tranforma en “lo conversado en el pasillo”?

Hay miles de ejemplos en el que la comunicación es un problema y de los gordos.

En cualquier caso hay un elemento particular que las distingue: alguien guarda conocimientos y no está dispuesto a transferirlos al destinatario correcto.

Dónde está el asesino?

Además de lo obvio. En cómo afecta esto al desempeño de los equipos. El principal síntoma de la muerte agónica es la caída en la moral de los individuos.

Esta caída se debe a que junto con la ausencia de información llegan los pedidos de conocimiento espontáneos. Esto quiere decir que se le exigirá a la persona que fue privada de la información que responda por no tenerla.

En el ejemplo del release a producción, las exigencias y críticas estarán relacionadas al “porqué no estaba preparado”, culpando al privado de información y no al privador.

La falta de comunicación es una de las peores asesinas. Es una de las más difíciles de erradicar ya que forma parte de la conducta del victimario por lo que cambiar esto requiere un esfuerzo gigante.


Asesinos de equipos

Con todos los cambios por los que he pasado recientemente se me ha hecho imposible continuar con algunos posts. Espero que se normalice todo y pueda volver a escribir. En todo caso, esta es una entrada para intentar re arrancar, desde el celular, con muchos errores.

Ya sabemos que hay malas empresas, malos managers, malos equípos, malos individuos en un equipo.

Yo los he tenido a todos y alguna vez he sido alguno de ellos. Con los años pulí muchas de mis equinas evitando seguir siendo un mal jugador en equipo. Por esto es que trataré de enumerar las lijas y limas y cinceles que he usado en este viaje.

Confianza

Uno de los primeros destructores de equipos, personas y empresas es la falta de confianza.

Es tan simple como decir: si no confías en tu equipo… Para que lo tienes?

He visto este comportamiento tóxico en muchas empresas, equipos y personas. Comportamiento que proviene, generalmente, desde un particular superior en escalafón empresarial y castiga al resto de los individuos de un equipo.

Esta desconfianza se suele ver cuando esta persona dirige, ordena, sin escuchar. No importan las propuestas, siempre estarán mal si provienen del equipo.

Suele verse también en comentarios de auto validación. Esta persona emite un juicio negativo sobre un subordinado cuando el mismo no está presente. Esta persona espera que alguien le diga: sí, estás en lo cierto.

Puede que la persona criticada requiera de atención. Pero la crítica siempre será para validar el punto de vista del generador de desconfianza. Nunca para pedir consejos en cómo solucionar el problema.

Generalmente esto se traduce en micromanagement. Una enfermedad empresarial que estupidiza hasta al más apto. Hace que la gente se transforme en un ente reactivo que espera que le digan que hacer. Que no tendrá iniciativa.

Por supuesto, no podemos culpar al afectado. Si sus iniciativas han sido sistemáticamente destruidas. Solo podremos jugar a la lotería tratando de acertar la fecha en la cuál decidirá irse de la empresa.

Soluciones

Si lees estas líneas pensando en que te daré una fórmula para acabar con este mal, estás equivocado. Si sufres de este mal seguramente te sentirás identificado. Si lo causas, buscarás una justificación de tus acciones para salvaguardar tu cerebro (Disonancia cognitiva).

Ahora, si estás comenzando con un equipo y te preocupa caer en esto, entonces sí te dejo un checklist de cosas a tener en cuenta:

  • Es tu equipo, conócelo. Conoce sus limitaciones. Ayúdalo a mejorar.
  • Si lo contrataste es por algo. Si contrataste a ese junior que luego del primer día le asignas el proyecto de IA y esperas que en tres días más te programe la Skynet… Bueno, estás muy mal. Acepta los conocimientos de las personas a tu cargo. Entiende sus tiempos.
  • Escucha. Tu no lo sabes todo. Puedes tener mucha experiencia pero no eres infalible. Permite que se expresen.
  • Acompaña. Si solo ordenas solo obtendrás individuos obedientes.
  • No fomentes el individualismo. Algo que nos mal enseñaron desde otras culturas es que el individualismo premia. Esto es un sinsentido total. Solo sociópatas se sienten bien con esto. El trabajo en nuestro rubro no llega a nada si se hace individualmente.

Hay mucho más, por supuesto. Esto es solo una pequeña mirada a esas conductas que intoxican los lugares de trabajo.


Interceptores (Continuación)

Siguiendo con la idea de los interceptores y esta pseudo AOP, finalmente pude subir el código a GitHub.

Claramente faltan algunas cosas (Minimizar por ejemplo), pero espero ir evolucionándolo.

En cualquier caso, pueden verlo aquí: https://github.com/MatiasIac/ToolPack

Como mostraba en el post anterior, algunos puntos a destacar eran la detección de dónde inyectar el código y cómo reconocerlo desde el mismo JavaScript sin tener que usar un meta lenguaje o algo que corra por fuera del mismo JavaScript.

s.prototype.sum = function (a, b, result, __interceptor) {
   console.log('Sum function called');
   console.log(a + b);
};

En este caso, cualquier variable que sea colocada en la firma de una función y que además inicie con __ sería tomada como el nombre del interceptor a ser ejecutado cuando esta función se llamase.

En la definición de los interceptores, entonces, tendríamos lo siguiente:

Interceptor.define('__interceptor')...

Definiendo el interceptor mediante su nombre y pudiendo agregar diferentes funciones anónimas, en cascada, que se ejecuten generando un resultado.

.having(function() {
   console.log('interceptor called');
   console.log(this);
   return "hola";
}, { context: { ok: true }, injectResult: true })

Si bien en este ejemplo no se manejan las variables que se pasaron originalmente a la función que intentábamos llamar, las mismas pueden ser declaradas en la firma de la función anónima o tomarlas desde arguments.

Solo como para darle algo de sabor a todo esto, opté por dar la posibilidad de configurar cada interceptor mediante un objeto de configuración. En este caso sería posible pasarle un contexto particular al interceptor, el que pudiera ser accedido mediante this, y también permiter retornar sus resultados e inyectarlos dentro de la función que finalmente es llamda.

Volviendo al código inicial, la variable result contendrá todos estos valores.

s.prototype.sum = function(a, b, result, __interceptor)

Seguramente dedique otro post a describir internamente el interceptor… pero eso vendrá luego 🙂