Invierte en tu educación con el precio especial

Antes:$249

Currency
$209

Paga en 4 cuotas sin intereses

Paga en 4 cuotas sin intereses
Suscríbete

Termina en:

12d

04h

15m

03s

1

Integrando Dagger2: Introducción concepto Inversión de Dependencias

DI

Dagger2 es un framework preferido por la comunidad de desarrolladores Android. Pero intentar entender la integración de Dagger2 en nuestros proyectos de Android no es muy fácil en un inicio.

La cuestión es que para poder usar Dagger2 es necesario tener buenos conocimientos sobre arquitectura de software, y muchos tutoriales existentes en internet omiten esta parte, enseñando Dagger2 sin este conocimiento básico. En esta seria de articulos, mi objetivo es compartir mi conocimento empírico para mostrar todos lo conceptos necesarios para la adopción de Dagger2 usando como base el proyecto Android con Kotlin de este curso (auqnue será en post posteriores, ya que este primero me encofo en explicar los conceptos).

¿Que es inyección de dependencias?

En informática, inyección de dependencias (en inglés Dependency Injection, DI) es un patrón de diseño orientado a objetos, en el que se suministran objetos a una clase en lugar de ser la propia clase la que cree el objeto

~Wikipedia

¿Razones para usar esta técnica?

  1. Nos ayuda adherirnos a los principios SRP y DIP
  2. Nuestro código es mas testeable
    TDD

Dagger2 es un framework para Inyección de Dependencias o Dependency Injection(DI). Para trabajar una arquitectura limpia, DI es generalmente usado en conjunto con el Principio de Inversión o Dependency Inversion Principle (DIP). DI y DIP son dos padrones distintos que a continuación voy a ejemplificar para entender su diferencia con un caso de uso de una persona Player que lanza un dado Dice.

classPlayer{
    funthrowDice(): Int {
        val r = Random()
        return r.nextInt(42) + 1
    }
    // other functions
}

En la clase anterior, Player depende de la clase Random. Además de eso, esta controlando como se crea la instancia de Random. El código anterior se puede refactorar usando DI para <ins>inyectar</ins> esa depencia y quedaria de la siguiente manera:

classPlayerDI(privateval r: Random) {

    funthrowDice(): Int {
        returnr.nextInt(42) + 1
    }
    // other functions}

La clase PlayerDI no tiene mas control sobre como es que la clase Random es instanciada. Y esto es el concepto básico de inyección de dependencias DI.

Sin embargo, depender de una clase de "bajo nível"como lo es Random en este ejemplo, es problematico en lo general. Lo ideial, sería que la clase PlayerDI usase una clase en el mismo nivel de abstracción. Y eso, sería DIP.

interfaceDice{
    funthrow(): Int
}

classPlayerDIP(privateval dice: Dice) {

    funthrowDice(): Int {
        return dice.throw()
    }
    // other functions
}

La clase PlayerDIP esta usando DIP para abstraer la operación del método throw o lanzar el dado, que ahora fue delegado para otra clase que implemente la interface ‘Dice’.

Es importante resaltar que PlayerDIP no precisa saber como es que la clase Dice es implementada, dejando el código más fácil de mantener. Esa seria la idea del Principio de Inversión o Dependency Inversion Principle (DIP).

¿Para que me sirve DIP?

Existen diversas controverisas con relación al uso y beneficios de DIP. Dejare algunas situaciones concretas, en donde en el mundo real aplican.

  1. Pruebas

¿Se podría testear la clase Player? Probandola con valores aleatorios generados por Random sería muy dificil. Entonces, no se podria.

Con la clase, PlayerDI, se podria inicializar una instancia de Random con un valor estático o un objeto mock. ¿Eso nos permitiria testes previsibles? Talvez, pero ¿ la clase PlayerDI necesita generar números aleatorios variables del tipo float, double, boolean, etc.? No, entonces no es óptimo para testear ya que sería complicado apra todos esos casos.

En conclusión, con la clase PlayerDIP, es mas fácil testear. Podemos mockar la interface Dice, asi retornamos lo que realmenten necesitamos durantes las pruebas.

  1. Abstracción de Detalles

La clase Playeresta apenas interesada en lanzar dados. La generación de número aleatorios es un detalle que la clase Player no tendria por que saber.

Cuando se muda a una abstracción, como lo es la interface Dice, para la clase PlayerDIP, se esta simplificando el código. Ya que al abstraer los detalles, no es necesario preocuparnos como es que el dado es lanzado, permitiendonos asi concentrarnos en resolver solo el problema en ella.

  1. Adaptación de Tecnología

Dice, es una interface, esto nos permite realizar varias implementaciones de acuerdo a nuestras necesidades. Una implementración puede usar la clase Random como se ilustra en los ejemplos anteriores, pero tambien pudiera tener otra implementación que llama a un servicio REST que desacopla esa logica y la clase tendria una petición HTTP request con cualquier liberia para ello (tal ves Retrofit o Fuel). O que pasa si se lee un valor existente en la base de datos usando SQLite o ROOM.

Entonces, una buena práctica es abstraerla en una clase repositorio. Esto, como lo mencione anteriorment, nos permite ademas de implementar varias veces la interface Diceadaptandola a nuestras necesidades.

Bueno, hasta aqui termina el primer articulo para entender posteriormente como integrar Dagger2 a PlatziStore. Espero te sea de mucha utilidad, cualquier cosa, dejalo en los comentarios.

Referencias

Escribe tu comentario
+ 2