DEV Community

IagoLast
IagoLast

Posted on

Inversión de dependencias

Si tuviese que elegir un primer tema a la hora de hablar de arquitectura de software lo tendría claro: Inversión de la dependencia. Este concepto no es nuevo y sin embargo son pocos los que lo aplican en su código. En este artículo me gustaría explicar este concepto de la forma más sencilla posible y poner ejemplos que faciliten su comprensión.

Abstracciones, detalles e interfaces

Antes de entrar en materia es importante definir una serie de conceptos que nos permitirán entender correctamente en que consiste el la inversión de la dependencias.

  • Abstracción (del latín abstrahere, 'alejar, sustraer, separar') es una operación mental destinada a aislar conceptualmente una propiedad o función concreta de un objeto, y pensar qué es, ignorando otras propiedades del objeto en cuestión.
  • Detalle es una parte, hecho o circunstancia que contribuye a formar o completar una cosa pero no es indispensable en ella.
  • Interfaz es la conexión funcional entre dos sistemas, programas, dispositivos o componentes de cualquier tipo, que proporciona una comunicación de distintos niveles de abstracción, permitiendo el intercambio de información.

Para entender estos conceptos vamos a poner un pequeño ejemplo aplicándolos en mundo de la automoción.

Abstracciones en automoción

Para la mayoría de los conductores el motor de sus coches es una abstracción, un concepto del que no necesitan conocer todos los detalles para poder conducir correctamente. Estoy seguro de que muy pocos sabemos si nuestro coche tiene un motor con una configuración de cilindros en línea o una configuración en V. Simplemente necesitamos saber cuatro cosas sencillas como si es diésel o gasolina o cada cuantos kilómetros necesita un cambio de aceite. El coche en sí es una abstracción para los conductores y esta abstracción es posible porque los coches nos ofrecen una serie de interfaces que nos permiten conducirlos sin necesidad de conocer sus detalles de implementación.

¿Os imagináis tener que estudiar absolutamente todos los detalles de cada coche para poder conducirlo? Gracias a las abstracciones podemos pasar de tener que conocer todos los detalles de implementación...

...a tener una serie de interfaces que nos permiten conducir sin necesidad de conocer los detalles

De esta forma podemos conducir cualquier modelo de coche, abstrayéndonos del tipo de motor, del amperaje de la batería, de si es de gasolina o eléctrico o de cuántos cilindros tenga... Es suficiente con conocer la interfaz que nos exponen los fabricantes a los conductores para conducir correctamente el vehículo.

Abstracciones en software

De la misma forma que en la automoción, en el mundo del software también se manejan estos tres conceptos. Por poner un ejemplo, las funciones son abstracciones que conociendo su interfaz (parámetros de entrada y valor de retorno) nos permiten realizas tareas complejas obviando los detalles de implementación.

Por ejemplo sabemos que la función btoa de javascript recibe como parámetro un string y devuelve su representación en base64 pero no necesitamos conocer el RFC donde se define el algoritmo para utilizarla ya que para nosotros es un detalle de implementación sin importancia.

Inversión de la dependencia

¿Qué nos dice el principio de la inversión de la dependencia?

A grandes rasgos nos dice que nuestro código debe depender de abstracciones en lugar de depender de detalles.

En lenguajes como Java este principio suele ser mas sencillo de aplicar porque el propio lenguaje dispone del concepto de interfaz pero en el mundo del frontend su aplicacón suele no ser tan directa.

Una forma sencilla que me gusta utilizar para que mi código no dependa de detalles es crear módulos intermedios que sirvan como abstracción de una implementación concreta.

Pongamos un ejemplo:

// LoginPage.tsx
import ReactGA from 'react-ga';

/**
 * Componente de react que contiene una página de login
 */
export default function LoginPage() {
    /**
     * Función de login que se ejecutará cuando el usuario haga click en el botón de "login"
     */
    function login(e: React.FormEvent<HTMLFormElement>) {
        /**
         * Enviamos eventos a Google Analytics
         */
        ReactGA.event({ category: 'User', action: 'login' });
        // ...
    }

    /**
     * Omitimos la UI dado que no es relevante para este ejemplo
     */
    return <form onsubmit={login}> ... </form>;
}

Enter fullscreen mode Exit fullscreen mode

Imaginemos una página de Login que registra un evento cada vez que el usuario envía el formulario de login al servidor. Esta página utiliza react-ga (Una librería de google analytics sobre React) para monitorizar los eventos del usuario.

Screenshot 2021-10-04 at 09.57.07

El problema de esta aproximación es que los componentes (páginas) están acoplados a google-analytics (react-ga).

Una forma sencilla de eliminar este acoplamiento sería crear un módulo intermedio llamado analytics y que sea este módulo quien dependa de google-analytics:

// LoginPage.tsx
import analytics from './analytics.ts'; // LoginPage solamente depende de analytics

/**
 * Componente de react que contiene una página de login
 */
export default function LoginPage() {
    /**
     * Función de login que se ejecutará cuando el usuario haga click en el botón de "login"
     */
    function login(e: React.FormEvent<HTMLFormElement>) {
        /**
         * ¡¡Enviamos eventos a nuestra abstracción de analíticas!!
         */
        analytics.event({ category: 'User', action: 'login' });
        // ...
    }

    /**
     * Omitimos la UI dado que no es relevante para este ejemplo
     */
    return <form onsubmit={login}> ... </form>;
}

Enter fullscreen mode Exit fullscreen mode
// analytics.ts
import ReactGA from 'react-ga'; // analytics.ts depende de google-analytics

/**
 * Exponemos una función que nos abstrae de la implementación concreta.
 */
function track(args: { category: string; action: string }) {
    ReactGA.event(args);
}
Enter fullscreen mode Exit fullscreen mode

Screenshot 2021-10-04 at 10.00.32

De esta forma el código de los componentes ya no depende directamente de Google analytics, si no que depende de una abstracción llamada analytics cuyo detalle de implementación es desconocido para los componentes.

Aunque puede parecer una tontería hemos desacoplado la lógica de las analíticas del resto de nuestro código y si dentro de unos meses decidimos migrar a cualquier otro proveedor de analíticas basta con hacer cambios en el archivo analytics y si estos cambios mantienen la misma interfaz el resto del código funcionará perfectamente.

Volviendo a la metáfora de los coches, podríamos decir qué mientras los pedales funcionen de la misma forma podríamos llegar a reemplazar el motor por otro diferente de forma totalmente transparente para el conductor.

Resumen

En este artículo hemos visto en que consiste la inversión de la dependencia, los conceptos de abstracción, detalle de implementación e interfaz y cómo se relacionan entre sí. También hemos visto una forma sencilla de abstraer el código de los detalles utilizando módulos intermedios.

Discussion (0)