13. Diseño simple

El Diseño Simple es uno de los valores y prácticas centrales de Extreme Programming (XP). En un entorno donde los requisitos cambian constantemente, crear diseños complejos para futuros inciertos es contraproducente. XP aboga por encontrar la solución más simple que funcione para los requisitos actuales, confiando en la refactorización para evolucionar el diseño a medida que surgen nuevas necesidades.

13.1. Crear solo lo necesario para cumplir los requisitos actuales

Este principio es conocido popularmente por el acrónimo YAGNI: "You Ain't Gonna Need It" (No vas a necesitarlo). La idea es resistir la tentación de añadir funcionalidades o complejidad al código basándose en especulaciones sobre el futuro.

En lugar de preguntarse "¿Qué podría necesitar este sistema en el futuro?", el equipo de XP se pregunta "¿Cuál es la forma más simple de resolver el problema que tenemos hoy?". Este enfoque tiene varias ventajas:

  • Entrega de valor más rápida: Al no invertir tiempo en funcionalidades no solicitadas, el equipo se centra en completar las historias de usuario actuales, entregando valor al cliente lo antes posible.
  • Menos código que mantener: Cada línea de código tiene un costo de mantenimiento. Escribir solo lo necesario reduce la base de código, lo que a su vez disminuye la complejidad y la probabilidad de errores.
  • Flexibilidad para el futuro: Un diseño simple es más fácil de entender y modificar. Cuando los requisitos cambian, es más sencillo adaptar un sistema simple que uno cargado de abstracciones y funcionalidades innecesarias.

13.2. Evitar sobreingeniería

La sobreingeniería es el acto de diseñar y construir un sistema de una manera mucho más compleja de lo necesario para los requisitos actuales. Es el enemigo directo del Diseño Simple. A menudo, los desarrolladores caen en la sobreingeniería por buenas intenciones: quieren crear un sistema robusto, flexible y preparado para cualquier eventualidad futura.

Sin embargo, esto suele llevar a:

  • Complejidad innecesaria: Se introducen patrones de diseño, capas de abstracción o configuraciones complejas que no aportan valor real para la funcionalidad actual.
  • Aumento de costos: Más código y más complejidad significan más tiempo de desarrollo, más tiempo de prueba y más esfuerzo de mantenimiento.
  • Rigidez: Irónicamente, un diseño excesivamente complejo puede volverse rígido. Si las suposiciones sobre el futuro resultan ser incorrectas, puede ser más difícil cambiar el sistema que si se hubiera partido de un diseño más simple.

XP confía en que es mejor y más barato adaptar un diseño simple cuando sea necesario, gracias a prácticas como TDD y la refactorización, que empezar con un diseño complejo basado en la especulación.

13.3. Principio KISS ("Keep It Simple, Stupid")

El principio KISS es una máxima de diseño que se originó en la Marina de los EE. UU. en 1960 y que ha sido adoptada masivamente en el mundo del desarrollo de software. Sostiene que la mayoría de los sistemas funcionan mejor si se mantienen simples en lugar de complejos. Por lo tanto, la simplicidad debe ser un objetivo clave en el diseño, y se debe evitar la complejidad innecesaria.

En XP, KISS se manifiesta en varias prácticas:

  • Código claro y legible: Preferir un código que sea fácil de entender para todo el equipo por encima de soluciones "ingeniosas" o crípticas.
  • Soluciones directas: Abordar el problema de la manera más directa posible, sin añadir capas de indirección que no sean estrictamente necesarias.
  • Menos es más: Siempre que sea posible, resolver un problema con menos clases, menos métodos y menos configuración.

Un equipo de XP evalúa un diseño preguntándose: "¿Podemos hacerlo más simple?". Si la respuesta es sí, y la solución más simple sigue cumpliendo todos los requisitos, esa es la dirección a seguir.

13.4. Ejemplo de diseño simple aplicado

Imaginemos que necesitamos una función que devuelva un saludo en diferentes idiomas. Un desarrollador podría pensar en el futuro y decidir aplicar un patrón de diseño complejo como el Patrón Factory.

Solución con sobreingeniería (Patrón Factory innecesario)

Este enfoque es flexible, pero excesivamente complejo para dos idiomas.


# Interfaz del saludador
class Saludo:
    def saludar(self):
        raise NotImplementedError

# Implementaciones concretas
class SaludoEspanol(Saludo):
    def saludar(self):
        return "Hola"

class SaludoIngles(Saludo):
    def saludar(self):
        return "Hello"

# Factory para crear el objeto correcto
class SaludoFactory:
    def obtener_saludo(self, idioma):
        if idioma == 'es':
            return SaludoEspanol()
        elif idioma == 'en':
            return SaludoIngles()

# Uso
factory = SaludoFactory()
saludo_es = factory.obtener_saludo('es')
print(saludo_es.saludar()) # Imprime "Hola"

Solución con Diseño Simple (KISS y YAGNI)

Aplicando los principios de Diseño Simple, creamos solo lo necesario para los requisitos actuales. Un diccionario es suficiente y mucho más fácil de leer y mantener.


SALUDOS = {
    'es': 'Hola',
    'en': 'Hello',
}

def obtener_saludo(idioma):
    """Devuelve el saludo para un idioma, con un valor por defecto."""
    return SALUDOS.get(idioma, 'Idioma no soportado')

# Uso
print(obtener_saludo('es')) # Imprime "Hola"
print(obtener_saludo('fr')) # Imprime "Idioma no soportado"

Esta segunda solución es drásticamente más simple. Tiene menos líneas de código, ninguna clase o indirección innecesaria, y es trivial de entender. Si en el futuro se necesita una lógica más compleja (por ejemplo, saludos que dependan de la hora del día), el equipo puede refactorizar esta solución simple con la confianza que le dan sus pruebas. Empezar con la solución compleja desde el principio habría sido un desperdicio de esfuerzo.