Saltar al contenido
Explorar conocimiento

concepto · fundamentos · 6 min de lectura

Abstracción

La abstracción modela lo esencial de un problema mediante contratos claros, ocultando detalles que no necesita conocer quien usa esa pieza de software.

Antes de leer esto, conviene conocer: Clase.

Alcance en breve

Cubre

  • abstraction as modeling essential behavior while hiding unnecessary details
  • interfaces, abstract classes, contracts, and intention-revealing APIs at a conceptual level
  • practical boundaries between useful abstraction, over-abstraction, encapsulation, and polymorphism

No cubre

  • category theory or mathematical abstraction
  • full type-system theory
  • language-specific abstract class and interface edge cases

Supone

  • The reader understands classes, methods, objects, and the idea of calling code through a named API.

Resumen

La abstracción es el principio de diseño que permite trabajar con una idea útil sin cargar todos sus detalles internos. En software, significa exponer un contrato claro —qué se puede pedir y qué se promete devolver— mientras se esconden las decisiones de implementación que no deberían importarle al consumidor.

Importa porque reduce acoplamiento. Si el resto del sistema depende de una idea estable, como PaymentGateway o NotificationChannel, puedes cambiar Stripe por otro proveedor, email por SMS o una base real por una fake de tests sin reescribir cada caso de uso. Una buena abstracción no es una capa extra por estética; es una frontera que preserva intención.

Alcance y supuestos

Este paquete cubre abstracción aplicada a diseño de software y OOP: interfaces, clases abstractas, contratos, APIs con intención y separación entre qué hace algo y cómo lo hace.

No cubre abstracción matemática, teoría de tipos avanzada, todos los detalles de abstract class en cada lenguaje, ni patrones de arquitectura completos. Asume que entiendes clases, métodos, objetos y llamadas a través de una API.

Modelo mental

Piensa en conducir un auto. Para avanzar usas volante, pedales y palanca o selector. No necesitas saber cómo se calcula la mezcla de combustible, cómo trabaja la transmisión o qué sensores ajustan el motor. La interfaz de conducción te muestra lo esencial para operar el sistema.

Una abstracción de software funciona igual: te deja usar una capacidad sin depender de su mecanismo interno. El consumidor necesita saber "puedo enviar una notificación", no si internamente usa SMTP, Twilio, Firebase o una cola.

El riesgo está en abstraer demasiado pronto. Si una abstracción no expresa una intención real, solo agrega nombres genéricos y salto mental. Una buena abstracción simplifica el uso; una mala abstracción oculta el problema.

Uso práctico

Usa abstracción cuando quieras separar una decisión estable de implementaciones variables:

  • ✅ Un caso de uso puede depender de PaymentGateway en vez de depender directamente de Stripe.
  • ✅ Un test puede usar InMemoryUserRepository si el contrato UserRepository está bien definido.
  • ✅ Un componente puede pedir NotificationChannel y aceptar email, SMS o push.
  • ❌ No crees IThingManagerService si todavía no sabes qué contrato real necesitas.
  • ❌ No confundas abstracción con esconder todo: el contrato debe decir algo preciso.

Ejemplo trabajado: abstraer el envío de notificaciones

Supón que una aplicación parte enviando emails, pero pronto puede necesitar SMS o push. Si el caso de uso conoce directamente EmailClient, quedará acoplado a ese detalle:

class EmailClient {
  sendEmail(to: string, subject: string, body: string) {
    return `Email sent to ${to}`;
  }
}

class WelcomeUser {
  constructor(private email: EmailClient) {}

  execute(userEmail: string) {
    return this.email.sendEmail(userEmail, "Welcome", "Thanks for joining");
  }
}

La abstracción aparece cuando nombramos la capacidad esencial: enviar una notificación. El caso de uso ya no depende del mecanismo concreto:

interface NotificationChannel {
  send(message: { to: string; title: string; body: string }): string;
}

class EmailNotificationChannel implements NotificationChannel {
  send(message: { to: string; title: string; body: string }) {
    return `Email sent to ${message.to}: ${message.title}`;
  }
}

class WelcomeUser {
  constructor(private notifications: NotificationChannel) {}

  execute(userEmail: string) {
    return this.notifications.send({
      to: userEmail,
      title: "Welcome",
      body: "Thanks for joining",
    });
  }
}

Ahora WelcomeUser expresa lo que necesita: un canal capaz de enviar mensajes. No sabe si es email, SMS o push. Esa es la abstracción útil: una frontera pequeña, estable y semántica.

Antes de introducir una abstracción, revisa tres preguntas:

  1. ¿Hay más de una implementación real o probable?
  2. ¿El consumidor puede describir su necesidad sin nombrar la tecnología concreta?
  3. ¿El contrato reduce acoplamiento o solo agrega una capa de nombres?

Si la respuesta es sí, la abstracción ayuda. Si no, probablemente conviene empezar con código directo y extraer la frontera cuando el cambio aparezca.

Evidencia

Conexiones

Requisitos

Requiere

Relacionados y alternativas

Ver grafo local

Fuentes citadas