AngularJS: Indicando dependencias manualmente

angular_js_ui_router_cheat_sheets

Una de las primeras funcionalidades con la que nos topamos a la hora de aprender AngularJS, es su potente inyector de dependencias. El inyector de dependencias es el encargado de instanciar de manera perezosa (es decir, los componentes se instancia bajo demanda de uso) todos los servicios que un componente precise para so correcto funcionamiento.

Imaginemos que tenemos el siguiente código:

El código muestra la tipica definicion de un controlador. Dentro de la funcion de definicion encontramos 3 parametros: $scope, $http, $q. Si estamos familiarizados con estos nombres, veremos rapidamente que se trata de 3 servicios tipicos con los que cuenta el propio framework.

Lo que le estamos indicando a AngularJS es que nuestro controlador va a hacer uso de 3 servicios y que el framework nos los tendrá que proporcionar cuando el controlador se instancia. Es decir, le estamos diciendo a AngularJS que el controlador tiene 3 dependencias y que nos tiene que inyectar un objeto con el tipo indicado en los parámetros.

Esta es una de las partes más mágicas de AngularJS pues, una vez que se instancie el controlador, lo primero que va a hacer el framework es buscar servicios que coincidan con los nombres indicados, instanciarlos y pasarlos al controlador. Este mecanismo es lo que se conoce como inyección de dependencias automática. Internamente todo este mecanismo tiene su explicación y su ciclo de vida bien definido por los desarrolladores de Google, pero no nos centraremos en ello en este momento. Me interesa más explicaros el problema que nos puede acarrear esta inyección automática.

La inyección automática nos da fluidez y rapidez de desarrollo para aplicaciones pequeñas o prototipos. El problema viene cuando necesitamos realizar una aplicación compleja que contenga un gran número de elementos y que haga que nuestros ficheros y código crezcan exponencialmente.

Es buena práctica, por rendimiento y por ‘seguridad’, empaquetar todos nuestros ficheros JavaScript de una aplicación AngularJs en un único fichero y que todo este código se encuentre minificado y ofuscado para evitar que nuestro código pueda ser analizado en producción.

La ofuscación de código es una técnica que se encarga de convertir todas nuestros nombres de variables, parámetros, clases y funciones en identificadores menos legibles para evitar este análisis que decimos. Si por ejemplo ofuscamos el código del script anterior, obtendriamos algo parecido a esto:

El código siguiente sigue siendo correcto. Sin embargo, cuando ofuscamos por primera vez nuestra aplicación AngularJS, nos damos cuenta que algo ha ido mal y que el inyector de AngularJS no está inyectando las dependencias correctamente.

Lógicamente, el inyector, con esta transformación, no sabe cómo relacionar estos nuevos identificadores con nuestros servicios (Los servicios son definidos con un identificador de tipo ‘String’). ¿Como podemos solucionar esto? Podemos usar dos formas de indicar las dependencias de un componente manualmente y no dejar al inyector que decida que servicio usar por si solo. Analicemos cuales son estas dos formas:

Indicando dependencias manuales al inicializar el componente

AngularJS nos permite que indiquemos las dependencias de manera manual por medio de un ‘Array’ de dependencias. Tanto los métodos ‘controller’, como ‘factory’ o como ‘services’ nos permiten indicar como segundo parámetro un ‘Array’, además de la típica función constructora del elemento. Lo único que nos obliga AngularJs es que el ultimo elemento del ‘Array’ sea la función de definición del elemento. Este seria un ejemplo:

Como vemos, indicamos en un ‘Array’ las dependencias por medio de una cadena. Los ofucadores no son capaces de convertir cadenas porque pueden ser valores de estados y constantes de una aplicación, por lo que de esta manera, aunque los parametros se denominen a, b y c, el inyector ya sabrá que tendrá que instanciar para cada uno de los elementos.

Hay que darse cuenta también que el ‘Array’ debe encontrarse ordenado tal y como queramos que se pasen los objetos como para metros en la función. Si no lo hacemos de esta forma, no podemos asegurar que se realice correctamente la inyección. Es bastante lógico.

Indicando dependencias manuales en el atributo $inject

Muchos desarrolladores acaban utilizando la opción anterior. Sin embargo, en mi opinión, el código escrito queda algo enrevesado. Para mi gusto (y el de cada vez más desarrolladores), usamos demasiados elementos como parámetro del método (sin darnos casi darnos cuenta, tenemos un método al que se le pasa un ‘Array’ de tipo ‘String’, menos en el último elemento que contiene una función). Es poco legible. Además, que si tenemos que inyectar muchos componentes, la lectura de la declaración se hace todavía más difícil.

Es por ello que se está tomando como buena práctica la de insertar un parámetro en la propia función constructora denominado $inject. Lo que hace AngularJS, antes de instanciar, un controlador por ejemplo, es comprobar si esta propiedad se encuentra rellena. Si dentro de esta propiedad existe un ‘Array’ con las dependencias, se encarga de instanciarlas e inyectarlas.

Aquí tenemos un ejemplo:

Conclusión

Como hemos visto en esta entrada, tenemos varias formas de inyectar las dependencias en un componente de AngularJS. Una de las cosas que más me gustan del framework de Google es la gran flexibilidad que existe para desarrollar diferentes funcionalidades y lo fácil que es configurar y estructurar el código a nuestro gusto. Esto sin duda puede ser un arma de doble filo pues el desarrollador tendrá que saber en todo momento cual es la forma idónea de usar el framework.

Os recuerdo que hace tiempo mostré la guía de estilos creada por John Papa donde se cuentan todo este tipo de buenas prácticas. Puede ser una buena lectura antes de que empecemos nuestro siguiente proyecto AngularJS.

Nos leemos 🙂

Imagen entrada | egghead.io

Anuncios

Responder

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Cerrar sesión / Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión / Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión / Cambiar )

Google+ photo

Estás comentando usando tu cuenta de Google+. Cerrar sesión / Cambiar )

Conectando a %s