viernes, 18 de marzo de 2011

The Mythical Man-Month

Este libro, un clásico de referencia sobre la ingeniería del software, es una colección de ensayos en los que el autor, Frederick P. Brooks, expone sus experiencias como gestor en un gran proyecto de desarrollo.

Aunque se trata de un libro de hace más de 30 años, que refleja experiencias de un proyecto realizado 20 años atrás, este libro sigue resultando valioso. En lugar de centrarse en los ya obsoletos problemas técnicos del proyecto, se centra en los problemas organizacionales de los mismos, y en cómo gestionar a las personas involucradas en ellos.

A continuación, haré un resumen de cada uno de los capítulos que forman parte de este libro:

1. El pozo de alquitrán

Los proyectos de software con como un pozo de alquitrán, en el cual uno se adentra sin darse cuenta y, cuando comienzan los problemas, luchar contra ellos sólo hace que uno se hunda más.

No hay razón aparente para la dificultad de los proyectos, sino un cúmulo factores. Para conocer la naturaleza de este problema es necesario identificar la finalidad de la programación y las satisfacciones y dificultades que entraña.

Existen distintos productos de software en función su usuario final que requiere más o menos diseño, integración o pruebas, e implican diferentes grados de esfuerzo. Un producto que vaya ser usado por otros supone el triple de esfuerzo que un programa de uso privado. Un programa que va a ser usado dentro un sistema supone el triple de esfuerzo que uno que va a ser usado de forma independiente. Estas implicaciones son independientes entre sí, por lo que un producto de software que va a ser usado por sistema cuesta nueve veces más esfuerzo que un programa independiente de uso privado.

La programación proporciona la satisfacción de crear cosas complicadas que sean de utilidad para los demás. Es algo tan maleable que permite hacer casi cualquier cosa. Sin embargo, se sufre la necesidad de perfección y el estar trabajando con objetivos impuestos por otros.

2. El mito del mes-persona

La principal causa de fracaso de los proyectos de software es la desviación respecto a la planificación estimada. Esto se debe al optimismo a la hora de estimar por parte de los programadores, que no tienen en cuenta que las ideas iniciales pueden ser incompletas e incluso erróneas. Además se carece de datos fiables sobre las estimaciones, lo que hace difícil justificar estimaciones que vayan en contra de los intereses del gestor o del propio cliente.

A la hora de estimar, se suele caer en el error de creer que personas y meses son intercambiables. Se olvida que al añadir más personas a una tarea se incrementa el esfuerzo total necesario debido a la necesidad de reorganizar las tareas, de formar a los nuevos miembros y al aumento de la intercomunicación.

La ley de Brooks dice que: “Añadir gente a un proyecto retrasado lo retrasa más”.

Como regla general, Brooks propone repartir el tiempo de un proyecto de la siguiente forma: 1/3 para diseño, 1/6 para la codificación, 1/4 para las pruebas de componentes y 1/4 para las pruebas de sistema.

3. El equipo de cirujía

Los buenos programadores son mucho más productivos que los malos. Además, los equipos, cuanto más pequeños sean menos los problemas de intercomunicación tendrán.

Hay que favorecer el trabajo de los buenos programadores simplificando la comunicación dentro del equipo.

Los equipos pequeños son demasiado lentos para realizar grandes sistemas y, por otra parte, un equipo de mucha gente es costoso, lento e ineficiente, y produce sistemas que no están conceptualmente integrados.

Una solución es tener un equipo organizado en torno a un programador jefe a quien da apoyo, de la misma manera que un equipo de cirugía. De esta forma se logra mantener la integridad de un producto de un número reducido de mentes con la ayuda de unos cuantos colaboradores, reduciendo la comunicación de forma radical.

4. Aristocracia, democracia, y diseño de sistemas

La consideración más importante en el diseño de un sistema es preservar la integridad conceptual. La integridad conceptual otorga mayor facilidad de uso, y permite construir y probar el sistema más rápidamente.
Para lograrla, el diseño debe ser fruto de una sola mente o de un grupo reducido de mentes que están de acuerdo. La separación entre arquitectura e implementación es la forma de conseguir esta integridad conceptual en sistemas grandes.

Alguien debe controlar los conceptos fijando la arquitectura, pero ello mejora la creatividad en la implementación, puesto que permite enfocar el esfuerzo.

De cualquier manera, arquitectura (requisitos), implementación (diseño) y realización (programación) pueden discurrir en paralelo.

5. El efecto del segundo sistema

Una buena comunicación puede dar al arquitecto una lectura adecuada de los costes y al constructor confianza en el diseño, sin difuminar la clara división de responsabilidades entre ellos.

Para que el arquitecto pueda influir con éxito en la implementación debe tener en cuenta que:
  • Es el constructor quien tiene la responsabilidad de la implementación. El arquitecto solo sugiere.
  • El arquitecto debe ser capaz de sugerir una forma de implementar lo que especifica, pero debe estar preparado para aceptar cualquier otra forma igualmente válida.
  • Debe escuchar las sugerencias del constructor para mejorar la propia arquitectura.

El segundo sistema es el más peligroso, porque se tiende a sobrediseñarlo. Asignar a priori valores de memoria y tiempo para cada función ayuda a detectar el sobrediseño durante la implementación.

6. Pasar la Palabra

A la hora de redactar el diseño de un sistema, por grande que sea, es mejor que lo hagan pocas personas (preferiblemente una) para que el resultado sea consistente.

Se necesita tanto una descripción formal que aporte precisión como una descripción en prosa que aporte claridad. Una de ellas debe ser la de referencia y la otra servir como apoyo. Utilizar una implementación como definición es una fuente de problemas.

Es importante registrar y publicar todas las consultas de los desarrolladores a los arquitectos.

7. ¿Por qué cayó la Torre de Babel?

Si no hay comunicación cada uno hace sus propias suposiciones, provocando retrasos, desajuste funcional y errores en el sistema. Los equipos de deben comunicar de todas las formas posibles, tanto informal como formalmente.

Se debe especificar cuanto antes el conjunto de documentos a través de los cuales se producirá la comunicación formal en el proyecto. Esta documentación debe estar al alcance de cualquier miembro del equipo. Se debe actualizar constantemente y resaltar los cambios realizados respecto a la última versión.

Sin embargo, Parnas propone que nadie debe ver las interioridades de ninguna otra parte que no sea aquella en la que se está trabajando. Sólo se deben publicar las interfaces.

La organización debe encargarse de reducir la cantidad de comunicación y coordinación necesaria, mediante la división de tareas y la especialización en las funciones.

En cada proyecto se deben establecer dos roles, el productor y el arquitecto o director técnico, que requieren de distintas habilidades.

8. Apuntando para disparar

No se puede estimar el esfuerzo total de un proyecto estimando el tiempo de codificación y extrapolándolo a las demás tareas.

Tampoco sirve extrapolar la construcción de pequeños sistemas a proyectos de sistemas. El incremento en el esfuerzo es una potencia del tamaño del proyecto.

Hay estudios que dicen que los programadores sólo dedican el 50% de su tiempo a la programación y el resto a otras tareas.

Otros estudios sobre la productividad indican que ésta se mantiene constante en términos de secuencias elementales. La productividad se incrementa por 5 cuando se pasa a usar un lenguaje de alto nivel.

9. 10 libras en una bolsa de 5

Además del tiempo de ejecución, el espacio de memoria que ocupa un programa es su coste principal. Se deben establecer límites de tamaño en cada función para que los costes no se disparen.

Durante la implementación, los arquitectos deben velar por la continuidad de la integridad del sistema.

Para poder hacer un buen balance entre tiempo y espacio, el equipo debe estar entrenado en las peculiaridades del lenguaje de programación y de la máquina que se están usando.

Todo proyecto de programación necesita una librería de componentes estándar.

Los programas sencillos y rápidos son resultado de la innovación estrategia más que de una buena táctica. Esto se puede lograr a través del uso de un nuevo algoritmo o de rehacer la representación de los datos.

10. La hipótesis documental

Sólo unos pocos de todos los documentos del proyecto son el eje sobre el que gira toda la gestión del proyecto: objetivos, manual, calendario, presupuesto, diagrama de organización y situación física de los miembros del equipo.

El gestor debe formalizar este conjunto de documentos. Mantener estos documentos proporciona un mecanismo de vigilancia y alarma.

El gestor debe encargarse de que todo el mundo vaya en la misma dirección a través de la comunicación, y no tomando todas las decisiones. Solo una pequeña parte de las tareas del gestor están relacionadas con información que está fuera de su mente.

11. Planea deshacerte de uno

Cuando se pasa de un entorno protegido a uno de producción es necesario un paso intermedio de prueba. Al probar el primer sistema construido se suele comprobar que éste es demasiado lento, grande o difícil de usar, y que debe ser rediseñado.

Este rediseño se puede hacer de golpe o pieza a pieza, pero habrá que hacerlo de todas formas. Si se entrega el primer sistema, esto será en detrimento del usuario y del desarrollador que lo debe mantener. Por tanto, debe incluirse en la planificación el rediseño de la primera solución.

Las necesidades del cliente y la percepción de las mismas cambiarán a medida que avanza el proyecto. La maleabilidad del software hace que los requerimientos no dejen de cambiar porque los cambios se presuponen fáciles. Algunos de estos cambios son válidos y hay que estar preparados para poder afrontarlos. Las técnicas que nos permiten hacer esto son conocidas pero no son usadas.

Los esfuerzos de los desarrolladores son tentativas de satisfacer los requisitos, sujetos a modificaciones y, por tanto, hace que sean reacios a documentarlos.

Para acomodar una organización al cambio los miembros de los equipos de ben ser intercambiables y reubicables, tanto en la parte de gestión como en la técnica. Una posible solución es la propuesta organizar el equipo en torno a un programador jefe.

El mantenimiento del software consiste principalmente en reparar defectos de diseño, añadir nuevas funcionalidades y adaptarse a los cambios en el entorno o la configuración. El coste de mantenimiento de un programa es aproximadamente el 40% del coste de su desarrollo.

El número de errores encontrados aumenta con el número de usuarios. El número de errores a lo largo de la vida de un proyecto primero aumenta y luego se estabiliza.
Al corregir un error existe una alta probabilidad de introducir otros, por los que se debe disponer de casos de prueba que aseguren que esto no se produce.

Durante la vida de un proyecto el número de módulos se incrementa de forma lineal, pero el número de módulos afectados por las modificaciones se incrementa de forma exponencial. Toda corrección tiende a romper la estructura e incrementa la entropía y el desorden del sistema. Inevitablemente, se llegará a un punto donde la mejor solución es el rediseño.

12. Herramientas precisas

Todo proyecto necesita herramientas personalizadas, por lo que el gestor debe establecer la filosofía para establecer los recursos necesarios para su construcción.

Es necesario instrumentalizar las máquinas sobre las que se va probar para poder extraer resultados de ellas. A la hora de probar en la máquina es mejor repartir periodos separados de tiempo para los distintos miembros.

La documentación voluminosa introduce mayor complejidad al proyecto.

Se debe construir de forma temprana un simulador de rendimiento que analice el programa desde fuera, y hay que prestar atención a lo que dice.

Las mejores herramientas que existen actualmente (1975) son los lenguajes de alto nivel (aumentan el rendimiento y facilitan la depuración) y la programación interactiva (reduce el tiempo de respuesta en la depuración).

13. El todo y las partes

Una buena arquitectura hace que un sistema sea más fácil de usar, más fácil de construir y que tenga menos errores. Antes de empezar la construcción se debe entregar las especificaciones al grupo de test, que debe comprobar si está completa y es clara.

Diseñar de lo general a lo específico refinando la especificación paso a paso reduce los errores y permite volver atrás cuando sea necesario. Hay que usar una notación de tan alto nivel como sea posible en cada paso.

La programación estructurada es el diseño de programas formados por un conjunto reducido de estructuras de control.

Se demuestra que en la primera interacción de depuración se un progreso hace tres veces mayor que en las subsecuentes. La depuración de un sistema siempre lleva más tiempo de lo planeado.

Se debe empezar la depuración sólo cuando las piezas parezcan funcionar, en vez de adelantarlo a cuando se hayan detectado errores pero sigan sin ser corregidos.

Merece la pena construir código de apoyo para la depuración, que puede llegar a ser el 50% del código a depurar.

Durante la depuración se deben añadir los componentes de uno en uno. Es mejor introducir grandes cambio de forma poco frecuente porque esto introduce menos inestabilidad.

14. Vislumbrando una catástrofe

Los proyectos se retrasan día a día. Esto es difícil de reconocer, de prevenir y de arreglar. Para poder controlar un proyecto es necesario tener un calendario con hitos concretos y bien definidos y fechas identificables.

Diversos estudios han demostrado que las estimaciones no suelen variar hasta el arranque del proyecto, posteriormente se van reduciendo las sobreestimaciones y, tres semanas antes del fin estimado del proyecto, lo que cambian son las infraestimaciones.

La planificación de ruta crítica permite identificar que desviaciones son las que realmente importan. Se debe identificar esta ruta crítica lo antes posible.

Todo jefe necesita ser alertado de las excepcionen que precisen de acciones correctoras y que se muestre el estado del proyecto para su conocimiento. Esto es difícil puesto que los subordinados temen la intromisión del jefe en sus responsabilidades. Se debe disponer de técnicas de revisión que ofrezcan el estado del proyecto a todo el mundo.

15. La otra cara

La documentación para el usuario es tan importante como el propio producto. Es importante también para el autor como memoria de lo que se ha hecho.

Por regla general no se entrega una buena documentación porque no se ha instruido a los desarrolladores en cómo hacerlo de forma efectiva y económica.

La documentación crítica para el usuario se debe establecer antes de la construcción ya que contiene decisiones de planificación básica.

A nivel de documentación interna, para mantener la documentación actualizada es necesario incorporarla junto con el código fuente. Se debe explicar por qué las cosas son como son, no solamente cómo están hechas. Los lenguajes de alto nivel permiten técnicas de auto-documentación dentro del propio código.

16. No hay balas de plata – Esencia y accidente

El autor compara el desarrollo de software con los hombres-lobo, gente normal que se convierte de repente en algo fuera de control que solo pueden ser eliminados con una bala de plata. Sin embargo, no existen balas de plata para el software que den una mejora de un orden de magnitud en su desarrollo, aunque existen innovaciones que de forma conjunta sí pueden ofrecer esta mejora.

La construcción de software implica tareas complejas, acomodar sus estructuras conceptuales, y tareas accidentales, representarlas en lenguajes de programación.

Las dificultades esenciales del desarrollo de software son la complejidad, conformidad, variabilidad e invisibilidad a la hora de acomodar las complejas estructuras conceptuales que implica.

El desarrollo de software también implica tareas accidentales, que son la representación en lenguajes de programación.

Las mejoras de los últimos tiempos han estado enfocadas en solucionar las dificultades accidentales a través de:
  • Lenguajes de alto nivel.
  • Tiempo de ejecución compartido.
  • Entornos de programación unificados.

Sin embargo, la mayor parte del tiempo se dedica a acomodar estructuras conceptuales abstractas de gran complejidad y, por tanto, es esta tarea esencial la que se debe atacar. Se han propuesto las siguientes formas:
  • Avances en lenguajes de alto nivel.
  • Programación orientada a objetos.
  • Inteligencia artificial.
  • Sistemas expertos.
  • Programación automática.
  • Programación gráfica.
  • Verificación de programas.
  • Entornos y herramientas de trabajo.
  • Estaciones de trabajo.

Estas alternativas, aunque introducen mejoras, no han alcanzado los niveles esperados. Es necesario atacar la esencia del software elevando el nivel de abstracción que implica su desarrollo. Los avances más prometedores en este sentido son:
  • Comprar en lugar de desarrollar.
  • Refinado de requisitos y prototipado rápido.
  • Desarrollo incremental.
  • Encontrar y educar a los mejores diseñadores.


17. “No hay balas de plata” revisado

En este capítulo el autor rebate las críticas recibidas al artículo presentado en el capítulo anterior “No hay balas de plata”. Sobre todo aquellas que van contra el principal argumento del mismo (que no hay ningún avance en el mundo del software que pueda dar por sí solo una mejora de n orden de magnitud), para presentar la propia bala de plata de cada investigador de turno.

El autor se reafirma en la idea de que la complejidad es la mayor dificultad inherente al software, aunque la mayor parte de esta complejidad se suele deber a problemas de organización de la propia realidad que se intenta modelar. Esta complejidad se puede atacar aumentando el nivel de abstracción de los elementos utilizados y manteniendo en todo momento sistemas que funcionen y que incorporen nuevas funcionalidades de forma incremental.

Se introduce el enfoque a la calidad, que aumentaría de la productividad reduciendo el tiempo dedicado a la corrección de errores.

La productividad también aumenta con mejores equipos y herramientas de trabajo y el uso de la programación orientada a objetos (que promueve la modularidad, la encapsulación, la herencia y el tipado de datos). Aunque se lamenta de la poca introducción de la orientación a objetos y la reutilización.

18. Proposiciones de “El mito del mes-persona”

Este capítulo muestra una recopilación de las afirmaciones expuestas en el libro a modo de resumen.

19. “El mito del mes-persona” 20 años después

Este capítulo es una revisión del libro hecha tras 20 años por el propio autor. En ella expone los argumentos que mantiene tras este tiempo y aquellos en los que ha cambiado de opinión.

El autor mantiene que la integridad conceptual es el factor más importante para la facilidad de uso de un sistema. Esta integridad conceptual suele lograrse cuando el producto ha sido diseñado por una única persona, pero este enfoque no es productivo para grandes sistemas que sufren presiones competitivas.

En estos entornos es necesario tener un arquitecto (o un grupo de ellos organizados de forma jerárquica) que se encargue de la integridad conceptual de todos los aspectos del producto percibibles por el usuario. Además sus tareas estarán separadas de la implementación.

Otro peligro que se recalca en el desarrollo de sistemas es el de cargarlos de funcionalidades de mínimo valor que compliquen el diseño y el uso de los mismos. Se debe ser consciente de quienes son los usuarios y ponderar las nuevas capacidades que se introducen en función del mayor valor ofrecido al mayor número de usuarios.

En lo que sí cambia de opinión es en el consejo de que el primer sistema implementado deba ser desechado. Esto era una consecuencia de la aplicación del desarrollo en cascada, que asume que los pasos del proyecto avanzan uno a continuación de otro, y supone que todos se realizan de forma correcta. El sistema se construye de una sola vez y se asume que todos los errores se introducen en la implementación.

Un modelo de desarrollo incremental permitiría el refinamiento progresivo del sistema. Se puede construir un sistema inicial de funcionalidad limitada y, a partir del cual hacer crecer el sistema introduciendo nuevas funcionalidades. De esta forma se pueden adelantar las pruebas del sistema y se puede entregar un sistema que funciona cuando sea necesario, aunque de funcionalidad reducida.

En cuanto al ocultamiento de información que Parnas proponía y del que el autor desconfiaba, éste se retracta y asume que los programadores son más efectivos si no están expuestos a las interioridades de módulos que no son de su propiedad.

El avance en el desarrollo del software se producirá al aumentar el nivel de abstracción de los elementos que se utilizan. En este sentido se han dado los siguientes pasos:
  • La definición del ocultamiento de información de los módulos hecha por Parnas.
  • La aparición de los tipos de dato abstractos de los que pueden derivar otros objetos.
  • La programación orientada a objetos.

El hecho de disponer de clases diseñadas y probadas para ser reutilizadas es lo que permitiría elevar dicho nivel de abstracción.

La Ley de Brooks (añadir más gente a un proyecto retrasado lo retrasa más) ha sido refinada gracias a varios estudios, aunque se mantiene como una buena aproximación a la realidad. En realidad, añadir más gente a un proyecto retrasado aumenta su coste, pero no siempre lo retrasa.

Otra idea que se ha reforzado durante este tiempo es la importancia de las personas que forman parte de los proyectos, y cómo los factores humanos deben ser tomados en consideración. Es importante dar responsabilidades a la gente y no centralizar todo en una única entidad, puesto que esto fomenta la creatividad.

Se hace eco del avance en el campo de la informática y de la explosión del número de ordenadores. Esto ha cambiado la forma de desarrollar el software y creado una nueva industria, los programas empaquetados.

Respecto al futuro de la ingeniería del software, presume que, a través del conocimiento, será capaz de lidiar en el futuro podrá con la complejidad del comportamiento humano y los aspectos no lineales que introduce.