skip to main |
skip to sidebar
Showing posts with label
Decision Analysis and Resolution.
Show all posts
Showing posts with label
Decision Analysis and Resolution.
Show all posts
Esta es una continuación del post donde contaba como nos habíamos hecho pasar por epistemólogos en pantuflas al momento de abordar el área de proceso de Decision Analysis and Resolution.
Las prácticas específicas de esta área son:
- Establecer guías para el análisis de decisión (SP 1.1-1)
- Establecer criterios de evaluación (SP 1.2-1)
- Identificar soluciones alternativas (SP 1.3-1)
- Seleccionar métodos de evaluación (SP 1.4-1)
- Evaluar las alternativas (SP 1.5-1)
- Seleccionar las soluciones (SP 1.6-1)
Más allá del mantra tenemos que cumplir con CMMI, intuimos que había (hay) una enorme oportunidad de apoyarnos en estos conceptos para mejorar la calidad de lo que producimos. Algo nos hacía (hace) ruido entre nuestra autovaloración y el resultado observado, aunque siempre hemos podido balancear la ecuación agregando un delta que sería la culpa de un tercero.
Todos confiamos en nuestras capacidades de decisión. Todos creemos entender que sucedería ante un curso de acción u otro ( sí, sí, ya se: tampoco escapamos al sesgo de creer que conocemos las variables y las opciones posibles, o dicho de otra manera, siempre vamos a tener el riesgo de ser engañados por la aleatoriedad ). Pero, como decía antes, el resultado nos empujaba hacia la acción: la realidad sugería que el proceso podía ser mejorado (muy mejorado, de hecho), porque más allá de nuestra confianza, los resultados estaban lejos de ser los que esperábamos.
El primer punto de la práctica habla de decidir que temas han de someterse al proceso formal de toma de decisiones (SP 1.1-1). No fuimos capaces de dar un algoritmo para determinar ante que situaciones comenzar con el proceso, y francamente no creo que lo haya. El gerente/líder/jefe de proyecto (o como quieran llamarlo) es insustituible por una máquina: va a tener que decidir que cosa es importante, clave o crítica.
Lo que sí fuimos capaces de hacer es de escribir ciertas obvias recomendaciones para definir que algo es importante, clave o crítico: si tiene un impacto no menor en atributos de calidad del producto, rentabilidad o tiempos del proyecto (que no son dos compartimientos estancos), o en las personas involucradas, es altamente probable que amerite el proceso de decisión formal.
Toda decisión se toma de acuerdo a cierto marco de referencia que prioriza determinadas cuestiones sobre otras. Ocurre que muchas veces (diría siempre, pero me contengo) no compartimos los marcos de referencia y de acuerdo a nuestras preferencias personales, experiencias, conocimientos y, sobre todo, posición en la organización, ponderamos mucho más ciertos factores que otros. Así se dan discusiones donde la seguidilla de argumentos y contra argumentos se hace interminable solo porque se discute presuponiendo un acuerdo en el marco valorativo. Una buena manera de evitar esto es que el marco valorativo fuera explícito (SP 1.2-1), e incluso, si fuera posible consensuado.
Todos pensamos, por cierto caracter de formación, que la explicitación del marco en términos cuantitativos sería preferible a una en términos cualitativos. Al final, se impuso la razón: los términos cuantitativos son deseables solo para aquello que sepamos cuantificar bien (performance, por ejemplo). No solo es inútil, sino también peligroso, andar poniendole números a las cosas sin ninguna base solo porque la matemática nos hace rendir ante su irrazonable efectividad. La efectividad de la matemática, tal como se entendió Eugene Wigner era un fenómeno de la física, no de la informática (ni de la economía).
Esto generó cierta inesperada reacción, que en ningún momento se planteó de forma abierta, en el nivel de gerenciamiento de los proyectos. Hubo algún tibio intento de sostener que determinados criterios debían permanecer privados porque eran demasiado delicados para exponerlos a la plebe: algo así como acabo de bajar del monte con las decisiones de dios escritas acá, miren. La posibilidad de no exponer motivos le da cierta ventaja al que asegura conocerlos, ya que siempre puede rechazar ideas con reglas ad hoc. Ser explícito es el primer paso para ser honesto. Unos pocos gritos después, seguimos adelante con el acuerdo de que los marcos de decisiones tienen que ser explícitos.
Los métodos de evaluación fueron un punto conflictivo. Hay determinados tipos de decisiones que necesariamente se definirán en el campo de las hipótesis, por así decirlo: son aquellas donde es imposible experimentar y los que pasa si son solo elucubraciones, ya sea por la naturaleza de la pregunta ( por ejemplo, como va a impactar en nuestra relación con el cliente un atraso de quince días?) o porque no tenemos la información adecuada .
Pero hay otro tipo de decisiones, particularmente decisiones importantes, donde el tiempo y la energía que se pierde discutiendo y conjeturando que va a pasar pueden ser invertidos en desarrollar una prueba. El post anterior contaba la historia del desarrollo de la guías para adoptar el método de decisión basado en la experimentación. El proceso de definir los métodos de evaluación (SP 1.4-1) es el mismo que el definir las soluciones alternativas (SP 1.3-1). En particular cuando la decisión sea lo suficientemente importante como para requerir experimentación, algunas alternativas quedarán descartadas por infalsables.
Para los métodos de evaluación basados en las etéreas elucubraciones, comenzamos por el final: el proceso de evaluación de alternativas tiene que tener una fecha de finalización o un máximo de esfuerzo invertido en él. La experiencia muestra que las primeras horas de las reuniones de revisión de pares y de análisis son las más productivas. No es que subestimemos la importancia y el poder del análisis abstracto, pero si nuestro proceso de análisis 'en abstracto' no tiene al menos algunos puntos de corrección por la experimentación, corremos el riesgo de desarrollar invertir esfuerzo en elucubraciones inútiles.
El ser humano no será demasiado racional, pero está enamorado de la coherencia. Nos resulta más fácil ponernos a defender la alternativa elegida con uñas y dientes que aceptar un error, porque así podemos percibirnos a nosotros mismos como personas coherentes, y porque, además, defendiendo nuestra elección, nos convencemos de que hemos elegido bien. Por esto, había que decidir que el jueguito dialéctico en alguna parte debía cortarse.
En este punto, alguien dijo la palabra mágica: brainstorming. Debo decir que no soy un gran fan del brainstorming. En particular, no compro la idea de que sin crítica se pueda arribar a una buena solución. No me imagino como se decantan por las mejores ideas si no las someten a un proceso de análisis crítico buscando los puntos débiles de las ideas propuestas. Por supuesto que la crítica tiene que ser fundamentada y no debe basarse en la autoridad ( el post sobre falacias argumentales, vale la pena o se soluciona con guglear un rato?) o en motivos emocionales, pero pensar que sin crítica vamos a obtener una buena solución es igual a pretender llevar a producción un sistema sin testing.
Definidas las guías para entrar al proceso, las de documentación de criterios de evaluación y del proceso, habiendo escrito un pequeño tutorial sobre como hacer experimentos, y como documentar los resultados (nada muy estructurado, apenas guías para que quede rastro del asunto) había algo que seguía haciendo ruido: nos parecía que había una tendencia general a no profundizar en las causas de algo al tomar una decisión.
No éramos los primeros en sentir eso, ya alguien había determinado que con cinco 'por qué' estábamos cerca de la causa última. Me mantengo escéptico sobre la pertinencia de este número, pero rescato el hecho de que anima a ir más allá al analizar algo y no quedarse con la primera explicación que, normalmente, suele ser incompleta. Por lo que pese a mi escepticismo (o gracias a él) la regla quedó en cinco por qués, o una explicación de por qué hay menos. El tiempo dirá como nos va con esta regla.
La tendencia a no profundizar lo suficiente en las causas se aprecia cabalmente cuando entramos en esa hermosa fase del ciclo de vida llamada 'mantenimiento': un bug corregido produce otros tres que a su vez producen otros más y así. Afortunadamente (porque no se debe sino a la fortuna de vivir en un universo con reglas que, al fin y al cabo, permiten la vida) en algún punto se estabiliza y cada patch nuevo no genera otros tres bugs, y entramos en régimen de uno a uno, o casi. Un régimen de mierda (aunque régimen al fin) provocado porque estamos solucionando síntomas y no causas.
Que como y cuando se solucionan las causas últimas? Bueno, llegado cierto momento, de ninguna manera, nunca. Pero aún cuando no tengan solución, siempre es mejor saber cuales son. Al menos, para no intentar resolver lo irresoluble.
Hubo un tiempo que fue hermoso, y fui libre de verdad. En ese tiempo era un técnico, me perdía entre arquitecturas y optimizaciones, y las fechas, rentabilidades, calendarios, ofertas no eran mi problema. Mi responsabilidad se limitaba a aquellas cosas que hacía yo directamente. Estaba en la gloria. Además, como solo mi trabajo era mi responsabilidad, podía hacerme el vivo.
Magnificadas y embellecidas por la memoria, de esa época tengo recuerdos como el que sigue.
Una programadora del equipo se acercó a D., intuyendo lo peor. No se por qué se acercó a D. , siendo que yo era la interfaz más amable de ambos y nos sentábamos uno al lado del otro (yo era algo así como el arquitecto de aplicaciones y D. el de base de datos). Ella, que sabía lo que seguía, le dijo a D.: "esta query anda lenta" y se dispuso a aceptar con resignación su destino. D. ni siquiera levantó la cabeza del monitor y dijo "ahá. y que querés hacer..." (D. siempre citaba a Tom Kyte diciendo "no optimices queries, comprendé la pregunta").
Hasta aquí, la morocha (dije que la programadora era morocha?. Bueno, era morocha y de ojos verdes) tenía una oportunidad. No es que D. fuera muy amable, tampoco es que la curvilinea figura de esta chica lo conmoviera, sino que él siempre intentó ser justo. Ella no se dio cuenta que tuvo una oportunidad de ser rediminda y dijo "no, es que quería ver si desde la base podíamos hacer algo para que ande más rápido". Era exactamenet lo que D. estaba esperando para reconfirmar que toda oportunidad otorgada es una pérdida de tiempo: "algo así como poner el parámetro turbo=true? no, todavía no existe. Te aviso cualquier cosa".
Se puede decir que D. era (es) un tipo áspero. Que no hay necesidad de andar presumiendo de lo que uno sabe, porque uno en algún momento uno tampoco supo. Pero creo que en esta oportunidad el problema no era con la ignorancia, sino con un concepto problemático: la performance no importa, la performance se agrega después, es como la cobertura de un helado, y además es algo que depende del DBA.
A D. lo irritaba esa postura. A mí también. El origen de mi molestia tiene que ver con que considero que no se puede evitar el pensar la arquitectura al principio del proceso de desarrollo del software (lo que no implica, claro, que uno no tenga que pensarla durante todo el proceso), no importa cuan ágil sea uno (de todas formas, el paso de planear la arquitectura se evita más por desordenado que por ágil, se reconoce desde la comunidad ágil que la fase de architecture envisioning es necesaria), particularmente si uno no quiere encontrarse al final del proyecto con que algo anda más lento de lo esperado, o algo peor.
Se podría argumentar que ese no es un problema hoy en día: hay arquitectos, fases para definir la arquitectura, sectores de arquitectura, libros sobre arquitectura y toda una parafernalia sobre el asunto. Me permito pensar que todo eso, o bien es insuficiente, o bien está mal dirigido.
Volvamos al principio, que es la arquitectura?. Yo tengo una definición de arquitectura: “la arquitectura de un sistema es el conjunto de decisiones de diseño que tienen un impacto profundo en la calidad del mismo” (en realidad, como todos las cosas que valen la pena, ya alguien la pensó antes).
Por eso, creo que la fase de pensar la arquitectura, de decidir las características más importantes del sistema antes de comenzar la construcción y no esperar que las decisiones tomadas por un grupo de desarrolladores sobre la marcha sean acertadas, es ineludible. De todas maneras, creo que una vez más conviene bajar a detalle y preguntarse que significa obtener una visión de la arquitectura. No creo que unos modelos en papel alcancen para tomar decisiones importantes, particularmente cuando uno incorpora componentes nuevos (no recuerdo ningún proyecto en los últimos años en los que no haya tenido por lo menos un componente nuevo). La solución viene dada por construir diseños experimentales que sometan a la arquitectura propuesta a condiciones extrapolables a las que soportará una vez implementada.
Las características que normalmente deseo observar al someter a una arquitectura a un experimento son:
- El comportamiento bajo alta carga.
- La posibilidad hacer andar en forma aislada los componentes, como forma de poder detectar y corregir problemas una vez que esté el sistema implementado.
- El comportamiento ante situaciones límite, como caídas de equipos, operaciones maliciosas, errores en otros componentes.
- La facilidad de implementar cambios en la arquitectura (reemplazar un componente por otro).
- Cierta seguridad sobre la estabilidad de los componentes. Si bien no tengo demasiado cariño por la costumbre de gritar ‘hay un bug en Oracle’ ante el primer error que uno cometió en una query, me he encontrado con algunos productos open source con algún que otro error (un memory leak, por ejemplo). Y me he encontrado con que MS se pasa algunos estándares por el forro, y agrega algunas condiciones a las del estándar....
- Y el más importante, nuestras suposiciones sobre el funcionamiento de lo que vamos a usar son razonables? O sea, podemos estar seguros que, al menos en lo importante, nuestro diseño no va en contra de algunas limitaciones de la tecnología?
Bien, el problema es que esto es mucho más fácil de enunciar que de hacer. Diseñar un experimento significativo y a la vez sencillo es una habilidad que requiere conocimiento, práctica, y hasta diría que talento. Si es difícil hacerlo, escribir unas guías sobre como hacerlo es aún más difícil, pero concluímos que hacer el esfuerzo (más adelante explico el por qué, además de porque consideramos que aporta valor) de explicitar algunas guías para definir experimentos valía la pena. Acá va un resumen de los pasos de la guía:
- Identificar las interfaces relevantes: pueden ser algunas pantallas, mecanismos de IPCs e integración (colas de mensajes, web services)
- De las pantallas identificadas, abstraer la presentación y pensar unicamente la interfaz de la operación
- Desplegar el software de base. Acá me refiero a desplegar todo el software de base, no un poco, particularmente si uno no lo conoce. Me refiero a base de datos, appl. server, broker de mensajes, todo.
- Implementar mocks de cada interfaz relevada. El mock, de acuerdo a cada caso, puede ser una clase que simplemente no haga nada y tenga un sleep o similar para simular el delay de procesamiento o una clase que haga algunas operaciones contra el soft de base, sin mayor lógica, simplemente para obtener tiempos reales de operaciones en el soft de base
- Conseguir un simulador de carga (o hacer al menos un par de scripts en ant, nant o shell) que tire transacciones.
A partir de ahí, ir variando las condiciones y ver que sucede (algunas ideas):
- Ejecutar lo construido en (5) y verificar límite de capacidad de procesamiento (ese momento donde las colas no entran en régimen: al margen, la utilidad de los modelos de colas para el análisis de performance, tema para otro post)
- Bajar intempestivamente un componente y ver cuan fácil es determinar el problema
- Determinar que posibilidad hay de ejecutar aisladamente un componente construido sin el software de base (obviamente, con máquina virtual y sistema operativo, unicamente)
- Medir el consumo de memoria de los componentes, particularmente de los nuevos (si pusimos un nuevo framework, medir el consumo de memoria en la máquina virtual, por ejemplo)
Un experimento (o prueba de concepto, o como se desee llamarlo) es un entorno controlado donde podemos generar variaciones planificadas y observar los resultados. Es sencillo de enunciar, pero diseñar un experimento razonablemente significativo es algo que requiere práctica, conocimiento del dominio y no se si talento natural ( sí, se que todo parece indicar que no somos una tabla rasa, pero tampoco es que don Pinker se haya impuesto por tanto).
Aún así, y dado que teníamos que cumplir, pensamos que sería útil hacer el esfuerzo de escribir un manual, o al menos unas guías, que ayuden a quien tenga que hacerlo a diseñar un experimento. Al fin y al cabo, que sea difícil de aprender, no significa que no valga la pena de ser enseñado, no?
Por qué todo esto?. Basicamente porque existe en CMMI L3 un área de proceso llamada ‘Decision Analysis and Resolution’. Como además de la certificación siempre tuvimos como norte que el proceso sirva, además, para que mejoremos la calidad de nuestros productos, nos atrevimos a perder tiempo pensando en el proceso de desarrollo además de la estrategia para el SCAMPI.
En la próxima parte de este post veremos como encaja esto en la process area de 'Decision Analysis and Resolution'.