miércoles, 23 de enero de 2008

Sobre diseño y algo más

Ya estoy de vuelta de mis vacaciones y algo en lo que estuve pensando la última semana fue sobre lo que se entiende por diseño. Se me metió esa idea en la cabeza y quería compartir algunas cosas de manera completamente desordenada, tal como me salen, que pensé y que vengo pensando y conversando con otros hace rato.
Una de ellas es como últimamente se observa cada vez más en nuestra profesión es la confusión del fin con el medio, donde el medio pasa a ser el fin (algo muy común en nuestra época en todo tipo áreas). Es muy común que cuando a gente que estoy entrevistando le pregunto si saben diseñar utilizando objetos respondan que sí, que saben UML. Esto es similar que a un arquitecto le pregunte si sabe diseñar edificios y este responda que sí, que sabe usar el CAD. Queda claro con esta respuesta que dicha persona no sabe qué es diseñar.
Pero como dije, es muy común que se produzca esta confusión en gran medida a las grandes falencias que existe en la educación en nuestra profesión, cada vez más vapuleada por el frenesí de tener todo listo lo más rápido posible. O sea, ese frenesí se traslada a la enseñanza donde "enseñar diseño" pasa a ser enseñar una herramienta puesto que es mucho más rápido aprender a usar una herramienta que manejar la teoría, la esencia de diseño. Tampoco puedo dejar de nombrar la presión que las grandes corporaciones siguen incrementando sobre las universidad, a las cuales realmente les interesa que utilicen sus herramientas (tienen que vender, tienen que lograr adeptos) y ese interés hace que nuevamente se confunda el medio (o la herramienta) con el fin. Ya no se enseña "Base de Datos" se enseña "SQL Server", ya no se enseña "Objetos", se enseña "Java" o ".Net". En fin, un poco de catarsis que hago que muestra una triste realidad y que termina siendo uno de los motivos de los graves problemas que existen en el desarrollo de software.
Volviendo al tema principal de este post, el mismo surgió en mi cabeza cuando quise recordar la definición de "Diseño" o "Diseñar". La verdad que no recuerdo una definición exacta, no recuerdo que definición me dieron en la facultad si es que lo hicieron. Tampoco estuve haciendo mucho reasearch al respecto, quizá debería haber ido al libro de Rebecca, Meyer o Booch, pero no lo hice. Lo más sencillo, o por lo menos lo que tenía a mano, era ir la wikipedia y buscar que definición describe. En ella se puede leer: "Software design is a process of problem-solving and planning for a software solution. After the purpose and specifications of software is determined, software developers will design or employ designers to develop a plan for a solution. It includes low-level component and algorithm implementation issues as well as the architectural view."
La verdad me parece una definición muy pobre y llena de falencias. Falencias empezando por creer que la especificaciones del software se "determinan" en algún momento, muy pobre porque no queda claro finalmente qué es diseñar, más allá de ser un proceso para "resolver problemas y planificar una solución".
Personalmente me cuesta mucho definir ahora y bien qué es diseñar, pero si estoy seguro que un buen diseño de un sistema hará que sus desarrolladores tengan una vida mejor y menos traumática. Para mi diseñar es toda tarea que se hace durante el desarrollo de un sistema orientado a mejorar los objetivos que se propusieron al realizar dicho sistema. El problema es que hay varios tipos de objetivos, aquellos orientados al desarrollo per se como el mantenimiento y la evolución del sistema, objetivos orientados a la ejecución como la performance, la independencia de la plataforma, objetivos orientados a la usabilidad del sistema, etc.
De todos estos objetivos, el que más me importa hablar ahora es el relacionado al desarrollo del sistema, puesto que es ahí donde se puede ver una gran diferencia con otras disciplinas, básicamente porque hay una diferencia muy grande en construir un sistema y construir cualquier otro tipo de producto como una casa, un auto o un electrodoméstico. La principal diferencia es que en estos producto que acabo de mencionar, una vez construidos no se los puede modificar (o no en gran medida). O sea, una vez que salió el Renault xx a la calle, todos serán iguales y no se los podrá modificar. Si hay que hacer algún cambio, por ejemplo que ahora el auto soporte andar sobre hielo, se deberá esperar a toda una nueva generación de autos, los que ya existen no cambiarán. Pero la necesidad de una nueva funcionalidad no tiene porque ser el disparador de una nueva "versión" de autos, también los autos, como cualquier producto, tienen errores de diseño.
Recuerdo un amigo que compró justamente un Renault muy caro (no recuerdo el modelo) que tenía la luz de stop superior ubicada de tal manera que dificultaba la visión por el espejo retrovisor. Claramente un error de diseño de usabilidad. Por supuesto este error no puede ser resuelto en ese auto de mi amigo, no se puede romper el vidrio trasero y el techo para poner la luz en otro lugar y así solucionar este error de diseño; si quiere una solución hay que tener otro auto físicamente hablando que tenga la luz en otro lugar (¡y rogar que ese otro lugar no sea molesto tampoco!). ¿Qué consecuencias trae esta característica?, que los diseñadores de autos no se preocupen por diseñar el auto de tal manera que si surge un error o nuevo requerimiento, este pueda ser solucionado en el mismo auto, en el auto que ya tiene el usuario. Si surge un problema no previsto, un requerimiento nuevo o un error de diseño, se diseñará su solución en otra "versión". Y sacar otra versión de una auto cuesta dinero, no es fácil cambiar matrices, para una linea de producción y empezar otra, etc.
Sin embargo esto en el software no es así, justamente la maleabilidad del software, una de sus características esenciales de ser fácilmente cambiable, según nombra Brooks, obliga a los desarrolladores a tener en cuenta este característica al momento de diseñar. Esto nos puede llevar a pensar que lo mejor es tratar de resolver todo problema que pueda surgir antes de terminar el producto y así caer en un "design paralisis" (muy común en sistemas) y no terminar nunca. O que es conveniente tener diseños preparados para realizar cambios fácilmente, o sea tratar de adivinar el futuro sobre que puede llegar a cambiar en un sistema y por lo tanto diseñarlo para que el impacto de dicho cambio no sea grande. Utilizando un analogía con el ejemplo del auto, sería adivinar que nos van a pedir que el mismo funcione sobre hielo o prever que habrá errores de diseño como esa maldita luz de stop que quedó mal ubicada y que demuestra en definitiva que nadie se subió a manejar el auto antes de que saliera a la venta.
Esta es la linea de pensamiento que muchos tienen y que muchos proponen puesto que están acostumbrados a traer ideas de otras disciplinas, a veces porque no se entiende el problema y a veces porque se quiere forzar la solución. Sin ir más lejos, el Gang of Four en el libro de Design Patterns, proponen a estos como una solución a este problema, proponen diseñara para el cambio. Esta manera de pensar lleva a muchos a crear los grandilocuentes diagramas de clases usando UML como si estos fuesen el diseño que permitirá resolver cualquier cambio que surga. No existe falacia mayor que esa, un diagrama de clase nunca ayudará a tener un buen diseño y menos a resolver posibles cambios en el software puesto que el mismo es una vista "estática" del sistema y peor aún, hecha sobre un medio que no "ejecuta", donde nunca puede surgir algún error. Esta concepción de tener resuelto todo antes de empezar es válida en otras industrias pero no en la nuestra.
Otro problema que tiene esta linea de pensamiento es que debido a que todo tiene que estar resuelto antes de empezar a "programar", se utilizan todo medios satélites para crear esos artefactos que supuestamente ayudarán a dicha tarea. Se utilizan enormes diagramas UML, inentendibles algunos por cierto, con una notación que es tan compleja como inútil. Enormes documentos de especificaciones que nunca nadie lee y luego nadie modifica cuando se descubre que algo estaba mal. Se le da tanta importancia a estos artefactos que se desvía la vista de aquel principal, el código. Se desvía tanto la atención de este que pasa a tener más valor un diagrama UML que el código mismo, claro el primero fue hecho por un "diseñador" o "arquitecto", el segundo por un simple "programador", como si estuviésemos comparado el blue print del auto hecho por un ingeniero con el metal soldado por el pobre obrero de la linea de producción, nada más lejano de la realidad pero que sucede debido a tratar de copiar los modelos utilizados en otras industrias.
"Metodologías" ágiles como XP, aconsejan olvidarse del problema del cambio y utilizar otro tipo de técnicas que permitan, cuando llegue el momento, realizar cambios y asegurarse que todo siga funcionando correctamente como así también elevar el status del código a su máximo nivel. Algunas de estas técnicas son Test Driven Development, Code Ownership, Continuous Integration, Refactoring, etc.
En el caso de los cambios, la solución que proponen se basa principalmente en que no hay manera de predecir que cambios se realizarán, básicamente que no es fácil predecir el futuro, tesis con la que concuerdo 100%, no por que lo pueda demostrar formalmente sino más bien por resultados empíricos, que en criollo se traduce como "experiencia". Sin embargo este "consejo" que nos da Kent Beck por medio de XP tiene su lado peligroso, puede ser mal interpretado y se concluya que "no hay que diseñar", que no es importante diseñar como una vez dijo el "no respetable" (desde mi punto de vista y otros tantos) Martin Fowler en su key note de OOPSLA 2005.
El caso de elevar el status del código se basa principalmente en entender que no hay mejor lugar que este para mantener toda la información necesaria del desarrollo. Claro está que en aquellos lenguajes "textuales" como Java, .Net, etc. donde aún se siguen utilizando editores de texto para programar como si siguiéramos en la década del '60 programando FORTRAN en una green screen esto es difícil de imaginar. En un ambiente de desarrollo real, pensado para eso justamente, para desarrollar, como Smalltalk, es mucho más fácil de ver puesto que todos los elementos de un programa están reificados y al alcance de la mano. ¿Para qué perder tiempo modificando diagramas UML para luego modificar el código (siempre que no haya cometido el estúpido error de generar código automáticamente desde los diagramas), compilarlo y por último arrancar el sistema de nuevo para ver si arregló algo el cambio realizado, si puedo directamente sobre el sistema corriendo modificar mis objetos y ver el resultado?. Hay gente de sistemas que se olvida para que fueron hechos los sistemas, para simplificarnos la vida, no para hacerla la complicada. Sin embargo aún hay propuesta que se asemejan a pedirle a un diseñador gráfico de aplicaciones web que antes de usar alguna herramienta de edición HTML, escriba diagramas que definan el formato de las páginas web como algunas metodologías escolásticas lo proponen, o que a un vendedor le pidan que realice diagramas de contenido antes de ir directamente al PowerPoint y crear la presentación que utilizará para realizar su venta. Es absurdo por donde se lo vea.
Resulta que si cuando se desarrolla, el modelo que se está creando es "similar" a la realidad que se está representando, en definitiva que el diseño de mi sistema es similar al diseño que tiene el dominio de problema que se está sistematizando, y dicho modelo se está representando directamente en un medio activo, vivo como es Smalltalk, los cambios que surjan en el dominio serán de fácil e inmediata aplicación en el modelo, que en definitiva es el sistema.
Test Drive Development nos permite realizar estos cambios con mayor confianza y seguridad puesto que si metimos la pata algún test TIENE que fallar (y digo TIENE y no DEBERIA puesto que esto último implica no hacer TDD correctamente, o sea, no hacer TDD).
En conclusión (este post ya se hizo muy largo), cuando se desarrolla un sistema hay muchas cosas que se deben diseñar. Desde temas relacionados al mantenimiento del software, pasando por sus características tecnológicas hasta llegar a cuestiones de usabilidad. Pero no solo esto, también hay que diseñar los procesos que se utilizarán para desarrollar y coordinar el grupo de trabajo, el ambiente en el que se trabajará, la administración del proyecto, etc. La característica esencial de maleabilidad del software obliga a los desarrolladores a prestar atención a un problema que en otras disciplinas no existe o por lo menos no es tan importante, como la posibilidad de realizar cambios al producto que está usando el usuario. Esta característica esencial hace que no podamos deslindarnos de este problema y que si o si pensemos en que nos vamos a topar con él. Una corriente de pensamiento trata de solucionarlo utilizando herramientas que terminan siendo el fin en vez del medio, intentando "adivinar" el futuro, dándole más importancia a los "artifacts" que se generan con dichas herramientas que al código mismo, mientras que otras utilizan el código como fuente de toda verdad y justicia, el fin obligado y no el "artefacto" del que toda persona de desarrollo de sistemas, que se precie como tal, trate de huir.

5 comentarios:

Anónimo dijo...

Estuve leyendo algunos post salteados y me parecieron muy buenos!

Tenes algun libro que me puedas recomnedar sobre como modelar con objetos?

Hernan Wilkinson dijo...

La verdad que no hay UN libro que esté completamente de acuerdo con la manera que nosotros entendemos sobre como modelar con objetos. Algunos que te puedo nombrar son el de Rebecca Wirfs-Brock, "Designing Object-Oriented Software" (no conozco el nuevo), u otros que no tienen que ver directamente con modelar pero que sirven para sacar conclusiones como "Smalltalk Best Practices" de Kent Beck.
Lamentablemente no hay mucho más que te pueda recomendar que recuerde ahora y que sea de mi gusto...

elmasse dijo...

Hernán, realmente no creo tener la experiencia como para cuestionar este post, pero si, desde mi humilde punto de vista puedo hacer una acotación. En cuanto a diseñar, estoy muy de acuerdo en varios de los puntos que planteas, ahora, TDD y las utópicas metodologías ágiles son parte de la moda de hoy en las empresas de software. Mi experiencia dice que no es posible desarrollar con el código como fuente de documentación, más aún ,cuando en las empresas los equipos de trabajo son tan cambiantes el no tener un marco de referencia (léase diagramas UML o algún componente de esa parafernalia) para saber a grandes rasgos como se compone un sistema que está en integración continua hace que la tarea de inserción de un nuevo integrante dependa de la capacidad que el grupo mismo tenga para comunicar y explicar. Creo que deberíamos tener como premisa la vieja frase de "Desarrollar sin documentar no es desarrollar". Lamentablemente mi experiencia no me deja hablar de Smalltalk, lenguaje que respeto mucho pero no he tenido el gusto de conocer en un ambiente de trabajo. Este comentario se esta haciendo largo, me gustaría publicar una entrada en blog para citar el tuyo y hacer un poco mas extenso y explicativo mi punto de vista.

Saludos

Hernan Wilkinson dijo...

Que tal Maximiliano (llegue a tu nombre por medio de tu profile).
Antes que nada, cuestioná todo lo que quieras, para esto está!, porque ahora yo voy a cuestionar unas cosas que pusiste vos!! jaja.
Lo primero es que no entiendo por que decís que la metodologías ágiles son utópicas. Nosotros desarrollamos utilizando varias técnicas de estas metodologías como por ejemplo TDD con muy buen resultado, es más, TDD en la columna vertebral de nuestro procedimiento de desarrollo y de la calidad de nuestro producto.
Respecto de lo que decís del código como fuente de documentación, la realidad es que en definitiva lo termina siendo. Cualquier otra documentación que se haga generalmente queda desactualizada rápidamente por lo que en definitiva se termina yendo al código. Pero para que el código sirva para esto tiene que estar bien escrito, un objetivo que siempre hay que ponerse de entrada, mismo objetivo que hay que tener con la documentación, porque una documentación mal escrita es tan inútil como un programa mal escrito. Por otro lado, también hay que tener en cuenta que no todos los lenguajes facilitan la lectura del código de tal manera que pueda ser utilizado como reemplazo de la documentación. En este ejemplo mezclo código mal escrito con lenguaje poco no útil para documentar:

cuenta.depositar((Money) a, fecha);

Algo mejor sería:
cuenta en: unaFecha depositar: unaCantidadDeDinero.

Aunque el ejemplo no es muy completo, se puede entender mucho mejor en el último que se está depositando una cantidad de dinero a una fecha, mientras que en el primero no se sabe en primera instancia el rol que cumple "fecha" y además los paréntesis molestan la lectura, alejan el código del lenguaje natural.
Respecto de lo que decís de la rotación del personal, si realmente pasa eso más difícil te va a ser mantener la documentación que el código! Más rápidamente la documentación estará desactualizada y menos importancia y prioridad se le dará porque hay que "producir". Nosotros hemos tenido rotación en nuestro equipo de trabajo y no hemos tenido mayores problemas para que los nuevos integrantes puedan trabajar.
Ahora, en algo si estoy de acuerdo con vos, y es que es bueno tener alguna documentación con los lineamientos básicos de la arquitectura del sistema, del diseño a grandes rasgos, pero esta documentación no debe ser completa ni tener por intención reemplazar la importancia del código. Tampoco (algo que vos no dijiste pero que yo nombro en mi post) pasar a ser el fin y dejar de ser un medio que es lo que muchas veces se ve.
Por otro lado, quizá por no haber trabajado con Smalltalk te resulta más difícil verlo, pero tener un herramienta como Smalltalk que te permite fácilmente navegar por los objetos, manipular su comportamiento de manera dinámica, browsear el código fácilmente y organizarlo en una forma más útil que un mero archivo de texto, hace que la documentación sea cada vez menos necesaria y se documente solo aquello que no se puede ver a simple vista como lo que comenté más arriba.
Mi conclusión sería: No diseñar con documentos, elevar la importancia del código, documentar lo mínimo e indispensable solamente para transmitir conocimiento.
¿Te parece?

elmasse dijo...

Primero gracias por responder! Muy buena y acertada la respuesta en algunos aspectos. Segundo, me tomé el atrevimiento de hacer un reply en mi blog, espero tengas el tiempo y las ganas de darle una leída, todo comentario es bienvenido. Siempre es bueno escuchar para poder aprender.

te dejo el link: http://elmasse.blogspot.com/2008/01/sobre-diseo-y-algo-ms-reply.html

Un gran abrazo.