Saltar al contenido
Explorar conocimiento

práctica · fundamentos · 8 min de lectura

Principio KISS

KISS —Keep It Simple, Stupid— es el principio de diseño que establece que la simplicidad debe ser un objetivo prioritario: la solución más simple que funciona es preferible a una más compleja que anticipa necesidades futuras sin evidencia.

No requiere conocimientos previos.

Alcance en breve

Cubre

  • KISS as a design heuristic: prefer the simplest solution that meets current requirements
  • the cost of unnecessary complexity in maintenance, onboarding, and debugging
  • practical signs of over-engineering and how to avoid them
  • the relationship between KISS and other principles (YAGNI, SOLID, DRY)
  • when complexity is justified and KISS should yield to other concerns

No cubre

  • formal complexity theory or algorithmic complexity analysis
  • specific refactoring techniques beyond conceptual examples
  • the history of the principle beyond its origin and motivation

Supone

  • The reader has written or reviewed code and has encountered solutions that felt more complex than the problem they solved.

Resumen

KISS es un acrónimo de Keep It Simple, Stupid —«mantenelo simple, estúpido»—, un principio de diseño formulado por el ingeniero aeronáutico Kelly Johnson en los años 60. Su premisa es contundente: la mayoría de los sistemas funcionan mejor si se los mantiene simples. La complejidad innecesaria es la fuente principal de bugs, costos de mantenimiento y barreras de entrada para nuevas personas en el equipo.

Importa porque el software tiende naturalmente a la complejidad. Cada requisito nuevo, cada caso borde, cada «por las dudas» agrega capas que parecen inofensivas en el momento pero que se acumulan. KISS no es un llamado a hacer código mediocre o incompleto: es la disciplina de preguntarse, antes de agregar cualquier abstracción, «¿esto resuelve un problema que tengo hoy, o uno que imagino que podría tener mañana?».

KISS complementa otros principios. YAGNI —You Ain't Gonna Need It— es KISS aplicado a features: no construyas lo que no necesitás. SOLID es KISS aplicado al diseño de clases: cada clase hace una sola cosa. DRY —Don't Repeat Yourself— es KISS aplicado a la duplicación: una sola fuente de verdad es más simple que tres copias desincronizadas. KISS es el principio paraguas: si no podés explicar tu solución en cinco minutos, probablemente sea más compleja de lo necesario.

Alcance y supuestos

Este paquete cubre KISS como heurística de diseño: su origen, cómo detectar complejidad innecesaria, cómo aplicar simplicidad sin caer en simplismo, y cómo balancear KISS con otros principios cuando entran en tensión.

No cubre teoría formal de complejidad algorítmica, análisis de complejidad ciclomática, ni métricas cuantitativas de mantenibilidad. Tampoco cubre técnicas de refactoring específicas más allá de ejemplos conceptuales.

Asume que has escrito o revisado código y te has encontrado con soluciones que te hicieron pensar «esto es más complicado de lo que debería ser».

Modelo mental

Pensá en una navaja suiza versus un cuchillo de cocina. La navaja suiza tiene 20 funciones: tijera, destornillador, sierra, abrelatas. El cuchillo de cocina tiene una: cortar. Para cortar un tomate, ¿cuál agarrás? El cuchillo. La navaja suiza puede hacerlo, pero es incómoda, insegura y difícil de limpiar. Tener más funciones no la hace mejor para cada tarea: la hace peor para la mayoría.

En software pasa lo mismo. Una función que recibe un objeto de configuración con 15 parámetros —8 de los cuales son opcionales y 3 solo se usan en un modo específico— es la navaja suiza. Una función que recibe exactamente lo que necesita y hace una sola cosa es el cuchillo de cocina. La navaja suiza tiene sentido cuando realmente necesitás las 20 funciones en un solo dispositivo. Pero la mayoría de las veces, solo necesitás cortar un tomate.

KISS te pide que uses el cuchillo salvo que tengas evidencia de que necesitás la navaja.

Uso práctico

Aplicá KISS como filtro mental en cada decisión de diseño:

  • ✅ Elegir un Map<string, number> en vez de una clase Counter con 5 métodos si solo necesitás acumular conteos.
  • ✅ Escribir un if/else de 3 ramas en vez de un Strategy pattern con 3 clases si el equipo no prevé más variantes.
  • ✅ Usar un JSON file como configuración en vez de una base de datos si los datos cambian una vez por mes.
  • ✅ Hardcodear un valor en vez de crear un sistema de feature flags si ese valor solo cambia entre entornos y ya tenés variables de entorno.
  • ❌ Simplificar tanto que el código se vuelva críptico. a, b, x como nombres de variables no es KISS, es desprolijidad.
  • ❌ Evitar una abstracción necesaria porque «es más simple sin ella». Si tres módulos duplican la misma lógica de validación de email, extraerla a una función es KISS.

Cómo detectar complejidad innecesaria

La complejidad se anuncia con síntomas concretos. Reconocelos:

  • Sobre-abstracción: creaste una interfaz, una clase base, dos implementaciones y un factory para una variante que nunca llegó. Si solo hay una implementación de una interfaz, preguntate si la interfaz está justificada o es speculative generality.
  • Flexibilidad sin uso: agregaste un parámetro opcional «por si acaso» que nadie usó en 9 meses. Cada parámetro opcional es una rama que testear, documentar y mantener.
  • Generalidad prematura: escribiste una función genérica con 3 type parameters que solo se llama con string. La generalidad que no se usa es deuda técnica disfrazada de buen diseño.
  • Profundidad innecesaria: para entender qué hace un endpoint, tengo que abrir Controller → Service → Repository → Entity → Mapper → DTO. Si el 80% de las operaciones son CRUD directo, quizás con Controller → Repository alcanza.

Relación con otros principios

| Principio | Relación con KISS | |---|---| | YAGNI | KISS dice «hacelo simple». YAGNI dice «ni siquiera lo hagas si no lo necesitás». Son el mismo consejo desde dos ángulos. | | SOLID | SRP simplifica clases. OCP evita modificar código que funciona. DIP simplifica testing. SOLID bien aplicado produce código más simple, no más complejo. | | DRY | No repetir lógica hace el sistema más simple, pero DRY mal aplicado —abstraer dos cosas que parecen iguales pero cambian por motivos distintos— genera acoplamiento y viola KISS. |

Cuándo la complejidad está justificada

KISS no prohíbe la complejidad. La exige cuando el problema la requiere:

  • Rendimiento crítico: un algoritmo O(n²) es más simple que un O(n log n), pero si n = 10 millones, la complejidad está justificada.
  • Dominio inherentemente complejo: un sistema de compliance financiero o de control de tráfico aéreo tiene complejidad esencial que no se puede simplificar sin perder corrección.
  • Restricciones no negociables: si una certificación de seguridad exige cierta arquitectura, KISS cede ante el requisito regulatorio.

Ejemplo trabajado: dos formas de filtrar usuarios

Un sistema necesita obtener usuarios activos mayores de 18 años. Dos programadores proponen soluciones.

Solución A — "preparada para el futuro":

interface UserFilterCriteria {
  status?: string;
  minAge?: number;
  maxAge?: number;
  role?: string;
  joinedAfter?: Date;
}

class UserFilter {
  constructor(private criteria: UserFilterCriteria) {}
  apply(users: User[]) {
    return users.filter(user => {
      if (this.criteria.status && user.status !== this.criteria.status) return false;
      if (this.criteria.minAge !== undefined && user.age < this.criteria.minAge) return false;
      if (this.criteria.maxAge !== undefined && user.age > this.criteria.maxAge) return false;
      if (this.criteria.role && user.role !== this.criteria.role) return false;
      return true;
    });
  }
}

const filter = new UserFilter({ status: "active", minAge: 18 });
const result = filter.apply(users);

Solución B — KISS:

const result = users.filter(user => user.status === "active" && user.age >= 18);

La solución A anticipa necesidades que no existen hoy: filtrar por rol, por fecha de registro, por rango de edad. Esas seis líneas extra son deuda desde el día uno. Nadie las pidió, nadie las testea, y cuando alguien necesite filtrar por rol probablemente los requisitos sean distintos a lo que UserFilterCriteria asumió.

La solución B resuelve el problema actual con una línea. Si mañana aparece el requisito de filtrar por rol, se agrega && user.role === "admin". Si aparece filtrar por fecha, se agrega otra condición. Cada adición está justificada por un requisito real, no por una especulación.

Eso es KISS aplicado.

Antes de escribir la próxima abstracción, hacete tres preguntas:

  1. ¿Este código resuelve un problema que existe hoy en producción?
  2. ¿Puedo explicarle esta solución a un compañero en dos minutos sin dibujar un diagrama?
  3. Si en seis meses aparece el requisito que estoy anticipando, ¿agregarlo sobre la solución simple va a costar más que mantener la complejidad actual durante seis meses sin usarla?

Si la respuesta a la primera es no, no escribas ese código. Si la respuesta a la tercera es sí, documentá la decisión y aplicá KISS.

Evidencia

  • Wikipedia, KISS principle documenta el origen del principio en la ingeniería aeronáutica de Kelly Johnson en Lockheed, su enunciado original —«Keep it simple, stupid»— y su adopción en múltiples disciplinas incluyendo el desarrollo de software.

Fuentes citadas