Los principios DRY, KISS y YAGNI comparten un objetivo: mantener el software simple, coherente y enfocado. En proyectos con Java, adoptarlos en conjunto permite evitar duplicaciones, reducir la complejidad accidental y posponer el trabajo especulativo.
Comprender cómo se complementan ayuda a tomar decisiones equilibradas. Cada principio aborda un ángulo distinto de la simplicidad, y su combinación protege al equipo de desviarse hacia soluciones innecesarias.
Aplicar solo uno de los principios puede crear desequilibrios. Por ejemplo, eliminar duplicaciones sin cuidar la claridad produce abstracciones difíciles de leer; mantener el código simple pero repetido incrementa el costo de mantenimiento; evitar funcionalidades futuras sin DRY puede multiplicar inconsistencias. Al usar los tres:
La siguiente tabla resume qué preguntar ante una nueva funcionalidad:
| Pregunta | Principio relacionado | Acción recomendada |
|---|---|---|
| ¿Existe código similar que ya resuelva esto? | DRY | Reutilizar o extraer la lógica compartida en un módulo único. |
| ¿El diseño es comprensible para alguien que lo lee por primera vez? | KISS | Simplificar nombres, dividir responsabilidades y eliminar pasos superfluos. |
| ¿Hay evidencia de que realmente se necesita esta funcionalidad ahora? | YAGNI | Posponer la implementación hasta contar con métricas o requerimientos claros. |
Repasemos un caso donde los tres principios se aplican en conjunto. Partimos de una implementación que intenta ser extensible desde el inicio, con duplicaciones y lógica dispersa.
// Implementación inicial: duplicación, complejidad y lógica especulativa
class NotificationService {
private final EmailClient emailClient;
private final SmsClient smsClient;
private final FeatureToggle toggles;
NotificationService(EmailClient emailClient,
SmsClient smsClient,
FeatureToggle toggles) {
this.emailClient = emailClient;
this.smsClient = smsClient;
this.toggles = toggles;
}
void notifyOrderCreated(Order order) {
if (toggles.isEnabled("EMAIL_NOTIFICATIONS")) {
emailClient.send(order.customerEmail(), buildEmail(order));
}
if (toggles.isEnabled("SMS_NOTIFICATIONS")) {
smsClient.send(order.customerPhone(), buildSms(order));
}
if (toggles.isEnabled("PUSH_NOTIFICATIONS")) {
// Implementación pendiente para futuras plataformas
}
}
private String buildEmail(Order order) {
return "Pedido " + order.id() + " creado";
}
private String buildSms(Order order) {
return "Pedido " + order.id() + " listo";
}
}
La refactorización aplica DRY, KISS y YAGNI: se extrae la lógica común de mensajes (DRY), se simplifica el flujo (KISS) y se elimina la rama especulativa de push notifications (YAGNI).
// Implementación refinada: responsabilidades claras y sin suposiciones futuras
final class NotificationService {
private final List<Notifier> notifiers;
NotificationService(List<Notifier> notifiers) {
this.notifiers = List.copyOf(notifiers);
}
void notifyOrderCreated(Order order) {
String message = MessageTemplates.pedidoCreado(order);
notifiers.forEach(notifier -> notifier.send(order, message));
}
}
interface Notifier {
void send(Order order, String message);
}
Las implementaciones concretas de Notifier se crean solo para canales existentes. Si mañana surge un canal adicional con evidencia real, se agregará una nueva clase sin modificar el servicio principal.
DRY, KISS y YAGNI no compiten: se refuerzan mutuamente. Mantenerlos en equilibrio permite entregar valor con rapidez, minimizar la complejidad y conservar la flexibilidad para responder a cambios del negocio.