martes, 19 de noviembre de 2013

Principios DRY, YAGNI y KISS

En este post vamos a ver otros principios de diseño a tener en cuenta.
Que los ponga todos en el mismo post no quiere decir que sean menos relevantes que los principios explicados hasta el momento.



Principio DRY (Don't Repeat Yourself)

Este principio fue formulado por Andy Hunt y Dave Thomas en "The Pragmatic Programmer". La interpretación popular de este principio es algo así como: 
"No repitas código, si hay código duplicado refactorizas y reutilizas el código en lugar de duplicarlo". 
Todos estaremos de acuerdo que el código duplicado es un problema. Cuando necesitamos hacer cambios tendremos que cambiar en varios sitios con el riesgo de olvidar hacer esos cambios en algún sitio y dejar el código inconsistente. Incluso aunque no olvidemos ningún sitio donde debemos hacer los cambios el propio hecho de tener que cambiar en varios sitios nos obliga a hacer un esfuerzo extra de mantenimiento.

Sin embargo los propios autores se quejan de la interpretación anterior del principio por considerarla superflua. El principio DRY tiene unas pretensiones mucho más amplias. Su formulación original es "Cada pieza de conocimiento dentro de un sistema debe tener una representación única, clara y acreditada" (pongo aquí la versión original por si alguien sugiere una mejor traducción -Every piece of knowledge must have a single, unambiguous, authoritative representation within a system.-)

Es importante destacar que el principio DRY habla de pieza de conocimiento. No se refiere solamente a código. Una pieza de conocimiento puede ir desde el código, un esquema de base de datos, el conocimiento de un experto, requisitos, planes de pruebas, planes de compilación, hasta la propia documentación, etc.

El problema es cómo crear una representación única de ese conocimiento. Si se trata de código parece obvio que como hemos mencionado antes se trata de refactorizar y reutilizar. Pero, ¿cómo se maneja desde la perspectiva del principio DRY conceptos como esquemas de base de datos, planes de compilación o incluso el conocimiento determinado de un experto? Andy Hunt y Dave Thomas nos sugieren para esto el uso de técnicas como generadores de código, sistemas de compilación automáticos, uso de lenguajes de script - (como plantillas T4), etc.

Como ejemplo, las plantillas de proyectos o las plantillas T4 para la creación de objetos POCO con Entity Framework que ofrece Visual Studio las podemos considerar como la representación única del conocimiento de un experto (en este caso de Microsoft) que generan muchas líneas de código que muchos de los desarrolladores que las usamos probablemente no entenderíamos pero que usamos habitualmente. Piezas de conocimiento únicas, claras y acreditadas.

En resumen, el principio DRY nos dice que una pieza de código en un sistema nunca debería estar duplicada. Y por pieza de código entendemos un concepto que va mucho más allá que el código.

Principio YAGNI (You Ain't Gonna Need It)

YAGNI es un principio de Extreme Programming (XP) que establece que no se debe implementar funcionalidad hasta que sea necesario. En palabras de Ron Jeffries uno de los fundadores de XP "Siempre implementa las cosas que necesitas actualmente, nunca las que preveas que vas a necesitar".

Incluso si estamos totalmente seguros de que hay algo que necesitaremos en el futuro es mejor no implementarlo ahora por varios motivos. Primero puede que después de todo acabemos por no necesitarlo, y segundo porque puede que lo que necesitemos en el futuro sea bastante diferente de lo que creemos que vamos a necesitar.

El sentido de este principio no es que no hagamos diseños flexibles aplicando los principios que llevamos visto hasta ahora. Sino que no se sobredimensione algo basándose en las cosas que creemos que vamos a necesitar.

Hay dos razones fundamentales para aplicar el principio YAGNI en nuestros diseños:
  • Ahorramos tiempo, porque no escribimos código que al final resulta que no necesitábamos.
  • Mejoramos la calidad del código, porque evitamos "contaminar" nuestro código con conjeturas más o menos erróneas que no se usan, pero que acaban apareciendo por todas partes. 
Desmontando la falacia del ahorro de tiempo.
Esta es una excusa muy habitual a la que nos acogemos cuando estamos creando un diseño e imaginamos, soñamos o suponemos lo que necesitaremos en el futuro, "si hacemos tal o cual cosa ahora ahorraremos tiempo". Veamos las opciones posibles:
  • En el mejor de los casos acertamos de pleno y usamos lo que habíamos previsto en el futuro. En este caso (el mejor y el menos probable) sólo hemos empleado en el presente el mismo tiempo que hubiéramos empleado en el futuro para implementar la característica que habíamos previsto. No hay ahorro de tiempo. Alguien podría decir, "si no lo hago ahora en el futuro tendré que rehacer el diseño y refactorizar el código y será más complicado que ahora". Bien, si es lo suficientemente complejo para que a ti mismo te cueste mantenerlo en el futuro es que algo estás haciendo mal, hazlo más simple (mira el siguiente principio más abajo, principio KISS).
  • En un caso intermedio "casi" nos vale en el futuro lo que hemos previsto. En este caso sólo necesitamos hacer unos retoques aquí y allá, unas cuantas pruebas de regresión... etc. Al tiempo de hacer esto hay que añadir el que ya invertimos en hacer la implementación original. En fin, no hay evidentemente ahorro de tiempo sino todo lo contrario.
  • En el peor de los casos al final resultó que no lo necesitamos. El diseño acaba en la basura en el mejor de los casos o peor aún, eternamente "ensuciando" nuestro código y dificultando el mantenimiento. Con respecto al ahorro de tiempo en este caso no voy a comentar nada.
Con lo visto anteriormente creo que queda claro que YAGNI es un principio que deberíamos tener muy en cuenta a la hora de crear nuestros diseños y sobre todo a la hora de "parar de crear".

Principio KISS (Keep It Simple Stupid)

Este principio establece que "la mayoría de los sistemas funcionan mejor si se mantienen simples en lugar de hacerlos complejos". La frase se le atribuye al ingeniero aeronáutico Kelly Johnson. No es un principio específico del diseño de software sino más bien de la ingeniería en general, pero su aplicación es muy recomendable también en nuestros diseños. 

No son los lenguajes los que hacen parecer a los programas simples, son los desarrolladores los que hacen parecer simples a los lenguajes. - Robert C. Martin -

Un objetivo a la hora de crear nuestros diseños debe ser la simplicidad y evitar complejidades innecesarias. 
En XP se aplican dos reglas para conseguir mantener simples los diseños:
  • Diseña las nuevas características de la forma más simple que "crees que podría funcionar". Evita súper diseños fantásticos. Solamente pon ahí la nueva característica y haz que funcionen los test unitarios (tendremos que hablar de tests también en algún momento).
  • Refactoriza el diseño para conseguir el código más simple y que sigan funcionando todas las características. Sigue todos los principios de diseño que hemos visto para mantener el diseño tan claro como sea posible.
En cada iteración del desarrollo debemos crear el diseño más simple que creemos que podría funcionar. No me refiero al diseño más simple que funcionará, sino al más simple que podría funcionar. Hay que estar seguro de que funcionará pero esto no hay que probarlo hasta que hacemos la implementación del diseño.

Existen muchos otros principios y citas más o menos célebres que van en la línea del principio KISS. 
  • Navaja de Ockham: "En igualdad de condiciones, la explicación más sencilla suele ser la correcta".
  • Antoine de Saint-Exupéry (Autor de El Principito): "Parece que la perfección no se alcanza cuando no queda nada más que añadir, sino cuando no queda nada por quitar".
  • Leonardo da Vinci's: "La simplicidad es la máxima sofisticación"
Es importante que entendamos que no estamos buscando la forma más rápida de hacer el diseño, sino obtener como resultado el diseño más simple.
Simple quiere decir que no hagamos un objeto basado en tablas hash muy eficiente, ordenado, etc. si un array puede hacer esa función. 

Con este post acabamos con los principios de diseño más genéricos. Vendrán más un poco más adelante, pero lo siguiente será una serie donde habrá que "remangarse" y entrar en faena. Patrones de diseño. 

6 comentarios:

  1. Muy bueno, de acuerdo con todos los principios, gracias por el post!

    ResponderEliminar
  2. Me alegro que te guste el post Anton. Te invito a que eches un vistazo por lo demás que he publicado y que te suscribas por email a las actualizaciones. En breve empezamos con una serie sobre patrones de diseño que espero que también te guste.

    ResponderEliminar
  3. Excelente, justo que estoy haciendo cosas complejas, llega este post a darme pensamientos frescos, gracias!

    ResponderEliminar
  4. Discrepo sobre la interpretación de los principios.
    No creo que algo sin "pulir" siga un principio claro.

    Siguiendo tu ejemplo, las plantillas T4, según la interpretación que se de, no seguirán principios como DRY, YAGNI o KISS. Son los desarrolladores (como bien insinúas), los encargados de cumplir dichos principios.

    Por otra parte, pero en total conjunción con lo anterior, la ilimitación es ambigua, pero es a lo que cualquiera código o persona debería aspirar.

    De igual forma, YAGNI, mal entendido, censura en cierta forma la reutilización de código o la elección ante el camino difícil, cuando el coste de un cambio a tiempo puede suponer no perder un proyecto, apañarlo con código lamentable, etc.

    KISS es lo que debería predominar siempre, como dijo Leonardo da Vinci's. Pero simplicidad y simplismo es algo que tampoco diferencian muchos.

    Me parece muy interesante tu blog, la información que das, pero sobre todo tus planteamientos. Un saludo.

    ResponderEliminar
    Respuestas
    1. Hola Gabriel.
      Ante todo agradecerte tu comentario. Como ya he dicho en alguna ocasión contrastar opiniones y que aprendamos unos de los otros es un objetivo de este blog.

      Efectivamente una plantilla T4 puede que no siga ningún principio de los que hablo en este blog. La plantilla no es más que un generador de código y como bien dices debe ser el desarrollador que la crea el responsable de que el código generado siga estos principios.

      En el ejemplo de la plantilla T4 lo ponía como ejemplo de aplicación del principio DRY. No quiero decir que por ser una plantilla T4 el código que genera cumpla ese principio. Me refiero al sentido de la propia plantilla en si. Es decir, crear una entidad de Entity Framework requiere una serie de conocimientos que quizá no todos lo desarrolladores que usan Entity Framework tienen. Para ese caso la plantilla T4 es una representación única del conocimiento de un experto.

      Con respecto al principio YAGNI, completamente de acuerdo contigo. YAGNI no nos puede valer de excusa para no hacer lo que debemos hacer. El el post ya digo que aplicar este principio no quiere decir que no debamos crear diseños flexibles.

      También comparto contigo la importancia de distinguir entre simple y simplista. Aunque mi intención es un poco dejar claro eso cuando digo que al aplicar KISS buscamos un el diseño más simple que podría funcionar. Quizá debería haber aclarado más esta idea en el post.

      Quiero volver a agradecerte tu comentario, invitarte a seguir leyendo las próximas entradas y por supuesto a seguir dando tu punto de vista.

      Un saludo

      Eliminar