domingo, 21 de julio de 2013

Hace un tiempo leí este maravilloso post: http://me.veekun.com/blog/2012/04/09/php-a-fractal-of-bad-design/ es un poco viejo, y ya paso su cuarto de hora en Internet, pero en su momento me impactó lo suficiente como para no solo leerlo, sino traducirlo (dos veces... ¡ya no se me olvida salvar mi trabajo!) y lo publiqué en mi Universidad. El efecto fue... interesante :) Como sea, aqui les dejo mi versión de aquel post, traducida, decorada, aumentada y un poco más moderna. Enjoy... PHP: Un fractal de mal diseño

viernes, 10 de julio de 2009

La complejidad como propiedad esencial del software

Décadas han pasado desde la primera publicación del artículo de Brooks, No Silver Bullet, en 1986. Desde entonces la tecnología informática ha hecho grandes avances: se han realizado descubrimientos científicos impresionantes, la ley de Moore ha funcionado para asombro de muchos, las técnicas y los conceptos de desarrollo y administración de software no recuerdan en nada aquellas aplicadas décadas atrás. Sin embargo, las tasas de éxito de los proyectos de software no se han incrementado de forma exponencial como podría deducirse de los avances logrados tanto en el desarrollo de software como en el hardware.

Es seguro suponer entonces que existen factores que no estamos contemplando a la hora de analizar los resultados del proceso de desarrollo de software, y que esperar sorprendentes avances debido a la aplicación de tecnología y personal no es realista. Estos son los conceptos que intentaremos rescatar del escrito de Brooks, a pesar de que muchos consideren que los libros técnicos en nuestra profesión ya no tienen valor pasados un par de años.

Debemos comenzar por decir que, a pesar de lo dicho anteriormente sobre la falta de aumento exponencial en las tasas de éxito de los proyectos informáticos, dicho aumento sí existe, consecuencia de la aplicación de las técnicas y de la experiencia acumulada.


Quizás, y después de todo, el avance en orden de magnitud esperado por Brooks sí se ha logrado, enmascarado en alguna de las innumerables innovaciones que sufre nuestro campo diariamente. Decimos quizás porque dicho avance no es como cualquier avance que estemos acostumbrados a observar. En las palabras de Brooks:

“(…) El primer paso para el manejo de las enfermedades fue el reemplazo de las teorías de influencia demoniaca y de los humores corporales por la teoría de los gérmenes. Este paso particular constituyó el comienzo de toda esperanza, al desplazar automáticamente todas las soluciones mágicas. Demostró que el progreso se alcanzaba paso a paso y con gran esfuerzo, y que debía prestarse un cuidado persistente a una disciplina estricta de limpieza (…)”

Es esto precisamente lo que Brooks considera un orden de magnitud, un cambio cualitativo y pivotal en la forma en que se desarrolla una disciplina. El tener diligencias más rápidas todos los años no constituyó un avance de magnitud, sino solo la consecuencia lógica del desarrollo tecnológico. Sin embargo, el cambio de la diligencia por el automóvil si constituyó un avance de magnitud, porque trajo aparejado un sistema de interacciones nuevo que afectó todo a su alrededor de forma correspondiente.

Por tanto los números mostrados en la figura 1 no son completamente demostrativos debido a que no tiene en cuenta la diferencia en los tipos de proyectos, ni la cantidad neta de los mismos, como todo estudio porcentual. El estudio CHAOS toma muchos criterios para dar su informe, no solo los presentados, pero el gráfico es suficientemente ilustrativo para nuestros propósitos.

El artículo de Brooks tiene, en resumen, una idea central subyacente: El desarrollo de software siempre va a ser difícil, porque la complejidad existe en la naturaleza misma del software. La única forma de enfrentarse a esta dificultad es a través de las personas, no de las técnicas.

El artículo original es muy extenso y de una riqueza exquisita. Aborda muchos temas e ideas de interés para cualquier ingeniero y personal general que se dedique al desarrollo de software de forma profesional o por afición. Sin embargo, para nuestro análisis nos concentraremos en lo que Brooks llama las dificultades del software, su clasificación, origen e impacto en nuestro trabajo.

Las dificultades de la tecnología de software

Cuando Brooks habla de tecnología de software, o de desarrollo de software, está hablando de todo el proceso de concepción, desarrollo y mantenimiento del software. Su desarrollo no termina cuando el software es entregado al cliente, sino que continua en las fases de prueba, transición y durante el resto del ciclo de vida del software ya en manos del cliente. Tiene en cuenta también el peso fundamental de los proyectos grandes de software: El peso de los cambios a posteriori, originados por el uso del sistema en las condiciones reales.

La división de las dificultades se basa en la definición de la esencia del software:

“(…) La esencia de una entidad de software es una construcción de conceptos interrelacionados: datos, relaciones, algoritmos, métodos, objetos, etc. La esencia es abstracta porque es la misma aunque toma muchas representaciones distintas (…)”

Es decir, que el software es una entidad abstracta, que puede tomar muchas manifestaciones en dependencia del aspecto que estemos buscando representar. Las dificultades esenciales o propiedades del software son entonces aquellas inherentes a la naturaleza del software, identificadas por Brooks como complejidad, conformidad, cambiabilidad e invisibilidad; mientras las dificultades accidentales son todas aquellas dificultades que existen en el desarrollo del software en un momento dado, pero que no son inherentes a su naturaleza.

Analicemos las propiedades identificadas del software con más detalle.

Complejidad

“(…) Las entidades de software son más complejas con respecto a su tamaño que cualquier otra construcción humana, debido a que no hay dos partes iguales, al menos en su intención. Si existen dos partes que son iguales, se abstraen dentro de una subrutina. En este sentido, los sistemas de software difieren profundamente de las computadoras, edificios o automóviles, donde abundan los elementos repetidos (…)”

Ciertamente, en un sistema software de cualquier tamaño no existen elementos duplicados de forma exacta. Cada elemento de código que se escribe es único, con su propia función y su propio lugar en el grafo de relaciones. De ser necesaria la misma funcionalidad en más de un lugar, se hace referencia al elemento que la contiene, o se ajusta la estructura de forma que dicha funcionalidad quede accesible. Este comportamiento es tan aceptado que se considera mala práctica la existencia de código duplicado en los proyecto de software. Esta propiedad de que cada parte del sistema es única y ha sido diseñada específicamente para la función que cumple es precisamente la que brinda al producto final su complejidad relativa. No es lo mismo una casa compuesta por miles de ladrillos o losas semejantes, cuya complejidad constructiva se amortiza debido precisamente a la uniformidad de sus elementos; que un sistema software, donde se debe buscar la uniformidad en las partes en las cuales esta es posible, pero donde cada elemento existente tiene una estructura específica para su función particular.

“(…) De la misma manera, el crecimiento de una entidad de software no es meramente el aumento de los mismos elementos en tamaños mayores. Es necesario un incremento en el número de elementos diferentes. En la mayor parte de los casos, los elementos interactúan los unos con los otros de forma no lineal, y la complejidad total aumenta mucho más que linealmente (…)”

Siguiendo con la metáfora de la casa, al hacer un piso nuevo la complejidad del edificio ha aumentado de forma lineal, debido a que no varía la estructura general de la casa. Ciertamente, se han tenido en cuenta las fuerzas que actúan sobre los cimientos y las paredes, pero solo se tienen en cuenta estas fuerzas en relación con el nuevo elemento adicionado (en dependencia, claro está, de la arquitectura de la construcción). En una construcción de software, sin embargo, cada uno de los elementos nuevos introducidos tiene en sí el potencial de desarrollar relaciones con muchos otros elementos, además de modificar las relaciones de los elementos que ya existen. Estos cambios internos, o refactorizaciones del sistema son la causa principal de las dificultades del cambio en sistemas grandes una vez que ya están construidos.

Fig. 1 La complejidad del sistema aumenta de forma no lineal con cada nuevo elemento. La existencia del nuevo elemento provoca cambios en varios otros y el surgimiento de nuevas relaciones.


Por tanto podemos decir que la complejidad del software es una propiedad esencial, no accidental. Todos los sistemas de software son complejos por naturaleza, esto es, no es una característica que se manifieste en un momento de tiempo o con unas condiciones determinadas. Además, un sistema que tenga 10 veces más elementos que otro no es 10 veces más complicado, sino muchas veces más, debido a la gran cantidad de relaciones y cambios necesarios en la estructura para acomodar todos esos elementos. No es posible, en el software, extrapolar resultados de desarrollo de software pequeños y estar convencidos de que funcionarán en un software más grande, porque las relaciones no se comportan de forma predecible ni siquiera entre sistemas del mismo tamaño con funcionalidades o propósitos diferentes. En las palabras de Brooks:

“(…) Durante siglos las matemáticas y ciencias físicas hicieron muchos avances simplificando los modelos de los fenómenos complejos, derivando propiedades de los modelos y comprobando estas propiedades experimentalmente. Este paradigma ha funcionado porque las complejidades ignoradas en los modelos no eran propiedades esenciales del fenómeno. Esto no funciona si las complejidades son la esencia. Muchos de los problemas clásicos del desarrollo de productos de software se derivan de esta complejidad esencial y su incremento no lineal con respecto al tamaño (…)”

Una excepción a esta falta de extrapolación de resultados en productos pequeños a productos más grandes son los llamados spikes o pinchos, pequeñas aplicaciones que sirven como pruebas de concepto de una idea determinada. Sin embargo el principio sí funciona en este caso porque lo probado es una idea determinada, no la forma de llevarla a cabo. Uno puede, por ejemplo, desarrollar una pequeña aplicación para desarrollar un menú de usuario o un algoritmo criptográfico particular para ser utilizado en una aplicación mayor, pero una vez aprobado el concepto, la labor de integrar dicha idea en un sistema mayor no es trivial, y es precisamente la complejidad que se estaba evitando en primer lugar con el pincho. Los patrones de diseño y el desarrollo orientado a componentes han probado ser insuficientes para paliar esta dificultad. Todo el software de cierta magnitud aumenta su complejidad de forma no lineal con cada nuevo componente, aun cuando este no tenga relaciones con el resto del sistema. Como mínimo la arquitectura general del sistema y las relaciones que esta gobierna se resienten del nuevo peso añadido a la estructura. Podemos reducir, pero no eliminar, el peso de la no linealidad, como una asíntota que no puede superarse.

Conformidad

“(…) Los ingenieros de software no están solos cuando se enfrentan con la complejidad. La física, por ejemplo, lidia con objetos terriblemente complejos incluso al nivel fundamental de las partículas. Los físicos trabajan, sin embargo, con la firme convicción de que existen principios unificados que pueden ser encontrados (…). Einstein sostenía que debe haber una explicación simplificada de la naturaleza, porque Dios no es caprichoso ni arbitrario.

No existe tal creencia que conforte al ingeniero de software. Mucha de la complejidad que debe dominar es arbitraria, forzada por las instituciones humanas y los sistemas a los cuales deben adaptarse sus interfaces (…)”

Ciertamente, el ingeniero de software trabaja sin el convencimiento de las leyes que gobiernan el campo que maneja. Las estructuras que constituyen un sistema son complejas debido a la forma en la que son construidas, a los requisitos que debe cumplir, a los sistemas con los que debe comunicarse. Sin embargo, no existen leyes que determinen inexorablemente el desarrollo de un sistema. Todo lo que atañe al software es arbitrariamente creado por humanos. La experimentación con el software no funciona como con las demás ciencias. No existe un laboratorio donde puedan probarse ideas de desarrollo una tras otra hasta encontrar una correcta que luego se ponga en práctica. No, en el software las buenas y malas prácticas se validan durante la creación de sistemas, en el campo de batalla, puede decirse. Se puede crear valor dentro de un laboratorio, en forma de algoritmos, de metodologías de prueba, de benchmarks, de ambientes limpios en los cuales aislar un código problemático o hacer ingeniería inversa a un sistema existente, pero lo que no puede hacerse aislado del mundo real es encontrar la forma de solventar los problemas del desarrollo de software ni siquiera teóricamente,

El desarrollo de software es, por tanto, una carretera dolorosa de fracasos uno tras otro, basados en los cuales se forman teorías que son puestas en práctica hasta que sus fallas vuelven a ser obvias. La complejidad de un sistema particular parte también de la técnica que se utilice en su concepción, la cual es validada tan solo por aplicaciones anteriores. El terreno del software, como el desarrollo de las ciencias sociales, es un camino oscuro que va construyendo sus propias leyes.

“(…) En muchos casos, el software debe conformarse porque es la adición más reciente en la escena. En otros, debe conformarse porque se percibe como el más confortable para ello. Pero en todos los casos, mucha de la complejidad viene precisamente de la conformidad con otras interfaces; esta complejidad no puede ser simplificada por ningún rediseño que se le aplique al software aisladamente (…)”

El software se aplica a una institución existente. Ningún software se produce con vistas a modelar la institución en la que será utilizado. Por tanto, siempre es el último en llegar a la escena, la última adición a un panorama ya establecido. La resistencia al cambio en la implantación de un sistema software es superior en todos los casos a cualquier otro cambio de tecnología (excepto, quizá, la sustitución de un sistema software por otro que utilice los mismos paradigmas). Estas condiciones son las que provocan precisamente los resultados que comenta Brooks: El software siempre debe conformarse a los demás elementos existentes en su ambiente, y esto provoca una complejidad que no puede resolverse modificando tan solo el sistema. Cualquier cambio que no pueda reconciliarse con el sistema y que implique un cambio en el negocio en el que el software está siendo aplicado es una manifestación de complejidad de desarrollo del más alto nivel. El sistema software no es una entidad separada, convive en un continuo intercambio con su entorno y es presionado por este para adaptarse.

Este es el verdadero significado de la conformidad: La adaptación arbitraria del software a los sistemas y los usuarios que lo utilizan, y la complejidad, también arbitraria que de ello se deriva.

Cambiabilidad

En las palabras de Kent Beck, el cambio es la única constante [Beck, 2005]. El software es de todas las industrias la que más cambios acomoda durante el desarrollo del producto. Si a esto sumamos que el ciclo de vida del software se extiende más allá de la entrega del producto para el uso del cliente, podemos comprender mejor las palabras de Brooks:

“(…) La entidad de software está constantemente presionada por el cambio. Por supuesto, también lo están los edificios, autos y computadoras. Pero los bienes manufacturados no son frecuentemente modificados después de fabricados, son sustituidos por modelos posteriores, o algunos cambios esenciales son incorporados en copias posteriores con otros números de serie pero sobre el mismo diseño básico.

En parte, esto se debe a que el software de un sistema contiene su función, y la función es la parte que más siente la presión del cambio. En parte es porque el software se puede cambiar más fácilmente (…) los edificios sí cambian, pero los altos costos del cambio, entendidos por todos, sirven para contrarrestar los lamentos de los promotores del cambio (…)”

Ciertamente, como regla general es más fácil cambiar el software que las computadoras donde este se ejecuta, aunque esto depende de las características de cada negocio. Los cambios de los sistemas de software se producen constantemente y por muchas razones: algunas internas, producto de las mismas inquietudes del equipo de desarrollo; otras, más importantes y menos controlables, son producto de los procesos identificados por Brooks que actúan sobre el software una vez que este es presentado a los clientes:

“(…) Todo software exitoso es cambiado. Aquí hay dos procesos trabajando. Primero, al mismo tiempo que un producto de software demuestra su utilidad, las personas lo prueban en casos extremos o para los cuales no fue diseñado. Las presiones para extender la funcionalidad proviene principalmente de los usuarios a los cuales les gustan las funcionalidades básicas e inventan nuevos usos para estas.

Segundo, el software exitoso sobrevive la vida normal de la máquina soporte para la cual fue escrito en primer lugar. Si no son nuevas computadoras, al menos nuevos discos, nuevas pantallas, nuevas impresoras sobrevienen. El software debe adaptarse [conformarse] a estos nuevos vehículos de oportunidad (…)”

Estos procesos, son por demás normales y están trabajando en cualquier producto industrial. Sin embargo, en el caso de los bienes manufacturados estos procesos guían la evolución de la serie de productos, sirviendo como material para el diseño de modelos superiores, mientras que en el software son la principal fuente de cambios del mismo producto ya entregado, en versiones sucesivas. Existe también, por supuesto un tercer proceso, el proceso natural de evolución de la institución a la cual sirve el sistema, el cual exige nuevas funcionalidades con cierta frecuencia en dependencia de su naturaleza:

“(…) El producto de software está embebido en una matriz cultural de aplicaciones, usuarios, leyes y soporte electrónico. Todos estos cambian continuamente, y sus cambios fuerzan inexorablemente sobre el producto de software (…)”

Es decir, que el negocio al cual está destinado a servir el sistema software no es estático, sino que cambia y asimismo cambian sus componentes. Sin embargo desde el mismo momento en que el software es entregado este existe también dentro de la organización, pasa a ser uno de sus elementos, y por tanto presiona y es presionado para cambiar junto a los demás. La gran diferencia está en que el software es el que más posibilidades tiene de ser modificado, debido a los factores vistos anteriormente.

Invisibilidad

“(…) El software es invisible e invisualizable. Las abstracciones geométricas son herramientas poderosas. Los planos de un edificio ayudan tanto al arquitecto como al cliente a evaluar espacios, flujos de tráfico, vistas. Las contradicciones y omisiones son obvias (…) una realidad geométrica es capturada en una abstracción geométrica.

La realidad del software no está embebida inherentemente en el espacio. Por tanto, no existe una representación geométrica de la misma forma en la que la tierra tiene mapas, los chips tienen diagramas o las computadoras esquemas de conectividad (…)”

Esta idea puede encontrarse un poco desafiante. Ciertamente, ¿cómo puede el software ser invisible si casi tres cuartas partes del trabajo de un proyecto de software se realiza sobre herramientas cuyo único objetivo es mostrarnos el producto que estamos desarrollando? ¿Si tenemos la representación delante, como puede ser el software invisible? Según Brooks:

“(…) en cuanto intentamos diagramar la estructura del software, encontramos que constituye no uno, sino varios grafos dirigidos superpuestos unos sobre otros (…)

A pesar del progreso en la restricción y simplificación de las estructuras del software, este permanece inherentemente invisualizable, y por tanto no permite a la mente el uso de algunas de sus más poderosas herramientas (…)”

El software no tiene una representación única, debido a que no existe en un espacio geométrico que pueda representarse directamente en ninguna herramienta. Las representaciones posibles son forzosamente limitadas o se limitan a propósito para poder controlar las funciones del sistema. Según Brooks esto no limita solamente la capacidad de visualización de la mente de la persona, sino que también reduce ostensiblemente la capacidad de comunicación del diseño entre todas las personas involucradas.

Conclusiones

Estas propiedades esenciales del software son aquellas que no podemos o no hemos podido resolver hasta momento. Aun tantos años después de que Brooks escribiese su artículo, el software sigue siendo complejo, necesitando conformarse a interfaces externas, soportando la presión constante del cambio y manteniéndose invisible. Los avances alcanzados en el pasado solo han resuelto dificultades accidentales. Los cambios reconocidos por Brooks hoy son tan comunes que ni siquiera se piensa en ellos en forma de adelantos sino de elementos básicos del arte: lenguajes de alto nivel, tiempo compartido, ambientes unificados de desarrollo, verificación de los programas, estaciones de trabajo… Algunos avances que han atacado la complejidad esencial, como la programación orientada a objetos, algunas aplicaciones de inteligencia artificial, los sistemas expertos aplicados al desarrollo de software y otros no son suficientes para reducir la dificultad del desarrollo de software de forma significativa.

A fuerza de cometer errores hemos aprendido el camino para desarrollar nuestros productos. Sin embargo, la construcción de software no es estática, cambia y crece según crece su demanda. Y cada día, nuevos alcances, nuevos requisitos, nuevos ámbitos de complejidad se abren ante nosotros. Y en estos nuevos caminos, no tenemos predecesores para mostrarnos nuestros errores.