Hola a todos, como veo que hay mucha inquietud por todas esas prácticas de desarrollo ágil, como el TDD, el refactor y el pair programming, y como me huelo que por ahí que se ha puesto de moda eso del SOLID, he decidido hacer unos cuantos de posts sobre el diseño de software ágil. Espero que me salga algo coherente…
En posts anteriores he hablado mucho de gestión de proyectos, sobre todo de Scrum. Me centré en que lo bueno de las metodologías ágiles es que proponen que se debe entregar valor de forma continua y cuanto antes mejor. Ésto es mucho más sencillo de decir que de hacer. Scrum, por ejemplo, no nos orienta sobre cómo conseguir implementar en cada sprint rodajas de funcionalidad potencialmente entregables al usuario. De hecho esto es bastante complicado de hacer, ya que implica que con cada nueva funcionalidad que queramos implementar, debemos modificar o extender los componentes de software que hayamos realizado hasta el momento. Además es probable que debamos introducir nuevos componentes, no previstos hasta el momento, en la arquitectura del sistema y que estos encajen con los ya existentes. Todo un desafío. Las prácticas de ingeniería ágiles no son más que unas herramientas para conseguir estos objetivos. Muchas de dichas prácticas existen desde hace mucho tiempo (pre agilismo) dentro del paradigma OO, aunque hayan sidos ignoradas por nosotros, programadores de JABOL.
Antes de meterme en materia técnica, y abrir el arsenal de armas de destrucción masiva, voy a explicar en este post lo que quiero decir cuando en una consultoría digo: “pues depende…”. Es un tema que me preocupa porque empiezo a oír hablar de SOLID, código expresivo y demás, y todo ello justificado en nombre de una entidad abstracta llamada “calidad”. Es una corriente que me está dando algo de miedo, ya que en nombre de la “calidad”, me puedo tirar refactorizando mi código y chapándolo en oro por los siglos de los siglos sin entregar nunca a tiempo nada de valor a mi cliente. Me da la impresión de que algunos hablan de la “calidad” de la misma manera en la que un sacerdote podría hablar del “bien supremo” o un artista de la “belleza” de su obra. Las técnicas de diseño ágil son armas poderosas, y con ese poder viene la responsabilidad de no hacernos pajas mentales con ellas
Mi postura es que la calidad del software, como entidad platónica y absoluta no existe. Es algo que no es medible, ¿alguien me puede proponer una fabulosa métrica que la mida y que sea factible de implementar? Si algo no es medible no debemos tomarlo como guía para tomar decisiones de diseño de nuestro código, por lo tanto, yo no uso la calidad para estos fines. Veamos pues como bajar al mundo real para tomar decisiones de diseño. En el mundo real del desarrollo de software profesional el objetivo es entregar software al cliente y que éste esté satisfecho con él. Por satisfecho quiero decir que se deben cumplir las dos siguientes condiciones:
- El funcionamiento del software cumple las expectativas del cliente de forma razonable.
- El software se entrega en un plazo de tiempo y con un coste razonable para el cliente. Si es más importante el coste o el tiempo lo debe decidir el cliente al principio del proyecto, de forma que podamos balancear estos dos factores adecuadamente.
O sea, que no descubro la pólvora, el cliente estará satisfecho si el software funciona, está a tiempo y su coste no se ha ido de madre. La parte quizás más problemática es la definición de “razonable”. Para mi el significado de razonable es algo que se debe acordar con el cliente mediante negociación, aunque eso sí, es una negociación asimétrica donde el cliente tiene la última palabra.
Por lo tanto el objetivo del diseño de software ágil es hacer software que funcione, respetando unas restricciones de tiempo y de dinero, y se entregue dicha funcionalidad de forma continua e incremental, aceptando posibles cambios. Las técnicas y principios de desarrollo ágil como TDD, Pair Programming, SOLID, KISS, DRY, etc. no son más que meras herramientas para conseguir ésto, no las confundamos con el objetivo. Antes de aplicar un patrón de diseño, o una refactorización, calculad el coste que os supondrá hacerlo en tiempo y dinero y comparadlo con el ahorro de coste y dinero que os supondrá a largo plazo. Si no hay un beneficio obvio, no lo hagáis. Así que cuando alguien me pregunta: “¿es bueno seguir los principios SOLID?”; y yo respondo: “pues depende..”; simplemente estoy diciendo que en función del contexto de tu proyecto tendrás que analizar si te va a dar beneficios o no.
En este sentido, la primera técnica que podemos aplicar es usar un timebox. Un timebox es un intervalo de tiempo predefinido, y no alterable, que restringe la implementación de una tarea. Ejemplos de timeboxes son: pomodoro, jornada de trabajo, sprint, deadline… La idea es que nos concentremos en cumplir con nuestras tareas y sintamos la presión de que se no acaba el tiempo. Esta presión nos ayudará a evitar que nos “entretengamos” en cosas que no sean conseguir terminar nuestra tarea. Usar timebox es una técnica común en el mundo ágil, ya que nos permite controlar nuestro ímpetu por demostrar como de bien sabemos programar, y centrarnos en simplemente implementar la funcionalidad, y si da tiempo se mejora su “calidad”. Usar timebox es una forma efectiva de conseguir KISS y YAGNI, si tienes claro que tienes un límite de tiempo vas a lo práctico, y haces lo más simple que puede funcionar y te olvidas de cosas que no vas a necesitar.
Enganchando con la primera parte de este post, el desafío técnico del agilismo, consiste por un lado en entregar incrementos de funcionalidad, y por otro aceptar cambios en la funcionalidad y el contexto del proyecto. Por lo tanto en un proyecto gestionado de forma ágil, vamos a estar continuamente cambiando nuestra arquitectura, nuestro diseño y los componentes ya existentes. Esto es así, aunque no cambien los requisitos funcionales, al tener que modificar el software ya existente para poder acomodar al menos la siguiente funcionalidad a entregar. Si hay cambios funcionales, el ritmo de cambio a absorber por nuestra arquitectura es mayor aun. Por lo tanto nuestro diseño y nuestros componentes deben ser maleables y flexibles. Cualquier técnica o principio de diseño, que recorte los gastos o el tiempo de implementar un cambio, rendirá beneficio en un proyecto ágil.
Por lo tanto ya tenemos una regla para guiarnos a la hora de tomar rápidamente decisiones de diseño. Podremos aplicar una técnica y/o refactorización, siempre y cuando:
- Podamos aplicarla si no nos vamos a saltar el timebox de la tarea a implementar. Esto asegura que no tiene un coste alto, y no nos desvía de nuestro objetivo de hacer software que funcione.
- Tenemos claro que consigue hacer que nuestro diseño sea más sencillo de cambiar en un futuro.
La regla anterior tiene una debilidad, la posibilidad de que el timebox sea irreal y demasiado corto para realizar la tarea. En este caso nunca tienes tiempo para refactorizar ya que estas un ritmo de trabajo insostenible, y tu diseño puede hacerse frágil ante el cambio. Por lo tanto tengo otra regla que tiene más precedencia que la anterior: si te cuesta cada vez más encajar una nueva funcionalidad en el diseño, refactoriza. Esta regla actúa como una alarma que me indica que debo “complicar” el diseño, sí o sí, ya que éste no es lo suficientemente flexible para aceptar cambios.
Resumiendo mi postura,la calidad del software no existe en si misma. Lo que realmente nos importa es terminar en tiempo y dinero con software que funcione. En un contexto ágil esto va a implicar que tu software debe ser maleable y aceptar cambios de forma rápida y barata. Olvídate de métricas, documentación y estándares. Céntrate en que tu software funcione y acepte cambios fácilmente. Me gusta llamar a esto calidad mundana del software, en contraste con la idea de que la calidad es un ideal a alcanzar como objetivo. Para obtener suficiente “calidad mundana”, pero nada más, recopilando lo dicho anteriormente, yo suelo usar las siguientes reglas:
- Usar timebox para centrarme en implementar funcionalidad y no salirte de costes y tiempos. Puedo usar distintos timebox (pomodoros, jornadas y sprints) para distintos ámbitos (tareas, escenarios y Product Backlog Items). Esto promueve KISS.
- Si sobra algo del timebox, cambia tu diseño para que admita cambios de forma más sencilla. En función del nivel del timebox puedes afrontar cambios más locales o más globales en diseño. Por ejemplo, en un pomodoro puedes intentar un refactor local, en un sprint, proponer a tu equipo alguna tarea de review de código o de rediseño de un subsistema.
- Si detectas, de forma empírica (nada de corazonadas o instinto), que cada vez es más difícil aceptar cambios, entonces tu arquitectura es frágil ante el cambio. Da la alarma y prepárate para refactorizar.
- Si no tienes problemas céntrate en producir funcionalidad. Olvídate de posibles futuros problemas que pueden no ocurrir nunca (YAGNI). Al fin y al cabo la calidad cuesta tiempo y dinero, si no necesitas más, ¿para que comprarla?
Bueno, este es mi enfoque personal. Como veis es muy cauto e intento no complicar el diseño hasta que no es realmente necesario. Llegué a esta forma de trabajar tras darme cuenta de que tenía tendencia a “chapar en oro” mi software, y hacer programación barroca. Me di cuenta que esto es un defecto y hay que balancear muy bien el esfuerzo que se dedica a mejorar el código contra el que dedicas hacer funcionalidad. Hay que llegar a un sano equilibrio.
Para finalizar, si tu proyecto no es ágil, olvídate de todo esto. En los proyectos no ágiles, el cambio es algo malo, que hay que penalizar, no aceptar. Por lo tanto no tiene sentido diseñar para aceptar el cambio. Como mucho tendrá sentido diseñar para cumplir el plan. Ahora empiezo a entender, porque algunos principios como YAGNI, KISS, SOLID o DRY no se han aplicado como debían en la industria, porque simplemente en un proyecto no ágil no tienen mucho sentido.
¡ Salud a todos y felices fiestas !



Muy buen post Enrique,veo que ya estas recuperado.
El tema que planteas es controvertido ya que balancear entre timebox y calidad es complicado.Pienso que uno de los objetvos que persigue la artesania del software es justamente ese,conseguir la mayor calidad posible en timebox.
Me quedo con algunas ideas para comentar contigo en persona.
Saludos
Estando de acuerdo con lo que dices (efectivamente, eres muy cauto, y ése no es tu estilo “¡qué ha pasado que me lo han cambiado!”) me atrevo a aconsejar la lectura de este artículo de Corey Haines (uno de los impulsores del movimiento de la artesanía) donde viene a dar un puntito de reflexión en base a su experiencia.
Me acabo de leer el artículo que indicas. Me ha gustado bastante. Es interesante que Corey coincida conmigo en el tema del timebox, generalmente se decide que ya has refactorizado bastante porque ya has dedicado demasiado tiempo a un trozo de código o un test (“too much time”), es decir que se te acaba el timebox. Conforme vas siendo más experto tu productividad aumenta y te da tiempo a pulir más tu código.
Supongo que nos veremos el día 30 el dojo de Ruby !
Muy buen post Enrique, recoges muchas de las ideas e inclusive temores de las personas que entramos en este gran nuevo mundo.
No te preocupes que la paz aún prevalecerá, ya que todo este gran arsenal de armas viene acompañado de un código de activación: “Sufficient Design”, el cual nos permite mantener el balance entre el valor de negocio y calidad de software.
Un buen “Software Craftsman” es muy pragmático y entiende que nada tiene sentido si no hay valor hacia los usuarios.
Saludos
Angel
Mu buen post. Me ha gustado. Quiero recordar a todos que los requisitos funcionales deben incluir siempre requisitos “no funcionales”. El primero de toda la vida es el mantenimiento que ya tenemos gracias al aceptar cambios continuos. Por experiencia os confirmo que proyectos no agiles y pseudo agiles fracasan por completo, llaman al bombero y empiezan a rezar. Me refiero a la escalabilidad y disbonibilidad. Sí, es de sistemas. Pero un truño de software, aunque funcione muy bien, lo impide. A claro: pruebas de carga. Esto también se tiene que hacer de forma ágil.
¡Analistas funcionales del mundo, poneos las pilas con concerns del mundo de sistemas!
Suena a consejos para afrontar coyunturalmente los problemas de calidad a los que se enfrentan los proyectos Agiles.
Hay dos cosas que no podemos evitar, uno es el timeboxing y otro es la calidad. Cierto es que el balance parece complicado, pero no deberíamos optar por mermar calidad por favorecer un timeboxing.
El diseño y refactoring debería ingresar dentro de todos y cada uno de los sprint, pero me temo que se evita mucho de estos dos aspectos en etapas de planning y nos damos cuenta de su necesidad en medio del sprint. Dado que la evasión del refactoring es una práctica común, el diseño nunca es cuestionado y entonces sprint a sprint optamos por la fragilidad del diseño mientras lo que hagamos sea funcional y logremos un acuerdo satisfactorio con el cliente. Sucede sobre todo en cosas que hemos heredado. Eternas deudas técnicas para futuro?
A propósito, me gusta tu concepto de “Calidad Mundana”, es muy esclarecedor y ahora que lo comprendo me siento afín con ese pensamiento y en mi anterior comentario me referí justamente a la falta de ese tipo de búsqueda de la calidad. Yo solía llamarle “calidad intrínseca”.
Saludos.
[...] del interludio con el spring io, vuelvo a la carga con el tema del diseño ágil de software. Como ya comenté, considero que dentro de las limitaciones de tiempo y dinero de un proyecto, hay que estar [...]