domingo, 29 de junio de 2008

No hagáis esto en casa (II)

Los que no han leído la primera parte del artículo deberían comenzar por aquí.

¡Bien por Juan y Sebastián! Era eso, exactamente. Recapitulemos muy rápidamente.

Traduje desde VB.Net a C#

Public Function Resultado() as Integer ...(etc)... If Me.SumaDeAlgo()=xxx And Me.SumaDeOtraCosa()=yyy And Me.SumaDeAlgoMas()=zzz Then ...(etc)... End Function

como

public int Resultado() { ...(etc)... if( this.SumaDeAlgo()==xxx && this.SumaDeOtraCosa()==yyy && this.SumaDeAlgoMas()==zzz ) ...(etc)... }

El problema es la diferencia entre el "And" del VB.Net y el "&&" de C# (no me hubiese pasado de usar una herramienta automática). El "&&" del C# es equivalente al "AndAlso" del VB.Net. Es decir, cuando tengo varios términos booleanos unidos con un "And" primero se evalúan todos y luego se evalúa la expresión más general (en nuestro ejemplo eso implica que siempre se ejecuten las funciones SumaDeAlgo, SumaDeOtraCosa y SumaDeAlgoMas). En cambio, si tengo esos mismos términos unidos con un "AndAlso" o un "&&", se dice que la expresión es cortocircuitada (el término un poco raro lo saqué hace años de la ayuda traducida por Microsoft, igualmente no me desagrada). Si el primer término da false los siguientes no se evalúan, ya que su resultado es irrelevante para el curso de acción a seguir (en nuestro ejemplo, si SumaDeAlgo no es igual a xxx, SumaDeOtraCosa y SumaDeAlgoMas jamás se ejecutan).

O sea que la traducción exacta del código sería:

public int Resultado() { ...(etc)... double sumaDeAlgo = this.SumaDeAlgo(); double sumaDeOtraCosa = this.SumaDeOtraCosa(); double sumaDeAlgoMas = this.SumaDeAlgoMas(); if( sumaDeAlgo==xxx && sumaDeOtraCosa==yyy && sumaDeAlgoMas==zzz ) ...(etc)... }

Así nos aseguramos de que las tres funciones se ejecuten antes de llegar a la condición.

Muy divertido. Un error de distracción. Pero... pensemos un poco en cómo estaba escrito este código en VB y qué era lo que se supone que hacía. Un punteo.

1) Obviamente mi traducción no funcionaba porque las funciones, aparte de devolver un resultado hacían algo más. Concretamente modificaban variables de nivel de clase. Pero... si la función se llama "SumaDeAlgo" ¿cómo puede suponerse que la función modifica algo sin mirar el código? Es una convención de nombres básica el hecho de que si un procedimiento hace algo (en el sentido de modificar el estado del sistema, en este caso el de la clase a la que pertenece) debe tener un verbo en su nombre, o no devolver valor (así por lo menos sabemos que el resultado se establece en algún otro lado, aunque igual no sería muy divertido de leer).

Personalmente mi criterio es que si un procedimiento hace algo y por otro lado devuelve un resultado, el nombre debe referirse a lo que hace porque eso altera el estado del sistema. Si no, se supone que la función llega a su resultado sólo a partir de sus parámetros. En todo caso, si el resultado que devuelve es importante y su significado no es obvio (por lo cual tenemos quue documentarlo o hacerlo explícito) una variable "out" es bastante clara:

void HagoAlgo( out double sumaDeAlgo )

Así queda en primer lugar lo importante para el que lee, lo que no debe pasársele por alto, que es que al invocarla pasa algo, se altera el estado del sistema y que no es lo mismo no invocarla o invocarla dos veces seguidas.

2) Entonces, es un tema de nombres. Si, pero también es un problema de lógica "humana". No es un problema de codificación, sino un problema de semántica. Se ve que, funcionalmente, la tarea a realizar se divide en la ejecución de tres funciones y la posterior evaluación de sus resultados para determinar un curso de acción. ¿Por qué no escribir exactamente eso? El código más claro no siempre es el código más corto.

En clase es muy común que los alumnos pregunten si tal cosa se entiende mejor codificándola de esta manera o de esta otra. Yo siempre contesto: "La mejor manera de codificar es la que más se parezca a cómo pensaste el problema". Si el código sale intrincado, lo que hay que emprolijar es lo que tenemos en la cabeza. Una vez que tengamos el problema resuelto de una forma sencilla y prolija, lo escribiremos sencillamente sin problemas.

3) El punto 2) es el que a mi criterio justifica mis maldiciones. En la primera parte escribí que quería saber "quién fue el retorcido que escribió eso". Sutileza: no escribí "tonto", "estúpido", "inútil" o algo por el estilo, sino "retorcido" porque creo que escribió lo que tenía en la cabeza. Justifico la agresión por las tres horas que perdí tratando de entender algo simple, creo que me gané el derecho a descargar mi frustración. Pero más allá de eso, una vez calmados los ánimos, vale la pena sentarse a charlar un poco con ese programador para llegar a una visión más simple del problema, que no es otra cosa que decir "del negocio".

Estos problemas denotan siempre una pobre comprensión del negocio, que muy pocas veces es culpa del que escribe el código. El que escribe el código es un programador, que será bueno, malo, con mucha o poca experiencia, pero un programador al fin y al cabo. Usualmente no es un experto en facturación, ni en logística, ni en aquello a lo que está enfocado el negocio, y no tiene por qué serlo.

El problema de negocio está en la cabeza de analistas y líderes de proyecto. Tal vez el analista no le explicó bien el problema al programador (tal vez su análisis fue igual de retorcido), tal vez el líder de proyecto lo dejó sólo en la codificación de una funcionalidad demasiado grande, cuando debería haberle asignado un compañero de trabajo (de a dos estas cosas no pasan por el simple hecho de que la solución debe ser lo suficientemente simple como para explicársela al compañero de equipo). En ultimísima instancia el programador podría haberse dado cuenta de que estaba enrevesado y pedir ayuda pero... ¿no es pedir demasiado? ¿Cuántas veces nos damos cuenta solos de lo retorcido de nuestra propia lógica? No creo que muchas.

Para ir cerrando, creo este artículo en dos partes encierra un proceso muy común en cualquier desarrollo: en un primer momento, ante un problema de diseño, codificación o entendimiento, el escarmiento (mis maldiciones) truena sobre el que escribe el código. Pero a medida que pasa el tiempo se calman los ánimos, se avanza un poco en la reflexión y vemos que el problema rara vez está ahí. Cuando se cae un avión primero se le apunta al piloto. ¿Un avión puede caerse por el error de una sola persona? ¿Un bug puede llegar a producción o un sistema puede volverse inentendible sólo por que alguien lo escribió?

martes, 24 de junio de 2008

Minesweeper - The Movie

Trailer de la próxima película basada en el popular juego de Windows.

Sin falta hoy (o mañana) pongo algo serio, lo juro...

jueves, 19 de junio de 2008

Procrastinación extrema.

Nada mejor para procrastinar la segunda parte del artículo del sábado (No hagáis esto en casa...) que un link a un post sobre procrastinación, que encima ni descubrí yo mismo, sino que me pasaron:

Explicando la procrastinación, del blog de Enrique Dans, que de paso recomiendo.

Actividades o excusas varias, para aquellos que anden con pocas ganas de inventar las propias: hoy ya publiqué una entrada (ésta), tengo que practicar guitarra, (excusa con la que procrastino) ir al gimnasio, (procrastinado por) sueño, (pospuesto porque tengo) hambre.

Actualizado: links corregidos (ups!).

miércoles, 18 de junio de 2008

La fuente de toda sabiduría.

Jugando con Flickr. La cartelera en la oficina. Notas y descripciones sobre la foto haciendo click en ella.


La fuente de toda sabiduría., originalmente cargada por apanitsch.

martes, 17 de junio de 2008

Hay tabla

  • Si programan sin hacer testing, hay tabla.
  • Si no comentan el código, hay tabla.
  • Si no respetan los estándares, hay tabla.
  • Si se quejan de la performance, hay tabla.
  • Si preguntan boludeces, hay tabla.
  • Si cuelgan el servidor con un loop infinito, hay tabla.
  • Si reportan el mismo error dos veces, hay tabla.
  • Si me hacen laburar un fin de semana, hay tabla.
  • Si los casos de uso no están bien escritos, hay tabla.
  • Si no versionan, hay tabla.
  • Y si preguntan por esto, hay tabla.

sábado, 14 de junio de 2008

No hagáis esto en casa...

Antes de empezar aclaro: la siguiente anécdota está inspirada en hechos reales que pueden haber sido distorsionados o exagerados, que ningún conocido se sienta tocado.

En un día cualquiera, en un sistema en desarrollo cualquiera basado en uno "viejo" pero productivo, necesito una función que haga X. Como uno de los requerimentos básicos es "que haga lo mismo de antes", tomo como referencia el código viejo, escrito en VB. Lo leo, intrincado y feo (todo código en VB se me ha vuelto feo desde que me acostumbré a C#, y eso que VB me ha dado de comer por mucho tiempo) pero útil, al fin y al cabo es para una funcionalidad bastante acotada.

Tal vez el hecho de que el desafío no es muy apasionante haya influído en mi decisión, que fue la de traducir el código sin reparar demasiado en la lógica general. Algunas herramientas hacen esto automáticamente, pero quería por lo menos cambiar los nombres de las variables que no me gustaban, entenderlo en detalle y dejarlo prolijo, así que decido hacerlo a mano.

En general es algo lindo de hacer si uno no tiene ganas de pensar, que era el caso. Así que me pongo los auriculares, buena música y más o menos en una hora y media tengo todo traducido y bonito.

Lo pruebo. Obviamente no va para ningún lado. Media hora más depurando errores en la traducción.

Lo vuelvo a probar y funciona ok. Pruebo un par de casos más y en algún lado algo anda mal. Vuelvo a probar y otra vez funciona. Sigo así hasta que llego a un conjunto de datos de entrada bastante reducido, en el cual algunos casos daban bien y otros mal.

Tres horas depués...

El mismo conjunto de datos. A veces anda, a veces no. Tengo ganas de tirar el monitor al suelo, de romper todo y empezar de vuelta, de irme a casa, de hacer otra cosa, de empezar otra carrera, de cambiar de rubro. Me cuesta mantenerme concentrado, miro pero no veo. Decido probar una vez más (y van...) pero esta vez sin dar absolutamente nada por supuesto, así que entro a cada función, en cada llamada, no dejo nada sin revisar.

Y lo encuentro. Mejor dicho me doy cuenta, porque estuvo ahí, delante de mis narices todo el tiempo. Vuelvo al código original. Comparo. Es eso. Corrijo y pruebo, incrédulo. Si, es eso, ahora funciona.

Ganas de matar. En general a cualquiera, pero especialmente a alguien en particular. Porque cuando me encuentro con cosas así no puedo evitar ir al control de código fuente para saber quién fue el retorcido que escribió eso.

Voy a intentar una explicación. Recordemos que hice la traducción a mano, y que en general el proceso es bastante simple. Está encapsulado en una sola clase en la que se establecen un par de propiedades y se llama a un método que devuelve un resultado, y nada más. Adentro de esa clase decía:

Public Class RetorcidaVB Private Dim miVariable1 As Integer ...(etc)... Public Function Resultado() as Integer ...(etc)... If Me.SumaDeAlgo()=xxx And Me.SumaDeOtraCosa()=yyy And Me.SumaDeAlgoMas()=zzz Then ...(etc)... End Function End Class

y yo en C# escribí:

public class Retorcida { private int _miVariable1; ...(etc)... public int Resultado() { ...(etc)... if( this.SumaDeAlgo()==xxx && this.SumaDeOtraCosa()==yyy && this.SumaDeAlgoMas()==zzz ) ...(etc)... } }

Esto era lo que yo veía. ¿Dónde puede estar la diferencia? Hagamos una cosa. Esta historia continuará. Si alguien quiere enviar un comentario indicando cuál es la diferencia, bienvenido. Como están moderados, prometo liberarlos junto con la segunda parte, para no aguar el acertijo.

Actualización: Ya saqué la segunda parte, que puede leerse aquí.

jueves, 12 de junio de 2008

Estándares vs. creatividad en la codificación

Una charla de oficina un tanto extraña: ¿una metodología de desarrollo muy establecida va contra la creatividad de los programadores, llevándolos hacia un trabajo rutinario y finalmente hacia la desmotivación?

Acotemos el tema al tipo de sistemas que desarrolla el equipo en donde se da esta discusión: un sistema informático que soporta un circuito administrativo, una base de datos que es actualizada con los movimientos diarios propios del negocio a través de una interfaz relativamente simple. Buena parte de la aplicación (no me atrevo a tirar porcentajes, pero deben ser elevados) consiste en ABMs (pantallas de Alta-Baja-Modificación de datos, por las dudas) o reportes (desplegados con la herramienta xxx que accede directamente a la base).

Por supuesto, eso es la **mayor parte** de la aplicación. Hay otras funcionalidades que pueden dar dolor de cabeza al más avezado o quedar muy bien en su portafolio de logros.

En este contexto, puede surgir una forma muy establecida de hacer ciertas cosas. Por ejemplo: existe una herramienta que genera los ABMs todos igualitos con relativo poco esfuerzo, hay un entorno para los reportes de manera que la pantalla de ingreso de parámetros se arma también con relativa facilidad, etc.

Pero claro, luego de una curva de aprendizaje más o menos rápida hacer un ABM o un reporte ya no representa un desafío, y puede llegar a ser bastante monótono.

Creo que mi forma de presentar la cosa ya resume mi posición: en todo caso lo desmotivante y monótono es un negocio en particular, que puede ser estático o con funcionalidades muy establecidas, y puede estar en la pericia del que coordina distribuir las cosas de manera tal que a cada uno le toque "parte aburrida y parte divertida".

Si bien puede resultar divertido buscar nuevas maneras de hacer lo mismo, no deja de ser una pérdida de tiempo si no está justificado por una necesidad del negocio o una oportunidad para él.

Se ha dicho también que cuando el framework del equipo resuelve muchos problemas en los niveles más bajos (desde la conexión a la base hasta la seguridad, por ejemplo) los programadores no "aprenden" ya que se les "oculta" funcionalidad, y surge la desmotivación por no tener poder de decisión sobre el framework, como si éste fuera el castillo de unos pocos al que todos quieren entrar.

Enfocándonos en el tema de la idealización del framework y de la arquitectura del mismo (ya que ¡hola! las aplicaciones **también** necesitan una arquitectura enfocada al negocio, independientemente de la del framework), como algo divertido, siempre cambiante y a la cabeza de la tecnología, voy a tirarle un par de ladrillos a ese castillo de cristal.

Creo que últimamente se ha establecido la idea de que la carrera de un programador es: junior -> semi-senior -> senior -> arquitecto de software. No entiendo esto último, realmente (talvez tenga que ver con que "arquitecto" suena... importante, y "senior" suena solamente a viejo). Construir un framework es similar a construir determinado tipo de aplicaciones, no indica mayor o menor pericia del programador sino cierta especialización en un área determinada del desarrollo, y por lo tanto debería tener que ver ver con el tipo de orientación que el programador elige.

En mi opinión todos deben tener acceso -"de lectura"- a todo el código incluído el framework, pero así como se distribuyen tareas de codificación en la aplicación, también se distribuyen en el framework. Éste tiene la particularidad de que sufre realmente mucho cuando hay "demasiadas cabezas adentro", y propaga esa inconsistencia a todas las aplicaciones. Debe tener una y preferentemente sólo una filosofía subyacente y debe respetarse, ya que ofreciendo demasiadas maneras de hacer lo mismo las soluciones se complican en vez de facilitarse. Para decirlo crudamente, no deberían haber muchos monos en el baile.

Una solución para cada problema, que puede mejorarse o cambiarse, pero no duplicarse.

Por otro lado, el negocio es el negocio. El objetivo del equipo es desarrollar aplicaciones, no entornos de desarrollo. Cuando el framework alcanza el nivel de madurez necesario para construir las aplicaciones que el negocio necesita debe estabilizarse y los esfuerzos concentrarse en las aplicaciones ya que son el producto final del equipo y la fuente de ingresos para la empresa.

Un buen arquitecto jamás pierde de vista el negocio para el cual trabaja. En la mayoría de los casos esto implica saber cuándo parar: cuándo estabilizar el framework y concentrarse en el desarrollo de aplicaciones y cuándo es necesario volver sobre alguna parte de la arquitectura de apoyo para adoptar nuevas tecnologías o herramientas. Por otro lado esta posición en general asume tareas de coordinación hacia dentro y fuera del equipo que exceden las habilidades técnicas y hacen mucho al olfato y la experiencia en el manejo de equipos. ¡Cuidado aquellos que creen que el trabajo del arquitecto es una prueba continua de nuevos juguetes! Como en otras áreas, la mejor forma de aprender es acercándose de a poco, trabajando junto a alguien de experiencia, tomando al principio pequeñas decisiones, etc.

Un programador senior que en un cambio de trabajo se promociona como "arquitecto" suponiendo un paso más en su carrera puede llevarse una temprana decepción, o meterse en un bonito problema. Es como decirse experto en un negocio que no se conoce. Si yo digo que soy experto en sistemas de facturación estoy declarando mi experticia en un negocio, no mi nivel de programación. Nombrarse "arquitecto" indica un enfoque, conocer una tarea determinada en el desarrollo (que no es ni más ni menos que otras), no el nivel de manejo de una herramienta de programación.

Digamos, hay programadores que se orientan a negocios, comprenden rápidamente los circuitos administrativos, la mejor manera de resolverlos, la interacción con el usuario, etc. Otros se orientan a otro tipo de aplicaciones: científicas, de comunicaciones, servicios, con énfasis en la interfaz con el usuario, etc., y otros se orientan hacia la construcción de frameworks y librerías de apoyo, etc. Por supuesto la misma persona puede ser buena o ganar experiencia en varias áreas.

En este punto tengo que aclarar que personalmente me considero en una zona gris entre el negocio y la arquitectura. Es decir: me gusta trabajar en el framework, pero si no tuviese algo que hacer en el negocio me aburriría, y la coordinación me cansa terriblemente, si bien puedo hacerla. Obviamente dependiendo del caso hago uso del título marketinero, por qué no. Fin de la nota personal.

Todo esto para desmitificar un poco la idea Matrix-style del arquitecto que toca todos los hilos desde una superconsola de control.

En resumen, antídotos contra la desmotivación que se me ocurren al escribir esto:

  • La principal: un equipo balanceado para cada proyecto. Si 10 programadores senior construyen una aplicación como la que describimos, las "tareas desafiantes" no alcanzan, y no hay vuelta que darle. En todo proyecto hay tareas para todos los niveles, por lo que deberían estar involucrados programadores de todos los niveles, de ser posible, claro.
  • Siguiendo con la idea: buena distribución de tareas, tratando de olfatear la personalidad y la orientación de cada uno. Hay personas a las que no les gusta innovar, y personas a las que sí.
  • Orientar la creatividad o las ganas de innovar en las funciones que realmente pueden hacer único al sistema, aquellas que pueden ayudar a venderlo, hacerlo más atractivo, más valioso. Si alguien tiene ganas de revolucionar una funcionalidad, que no sea un ABM.
  • Y finalmente: nos guste o no, el buscar la motivación y el aprendizaje siempre depende en última instancia de uno mismo. La empresa puede tener más o menos intenciones de ayudar, pero lo hará o no en su propio beneficio. Léase por ejemplo: si el negocio es estable no podemos pretender revoluciones, y si queremos un cambio deberemos buscarlo en otro lado. El recambio en el equipo no es necesariamente malo ni para la persona ni para el conjunto, y no veo sentido en esa obsesión por retener a grandes programadores para los cuales ya no hay desafíos en el negocio. Un gran programador desmotivado es, ante todo, un programador desmotivado.

Antipatrones de diseño.

Me encantó este resumen antipatrones de diseño (en inglés). Lo traduje yo mismo con alma de programador, así que sean suaves con las correcciones. Me puse creativo en un par de párrafos, no pude evitarlo. Creo que va a dar para desglosar en un par de posts.

  1. Patrones de Cremación (Cremational Patterns)
    1. Pobreza vil (Abject Poverty): Código tan difícil de mantener y testear que el hacerlo resulta en la succión absoluta del presupuesto del proyecto, dejándolo en la extrema pobreza.
    2. Cegador (Blinder): Código que resuelve rápidamente el problema sin preocuparse por futuros cambios en los requerimientos. No está claro si el término se refiere a la cegera de aquellos que lo escribieron o a su deseo de sacarse los ojos durante la fase de mantenimiento.
    3. Falacia (Fallacy Method): Se presenta en el manejo de casos límite. El código parece correcto, pero si alguien se preocupara en probarlo, o si un caso límite apareciera, las fallas en su lógica se harían evidentes.
    4. Proto-Prueba (ProtoTry): Es un desprolijo intento de desarrollar rápidamente un modelo operativo del sistema. La intención original era reescribirlo utilizando la experiencia acumulada, pero las restricciones de tiempo en la planificación del proyecto nunca lo permitieron. También es conocido como "código heredado" (legacy code).
    5. Simpleza (Simpleton): Código extremadamente complejo para llevar a cabo la más simple y rutinaria de las tareas. Es una medida precisa de la habilidad de su creador.
  2. Patrones desestructurados (Destructural Patterns)
    1. Adoptivo (Adopter): Provee un hogar para funciones huérfanas que nadie sabe dónde ubicar. El resultado es una gran familia de funciones que no se parecen en nada y cuya única relación está dada por el hecho de pertenecer a la misma clase o módulo.
    2. Brig (¿traducción?): Es un contenedor para software pobremente desarrollado. También es conocido como módulo.
    3. Compromiso (Compromise): Balancea las siempre enfrentadas fuerzas de la planificación y las de la calidad, dando como resultado software de pobre calidad entregado fuera de tiempo.
    4. Detonador (Detonator): Es un patrón extremadamente común y usualmente no detectado. Un ejemplo son los cálculos basados en los dos últimos dígitos del año. ¡La bomba esta ahí fuera y esperando para explotar!
    5. Queso suizo (Fromage): Código lleno de agujeros. Software inconsistente lleno de pequeños trucos dependientes de la plataforma que hacen que sea imposible de actualizar. Cuanto más viejo se vuelve, más podrido huele.
    6. Diseño volador (Flypaper): Especificación creada por un diseñador y mantenida por otro, quien se encuentra absolutamente enredado en el trabajo del primero y usualmente muere antes de volverse loco.
    7. Pegamento de contacto (ePoxy): Código en módulos firmemente acoplados. A medida que el acoplamiento crece, parece haber una capa de pegamento de contacto entre ellos.
  3. Patrones de mala conducta (Misbehavioral Patterns)
    1. Cadena de posibilidades (Chain of Possibilities): Grandes módulos o clases pobremente documentadas. Nadie está seguro de hasta dónde se extiende su funcionalidad, pero las posibilidades parecen infinitas. También conocido como "no determinista".
    2. Comando (Commando): Código diseñado para llegar hasta su objetivo y hacer el trabajo entrando y saliendo rápidamente. Puede romper cualquier encapsulamiento para cumplir con su misión. No toma prisioneros.
    3. Intersperser (¿traducción?): Funcionalidad desparramada en varias porciones de código a través del sistema, haciéndola imposible de probar, modificar o comprender.
    4. Instigador (Instigator): Código aparentemente benigno pero que provoca fallos en partes insospechadas del sistema.
    5. Supernova (Momentum): Código que crece exponencialmente en tamaño, requerimientos de memoria, complejidad y tiempo de proceso en un corto período de tiempo.
    6. Sedante (Medicator): Código que consume tiempo de proceso haciendo que el resto del sistema parezca estar fuertemente sedado.
    7. Absolvedor (Absolver): Código mayormente desarrollado por ex-empleados, al que acuden los programadores actuales para lavar su culpas ante cualquier problema reportado. También es conocido como "no está en mi código".
    8. Orgullo (Stake): Código escrito por empleados que luego han elegido (correctamente) el camino del gerenciamiento de proyectos. Si bien está lleno de problemas, el ex-desarrollador, ahora líder de proyecto, está tan comprometido con él que no deja que nadie lo reescriba o siquiera ponga en duda, dado que representa su mayor logro técnico.
    9. Panegírico (Eulogy): Eventualmente aparece en proyectos que han utilizado los patrones anteriores y que una vez terminados son recordados amablemente. También es conocido como Post Mortem.
    10. Tempestad (Tempest Method): Código desarrollado en los días previos a la entrega del software. Está caracterizado por falta de comentarios e introducción de varios detonadores.
    11. Visitante del infierno -o Visita inesperada- (Visitor From Hell): Ciclo que no reconoce límites. Inevitablemente, al menos un ciclo del sistema tendrá un visitante del infierno que sobrescribirá datos críticos.

jueves, 5 de junio de 2008

Diseño para todo.

Una buena demostración de ello aquí. Por ejemplo:

martes, 3 de junio de 2008

El costo del cambio (parte II)

La primera parte (que recomiendo leer antes de seguir) de este artículo, comenzaba el comentario del libro de Kent Beck, Extreme Programming Explained presentando la curva de "costo del cambio" a través del tiempo, y finalizaba proponiéndonos imaginar cómo afectaría al desarrollo de un proyecto el pensar en una curva aplanada o asintótica. ¿Cómo desarrollaríamos? ¿qué factores tendríamos en cuenta en nuestras decisiones? ¿cómo diseñaríamos?

Decir que esa curva es aplanada, implica que el software puede modificarse indefinidamente sin perjudicar su calidad. El costo aumenta ya que -siguiendo las teorías "tradicionales"- cada modificación introduce errores, cierta incoherencia y complejidad al sistema, lo torna cada vez más difícil de entender, aumentando las horas/hombre necesarias para llevarla a cabo. Por otro lado están los costos de modificar un sistema en producción, y sobre todo los riesgos que ello implica. Bien, todos esos terrores desaparecen en nuestro nuevo mundo. Lo mismo me cuesta modificar el sistema hoy que hacerlo mañana.

Aclaremos antes de seguir que utilizamos "cambio" en un sentido amplio, que implica no sólo cambios en el software, sino en la planificación, en el diseño y en la conformación del equipo de trabajo. Ahora sí, ¿cómo nos afectaría esta nueva curva?

En primer lugar, diseñaríamos y planificaríamos "para hoy", ya que no tiene caso adelantarse en el horizonte, gastando más en planificar hoy lo que, de ser necesario, podremos planificar mañana al mismo costo. Y de esta manera no enfrentaríamos el riesgo de que cambios en el negocio o en las tecnologías tiren nuestra planificación y diseño por la borda.

Entregaríamos cada funcionalidad completa en su forma más minimalista, y trabajaríamos sobre los comentarios y propuestas del usuario, que mientras tanto podrá utilizarlo tal cual está, ya que si bien es probable que tenga mayores costos por modificar el sistema en producción, éstos no irán creciendo, y no superarán el riesgo de desarrollar a espaldas de la supervisión del cliente.

Eso en cuanto a nosotros. ¿Y al cliente, cómo lo afecta esta nueva perspectiva?

El punto más interesante es que desde este nuevo punto de vista los cambios en el negocio que afecten al sistema en desarrollo ya no son amenazas sino oportunidades. Cada cambio en la dirección del viento provoca movimientos que el cliente puede aprovechar para incorporar al sistema y adaptarse más rápido que sus competidores. El cliente tiene un sistema funcionando -porque hemos entregado temprano y mínimo-, y un equipo de desarrollo en marcha y dispuesto a cualquier giro brusco, ya que no tiene demasiado invertido en costosos planes para el futuro.

Cualquiera que haya trabajado en una PyME reconocerá en todo o parte esta forma de trabajar o de ver las cosas, más o menos explícita. Talvez intuya en los párrafos anteriores los clásicos requerimientos sorpresa de una semana a otra que hacen que de repente todo el mundo esté trabajando "en otra cosa". De hecho esta es la clásica ventaja competitiva de la PyME frente a, por ejemplo, las grandes consultoras para las cuales cada proyecto implica el movimiento de un ejército de analistas, diseñadores, programadores, etc., y en general una abultada factura.

En este planteo estas prácticas no son automáticamente tildadas de poco profesionales y desorganizadas. Si estos conceptos se han "pegado" es porque manejar el nivel de cambio del que hablamos es terriblemente más difícil que vivir en un ambiente calmo y estático creado por requerimientos inamovibles y diseños absolutistas... El problema es que esos ambientes son imaginarios, y tienden a explotar dejándonos frente a la cruda realidad: el negocio cambió y los requerimientos son diferentes, las nuevas tecnologías han vuelto obsoleto al diseño, y la realidad ha ridiculizado las planificaciiones.

La dificultad para mantener la organización en medio del cambio continuo puede hacer que la rueda gire fuera de control rápidamente y la curva del costo abandone su reciente placidez buscando de nuevo el techo del gráfico. Cuanto más rápido cambiemos más rápido puede desbocarse el proyecto, si no llevamos al mismo tiempo un estricto control sobre las formas de implementar esos cambios.

Volvemos a las PyMEs. ¿Control y organización para el cambio? Bueno, eso sí suena como una utopía. Pero recordemos la primera parte de este artículo: las herramientas han mejorado enormemente, nuestra comprensión de los procesos de cambio ha mejorado, y no es imposible para una empresa pequeña contar con la tecnología y sabiduría necesarias para llevarlo a cabo.

De todas maneras, ¿existe realmente otra posibilidad? No creo que estemos hablando de una opción. Una consultora puede perder un cliente, un proyecto. Puede darse el lujo ocasional -si bien doloroso- de salirse del presupuesto para enfrentar el costo de un cambio no previsto. Y así y todo son mayoría las consultoras -si no todas a este punto- que han adoptado algún tipo de metodología ágil para muchos de sus proyectos. Es decir, el manejo del cambio ya no es siquiera, como hasta hace algunos años, una ventaja competitiva, sino una característica necesaria para sobrevivir.

En la tercera parte repasaremos brevemente el cómo según Kent Beck (pero no demasiado, ya que él lo hace mejor que yo) y buscaremos un punto intermedio entre los cambios radicales que propone y las "metodologías tradicionales".

lunes, 2 de junio de 2008

Si alguna vez preguntaste...

¿AlGuIeN sAbE PoR qUe Me PaRpAdEa UnA lUz En El TeClAdO?

Si cuando uno hace algo mucho tiempo lo hace cada vez mejor; ¿por qué los taxistas manejan tan mal?

¿Adán y Eva tenían ombligos?

Ésta es tu página.