Blog
Blog Author
Mikel Cantero
  • 25 de mayo de 2026

Si alguna vez te has sumergido en el ecosistema de frameworks modernos como Spring (Java), Angular (TypeScript), NestJS (Node.js) o .NET, es casi seguro que te has cruzado con las siglas IoC (Inversion of Control) o Inversión de Control.

Al principio suena a pura teoría abstracta e intimidante, pero en realidad es el “ingrediente secreto” que hace que estos frameworks sean tan potentes. Hoy vamos a destripar este concepto para que no solo lo entiendas, sino que seas capaz de detectarlo a primera vista en cualquier código.

Para entender la Inversión de Control, primero debemos entender el control “tradicional”.

En la programación de la vieja escuela, tu código tenía el control total. Si tu aplicación necesitaba enviar un correo electrónico, tenías que crear la instancia del servicio de correo, configurar los parámetros y decidir exactamente cuándo y cómo se ejecuta. Tu código llamaba a las librerías.

Con la Inversión de Control, las cosas se dan la vuelta por completo. Ya no eres tú quien llama al framework; es el framework el que llama a tu código. Tú te limitas a definir las piezas del rompecabezas (tus clases, tus funciones) y el framework se encarga de unirlas, instanciarlas y ejecutarlas en el momento adecuado.

💡 La Ley de Hollywood: La mejor forma de resumir IoC es con la famosa frase que los directores de cine le dicen a los actores amateurs: “No nos llames, nosotros te llamamos”.

¿Qué problema viene a resolver?

Imagínate que estás construyendo un coche. En el enfoque tradicional, la clase Coche crea internamente su propio Motor V8.

[ Enfoque Tradicional ]
Tu Código ───(Crea e Instancia)───> Dependencias (Librerías)

¿Qué pasa si mañana quieres que el coche sea eléctrico? Tienes que romper y modificar la clase Coche. Esto genera un alto acoplamiento (las piezas están pegadas con pegamento extra fuerte). Si una pieza cambia, todo lo demás se rompe.

IoC rompe este paradigma al separar la creación de las cosas de su uso. El coche simplemente dice “necesito un motor, me da igual cuál” y un ente externo (el contenedor de IoC del framework) se lo inyecta.

Ventajas de usar IoC

Implementar este patrón en la arquitectura de software nos da superpoderes:

  • Desacoplamiento total: Las clases no saben cómo se crean sus dependencias, solo las usan.
  • Código más mantenible: Cambiar un componente por otro (por ejemplo, cambiar tu base de datos de MySQL a MongoDB) es ridículamente fácil.
  • Facilidad para hacer Testing (Mocking): Como las dependencias se inyectan desde fuera, en tus pruebas unitarias puedes inyectar un componente “falso” (mock) para probar tu lógica sin tocar la base de datos real.
  • Modularidad: Promueve que escribas código limpio, modular y enfocado en una sola responsabilidad.

Un ejemplo práctico: Del Caos al Orden

Vamos a ver un ejemplo muy sencillo en TypeScript (aplicable a cualquier lenguaje) para que veas la diferencia real en el código.

1. El enfoque tradicional (Sin IoC)

Aquí, la clase UserService tiene el control absoluto y crea directamente su dependencia. Está “atada” a SqlDatabase.

class SqlDatabase {
    save(user: string) { console.log(`Guardando a ${user} en SQL`); }
}

class UserService {
    private database: SqlDatabase;

    constructor() {
        // El control está aquí: UserService crea activamente la base de datos
        this.database = new SqlDatabase();
    }

    register(user: string) {
        this.database.save(user);
    }
}

2. Aplicando IoC (Mediante Inyección de Dependencias)

Nota: La Inyección de Dependencias (DI) es la forma más común de implementar IoC.

Primero, creamos una interfaz para que el servicio no dependa de una clase concreta, sino de un contrato. Luego, “invertimos el control”: en lugar de crear la base de datos adentro, la pedimos por el constructor.

interface Database {
    save(user: string): void;
}

class MongoDatabase implements Database {
    save(user: string) { console.log(`Guardando a ${user} en MongoDB`); }
}

class UserService {
    private database: Database;

    // ¡Control Invertido! No creamos nada, nos lo dan desde fuera
    constructor(database: Database) {
        this.database = database;
    }

    register(user: string) {
        this.database.save(user);
    }
}

// El "Framework" o el entorno se encarga de la configuración:
const miDb = new MongoDatabase();
const userService = new UserService(miDb); // Inyectamos la dependencia

¿Ves la magia? Ahora UserService es completamente agnóstico a la base de datos que uses. Si pasamos de SQL a Mongo, UserService ni se entera.

Cómo identificar IoC en Frameworks Modernos

Cuando trabajas con herramientas actuales, rara vez haces el new UserService(miDb) a mano. El framework tiene un “Contenedor de IoC” que lo hace por ti tras bambalinas. Puedes identificarlo si ves esto:

  • En Angular o NestJS: El uso de decoradores como @Injectable() en tus clases y ver que simplemente pides cosas en el constructor(private miServicio: MiServicio). Tú nunca haces new MiServicio(), el framework lo busca y te lo da.
  • En Spring Boot (Java): Anotaciones como @Component, @Service o @Autowired. Le estás diciendo a Spring: “Oye, gestiona tú esta clase y ponla donde haga falta”.
  • En .NET Core: La configuración en el archivo Program.cs mediante builder.Services.AddTransient<IRepository, SqlRepository>(). Le enseñas al framework cómo resolver las piezas del puzle.

Conclusión

La Inversión de Control no es más que delegar la responsabilidad de la creación y el flujo de la aplicación a una entidad externa (el framework) para que tú puedas concentrarte en lo que de verdad importa: la lógica de negocio de tu aplicación.

La próxima vez que veas un constructor recibiendo servicios de la nada en tu framework favorito, sonríe: estás viendo a la Inversión de Control trabajando para ti.

Mis números

Información relevante

Años de experiencia
+ 7
Años de experiencia
Proyectos
16
Proyectos
Posts
39
Posts