Skip to main content

Inicia sesión en CleanKata

Sigue tu progreso, gana XP y desbloquea todas las lecciones.

Al iniciar sesión aceptas nuestros Términos de uso y Política de privacidad.

Arquitectura Limpia80 XP8 min

DIP: El Principio de Inversión de Dependencias

Las dependencias del código fuente deben apuntar solo a abstracciones — las Fábricas Abstractas crean la frontera arquitectónica entre el código concreto volátil y la política estable.

Por qué importa

El DIP establece que la política de alto nivel (reglas de negocio) no debe depender del detalle de bajo nivel (bases de datos, frameworks, E/S). Ambos deben depender de abstracciones. En el mundo ideal del DIP, cada dependencia del código fuente apunta hacia una interfaz abstracta, nunca hacia una implementación concreta.

Martin ilustra la consecuencia práctica con el patrón Abstract Factory. El código de negocio necesita crear objetos — un pedido, un repositorio, un pago — pero no debe llamar directamente a new MySQLOrderRepository(), porque eso acoplaría la política de negocio estable a una elección de infraestructura volátil. La Abstract Factory crea objetos concretos al otro lado de una frontera arquitectónica, para que el código de negocio dependa solo de la interfaz de la fábrica y la interfaz del repositorio. La "línea curva" que separa lo abstracto de lo concreto es la frontera arquitectónica misma — todo lo estable y reutilizable de un lado, todo lo volátil y reemplazable del otro.

✗El problema

OrderService directly instantiates MySQLOrderRepository — the business layer is hardwired to a database technology it should never know about.

Bad

class MySQLOrderRepository:
    def save(self, order: dict) -> None:
        mysql.execute("INSERT INTO orders ...", order)

class OrderService:
    def __init__(self):
        self.repo = MySQLOrderRepository()   # hardwired to MySQL!

    def place_order(self, order: dict) -> None:
        # business logic...
        self.repo.save(order)
class MySQLOrderRepository {
  save(order: Order): void {
    mysql.execute("INSERT INTO orders ...", order);
  }
}

class OrderService {
  private repo = new MySQLOrderRepository(); // hardwired — DIP violation

  placeOrder(order: Order): void {
    // business logic...
    this.repo.save(order);
  }
}

✓La solución

OrderService depends only on an abstract repository interface. An Abstract Factory creates the concrete implementation — business policy and infrastructure detail are separated by an architectural boundary.

Good

from abc import ABC, abstractmethod

class OrderRepositoryInterface(ABC):
    @abstractmethod
    def save(self, order: dict) -> None: ...

class OrderRepositoryFactory(ABC):
    @abstractmethod
    def create(self) -> OrderRepositoryInterface: ...

# ── Stable policy (business side) ────────────────────────────────────────────
class OrderService:
    def __init__(self, factory: OrderRepositoryFactory):
        self.repo = factory.create()   # depends on abstraction only

    def place_order(self, order: dict) -> None:
        # business logic...
        self.repo.save(order)

# ── Volatile detail (infrastructure side) ────────────────────────────────────
class MySQLOrderRepository(OrderRepositoryInterface):
    def save(self, order: dict) -> None:
        mysql.execute("INSERT INTO orders ...", order)

class MySQLRepositoryFactory(OrderRepositoryFactory):
    def create(self) -> OrderRepositoryInterface:
        return MySQLOrderRepository()
interface OrderRepository {
  save(order: Order): void;
}

interface OrderRepositoryFactory {
  create(): OrderRepository;
}

// ── Stable policy (business side) ────────────────────────────────────────────
class OrderService {
  private repo: OrderRepository;

  constructor(factory: OrderRepositoryFactory) {
    this.repo = factory.create();  // depends on abstraction
  }

  placeOrder(order: Order): void {
    // business logic...
    this.repo.save(order);
  }
}

// ── Volatile detail (infrastructure side) ────────────────────────────────────
class MySQLOrderRepository implements OrderRepository {
  save(order: Order): void {
    mysql.execute("INSERT INTO orders ...", order);
  }
}

class MySQLRepositoryFactory implements OrderRepositoryFactory {
  create(): OrderRepository { return new MySQLOrderRepository(); }
}

💡Conclusión clave

Cada new ClaseConncreta() dentro de tu lógica de negocio es una violación del DIP — conecta rígidamente la política estable a un detalle volátil. Usa una fábrica o inyecta la dependencia para que la capa de negocio nunca sepa con qué tipo concreto está trabajando.

🔧 Algunos ejercicios pueden tener errores. Si algo parece incorrecto, usa el botón Feedback (abajo a la derecha) para reportarlo — nos ayuda a corregirlo rápido.

Pista: Cada `new ClaseConcreta()` en tu lógica de negocio es una violación del DIP — usa una fábrica o inyecta la dependencia.

✗ Tu versión

DIP: El Principio de Inversión de Dependencias — CleanKata — CleanKata