sábado, 6 de noviembre de 2004

Roles y retroalimentación

A veces los pensamientos más distantes se alinean en mi mente y forman un conjunto coherente hasta cierto punto. Cuando esto sucede y publico el resultado, no puedo menos que pedir algo de paciencia y curiosidad al lector para recorrer el texto que esta vez inicia en el asiento de un colectivo y termina con un hecho que veo repetidamente en los proyectos de desarrollo de software y me resulta difícil de explicar. Tratare de hacer el viaje entretenido y al final, pienso que alcanzaremos un destino interesante.

En los últimos meses he viajado mucho, posiblemente más que lo he viajado en muchos años. En uno de estos viajes tuve la suerte de sentarme delante de una pareja con su pequeño hijo de 3 o 4 años lleno de inquietud intelectual y energía. La energía era evidente en su constante ir y venir por el pasillo, en sus patadas a mi asiento y en los saltos sobre su padre. La inquietud intelectual se manifestaba en forma de las más variadas preguntas:

- Ma, ¿por qué no se mueve el colitivo?
- Colectivo
- Si, ¿por qué no se mueve?
- Porque está subiendo la gente.
- Ah...

- Ma, ¿adonde va ese otro colitivo?
- Colectivo
- Bueno, ¿adonde va?
- Capaz que vaya para Buenos Aires.
- Ah...

- Ma, ¿qué hay abajo del piso del colitivo?
- Colitivo no. Colectivo.
- ¿Qué hay abajo?
- Está la bodega donde dejamos los bolsos.
- Ah...

La persistencia maternal me hizo pensar en la importancia de estas correcciones para que ese pequeño más tarde o más temprano aprenda a decir colectivo. Entonces recordé pensamientos de mi niñez que han causado una fuerte impresión en mí dado el tiempo que ha pasado y la nitidez con que los recuerdo.

A la temprana edad de 6 años, tenía un amigo cuyos padres eran sordomudos. A mí me llamaba mucho la atención visitar su casa ocasionalmente y verlos comunicarse con lenguaje de señas. Era algo que me hacía pensar mucho. Lo que pensaba en ese momento era la mala suerte de estas personas por tener problemas en los oídos y en la lengua simultáneamente. No era algo agradable tener problemas para hablar o para escuchar, pero tener problemas para las dos cosas a la vez, eso si que era mala suerte. Con esa idea en la cabeza comencé a observar que era algo más común encontrar una persona sordomuda de lo que era cruzarse con alguien sordo pero no mudo o mudo pero no sordo. También me fijé que no se daban otras combinaciones que suponía igual de factibles, ciego-sordo, ciego-mudo.

“¡Qué raro!” pensaba.
“Debe existir como una enfermedad que afecta los oídos y la lengua a la vez.”

Esa conclusión me parecía lógica considerando las evidencias pero de todas maneras consulte el tema con mi mamá.

- ¿Viste que las personas siempre son sordomudas? Casi nunca son sólo sordas o sólo mudas.
- Claro, porque cuando una persona tiene problemas para escuchar desde chiquita no puede aprender a hablar.
- ...

Esa respuesta me hizo pensar más aún. Todas esas personas estaban físicamente en condiciones de hablar. Podían producir sonidos sin problemas. Simplemente no lo hacían porque no podían escuchar. No podían copiar los sonidos que hacían sus padres, y tal vez más importante, no podían escucharse ellos. No tenían retroalimentación de lo que hacían. Aunque pudieran escuchar a los demás, si no podían escuchar que sonido emitían ellos, no tenían posibilidad de corregirse. Sin retroalimentación simplemente no había aprendizaje. Una y otra vez emitirían sonidos ininteligibles y no podrían mejorarlos. Estaban condenados a errar.

A nadie le gusta cometer errores pero los cometemos todo el tiempo. Una vez tras otra. En cada ámbito de nuestra vida. Los repetimos o, algo mejor, cometemos nuevos errores cada día. Somos como una delicada máquina errática que va corrigiendo su curso constantemente. En el ámbito laboral, rara vez nuestro accionar pasa desapercibido para otros. Nuestras acciones dependen de lo que hacen otros y viceversa. Esta relación que se teje entre el comportamiento de varias personas desarrollando una actividad da lugar al surgimiento del fenómeno de retroalimentación, esencial para el aprendizaje.

Este mecanismo tiene distintas formas de presentarse en un equipo de desarrollo de software. En muchos equipos, por ejemplo, se compila todo el código al menos una vez al día. Esto se hace para saber que siempre se tiene código que al menos es correcto sintacticamente. Esto que parece tan elemental a veces es algo difícil de alcanzar. Recuerdo historias de compañeros en la facultad que rendían su última materia, donde debían presentar una aplicación que habían desarrollado durante todo el año o más ante un auditorio de decena de personas, con sus padres observando orgullosos, un panel de profesores y con un cañón mostrando una interfaz de usuario de 1 metro y medio de alto, y su aplicación no se podía compilar. Como muchos sabrán algunos entornos de desarrollo como Visual Basic permiten ejecutar una aplicación sin compilarla. Simplemente va interpretando el código a medida que necesita ejecutarlo. Por supuesto, en el momento que se encuentra con una incoherencia como la asignación de una cadena a una variable numérica, la aplicación explotará en nuestra cara (y en la de las de la audiencia, panel, padres y/o tutores) informándonos que no coinciden los tipos. Bien, ellos sacaban provecho de esta característica y ejecutaban su aplicación de esta manera en la presentación de su materia final. ¿Por qué alguien podría arriesgarse a presentar una aplicación en ese estado? Porque pasaron mucho tiempo desarrollando sin compilar la aplicación. Son tantos los errores para corregir, y son tantos los nuevos errores que aparecen cada vez que se corrige uno, que deciden evitar tener que posponer su graduación un año y toman el camino de la audacia y de la fe cristiana (“Ma si, yo me presento y que sea lo que Dios quiera”).

Concientes de este tipo de problemas o inspirados en un artículo de Michael Cusumano, muchos equipos de desarrollo compilan frecuentemente su código, posiblemente una vez al día o más frecuentemente. Esto mantiene una base de código limpia de errores elementales como la asignación de cadenas a variables enteras y otros tantos. ¿Cómo funciona esto? Se programa alguna tarea en el sistema operativo para que tome la última versión del código fuente existente en el repositorio y lo compile. En caso que existan errores, el encargado de mantener la integridad del repositorio verá en el informe que la compilación del día anterior no se pudo realizar por errores en algún archivo (o en varios) y, usando la herramienta de control de versiones identifica al culpable. Aquí es donde se activa la condena social que hace que el sistema funcione. El culpable deberá corregir el error para retornar al buen camino, pero además deberá comprar facturas para todo el equipo, encargarse de realizar la tarea de mantener la integridad del repositorio hasta que un nuevo individuo cometa su error o algo por el estilo. La idea es que este pequeño ritual define la importancia que tiene para el grupo mantener el repositorio código sin errores elementales, y además le avisa a cada miembro cuando está afectando este objetivo. Eso es retroalimentación en su estado más puro. El mensaje es claro: “Eres muy buen desarrollador pero nos gusta tener un repositorio libre de errores y vos LO ROMPISTE.”

Para una persona con el rol de desarrollador, esta retroalimentación se presenta fácilmente y de muchas maneras. Si no cumple con una fecha de entrega su jefe de proyecto lo llamará y le preguntará que sucedió, probablemente con una cara de preocupación que manifieste que hay un retraso importante. Si escribe un método que debe actualizar un registro en una tabla de una base de datos y olvida poner la cláusula WHERE, la mirada suspicaz de sus compañeros le dirá que eso es un error bastante común y que sería bueno que no se cometieran esos errores comunes. Yo lo hice y capte el mensaje en el ambiente :-)

Pienso que esta retroalimentación es positiva porque nos permite corregir nuestro comportamiento con mayor rapidez. Los efectos de los errores llegarán igual, la retroalimentación permite acelerar los tiempos de las soluciones y evitar que las consecuencias se propaguen, además de reforzar el aprendizaje. Por supuesto, esta retroalimentación debe mantenerse dentro de ciertos límites que no afecten las relaciones. Si cada vez que rompo una compilación en el repositorio, recibo una sesión de pedradas en la sala de reuniones de la empresa, bueno, podría considerar que no es positiva. La manera en que se da esta retroalimentación es parte de la cultura de un grupo y es una característica distintiva del mismo.

No hay que ser un observador particularmente agudo para percibir que no todos tienen la suerte de recibir la cantidad de retroalimentación que reciben los desarrolladores. A medida que subimos en la pirámide organizacional que existe en la mayoría de las empresas, más allá que nos guste hablar de autogestión y empowerment, las posiciones comienzan a volverse adversas a la retroalimentación. Esto es un fenómeno fácil de observar. Hay menos personas dispuestas a decir su opinión sobre el accionar de un jefe de proyecto que a criticar el trabajo de un desarrollador, pocas personas dicen algo sobre como está actuando un gerente y posiblemente nadie se anime a decirle una palabra negativa al dueño o CEO de la empresa (bueno, su esposa tal vez pero ese es otro ámbito). Por supuesto, no se trata que todos piensen que estas personas hacen bien su trabajo. Simplemente nadie dice lo mal que lo hacen, si es que piensan eso. Podemos decir que algo de esto tiene que ver con una evolución histórica de la organización occidental y su origen en la milicia y la iglesia, donde uno no opina sobre sus superiores. Pero también tiene que ver con el carácter de las personas que tienen estos roles. Hay jefes de proyectos y gerentes que les gusta hablar, conducir la conversación en cada momento. Es algo que uno puede identificar con 5 minutos de charla casual. Simplemente hablan, cuentan sus puntos de vista, tal vez hacen chistes, pero no escuchan. Les cuesta terriblemente escuchar. Pareciera ser que les resulta extraño juntarse con otras personas y sentarse a escuchar. Los requerimientos de su tarea diaria los acostumbro a conducir, a hablar, a decidir y comunicar, pero no a escuchar. Entonces esta actitud reacia natural que cualquiera puede tener a decir que algo que su jefe o superior está haciendo mal se ve potenciada por esa característica. Es muy difícil trabajar de esta manera. Significa que si ocupamos estos roles nadie nos dirá nada aunque cometamos un error tras otro, uno más grande que otro. Diríamos “colitivo” una y otra vez. ¿Será posible que esto sea así?

Imaginemos un jefe de proyecto en un proyecto X complicado. Está renegociando el alcance del proyecto con el cliente y esta tarea nunca es agradable. Si bien nadie salta de alegría, se está trabajando profesionalmente, se están planificando pequeñas entregas, se está midiendo el avance y se están estableciendo puntos de decisión en el tiempo en base al avance. Hay una luz al final del camino. Se han activado mecanismos de control. De a poco y con esfuerzo el proyecto se encamina. De pronto, aparece su superior inmediato y le dice: “Noté que el cliente del proyecto X no estaba del todo conforme. Así que me reuní con él y les dije que iban a tener todo lo pactado originalmente para la fecha estipulada y además agregamos un módulo de reportes. Ahora ya se calmaron las aguas. Espero que el equipo responda a las expectativas de la empresa”
¿Qué es lo que piensa el jefe de proyecto? “¡Pedazo de imbécil! Cualquiera puede calmar las aguas hoy haciendo grandes promesas, el problema es que vamos a hacer mañana.”
¿Qué es lo que dice el jefe de proyecto? “Mmm, bueno, si, creo que será algo complicado pero veremos como nos acomodamos. Muchas gracias y suerte en su partido de tenis.”

La verdad es que si existieran rituales proporcionales para este tipo de errores con respecto al error de incluir un archivo defectuoso en el repositorio, Argentina importaría trigo por el desabastecimiento de harina en las panaderías. Y es que el equivalente de este error en el ámbito de un desarrollador no sería incluir varios archivos con errores repetidamente. Sería mas bien como entrar en la sala de servidores, arrancar los discos de los servidores con los dientes y prenderlos fuego junto con las cintas de backup. Sin embargo no existen rituales de retroalimentación para estos roles. Todo esto tiene otras consecuencias.

Hay roles que tienen responsabilidades operativas o ejecutivas, y otros roles de responsabilidades tácticas y estratégicas. Esto además de indicar cual es el sueldo anual de un empleado, también define la cantidad de daño que uno puede hacer. Si un proyecto se demora 6 meses difícilmente la responsabilidad pueda ser de los desarrolladores. No quiero decir que su accionar no pueda influir en esta demora. Quiero decir que existen cientos de alternativas y decisiones que otras personas en roles superiores pueden tomar para que esto no suceda. Y en conclusión, si estas decisiones no se toman, pueden sentirse responsables directos de las consecuencias sin temor a equivocarse. El fundador de una pequeña empresa de software que se decide a entrar en el mercado de los procesadores de texto para desbancar a Microsoft Word del liderazgo con un producto de precio más competitivo, ha tomado decisiones estratégicas estúpidas que no hay manera de arreglar por mejor gestión de proyecto que tenga. Asignar culpas a personas con roles cuya responsabilidad es mucho más limitada que la supuesta consecuencia de sus acciones es como pensar que el responsable del derrumbe de las torres gemelas podría ser un niño que estaba jugando con su bolón explosivo en la vereda del World Trade Center. Por supuesto, como las reglas sociales implícitas de una organización permiten evidenciar los errores en algunos roles pero en otros no, ya todos saben hacia adonde apuntaran los dedos cuando algo ande mal. Es algo que se repite una y otra vez.

“Colitivo, colitivo, colitivo”

Pero existen otras situaciones que se repiten una y otra vez en los proyectos de software. Lo suficiente para que me encuentre una y otra vez leyendo sobre el tema en libros sobre gestión de proyectos de software. Un tema en particular me desvela y la última vez que leí sobre el mismo fue en Debugging the Development Process de Steve Maguire.
Cuando los proyectos comienzan a complicarse, las primeras dos acciones que los lideres toman usualmente son las obvias y fáciles: contratar más personas y forzar al equipo a trabajar más horas. Estas pueden parecer respuestas razonables, pero de hecho estas son posiblemente las peores opciones que los líderes pueden tomar para volver a encaminar un proyecto en problemas.
Imagine un galeón mercante del siglo dieciséis cruzando el Atlántico del Viejo Mundo hacia el Nuevo Mundo. Cuando el galeón está alejado mar adentro, el primero de a bordo nota que la nave se está llenando de agua y alerta al capitán. El capitán ordena a los miembros de la tripulación que quiten el agua, pero a pesar de su esfuerzo, el agua sigue subiendo. El capitán les ordena a más miembros de la tripulación a quitar el agua€¦ Pronto el capitán tiene a la tripulación entera quitando agua en turnos, pero el agua sigue subiendo.
Dándose cuenta que no tiene más marineros para quitar agua, y con el navío inundándose, el capitán ordena a todos los miembros de la tripulación a que trabajen más horas, sus días y noches se transforman en quitar agua, colapsar exhaustos, despertarse y volver a quitar agua. Funciona. Los marineros no sólo están previniendo que el agua siga subiendo, sino que están haciendo progreso, quitando agua más rápido de lo que entra. El capitán está contento. Mediante su brillante gestión de recursos humanos, él previno que el navío se hunda.
Al menos durante la primer semana.
Pronto los miembros de la tripulación caen rendidos y comienzan a quitar menos agua de lo que quitaban cuando trabajaban en turnos y estaban más descansados. El navío nuevamente comienza a inundarse de más agua de la que ellos pueden quitar. El primero de abordo intenta convencer al capitán que debe permitir que los marineros descansen si quiere que sean efectivos. Pero porque el navío se está hundiendo el capitán rechaza cualquier charla sobre darle a la tripulación un descanso. 'Nos estamos hundiendo. La tripulación debe trabajar más horas,' grita el capitan. '¡Nos estamos hundiendo!'
El agua sigue subiendo y finalmente el navío se hunde, llevándose a todos con él.
¿Podría haber existido una mejor manera de salvar ese navío que poner a todos los miembros de la tripulación a quitar agua y forzarlos a trabajar más duro y más horas? ¿Si estuvieses en esa nave que se está inundando, que hubieras hecho? Yo puedo decir que hubiera hecho: yo hubiera buscado las filtraciones de agua.

Suena obvio. Pero una y otra vez observo que ese camino obvio no es tomado. Y me llama la atención porque conozco personas inteligentes, con experiencia, capacitadas, estudiando gestión de proyectos, gestión de riesgos, con títulos del PMI, cursos de CMM, posgrados, MBA. Y siguen tomando malas decisiones en estas situaciones. No se trata de opiniones, o de coincidir o no con un enfoque. Por un momento olvidémonos de las consecuencias que pueden tener en una persona trabajar 12 horas y no tener fines de semanas. Viendo la situación desde un enfoque completamente práctico, que un jefe de proyecto haga trabajar 12 horas y fines de semana a su equipo durante meses es mal desempeño. Tan simple como eso. Porque esta actuando de una manera poco racional, no está solucionando nada. Tiene la excusa perfecta (“hicimos todo lo que pudimos”) pero las excusas sirven de bastante poco. Lo que yo me preguntaría si fuera su superior sería: “¿cuándo piensa solucionar algo? Veo que trabajan muchas horas pero, ¿cuándo vamos a ver las soluciones?” Son simplemente malas decisiones. Es mal desempeño. Es un hecho cristalino como el agua de un arroyo cordillerano. Tan mal desempeño como lo es que un desarrollador entregue su trabajo fuera de término, lleno de errores, sin documentar y sin respetar directivas de codificación. O un vendedor que no pudo vender un helado en todo el verano.
Pienso que la falta de retroalimentación de algunos roles puede ser un factor que influye en esta repetición constante de errores. Esto se ha alargado demasiado y debe existir alguna conclusión, en este caso casi arrogante de mi parte:

Si tienes poder de decisión sobre un proyecto en el que la norma es trabajar 12 horas por día y fines de semana, si tienes poder decisión sobre ese proyecto y tienes la idea de agregar más gente al proyecto, si sabes que todos se quieren ir y sólo se te ocurre cerrar puertas y ventanas, si ves que más allá del esfuerzo los problemas siguen ahí, posiblemente las señales de retroalimentación que recibes son muy sutiles, casi imperceptibles. Déjame tomarme el atrevimiento y hacerlas más nítidas: estas haciendo mal tu trabajo, estas cometiendo el mismo error una y otra vez. Pero no hay nada que te impida hacerlo mejor. Eso es muy bueno. Significa que mañana mismo puedes empezar a buscar las filtraciones.

No hay que ser un genio para aprender. Sólo hay que observar nuestros errores y corregir nuestro accionar. Esto es cierto para el niño que pateaba mi asiento y decía “colitivo”, y es igual de cierto para el jefe de proyecto que piensa que la única manera de encaminar un proyecto es haciendo lo mismo que hace siempre y que nunca solucionó nada. Ambos pueden aprender y decir un día:

“Colectivo”

“Vamos a buscar las fallas en este proyecto y vamos a solucionarlas. Para empezar tómense el día libre.”

domingo, 12 de septiembre de 2004

No es mi culpa

"Si culpas a tus empleados, eres un mal manager. Los contrataste, los aceptaste, los supervisaste y dirigiste su entrenamiento. Eres el responsable. Si no te gusta lo que está sucediendo, observa tu propio comportamiento. Pero, si hay crédito para dar, es de ellos." Gerald Weinberg

Sigo con la serie "No hagas lo que yo hice" que inicie hace un tiempo. Esta vez se trata de un pensamiento que he tenido más de una vez: "No es mi culpa". Esta es una de las cosas más nocivas que uno puede pensar cuando trabaja en equipo, mucho más cuando coordina un equipo.

En un proyecto tuve que trabajar con dos estudiantes que estaban haciendo sus primeros pasos en el desarrollo de software. Conocían las herramientas de desarrollo que estábamos utilizando pero no habían participado nunca de un proyecto más allá de los trabajos para la universidad y carecían de algunos conocimientos importantes como diseño orientado a objetos.
Yo había iniciado el desarrollo del proyecto definiendo algunas cuestiones arquitectónicas para el manejo de la persistencia, la validación de errores y algunas otras cosas. Luego debí dejar el desarrollo para ocuparme de otras tareas, pero seguía el avance del proyecto. El problema no era sólo que el avance no era el esperado. La sensación que tenía en aquellos momentos cuando me ponían al tanto del estado del proyecto era que se estaba haciendo todo mal.

Una y otra vez se perdían modificaciones en el código por un mal uso de la herramienta de manejo de versiones, y siempre el origen de todo era, supuestamente, alguna falla de SourceSafe. Yo pensaba, "Vamos, SourceSafe tiene sus problemas pero sé que se puede hacer un check-in sin perder información si lo hago bien...". Luego observaba que el código estaba repleto de declaraciones de atributos enteros con signo de 16 bits (Integer en Visual Basic) cuando los valores posibles para esos atributos iban mucho mas allá de los límites de este tipo de datos. "¡Genial! Ahora nuestra aplicación es un campo minado de posibles errores de overflow esperando estallar cuando quiera utilizar un valor tan grande como... 32679". Los casos de uso que supuestamente estaban terminados, y que debían estar listos hace 2 semanas, tenían errores tan grotescos que no soportaban un smoke test mínimo. En realidad, no es que saliera humo al probarlos. ¡Se desataba un espectáculo de fuegos artificiales en el cielo cada vez que se ejecutaba la aplicación!

"¡¡¡GGRRRR!!! ¡Están haciendo todo mal!"

Es terrible tener ese pensamiento. Es injusto porque cuando uno trabaja en equipo siempre tiene algo que ver con los resultados y es poco práctico porque si siempre pienso que la culpa de todo la tiene otra persona, es poco lo que puedo hacer para mejorar las cosas. Y, al final, no hago nada.

¿Por qué no se capacito a esas personas para manejar las herramientas de control de versión antes que tengan que utilizarlas en un proyecto?
¿Por qué no se replanifican las iteraciones si vemos que la realidad no se adapta a nuestros planes?
¿Por qué nadie verifica que las personas que toman decisiones de diseño están capacitadas para hacerlo o cuentan con alguien que las ayude para hacerlo?
¿Por qué no se analizan cuales son los motivos de los errores, cuales son las fallas en nuestra manera de trabajar, como podemos merjorarla, que técnicas podemos utilizar?

Hacerse este tipo de preguntas puede ser doloroso. Porque los problemas de un proyecto pueden ser el reflejo de las limitaciones propias. Es mucho más fácil asignarle las culpas a otras personas, más aún si son nuevas en la empresa o con menos responsabilidad. Eso no está bien.

domingo, 5 de septiembre de 2004

Leer, leer, leer

En muchos momentos del día, casi inconcientemente, pienso en temas relacionados al desarrollo de software. Cuando observo algún problema en mis tareas diarias, analizo la situación más allá del escenario puntual que me toca vivir. Inevitablemente comienzan a nacer en mi mente relaciones de un tema con experiencias pasadas, con comentarios de amigos y colegas, con material que pude leer en el pasado.

Cuando algún tema ocupa mi mente un tiempo considerable es cuando pienso que podría tener mis ideas más claras si las escribiera y este sitio termina siendo el destino para ellas. Hace poco encontré uno de esos temas. La gran mayoría de aplicaciones que he desarrollado son aplicaciones empresariales, que soportan algún proceso de negocio para alguna empresa, que hacen uso intensivo de base de datos para guardar información y que deben convivir e intercambiar información con sistemas diversos en plataformas diversas.

Una y otra vez he observado que cuando se inicia el desarrollo de este tipo de aplicaciones se le da gran importancia a la manera de guardar los datos. Cualquier equipo de desarrollo con algo de experiencia en este tipo de aplicaciones conoce la importancia de aislar la funcionalidad relacionada con el acceso a datos de alguna manera.
Simplificando, lo que se intenta resolver es donde estarán las sentencias SQL. Puede existir un objeto que se encargue de armar las sentencias, puede existir una capa de persistencia que lo haga o se puede utilizar algún framework de persistencia open source para hacerlo. El punto es que he visto que gran parte de las definiciones arquitectónicas de una aplicación empresarial tienen que ver con esto. El objetivo es que sea fácil buscar, modificar y eliminar datos, y que no haga escribir mucho código para hacer un ABM (alta/baja/modificación) para una entidad. Entonces el desarrollo de una aplicación se limita casi a un copiar y pegar de una pantalla porque la manera de acceder a los datos está bien definida.

Pero el problema es que las aplicaciones rara vez se limitan a buscar, modificar y eliminar datos. Siempre hay lógica de negocio compleja, cambiante, con sutiles detalles que hacen que los distintos casos a considerar sean muchos.

Recuerdo, por ejemplo, un proyecto en el que participe donde una de las funcionalidades más criticas era un proceso de facturación por lotes que debía considerar muchas variantes. Es la típica empresa de servicios que factura a sus clientes periódicamente pero que siempre existen muchas reglas que hacen variar el monto facturado. Extrañamente, en este proyecto las definiciones arquitectónicas tenían que ver con el manejo de la persistencia y no sobre como hacer flexible el proceso de facturación para permitir variación en las reglas que rigen ese proceso.

El problema de centrarse en el acceso a datos es que se pierde de vista otros aspectos más importantes en algunas aplicaciones y se termina con el código de la lógica de negocio con gran acoplamiento, difícil de modificar, de probar y con funcionalidad repetida.

Es llamativo lo nocivo que pueden resultar algunas recomendaciones valorables cuando son simplificadas. Por ejemplo, Ivar Jacobson en Object-Oriented Software Engineering: A Use Case Driven Approach propone la representación de información, comportamiento y presentación de un sistema con distintos tipos de objetos. Los objetos de interfase encargan de la presentación, los objetos entidad tratan la información y los objetos de control representan el comportamiento.
El patrón MVC (model view controller) propone algo similar. El problema existe cuando se siguen mecánicamente estas sugerencias. Los objetos modelo (o entidad) son objetos bobos que solo tienen datos y el controlador es una ensalada de lógica difícil de modificar de extender y de probar.

En un momento pensé en escribir sobre este problema y hacer un ejemplo con diagramas, y tal vez hasta código, porque me resultaba un tema medianamente interesante. Pero algo sucedió antes que lo haga. Llegó a mi escritorio el libro Patterns of Enterprise Applications Architecture de Martín Fowler. Cuando comencé a leerlo vi todos estos temas tratados detalladamente incluyendo alternativas con pros y contras, además de soluciones a otros problemas que se presentan recurrentemente en el desarrollo de aplicaciones de este tipo. Y entendí que no tiene sentido que yo escriba al respecto porque difícilmente tenga algo para agregar más allá de lo que dice este libro. Me basta con recomendarle el libro a cada desarrollador de aplicaciones empresariales.

Lo que me marcó este hallazgo fue algo que he visto antes. Uno piensa en algo y le da vueltas al asunto. Y las respuestas están muchos más cerca de lo que uno cree. Son cosas que ya han pensado otras personas, sólo hay que leer para conocerlas. Leer. Leer. Leer. Tenemos que ampliar el espectro de nuestro conocimiento y prestarle atención a temas que no nos resultan útiles inmediatamente. Si uno no lee, se encuentra lanzado manotazos en la oscuridad cuando algún problema escapa de lo usual.
Cuando uno se mantiene informado sobre muchas cosas, comienza a conocer la punta del ovillo de cada tema y sabe donde buscar más información.

Por ejemplo, saber que existe algo que se llama Gestión de Configuración permite buscar herramientas de Gestión de Configuración, procedimientos de Gestión de Configuración, recomendaciones para la Gestión de Configuración en proyectos de todo tipo, averiguar como hacer un manual de Gestión de Configuración y hasta conocer patrones de Gestión de Configuración.
No saberlo nos lleva a juguetear con CVS o SourceSafe, y tratar de reinventar la rueda, mientras Pepe pisa por enésima vez las modificaciones de Juan y todos están tratando de adivinar que versión del producto está instalada en el cliente.

Esto es casi una frase hecha pero es real. El desarrollador de software es un trabajador del conocimiento. Es esencial para nuestro trabajo, es “el” elemento diferenciador, tanto para personas como para empresas en el rubro. El conocimiento no es sólo lo que hace que una persona sepa como resolver un problema y otro no. El conocimiento también es necesario para encontrar nuevas soluciones y esa búsqueda puede ser una diferencia abismal en tiempos y resultados.

Dada la importancia que tiene el conocimiento en nuestra profesión hay algo que me llama la atención y, para ser sincero, me molesta. He tenido la posibilidad de conocer empresas pequeñas y grandes, dedicadas al desarrollo de software específicamente o áreas de desarrollo de empresas de servicio. En ninguna de ellas he visto una biblioteca que llamará mi atención. En ninguna. Me resulta extraño que mi biblioteca sea la más amplia que he podido conocer con respecto a desarrollo de software. Si veo algún libro de administración de un servidor Exchange o alguno de PL/SQL o Java, pero no veo a McConnell, Cockburn, Weinberg, Beck, Fowler, Booch. Humprey. No están.

Posiblemente los resultados positivos de comprar libros no se ven nítidamente en los resultados de facturación a fin de mes y puede pensarse que los costos son inaceptables, pero con una visión más amplia se puede observar que los beneficios son abismales. En lo personal, los costos de no leer me resultan inaceptables

domingo, 11 de julio de 2004

Mejorar como desarrolladores

En el pasado he tocado varios temas: requerimientos, productividad, procesos, estándares, desarrollo agil. Todos estos temas son trascendentes cuando uno habla de desarrollo de software y piensa constantemente en mejorar. Pero, ¡el software es código! Ya es hora de pensar en el código que escribimos y elevar nuestros estandares en ese sentido.

¿Es realmente bueno el código que escribimos? Pensemos en la respuesta con criterio profesional y sin ligereza. ¿A qué me refiero?

Recorda la última vez que pediste una opinión sobre una película a un amigo o pariente. Posiblemente obtuviste una respuesta como: “No me gustó. Es un desastre.” o algo que suena mejor como “Mmm, es medio lenta pero con buena fotografía.” La mención de la fotografía pretende darle un toque sofisticado al comentario aunque no signifique para el neófito otra cosa que hay alguna toma de lindos paisajes en la película.

Usualmente no esperamos más que esto de un amigo o un pariente porque es suficiente para saber si voy a ver la película el sábado en el cine o un domingo a la tarde dentro de 3 años cuando la pasen por televisión abierta. Sin embargo este tipo de comentarios no es lo que esperamos de una crítica en una revista especializada. El crítico de cine observará otros detalles, comparara el trabajo de actores y directores con sus obras anteriores, analizará los personajes y los recursos utilizados para contar la historia, evaluará la reconstrucción del contexto histórico, rescatará la profundidad de los diálogos, etc.

De la misma manera, para criticar nuestro trabajo o el de otros no podemos decir “Este código es un desastre” o “Bah, anda mas o menos bien” con la liviandad de una charla de café en el bar de la esquina. Para mejorar nuestro código debemos conocer los conceptos que permitan evaluarlo críticamente. Debemos poder analizar el impacto de las dependencias, detectar el acoplamiento y la falta de cohesión, conocer maneras de mejorar su estructura, saber de patrones de diseño y saber encontrar el equilibrio entre la elegancia y la simplicidad de un diseño.

Es aquí cuando el camino hacia la mejora comienza a ganar nitidez y entendemos que aprender a programar con Struts o a usar Remoting en .NET no nos hace mejores desarrolladores. Conocer el entorno y las herramientas de trabajo siempre es útil y hacen una diferencia. Adquirirlo es parte del trabajo que debe hacer un desarrollador profesional. Pero personalmente no pienso que esto haga un aporte esencial para ser un mejor desarrollador.

¿Qué es lo que diferencia un desarrollador excelente de uno regular? ¿Qué podemos hacer para acortar la brecha? Debemos pensar en lo hacemos constantemente.
Dave Thomas y Andrew Hunt escriben en The Pragmatic Programmer: From Journeyman to Master:
“...te estamos desafiando a que pienses en lo que estas haciendo mientras lo haces. Esto no es una auditoria única de las prácticas actuales... es una evaluación crítica constante de cada decisión que tomas, cada día, y en cada desarrollo. Nunca corras en piloto automático. Piensa y critica constantemente tu trabajo en tiempo real.”

Coincidiendo con esta postura, Kent Beck ha dicho que él no es un gran programador sino un programador con grandes hábitos. Una manera de mejorar es suprimir los malos hábitos cuando desarrollamos y comenzar a adquirir los buenos, aquellos que aplican los grandes desarrolladores. Veamos algunos:

Aplicar Test Driven Development (TDD)


Personalmente pienso que la aplicación de TDD ha sido mi mejora como desarrollador más significativa en el último par de años. Si no sabes de qué se trata podes leer el artículo Test Infected como introducción.

Esencialmente al aplicar TDD escribimos las pruebas de unidad antes de implementar un módulo por lo que contamos con la prueba que demuestra que nuestro código funciona. Este es un salto enorme para el desarrollo de software. Voy a repetir el concepto porque es brillante. Estamos diciendo que, aplicando esta práctica, como desarrolladores estamos obligados a demostrar que el código que escribimos *funciona*. Esto es importante porque una parte significativa de nuestro trabajo como desarrolladores es, precisamente, escribir código que funcione. Hoy considero como un requerimiento básico la existencia de una prueba de unidad que verifique la funcionalidad de cualquier modulo que escribo en cualquier lenguaje.

Los beneficios de aplicar TDD no tienen que ver únicamente con el hecho de contar con pruebas unitarias automatizadas para todo el código que escribimos. Como las pruebas requieren de módulos sin acoplamiento y con responsabilidades bien definidas, el diseño de la aplicación se ve mejorado notablemente. También las pruebas juegan un rol importante como documentación porque su código es un ejemplo del uso de las clases.

Comenzar a desarrollar de esta manera es difícil al principio y en varias situaciones escribir las pruebas unitarias antes que el código es una tarea particularmente complicada. Pero los beneficios son tremendos. La diferencia entre dos desarrolladores es marcada cuando uno aplica TDD y otro no. Si no estas aplicando TDD, tenes una oportunidad excelente para mejorar notablemente como desarrollador. Además de toda la información disponible en la web referida al tema, ya existen varios libros al respecto. Kent Beck escribió Test Driven Development: By Example y es apropiado para introducirse al tema. En http://www.xprogramming.com/software.htm Ron Jeffries mantiene una lista de herramientas que permiten escribir y ejecutar pruebas de unidad para todo tipo de lenguaje y entorno de desarrollo.

Aplicar Refactoring

Cualquier persona que haya escrito código para alguna aplicación medianamente exitosa (en términos de vida útil al menos) se ha encontrado en la situación de tener que extender su código y pensar que hubiera sido mejor tomar decisiones de diseño distintas en el pasado para facilitar el tipo de cambios que se tiene entre manos. El problema es que uno no quiere modificar algo que está funcionando, entonces prefiere dejar las cosas como están y buscar la manera de implementar la extensión (aunque se parezca mucho a un “parche”). Es evidente que poco a poco esto degrada el diseño y será cada vez más difícil extender o modificar nuestra aplicación.

Cuando uno tiene un conjunto de pruebas unitarias extensivas que actúan como red de seguridad para hacer cambios, las mejoras en el diseño pueden ser realizadas sin temor. Entonces podemos evaluar constantemente el diseño del código, asegurándonos que es el más adecuado para los requerimientos actuales, y hacer las modificaciones que consideremos necesarias de manera disciplinada.

Esto es refactoring, la mejora disciplinada de la estructura interna del código existente sin afectar su comportamiento.
Varios entornos de desarrollo han comenzado a dar soporte extensivo a esta práctica. IntelliJ IDEA, Eclipse y Borland JBuilder incorporan funcionalidad que nos permiten realizar modificaciones de este tipo con un par de clics. Microsoft también incorpora algo similar en Visual Studio 2005 (en sus versiones Beta).

Sin embargo, el soporte de una herramienta para hacer cambios que mejoren la estructura interna del código es una pequeña parte de lo que necesitamos para sacarle provecho al refactoring. También tenemos que saber cuando aplicar estos cambios y como hacerlo de manera disciplinada. El libro de Martin Fowler Refactoring: Improving the Design of Existing Code es el material de referencia por excelencia en este tema. En http://www.refactoring.com, Martin Fowler mantiene un catálogo de maneras de aplicar refactoring. Esta es otra práctica que nos hace mejorar notablemente como desarrolladores porque nos permite mejorar nuestro código constantemente, para que siempre conserve su simpleza, flexibilidad y extensibilidad.

Estudiar, leer y aplicar diseño orientado a objetos


Desde hace un tiempo estoy dictando cursos sobre desarrollo de aplicaciones Web con C# y he podido detectar algunas tendencias en los desarrolladores que han asistido a los cursos. Los desarrolladores conocen los conceptos básicos de orientación a objetos: clases, instancias, herencia, polimorfismo; pero no saben aplicarlos para diseñar e implementar una aplicación. Leer sobre el diseño orientado a objetos puede ser de gran ayuda para mejorar porque comenzamos a ver de manera distinta lo que hacemos.

No escribiremos un método en un formulario que se encargue de validar los datos ingresados, mostrar mensajes de validación al usuario, conectarse a una base de datos, armar una sentencia SQL, ejecutarla y tratar los posibles errores de base de datos que se puedan dar. Tal vez esta sea la manera más rápida de implementar la funcionalidad pero sabemos que tendríamos una clase con baja cohesión y que seguramente tendríamos código duplicado. Cuando comenzamos a entender más las características de un buen diseño orientado a objetos estamos más cerca de poder alcanzarlas.

De todo el material que he leído al respecto dos libros me han ayudado de manera más marcada a entender el diseño orientado a objetos. Uno es Design Pattern: Elements of Reusable Object-Oriented Software de Erich Gamma, Richard Helm, Ralph Johnson y John Vlissides. Cuando leí el ejemplo del primer capítulo del libro me sucedió lo que los americanos llaman “ah ha moments”. Por primera vez percibí las posibilidades de un buen diseño orientado a objetos, que iba mucho más allá de lo que yo podía pensar hasta ese momento.

El segundo es Agile Software Development: Principles, Patterns and Practices de Robert C. Martin. Posiblemente sea el libro que, a mi entender, mejor reúne y resume los conocimientos de orientación a objetos básicos y no tanto indispensables para cualquier desarrollador. Y como gran adepto a todo lo que escribe Robert Martin, no puedo dejar de mencionar sus artículos en http://www.objectmentor.com. Material sin desperdicio. No tengo dudas que estas lecturas nos dan los conocimientos para mejorar nuestro código.

Estas son algunas maneras de incrementar conocimientos, mejorar como profesionales y me animo a decir hacer más divertido nuestro trabajo.

En algunas oportunidades algunos conocidos me han mencionado el aburrimiento que les produce trabajar durante mucho tiempo con las mismas herramientas (Visual Basic por ejemplo). La necesidad de aprender una nueva tecnología o un nuevo lenguaje los motiva de una manera que un lenguaje que manejan hace años no puede hacerlo.

Pienso que existe otro camino: elevar nuestros estándares. Proponernos seriamente que nuestro código sea excelente, simple, claro, sin errores, fácil de mantener y extender, y hacerlo en tiempos mínimos. Prescindir de excusas (“Ah, en esta parte no capturo las excepciones porque teníamos un dead line y después me olvide de hacerlo”). Escribir código del que estemos orgullosos, que tengamos ganas de mostrarlo a nuestros colegas y amigos.

Este es un desafío definitivamente motivante.

viernes, 18 de junio de 2004

Aprendiendo de la experiencia propia y ajena

Tom DeMarco en uno de sus libros cuenta una historia que me llamó la atención poderosamente:
"Uno de mis clientes cuenta con una larga historia en el desarrollo de software, ahora llegando más de 30 años. A través de gran parte de este periodo, han mantenido trabajando a 100 o más desarrolladores de software. Por lo que ellos pueden alardear, sin exagerar, que tienen más de 30.000 persona/años de experiencia en desarrollo de software. Yo estaba muy impresionado: Imagine todo ese aprendizaje siendo depositado en cada nuevo proyecto. De tal manera que le pregunte a un grupo de ellos, ‘Cuando envian un nuevo manager a un proyecto nuevo de software, ¿cuáles sabias palabras le susurran al oído? Ellos pensaron sólo por un momento y contestaron, casi al unísono: 'Buena suerte'"

Podemos pasar años sin sacar provecho de nuestras experiencias, sin aprender de los errores. Esta es una idea que me preocupa y me esfuerzo porque no me suceda. Por eso observo con detalle lo que hago y lo que hacen otros. Analizo que es lo que he hecho mal, que es lo que otros han hecho mal. Siempre existe una lente algo crítica entre mis ojos y la realidad. Me resulta muy positivo este tipo de análisis porque es de allí que nace el aprendizaje que le da valor a la experiencia.
No importa si has gestionado varios proyectos de desarrollo si una vez tras otra culpas a la inmadurez e indecisión del cliente como origen de todos los fracasos.

Raymond Chen indica en su sitio que la NASA tiene un newsletter donde los aviadores pueden enviar reportes anonimos sobre "cosas estupidas que he hecho" para transmitir a otros pilotos la idea "No hagas lo que yo hice". Es una buena idea para compartir experiencias. Quien las lee puede sacar algo de provecho para no cometerlas, quien las escribe seguramente ha aprendido a no repetirlas.

Mi experiencia en el desarrollo de software es limitada pero tengo cosas para contar en la categoría "cosas estupidas", por eso posiblemente este sea el primero de una serie de artículos sobre esta temática. Hoy comenzaré con una frase clásica:

"En la proxima iteración recuperaremos el tiempo perdido."

Trabajar en una empresa pequeña y tener iniciativa da grandes oportunidades, como planificar un proyecto mucho antes de tener cierta experiencia para no caer en trampas clásicas. Pero se aprende mucho en el camino.

Una vez se presentó un proyecto pequeño que no parecía tener mayores complicaciones. El esfuerzo estimado para terminarlo era de 10 personas/meses. En mi rol de planificador decidí definir 5 iteraciones de 1 mes de duración. No podía dedicarme completamente a este proyecto pero existían otras dos personas que si lo hacían y eran quienes hacían la mayor parte del trabajo. Ocasionalmente yo observaba el avance, hacía alguna sugerencia pero mi tiempo estaba dedicado mayormente a otros proyectos (¡Ay, multitasking! Un buen tema para escribir en el futuro). La planificación era simple. Teniamos una iteración de un mes, con un conjunto de casos de uso para terminar y responsables para hacerlo.

Terminado el primer mes, nuestro avance no era el esperado. Los casos de uso planificados no estaban terminados y teníamos algunos días de retraso.
"No importa, vamos a recuperar el tiempo en la proxima iteración." pensaba yo. "Comenzaremos a trabajar de manera paralela en más de una iteración. Además empezamos por lo más dificil y no conociamos mucho el contexto del proyecto. Ahora todo ira más rápido".
Adivinen que pasó... No, no recuperamos el tiempo. En realidad eso nunca pasa.

Los planes deben alimentarse y mejorarse con lo que ocurre realmente, no se puede eliminar toda esta información de retroalimentación que dice a gritos: "las cosas no son como las planificaste. Los tiempos son otros." Lo peor que se puede hacer es desechar esta información y seguir con el plan. Porque un plan escrito en piedra no sirve.

Errores clásicos

Es muy cómun caer en este tipo de errores porque parece existir algo en nuestra naturaleza que nos lleva hacia ellos una y otra vez..

Yendo más allá del desarrollo de software, es muy interesante los disfraces que puede tomar este error en distintos ámbitos. Hace unos días vi un especial de un canal de televisión francés que hablaba sobre la organización de los Juegos Olimpicos de Atenas del 2004. En este especial se podía ver a miembros del COI justificando los retrasos dramáticos en la organización de los Juegos hablando del sertaki.
El sertaki es el baile griego que inicia a ritmo lento y a medida que pasan los compases el tempo comienza a acelerarse hasta que no pueden verse los pies de bailarines. Era su forma de decir que los griegos comienzan a trabajar lento pero que al final iran tan rápido que recuperaran el tiempo perdido. Hoy nadie puede asegurar si se podrá terminar el techo vidriado del estadio olímpico para la ceremonia inaugural. Algunas frases de la voz en off del programa me resultaron tragicómicas: "El retraso llego a un punto tal que no existió mas remedio que modificar el plan original y replantear los tiempos."

En resumen, la enseñanza que queda de todo esto es simple: nunca pienses que recuperaras el tiempo perdido en tu proyecto. Actualiza los planes para que sigan siendo útiles.

jueves, 22 de abril de 2004

Estándares

estándar. (Del ingl. standard). 1. adj. Que sirve como tipo, modelo, norma, patrón o referencia. 2. m. Tipo, modelo, patrón, nivel.
Diccionario de la Real Academia Española.

Christopher Alexander es un arquitecto cuyo trabajo sobre patrones en la construcción fue la fuente de inspiración directa para el surgimiento de los patrones de diseño orientado a objetos.
En el prefacio de Patterns of Software de Richard P. Gabriel, Alexander habla sobre estándares. Pero no trata sobre estándares de la IEEE.

Son mucho más importantes:
"En mi vida como arquitecto, encuentro que la cosa que inhibe más severamente a los nuevos estudiantes y jóvenes profesionales, es su aceptación de estándares que son muy bajos. Si le pregunto a un estudiante si su diseño es tan bueno como Chartres, generalmente sonríen ingenuamente como diciendo 'Por supuesto que no, eso no es lo que estoy tratando de hacer... Yo nunca podría hacer eso.' Luego, expreso mi disconformidad y le digo: 'Ese estándar debe ser nuestro estándar. Si vas a ser un constructor, no existe otro estándar que valga la pena. Eso es lo que espero de mí en mis construcciones, y es lo que espero de mis estudiantes.' Gradualmente, les muestro que tienen el derecho a exigirse eso de sí mismos, y que deben exigir eso de sí mismos. Una vez que ese nivel de estándar está en sus cabezas, ellos podrán darse cuenta por sí solos como hacerlo mejor, como hacer algo tan profundo como eso. Dos cosas emanan de este nuevo estándar. Primero, el trabajo se vuelve más entretenido. Es más profundo, nunca es aburrido o cansador, porque uno nunca puede alcanzar realmente ese estándar. El trabajo se torna un trabajo de por vida, y uno se mantiene intentando e intentando. Por lo que se vuelve muy gratificante vivir a la luz de un objetivo como ese. Pero segundo, esto cambia lo que las personas intentan hacer. Quita de ellos las aspiraciones rutinarias y de bajo nivel de naturaleza puramente técnicas (las cuales debemos aceptar) y las reemplaza con algo profundo, que realmente hace una diferencia para todos los que habitamos esta tierra."

Hay desarrolladores despreocupados por aprender cualquier cosa que implique algo de esfuerzo, hay otros buscan constantemente la manera de mejorar.
Hay jefes de proyectos que se preocupan por alcanzar los objetivos del proyecto teniendo en cuenta los intereses de *todos* los involucrados (cliente, empresa, desarrolladores). Hay otros más interesados en juntar pruebas para poder evitar culpas en el caso de fracaso.
Hay dueños de empresas de software que se interesan por las personas que trabajan con ellos y tienen un sentido de responsabilidad social por su posición. Hay otros que actúan como si el dinero fuera su motivación preponderante y hasta única.
Cada uno fija sus estándares en base a sus valores y aspiraciones. Hay quienes tienen grandes aspiraciones y valores, hay quienes tienen aspiraciones mínimas y valores exiguos.
Nuestros estándares dicen mucho sobre cada uno como persona. Es significativo preguntarse: ¿cuáles son mis estándares?

domingo, 11 de abril de 2004

Sobre documentación y requerimientos

La primera vez que desarrolle software para un cliente de manera profesional (porque recibí dinero a cambio) fue para la construcción de un pequeño sistema administrativo junto a unos amigos. Como pasa generalmente en estos casos, el aprendizaje que obtuve de este proyecto paso más por cómo no se deben hacer las cosas que por cómo hacerlas bien.

Entre todos los problemas que nos encargamos cuidadosamente de tener a lo largo del proyecto, uno de los principales fue la falta de definición y gestión de requerimientos.

Al inicio tuvimos un par de charlas con el cliente aunque sin hablar con demasiado detalle y sin definir un alcance claro. Durante el proyecto tuvimos alguna reunión ocasional con el cliente para presentar el avance del desarrollo, aunque más que presentar el avance, en la reunión mostrábamos que era lo que habíamos hecho durante el tiempo que no nos habíamos visto. O dicho de otra manera, se trataba de responder a la pregunta del cliente: "¿Qué han estado haciendo con mi dinero?".

Como carecíamos de dotes adivinatorias, frecuentemente lo que hacíamos no era lo que el cliente esperaba y comenzaban las peleas, la típica asignación de culpas con analogías:

- ¡Esto es como hacer una casa sin ventanas!
- Pero si querés ventanas me lo tenés que decir.
- Es obvio, si en una casa va a vivir gente necesita ventanas.
- Los bunkers no tienen ventanas y son construidos para que viva gente en ellos.

Bueno, la historia conocida por todos.

Así, desde mi primer contacto con un proyecto de software (o algo parecido) comenzó a ser evidente la ineludible necesidad de conocer y gestionar los requerimientos.

Creo que la importancia de saber definir qué se debe construir antes de hacerlo es algo conocido por cualquier profesional que tenga algo de experiencia por lo que no puede existir mucho espacio para debatir en este sentido. La controversia surge cuando se comenzamos a pensar: ¿cómo lo hacemos?, ¿cómo definimos qué debemos construir?

La especificación de requerimientos es una de las actividades que, a mi entender, tiene una relación más fuerte con la documentación en la mente de las personas que se dedican al desarrollo de software. Percibo que existe una sensación que la manera de medir que tan bien se está realizando esta actividad es proporcional a la cantidad de documentación de requerimientos que se genera.

Esta bien, todos sabemos que se pueden hacer malos documentos y que se puede perder mucho tiempo inútilmente cuando no se saben escribir, pero es difícil encontrar alguien que piense que se puede llevar adelante un proyecto de desarrollo profesionalmente si no se documentan extensivamente los requerimientos.

Alistair Cockburn dice en un artículo:
"...escribimos esos documentos de especificación y diseño como si realmente pudieramos explicar completamente que queremos decir. Y no podemos. Nunca podemos aspirar especificar completamente los requerimientos o el diseño. No tenemos la menor de las posibilidades. Cuando escribimos, asumimos que el lector tiene un cierto nivel de experiencia. Si podemos asumir más experiencia, entonces podemos escribir menos. Si tenemos que asumir menos experiencia, entonces tenemos que escribir más."
Software Development as a Cooperative Game, Alistair Cockburn

Cockburn profundiza la presentación del concepto en en el borrador de su libro "Crystal Clear" (http://members.aol.com/humansandt/crystal/clear/):
"Las personas que hablan entre ellas para comunicar ideas, necesariamente usan referencias de experiencias en común. Esto debe ser así, de hecho, no existe otra forma de comunicarse. Las personas con las experiencias compartidas necesarias entienden la comunicación, las otras no.
...La ventaja [de esta característica de la comunicación] es que los desarrolladores de software pueden acotar las descripciones de lo que están haciendo acudiendo a la extensiva experiencia compartida con sus compañeros. Esto les permite moverse más rápido."
Quien lleve un tiempo desarrollando seguramente habrá experimentado esta ventaja. ¿Cuántas veces hemos participado de un dialogo como el siguiente? :

- Juan, ¿no te acordas si en algún lado habíamos hecho una clase de búsqueda para el XML de seguridad de la versión vieja?
- Si, Carlos, creo que hay algo en el sistema del gobierno para la importación a Meta4. Fijate en la carpeta Varios, creo que por ahí estaba la dll y el código.

Este dialogo esta lleno de referencias a experiencias compartidas. Juan y Carlos saben que es "una clase de búsqueda para el XML de seguridad de la versión vieja", "en el sistema de gobierno para la importación a Meta4" y "la carpeta Varios".
Este tipo de conversación sería imposible entre dos personas sin experiencias compartidas. En ese caso la conversación tendría que ser más específica, detallada y lenta. Cockburn continúa:
"...esto no es algo que se pueda evitar. No es como se piensa, que escribiendo casos de uso los desarrolladores entenderán repentinamente los requerimientos. Los desarrolladores que leen los casos de uso deben tener un conocimiento adecuado en el vocabulario del negocio para entender lo que están leyendo. Si ellos tienen un conocimiento amplio, entonces los casos de uso pueden ser más cortos y anecdóticos... La especificación no es una especificación a menos que los lectores la entiendan."
Es interesante pensar como pueden afectar nuestra manera de valorar los requerimientos las connotaciones de esta última frase.
Karl Wiegers define algunas características de requerimientos excelentes. Entre ellas:
"Completo: cada requerimiento debe describir completamente la funcionalidad ha ser entregada. Este contiene toda la información necesaria para el desarrollador para diseñar e implementar esa funcionalidad..."

"Sin ambigüedad: Todos los lectores de una especificación de requerimientos deben llegar a una única y consistente interpretación de esta."

Writing Quality Requirements, Karl Wiegers

Si tomamos como ciertos los comentarios de Cockburn, podemos concluir que es imposible que estas sean características intrínsecas de los requerimientos. La completitud y ambigüedad variara según el lector.

Por eso una especificación puede carecer de ambigüedad, ser completa, y a la vez ser breve, para un lector o grupo de lectores en particular. La brevedad me resulta una característica muy valorable en una especificación de requerimientos, donde se aproveche al máximo las experiencias compartidas de las personas que se tratan de comunicar a través de esta especificación.
Saber que es lo que se debe construir no implica necesariamente escribir un extenso documento. Muchas veces no es la mejor manera de hacerlo aunque sé que en muchas situaciones es la manera posible, aceptada, o habitual. Y por eso pienso que documentar requerimientos no es una regla básica que se tenga que cumplir, aunque conocer las necesidades y definir las soluciones si lo es.

Muchas veces se plantea como un cambio difícil de lograr el que requiere dejar el caos para comenzar a desarrollar software aplicando buenas prácticas. Creo que un cambio igual de difícil es replantear esas buenas prácticas a la luz de los objetivos y pensar que pueden existir alternativas que merecen ser consideradas.

miércoles, 3 de marzo de 2004

Personas, aprendizaje y proceso de desarrollo

La influencia de las características de las personas en el desarrollo de software es un tema que me resulta de gran interés. Por eso es inevitable que los libros de Alistair Cockburn sean el origen de más de un artículo en este sitio.

Esta vez me gustaría pensar un poco sobre personas, aprendizaje y procesos de desarrollo. Comencemos...

Alistair Cockburn, en su libro Agile Software Development, hace mención de las tres etapas de aprendizaje, las cuales que me resultaron especialmente reveladoras. Se trata de lo siguiente:

La gente que está aprendiendo nuevas habilidades pasa por tres etapas de comportamiento bien definidas: following, detaching y fluent.

La gente en la etapa following busca un procedimiento que funcione. Aún cuando 10 procedimientos distintos puedan funcionar, ellos no pueden aprender 10 al mismo tiempo. Ellos necesitan uno para aprender primero, uno que funcione. Ellos lo copian y lo aprenden. Necesitan instrucciones explícitas, una receta.

En la etapa detaching la gente localiza las limitaciones de su procedimiento y busca reglas para saber cuando el procedimiento no sirve. En esta etapa la persona aprende a adaptar el procedimiento a varias circunstancias. Ahora está más interesado en aprender los 10 procedimientos alternativos, en aprender cuando aplicar cada uno y cuando no funcionan.

En la tercer etapa, fluent, se torna irrelevante para la persona si está siguiendo una técnica específica o no. Su conocimiento se ha integrado entre cientos de acciones y pensamientos. Si se le pregunta si está siguiendo un procedimiento particular seguramente levantara sus hombros: no es importante para él si está siguiendo un procedimiento, improvisando uno alrededor de uno existente, o creando uno nuevo. Entiende el efecto final deseado y simplemente se conduce hacia él.
Conocer esta evolución me ha aclarado gran cantidad de situaciones.

He vivido esta evolución más de una vez.

Recuerdo clases de Diseño de Sistemas en la universidad, cuando el paradigma orientado a objetos era algo relativamente nuevo para mí y me iniciaba en la tarea de encontrar objetos a partir de requerimientos. Allí estaba yo, algo desconcertado, conociendo una manera distinta de pensar los problemas y sus soluciones. Sin duda transitaba la primer etapa que menciona Cockburn, y necesitaba una receta que pudiera seguir. La receta clásica para encontrar objetos es extraer los sustantivos que forman parte de los requerimientos. Así, si en alguna parte de la especificación de requerimientos dice:

Mensualmente cada empleado recibe su sueldo según las horas trabajadas

yo detectaba los objetos empleado, sueldo y hora. Es una técnica bastante simple (y directamente inútil para algunos[1])
No hizo falta que pasara mucho tiempo para que me diera cuenta de las limitaciones de esta receta y que la utilizara sólo como un punto de partida para agregar luego otras abstracciones que me parecieran necesarias y quitar las prescindibles. Ya estaba en la etapa 2.

Hoy no uso concientemente una técnica particular para detectar abstracciones en los requerimientos, simplemente lo hago. Me resultaría molesto que alguien me obligue a aplicar una técnica como la extracción de sustantivos para detectar objetos. Haría mi trabajo más lento, los resultados serían peores y encima estaría de mal humor. Pero esa receta tuvo su utilidad en algún momento.

Etapas de aprendizaje y procesos de desarrollo

Ahora me gustaría establecer una relación entre estas tres etapas y la definición de procesos de desarrollo de software.
Me parece lógico que el nivel de definición de un proceso de desarrollo sea acorde al nivel de aprendizaje de las personas que lo utilizarán.

Supongamos un escenario extremo: no hay proceso de desarrollo definido (¡huy, qué extremo!). En este contexto, hay personas a las que se les puede dar un proyecto de desarrollo y lo hacen. Y pueden tener éxito repetidamente. Porque saben lo que necesitan para hacerlo y lo que no saben lo aprenden. Punto.

Tal vez comiencen registrando requerimientos en un documento casi sin formato y pasarán a algo más sofisticado si hace falta.
Seguramente acordarán un conjunto de directivas de codificación que respetarán uniformemente, y no les tomará demasiado tiempo porque saben que lo importante de las directivas de codificación es respetarlas, no definirlas.

Estableceran algúna política para el manejo de versiones y desarrollarán todo el código utilizando pruebas unitarias. Integrarán diariamente el código y no permitirán que código que no pase las pruebas unitarias esté presente en el repositorio. Se organizarán asignado tareas para cada uno considerando las dependencias y las fechas de entrega, y no será gran problema si alguna tarea tarda un poco más o menos sabrán resolverlo. Posiblemente hagan el seguimiento del proyecto en una simple planilla de cálculo. Si hay problemas de sincronización de cambios en la base de datos definirán un procedimiento para realizar estos cambios y tal vez hasta desarrollen una pequeña heramienta para hacerlo. Si faltan datos en la especificación de requerimientos, modificarán los documentos para que se incluyan. Tambien es muy probable que hagan revisiones de pares para partes críticas o, ¿quien sabe?, tal vez hasta apliquen pair programming.

El hecho es que no les importa si lo que hacen es parte de un proceso definido previamente o una nueva técnica digna de un premio Turing. Lo hacen. Funciona. Punto.

Un proceso simple con herramientas simples son suficientes para que ellos sean eficientes. Ellos piensan: "Desarrollar software no es rocket science". Simplemente lo saben hacer.

Tambien existen otras personas que necesitan recetas, guías paso a paso para poder sentirse seguras que están haciendo las cosas tal como deberían. Prefieren contar con grandes plantillas para definir requerimientos y no las modificarán aunque en la mitad de los datos solicitados siempre escriban "No aplica". Necesitan revisar listas de verificación de varias páginas en cada paso del proyecto para saber que lo hicieron bien y valoran una planificación detallada de actividades de horas de duración para saber quien hace cada cosa y que se debe hacer despues. La programación se les torna demasiado complicada sin un documento de diseño con diagramas de clases que les indique que métodos deben programar, como se relacionan los objetos y hasta que tipo de colección conviene utilizar para guardar los items de una factura.

No son malas personas, no son menos inteligentes, sólo estan en una etapa temprana de aprendizaje.

Un equipo de desarrollo de software compuesto por personas en este estado inicial de aprendizaje por más proceso de definido que tengan dificilmente pueda nivelar sus resultados con un equipo formado por personas en la tercera etapa, de la misma manera que un principiante en diseño orientado a objetos no puede alcanzar los diseños de Kent Beck identificando sustantivos en una frase. Esto es así y no hay nada que pueda cambiarlo. Además las recetas detalladas apropiadas para determinadas personas pueden ser contraproducentes para otras.

Esta idea de adaptación de un proceso a las personas que lo utilizan parece brillar por su ausencia, porque muchas veces pensamos que podemos resolver la mayoría de los problemas definiendo con más detalle nuestro proceso de desarrollo, agregando más documentos, más actividades, más listas de verificación. Dejando menos margen para el error. Mitigando más riesgos. Y estamos dispuestos a invertir dinero en este refinamiento del proceso porque parece que con esto ganamos en certidumbre, en predecibilidad.

Si observamos que agregar más detalle a un proceso que será utilizado por personas que saben desarrollar software no es necesario porque en realidad no representa una mejora, entonces es posible que exista una alternativa: invertir dinero en el aprendizaje de las personas para formar equipos que sepan adaptar las prácticas a su proyecto, que completen su proceso, que sepan desarrollar software. Priorizar las personas y sus interacciones sobre los procesos y las herramientas.


[1] Bertrand Meyer, en su libro Construcción de Software Orientado a Objetos, habla sobre la técnica de identificación de objetos mediante sustantivos:

"Si la vida fuera tan sencilla uno podría llevarse a casa por la noche los documentos de requisitos y jugar al Object Pursuit en la mesa del comedor. Esta podría ser una buena forma de mantener a los niños alejados de la TV y hacer que revisen sus nociones de gramática mientras ayudan a mamá y papá en su trabajo de ingeniería de software"

domingo, 11 de enero de 2004

SWEBOK

El IEEE SWEBOK es un intento para definir el cuerpo de conocimiento de nuestra profesión, de manera tal que pueda ser utilizada como base para transformarla en una profesión practicada bajo licencia. Busca identificar y describir un subconjunto del cuerpo de conocimientos que es generalmente aceptado.

¿Qué significa "generalmente aceptado"? Significa que el conocimiento y las prácticas descritas son aplicables a la gran mayoría de los proyectos, la gran mayoría de las veces, y que existe un consenso generalizado sobre su valor y utilidad.

Cuando uno analiza los objetivos de este proyecto piensa que su resultado será un documento que sintetiza las grandes verdades de la ingeniería de software, mayormente verdades incuestionables. Si un documento puede tener estas características, seguro que no es el SWEBOK.

Para empezar la ACM (The Association for Computing Machinery) evaluó el SWEBOK y concluyó que este era seriamente defectuoso y que la ACM debía alejarse de su desarrollo.

Por otro lado, Cem Kaner hace una crítica detallada de la sección de testing del SWEBOK y concluye:
"Podría escribir páginas y páginas sobre las flaquezas del SWEBOK, pero pienso que no tendría sentido.
Estoy de acuerdo con la evaluación de la ACM que el SWEBOK comenzó con un enfoque esencialmente defectuoso. El resultado continúa siendo esencialmente defectuoso...
Yo dicto cursos de testing de software. El SWEBOK no es una buena referencia para incluir en ellos.
El criterio de inclusión y exclusión del SWEBOK es poco satisfactorio. Muchos de los tópicos más importantes de mis cursos de testing, (como test driven development, testing a nivel de API, testing de escenarios, skilled exploration, la diferencia de objetivos y costo/beneficio entre los conjuntos de test regresivos a nivel de unidad y a nivel de sistema, testing basado en riesgos, ... y varios más), están ausentes en el SWEBOK.
Mucho de lo presente en el SWEBOK está organizado extrañamente, es anticuado, y muchas de las técnicas son marginales en términos de que tan frecuentemente son utilizadas y cual es el valor que realmente proveen."

SWEBOK Problems, Part 2, Cem Kaner

Grady Booch dijo en la lista de discusión de Extreme Programming:
"Yo fui uno de esos 500 revisores iniciales - y mis comentarios fueron completamente negativos. El SWEBOK que revisé era bienintencionado pero malenfocado, simplista, incoherente, y simplemente errado en tantas dimensiones."

Recuerdo mi entusiasmo cuando encontré la página del SWEBOK en Internet hace un par de años. En un primer momento consideré que había encontrado un recurso muy valioso. Bajé los documentos, los imprimí y comencé a leerlos. Poco a poco el entusiasmo se fue diluyendo. Nunca terminé de leer esos documentos y no está en mis planes hacerlo alguna vez. Posiblemente la explicación de mi desinterés se encuentre en la frase de Martin Fowler:
"Existen montones de estandares de la IEEE ahí afuera que son rutinariamente ignorados por cualquiera que esté haciendo desarrollo de software comercial. La mayoría de estos estándares son escritos por estudiosos y estos están ocupados en grandes proyectos gubernamentales. La gente de negocios no considera al ámbito gubernamental como un sinónimo de eficiencia."

Swebok, Martin Fowler