Thursday, July 24, 2008

Llave en mano

Al menos en mi experiencia y entorno, los proyectos llave en mano son comunes. Me refiero por proyectos llave en mano a esos donde se compromete un precio y calendario con el cliente, y luego de ganar algo así como una compulsa de precios, comienza el desarrollo del software.

Estimar correctamente es un punto clave en este tipo de proyectos: una mala estimación hace perder dinero, tiempo, enojar al cliente por problemas de calendario y todo eso lleva a una caída en la calidad que aumenta los costos y hace enojar aún más al cliente.


Scott Ambler tiene una
opinión bastante clara y razonada sobre los proyectos llave en mano. Ambler dice cosas ciertas: este tipo de proyectos te lleva a escribir todos los requerimientos de entrada, a pensar un diseño y una arquitectura y a implementar un mecanismo bastante restrictivo de gestión del cambio. Todo eso herético desde el punto de vista del desarrollo ágil. Yendo un poco más allá de mi último comentario, algo improcedente y sarcástico, se puede argumentar con razonable facilidad que intentar elucidar todos los requerimientos y pensar una arquitectura de un software que no existe antes de hacer siquiera una parte es una estrategia que traerá problemas, más temprano que tarde.

Por otra parte, no es un secreto que las estimaciones hechas a priori suelen diferir bastante del esfuerzo finalmente necesario.

Por eso, puedo estar de acuerdo con que la idea del proyecto cerrado es una idea perniciosa (puedo pensar en más de un ejemplo donde todos pierden: el cliente queda disconforme y el proveedor gastó más de lo que había proyectado).

Mirando desde el otro lado, si pensamos como el cliente, no es difícil entender por qué se desea saber por adelantado cuanto va a salir la joda: vamos, quien contrataría a un arquitecto (de casas y edificios) que dijera 'bueno, a medida que me vas pidiendo que construya algo en la casa, que agregue algo, te voy diciendo el precio'?. No vale argumentar que una casa es diferente al software, estoy hablando de dinero, que es bastante parecido en todos los ámbitos: quien se embarcaría en un proyecto sin tener idea de cuanto saldría y sin tener al menos la expectativa de tener dinero suficiente para no ahogarse a la mitad del río?. Yo no.


Aunque, como comenta Ambler, los proyectos cerrados puedan ser caros para el cliente porque el proveedor no tiene más remedio que cotizarle el riesgo e implementar algún mecanismo de control de cambio (efectivamente, como él dice, son mecanismos que tratan de impedir el cambio y no controlarlo). Más aún, con un mecanismo eficaz para impedir el cambio es altamente probable que el sistema construido diverja de las necesidades del usuario. Pero aún así, la previsibilidad financiera ( saber de antemano cuanto me va a costar) es terriblemente atractiva. Lo que se está pagando (lo que tanto cliente como proveedor están pagando), es la falta de información.

Se podría contra-argumentar que la idea de una metodología con foco en el control de cambios no es impedir el cambio, sino cobrarle al cliente por el mismo. No está mal, en definitiva, y eso nos acercaría a una estrategia ágil, donde ante cada cambio cobraríamos el diferencial de implementarlo ( costo de implementar lo nuevo menos el costo de no implementar lo que ya es necesario y no está implementado), lo que, incluso, penalizaría el cambio en etapas tardías del proyecto. Estaría incluso mejor si pudiéramos definir claramente, y por adelantado, qué es un cambio: no se puede cambiar lo que no se definió y el problema, muchas veces, no es que se haya definido un aspecto de un desarrollo en forma errónea, sino que no se lo ha definido de ninguna manera.


Claramente, necesitamos una solución. La solución ideal: que la industria se aleje de los proyectos cerrados, que el cliente nos contrate un equipo determinado por un tiempo pre-acordado y que adoptando el ciclo de vida de XP trabajemos haciendo lo que el cliente pide: pide más, hay más iteraciones. El problema es que parece demasiado bueno para nosotros, los informáticos, como para que se transforme en una práctica muy extendida.

A mitad de camino, tenemos la 'gestión de aplicaciones', o el servicio donde uno como proveedor implementa requerimiento a requerimiento. Es una buena idea, pero se necesita una confianza importante en la performance del equipo del proveedor. No es algo que un cliente le contrataría a un proveedor que recién conoce, me parece. Tampoco es, entiendo, demasiado común para desarrollos desde cero, sino que se adapta mejor a mantenimientos evolutivos y correctivos, donde, en definitiva, es más fácil estimar el esfuerzo de cada modificación.


Yo me imagino que la solución debería venir por alguna forma estándar en la industria de medir la performance de los grupos de trabajo en algo así como unidades estándares de software (que no sean lineas de código, por supuesto) producidas por unidad de tiempo. Volviendo al ejemplo del arquitecto ágil (el de casas y edificios) citado más arriba, creo que tal vez lo contrataríamos si pudiéramos acordar entre ambos, antes de comenzar el proyecto, una forma transparente de estimar los costos: nos aseguraremos que el arquitecto no se va a aprovechar de nuestra situación cuando sea muy caro abandonar el proyecto o cambiar de caballo. Que forma tendrían esas 'unidades estándares de software' (no de trabajo, sino de software)? Ni idea.

Tuesday, July 22, 2008

El objeto del negocio

rito (Del lat. ritus).
1. m. Costumbre o ceremonia.
2. m. Conjunto de reglas establecidas para el culto y ceremonias religiosas.

Siempre es peligroso entregarse al mito, pero más aún en los momentos de entusiasmo.
Comisario Inspector Díaz Cornejo
(citado por Leonardo Moledo en 'Los mitos de la Ciencia')



Los ritos y los mitos se mezclan de muchas maneras. Se podría decir que éstos dan origen a aquellos. Es divertido repasar mitos ajenos, como hace el libro de Moledo citado más arriba. Y es un poco inquietante descubrir que los mitos ajenos no no son tan ajenos, como nos recuerda el libro de Moledo citado más arriba.

Los ritos, en la primera acepción según la RAE, pueden ser útiles como una forma de adquirir hábitos benéficos sin que tengamos que detenernos a pensar en su beneficio. Diríamos que lo bueno de los ritos es que pueden lograr que un tonto se beneficie sin que tenga que entender por qué, ni como sucede.

Este efecto benéfico de la ritualización no fue el que había dejado su huella en la aplicación que aceptamos para mantenimiento correctivo y evolutivo (aceptamos es un abuso de la primera persona ni yo ni mis compañeros galeotes decidimos nada), sino más bien todo lo contrario. Digamos que lo que observamos fue el efecto más usual del reemplazo del pensamiento por la ritualización: algo así como el desastre. Podemos rastrear el mito que da origen a los ritos practicados en el diseño de la aplicación de marras, pero eso vamos a dejarlo a los antropólogos.

La gente que escribió esta aplicación era gente de principios. Con convicciones muy firmes. Idealistas. Sabían que había que tener tres capas: presentación, lógica, y datos, a como diera lugar. Su esfuerzo patriótico no iba a cejar simplemente porque no tuviera sentido hacerlo, no. Ellos tenían certezas, y por sobre todo la certeza de que la duda es la jactancia de los intelectuales.

Así, por ejemplo, los objetos de la capa de lógica de negocio son cosas del estilo:

public class CuentaServ implements CuentaServInt {
   CuentaDao cuentaDao;

   public void almacenarCuenta(Cuenta c)
   {
      cuentaDao.almacenar(c);
   }

   public Cuenta obtenerCuentaPorId(int id)
   {
      return cuentaDao.obtenerCuentaPorId(id);
   }

   [...]

}


Cualquier hereje podría preguntar para qué tienen una clase donde todos los métodos tienen una sola linea. Qué valor agrega. Para qué sirve. Pero no ellos: ellos eran gente de fe, gente que sabe que el
progreso humano es una ilusión, que el secreto de la felicidad está en copiar exactamente la conducta de nuestros ancestros, que vivieron armonicamente en una época de sabiduría que nosotros arruinamos con la costumbre de someter su legado a escrutinio crítico.

Mi primera impresión fue decidir que si una clase tiene solo métodos de una linea, si es solo un pasamanos, probablemente no tenga ningún sentido. Al fin y al cabo, si la aplicación no tiene reglas de negocio, no debiera tener una capa que implemente la lógica de negocio.

Pero, vamos a ver: que aplicación no tiene lógica?. Es decir, la lógica en la aplicación es algo que existe, si no está implementada tal vez simplemente no esté implementada. Por ejemplo, dar de baja una cuenta sin preguntar nada suena por lo menos extraño. Asignar un nuevo paquete de servicios a un cliente sin verificar algunas condiciones antes, también.

Me estaba desesperando, cuando encontré métodos de Business Objects que sí tenían más de una linea de código. Un alivio. El patrón estaba justificado. Al final, me decía la vocecita esa que siempre escucho (no, no es la conciencia, es un enanito que se sienta sobre mi hombro y que solo yo veo, porque él tiene poderes mágicos), viste que tenía motivos, que no sos tan vivo como crees?. Acá está la prueba:

public List obtenerCuentasEnRojo()
{
   List l = cuentaDao.obtenerCuentasEnRojo();
   for (Iterator it = l.iterator(); it.hasNext();)
   {
      Cuenta cu = (Cuenta)it.next();
      Cliente c = cu.getCliente();
   }
   return l;
}


Esto se ponía bueno: el críptico cu.getCliente() era para forzar a hibernate a buscar el cliente en la base de datos. Algo doblemente bueno, ya que hacía a mano lo que podía hacer en un join, transformando una única query en tantas como cuentas se obtengan, impidiendo el ordenamiento por nombre si es que se pagina el resultado y, como extra y por el mismo precio, haciéndolo antes de forma que la vista no dispare algún query de hibernate, cosa que se podría haber solucionado con un open session in view (está implementado en Spring)

De la colección de errores, mi preferido es el evitar escribir el join en la base de datos. Debo admitir que la alegria de ver el patrón justificado se vio algo perturbada por el hecho de que implementar a mano un join es una de las cosas más estúpidas que se pueden hacer: es más trabajoso (uno paga dos veces, una por el motor de la base y otra por las horas de desarrollo), suele quedar con más bugs que los que trae el join en la base de datos, tardar más, ser más vulnerable a cambios en el volumen de datos, es más dificil ordenar y paginar por algún atributo de la segunda tabla, y unas cuantas cosas más.

Subyacen a estas prácticas unos cuantos mitos y esperanzas descabelladas: portabilidad entre base de datos (mi preferida, merecedora de un post enteramente dedicada a ella), adaptación al cambio (sí, es muy fácil adaptar un montón de código innecesario), prolijidad (que alguien me explique como se mide). Tal vez, al fin y al cabo, viendo las esperanzas descabelladas que sobreviven por ahí afuera en cuestiones algo más trascendentes que un business object, no tengamos derecho a esperar que estas, nuestras esperanzas descabelladas, desaparezcan en un futuro cercano.

Monday, July 7, 2008

Métricas, procesos y de como se juntan

"Les recomiendo hacer este estudio si y solo si van a tomar conducta a partir del resultado", nos dijo hace un tiempo el médico genetista. a mi pareja y a mí, cuando estábamos iniciando los trámites para un estudio genético invasivo que entrañaba cierto riesgo.

Este buen doctor podría dedicarse a la consultoría en informática, o, al menos, podría aportar su criterio en lo que refiere a la definición, recolección e interpretación de métricas de procesos. Su criterio es simple y útil: uno no debería medir algo si luego no piensa hacer nada con esa medición. Las métricas que se recolectan pueden no ser útiles hoy, pero debería existir al menos expectativas de usarlas en un futuro, y estas expectativas deberían ir acompañadas de alguna idea de como se espera que sean útiles. Más allá del abuso de su jerga médica (en castellano, lo que él dijo se diría más o menos como "si no van a hacer nada con el resultado, les recomiendo no hacer este estudio ya que entraña algún riesgo") su idea es aplicable a casi cualquier ámbito, con excepción, quizá, de la ciencia básica.


La respuesta a la pregunta sobre que métricas se deben recolectar en un proceso de desarrollo de software es sencilla: las que sean útiles para tomar decisiones. Lo que es un poco más complicado es la instrumentación de esta respuesta. Vamos a tratar de aplicar una variación libre del método GQM, que, como todo, tampoco es rocket science. Un mapa de ideas siempre es bueno para ordenar las idem:

Lo que se desea, basicamente, es ganar dinero. La rentabilidad en un proyecto de software se puede ver amenazada por una mala estimación inicial ( los proyectos a precio cerrado tienen sus problemas, como bien nota Scott Ambler, pero son la forma más común hoy, al menos en el entorno donde yo me desenvuelvo. Será tema para otro post), por retrabajos (generados por mala calidad de lo producido o por cambios en los requerimientos) y retrasos en el calendario que, además de posibles multas, entorpecen la disponibilidad de las personas del equipo de trabajo y los recursos asociados.

Después de mucho pensar (o de poco pensar pero durante mucho tiempo), derivé un conjunto de métricas con las que me siento cómodo:
  • Cantidad de defectos, desagrupados por etapa del proyecto (cuando antes se producen, peor es) y tipo de entregable (defecto en software, en especificación funcional, en especificación técnica, o en el proceso mismo). Asimismo, me interesa el tiempo promedio de solución de un defecto.
  • Sobreesfuerzo generado por defectos, es decir, el esfuerzo necesario para corregir los defectos, desagregado por actividad.
  • Cantidad de cambios a los requerimientos, también desagrupados por etapa del proyecto y cantidad de cambios aceptados y rechazados.
  • Velocidad de avance del equipo, medida por la cantidad de historias del usuario o de requerimientos implementados por unidad de tiempo y como avance ganado, definido como tiempo insumido / (tiempo insumido + tiempo estimado para completar ).
  • Milestones cumplidos en tiempo, demorados y demora promedio.
  • Cantidad de cambios al plan del proyecto, y el motivo de los mismos (cambios a los requerimientos, cambios a la dotación del equipo de trabajo, errores en la estimación).
  • Desvío de la estimación original, por componente y actividad, para lo cual el sistema de registración de horas está alineado con la forma de estimar: se imputan horas con el mismo concepto y granularidad con que se estima el proyecto.
Es probable que al mapa le falten algunos objetivos (será más fácil ganar dinero si entrego un software que le entregue valor al usuario, no simplemente algo que cumpla con las especificaciones, por ejemplo), y seguir el rastro de esos objetivos probablemente nos agregue nuevas métricas.

Por otra parte, tengo un conjunto de métricas, las que por ahora no son útiles, pero espero poder utilizarlas en el futuro:
  • Cobertura de código por el testing: en entornos manejados (java, .net), asociado al proceso de integración continua, se mide el porcentaje de código cubierto por las pruebas unitarias y de regresión. Mi esperanza es, en algún momento, relacionar esto con la cantidad de bugs detectados por los procesos de prueba y certificación del usuario, para derivar un valor que minimice la suma entre el esfuerzo necesario para corregir bugs y el esfuerzo de construcción de pruebas unitarias y de regresión.
  • Cantidad de no conformidades detectadas por las herramientas de inspección automática, como PMD, Checkstyles, FxCop, Macker, con la misma esperanza que ya mencioné para la cobertura. Relación entre puntos de caso de uso y horas por actividad: guardo la esperanza de construir una base de datos lo suficientemente grande que pueda servirme de base para hacer una estimación por puntos de caso de uso.
  • Métricas de complejidad y tamaño de la solución, como cantidad de clases, paquetes, componentes desarrollados sobre los especificados. Aquí la idea para el futuro es poder determinar cuantitativamente cuan confiables son mis espeficiaciones técnicas y cuanto del producto real terminan por cubrir.
  • Espero poder madurar las métricas de defectos, para relacionarlas con la cantidad de pruebas realizadas y determinar si el no encontrar más defectos significa que el producto está estable o no se están buscando correctamente y armar tendencias de ocurrencias de errores.
De todas maneras, y como resumen, vale la pena recordar el concepto que vertió el buen doctor que nos atendió: el esfuerzo de recolectar una métrica sirve si ésta puede servir de base para una toma de decisión. Y por cierto, el objetivo de estas métricas (o de cualquier otras) no es cumplir con CMMI, signifique esto lo que signifique, sino dar información útil, que sirva para tomar decisiones, sobre la performance del proceso y el estado del proyecto.