lunes, 28 de abril de 2003

YAGNI

Hace unos años, cuando cursaba cuarto año de la facultad, participe en un proyecto de desarrollo con unos compañeros.
En aquella época gran parte de mi atención estaba centrada en el diseño orientado a objetos. Probablemente Bertrand Meyer fue el responsable mayoritario de esto. Para ser sincero, en aquel tiempo pensaba que la orientación a objetos podía resolver gran parte de los problemas que aquejaban al desarrollo de software. Me parecía fantástico conceptualmente y me provocaba sorpresa que no toda la gente lo viera como yo.

En aquel entonces programaba en Borland Delphi y era muy entretenido ver en acción la herencia, el polimorfismo y usar la RTTI (run-time type library, similar al concepto de Reflection en Java). Dado este interés, en este proyecto decidimos hacer uso de objetos para modelar las entidades del negocio (clientes, proveedores, facturas).

Pero nos encontramos con el problema de la impedancia entre el modelo relacional y el orientado a objetos; básicamente el problema de traducir los objetos, sus atributos y sus relaciones en tablas y campos. En búsqueda de una manera optima de resolver este problema, leímos todo artículo relacionado con el tema que pudimos encontrar en Internet. Llegamos a la conclusión que debíamos construir una capa de persistencia, un conjunto de clases mediante el cual uno podría manipular objetos, guardarlos y consultarlos sin necesidad de conocer nada acerca de la base de datos. Algo similar a lo presentado por Scott Ambler en The Design of a Robust Persistence Layer For Relational Databases. Recuerdo que desarrollar una capa de persistencia era un problema que me resultaba muy motivante para resolver. Hay muchas dificultades para sortear, muchas decisiones para tomar, muchas características para agregar.

* ¿Cómo manejamos las colecciones dentro de un objeto?
* ¿Qué pasa cuando traemos a memoria 100 objetos desde la base de datos?
* ¿También traemos los objetos relacionados?
* ¿O sólo los construimos por demanda?
* ¿Cómo controlamos la concurrencia?
* ¿Cómo hacemos con los generadores de reportes y otros componentes que generalmente requieren un conjunto de datos con filas y columnas?
* ¿Cómo diseñamos la capa de persistencia para que sea independiente de RDBMS?
* ¿Permitimos uso de transacciones anidadas?

Si, definitivamente era divertido.

Pero estábamos en la universidad. Y las disquisiciones de valor académico que son válidas en ese entorno no lo son cuando salimos de él. El tiempo invertido en aquel proyecto de desarrollo para construir ese framework celestial para guardar objetos representaría un uso ineficiente de recursos para un proyecto real. No contábamos con elementos significativos de retroalimentación (¿qué le importa a un cliente si mapeo una jerarquía de herencia con una tabla o dos tablas?) e invertimos trabajo en funcionalidad que nunca se utilizó.

He observado que en un proyecto de desarrollo se presentan muchas oportunidades para invertir recursos en funcionalidad que no se necesita, aunque estas aparecen de manera sutil, como funcionalidad completamente razonable.

Por ejemplo, pensemos en una aplicación donde se emite un formulario impreso que puede tener dos formatos distintos según la categoría del cliente al que se le envía, "mayorista" o "minorista". Es algo simple de hacer, seria algo así:

if (Cliente = "mayorista") ImprimirFormulario(Formato1)
else ImprimirFormulario(Formato2)


No, mejor guardamos en una tabla con parámetros las categorías de cliente y los diseños de formulario que le corresponden. Al momento de imprimir consultamos la tabla de parámetros y aplicamos el diseño adecuado. Es más, podríamos guardar un template que represente el diseño del formulario en algún formato. Ya sé, ¡en XML! Y podríamos hacer un diseñador de templates donde el usuario podría hacer sus propios formularios y asignarlos a nuevas categorías de clientes si estas surgen en el futuro...

¡¡¡ Y A G N I !!!

Eso gritaría un practicante de Extreme Programming. YAGNI es un acrónimo que significa "You Aren't Gonna Need It" (No lo necesitarás). YAGNI representa la idea: siempre implemente algo cuando realmente lo necesite, nunca cuando supone que lo necesitará.

Ron Jeffries, reconocido desarrollador y pionero en el campo de las metodologías ágiles, lo explica claramente con un ejemplo:
Usted está trabajando en alguna clase. Sólo agrega la funcionalidad que necesita. Supone que va a necesitar algo de funcionalidad adicional. Si no la necesita ahora, no la agregue ahora.

Por qué no?

"OK, Sam, ¿por qué quieres agregarla ahora?"

"Bueno, Ron, nos ahorrará tiempo más adelante."

A menos que tu universo sea muy distinto al mío, no puedes ahorrar tiempo. Sólo puedes hacer menos. Entonces me estas diciendo:

"Vamos a poder hacer menos más adelante (a costo de hacer más ahora)."

A menos que tu proyecto sea muy distinto al mío, ya tienes mucho por hacer ahora. Hacer *más* ahora es algo muy malo cuando ya se tiene mucho por hacer. A menos que tu mente sea muy distinta a la mía, tienes una probabilidad distinta de cero de no necesitar esa funcionalidad después de todo, o de tener que retocarla aún antes de necesitarla cuando modifiques la clase por alguna razón.
Si algo de esto pasa, has desperdiciado tu tiempo completamente, además de asignarte más cosas para hacer ahora, cuando difícilmente necesitas más para hacer.

"Pero Ron, si lo hago ahora sabré como hacerlo, y más adelante tal vez no lo sepa."

"Entonces, Sam, me estás diciendo que la clase que estás escribiendo es tan compleja que ni tú serás capaz de mantenerla?"

Mantenla simple. Si necesitas la nueva funcionalidad, la puedes agregar más adelante. Si no la necesitas, no tendrás que hacer nada de ese trabajo. Tomate el día libre.

Por supuesto, no basta con decir YAGNI para que un elegante diseño evolutivo emerja espontáneamente. Hay dos técnicas fundamentales que hacen posible este diseño evolutivo: refactoring y TDD, temas lo suficientemente interesantes como para dedicarle un espacio en el futuro.

Cada vez que escribo, termino con más preguntas que respuestas. Esta vez no será la excepción.
¿Por qué nos cuesta tanto hacer sólo lo que realmente necesitamos?

viernes, 18 de abril de 2003

Fábricas de software

Imaginemos, por un momento, como sería la empresa de desarrollo de software ideal. Como sería el trabajo en un proyecto en esa empresa. Visualicemos el día a día, los roles, la manera de trabajar...

He notado que muchas personas tienen una visión coincidente sobre la empresa de desarrollo ideal. Piensan que idealmente una empresa de desarrollo debería ser como una fábrica.

Una fabrica de software donde exista un proceso definido y repetible. Las actividades son planificadas y se desarrollan de manera predecible. Un plan inicial es trazado y día a día, los desarrolladores ingresan datos en un sistema que reflejan el avance al minuto. El tiempo es aprovechado al máximo porque se conoce con certeza la precedencia de las actividades, la disposición de recursos, las fechas de entrega. El conocimiento necesario para realizar las actividades esta formalizado explícitamente en documentos y cualquier nuevo componente incorporado al proceso productivo puede contar con esa información para hacer su trabajo. Existen los elementos que permiten medir la productividad de cada uno de los componentes de la fábrica y hacer ajustes donde sea necesario. Se tiene control sobre la calidad de los resultados y la productividad. Control, predecibilidad, certidumbre, calidad.

Una verdadera fábrica industrial de software.

Pero...

Hay otras personas que no creen que la fábrica de software sea posible. Y van más allá, opinan que muchos de los problemas que afronta nuestra actividad surgen del enfoque que pretende estructurar empresas de desarrollo de software como fábricas. Mike Beedle es una de esas personas y dice al respecto:
"Durante 30 años el mundo del software ha sido influenciado por las ideas de la manufactura. Todo esto comenzó cuando gerentes de manufactura tomaron empleos en compañías de desarrollo de software y se le solicito a pensadores de manufactura que pensaran sobre software. Desafortunadamente ellos llegaron con un montón de equipaje de manufactura y tratamos de aplicar las mismas técnicas usadas en manufactura en ese tiempo:

* Procesos estandarizados definidos y repetibles
* Técnicas de TQM[Total Quality Management]
* Gestión voluminosa, donde las entradas y salidas son sólo observadas como hitos de fases.

Desgraciadamente, este paradigma de fabricación no se acomoda demasiado bien al desarrollo de software. En cambio, el software requiere un enfoque mucho más parecido a un proceso de desarrollo de un PRODUCTO NUEVO , porque el software siempre es una combinación de 1) crear nuevos componentes o 2) ensamblar viejos componentes de formas nuevas.
Crear nuevos productos requiere investigación, creatividad y enfoques de prueba/error. Y esto se adapta muy bien al software porque:

detectar requerimientos,
diseñar una solución,
implementarla, y
testearla

requiere investigación, creatividad e implementaciones de prueba/error.
Por otro lado, la mayoría de las veces, estas actividades no llegan en secuencias lineales repetibles -- ellas son simplemente el resultado de inspecciones y pruebas constantes, donde cualquier actividad puede disparar cualquier otra.
Tal así, el software requieren de un nuevo conjunto de practicas y actitud, que permita que el software sea desarrollado en una manera mucho más dinámica, adaptable y auto-organizada."

También se cuestiona la idea de la fabrica de software porque no considera características de las personas, factores principales en el proceso de desarrollo. Alistair Cockburn, en su artículo Characterizing People As Non-Linear, First Order Components In Software Development expresa:
"Quizás más interesante y menos obvio ... es la manera no lineal en que las personas trabajan. Ellos no siguen un secuencia predecible para ir del problema a la solución. Esto es sabido para matemáticos y programadores, quienes se ganan la vida resolviendo problemas. Esto ha mantenido siendo un secreto para gerentes y especialistas en metodologías quienes aún tratan de hacer un proceso de desarrollo de software que sea lineal."

Mas allá de esto, la discusión sobre si se pueden aplicar principios de fabricación industrial al desarrollo de software no es la cuestión central. Pienso que la cuestión central es que queremos mejores resultados, queremos ser más productivos, queremos productos de más calidad.

Un camino de alcanzar esto ha sido observar otras actividades y detectar si hay algo que podamos aplicar en la nuestra. Otro camino posible es observar los proyectos exitosos de nuestra actividad y ver que características tienen para repetirlas en nuevos proyectos. Esto es lo que ha hecho James Coplien.

Analizando un proyecto exitoso

James Coplien escribió el famoso paper Borland Software Craftsmanship: A New Look at Process, Quality and Productivity donde documenta las conclusiones de su estudio del admirable proyecto de desarrollo de Borland Quattro Pro® for Windows (QPW).
"El desarrollo de Borland Quattro Pro for Windows (QPW) es una de las más notables organizaciones, procesos y culturas de desarrollo que hemos encontrado en el proyecto de investigación de procesos Pasteur de AT&T Bell Laboratories. El proyecto asimiló requerimientos, completó el diseño y la implementación de 1 millón de líneas de código, y completó el testing en 31 meses. La programación fue hecha por no más de ocho personas a la vez, lo que significa que la productividad individual fue mayor que 1.000 líneas de código por persona por semana."
"El producto QPW ingresó al mercado con gran aclamación. PC Sources dijo, 'Quattro Pro hace el mejor uso de la interfaz de usuario de Windows que ningún otra planilla de cálculo actual." PC User dijo que 'Quattro Pro for Windows es la mejor planilla de cálculo del mundo' Computer Shopper dijo sarcástico 'Quattro Pro for Windows supera al campeón actual de planillas de cálculo Microsoft Excel 4.0' "

Productividad y calidad impresionantes. Veamos algunos puntos que caracterizaron este proyecto:

* Alta comunicación entre los integrantes del equipo.
"El proceso de QPW tiene una comunicación superior que el 89% de los procesos que hemos observado... Es una organización pequeña e intensamente interactiva"
"El equipo de arquitectura se juntaba diariamente para elaborar las interfaces de las clases en C++, para discutir algoritmos y enfoques globales y para desarrollar los mecanismos fundamentales sobre los cuales el sistema sería construido"

* Equipo pequeño y estable con profesionales expertos en su campo.
"El equipo de desarrollo de QPW tiene una membresía cronológicamente madura para los estándares de la industria... Las personas son incluidas en el equipo por su reconocida experticia en dominios de importancia central para el proyecto: motores de planillas de cálculo, gráficos, bases de datos, y así sucesivamente... Cada uno trae un talento especial para el logro."
"QPW tuvo un equipo principal pequeño --cuatro personas-- quienes interactuaron intensamente durante 2 años para producir la parte principal del producto."

* Desarrollo iterativo.
"El desarrollo de QPW fue altamente iterativo"

* Sin proceso formalmente definido.
"Borland no está sujeto a estándares de proceso ISO 9000, no tiene noción de su valuación SEI CMM, y no es entendido en la jerga de procesos de desarrollo de software siendo usada cada vez más en grandes organizaciones de software...
Aún cuando la organización no tiene un sistema codificado de proceso, es agudamente conciente de lo que hace, como lo hace, y que funciona. Ven el desarrollo de software como algo fundamentalmente conducido por casos especiales (al menos para desarrollo inicial genérico) y la repetibilidad no es una parte importante de su sistema de valores. No obstante los miembros de la organización fueron capaces de articular con gran detalle aspectos de su proceso que demostraron para mi satisfacción que ellos compartían un único modelo, tal vez basado en reglas de desarrollo, de como el desarrollo debe ser realizado."

Un conjunto de personas conformaron un equipo de desarrollo asombroso basados en alta comunicación, retroalimentación constante, idoneidad de sus integrantes y valores compartidos. No eran una fábrica de software.

Conclusión

Pienso en este proyecto y me tomo la libertad de sacar algunas conclusiones rápidas casi imprudentes:
Tal vez no nos hace falta un proceso formalmente definido.
Tal vez no nos hace falta un proceso repetible.
Tal vez no nos hacen falta actividades predecibles.
Tal vez no nos hace falta control absoluto.
Tal vez no hace falta parecernos a una fábrica.
Tal vez simplemente deseamos empresas donde proyectos como el QPW sean posibles, y contar con las personas que lo hagan posible.