09 septiembre 2011

¿Realmente emerge el diseño con TDD?

Hola a tod@s,

como desarrollador de software cada vez soy más fan de TDD y creo que el “diseño emergente” nos conduce de forma natural a un diseño correcto de nuestras aplicaciones. Hace unos días intentaba explicar las bondades de TDD a unos compañeros y lo hacia con el típico ejemplo de la kata FizzBuzz:

  • caso de prueba con el 3: Red
  • implementación del método para el 3: Green
  • caso de prueba para el 5: Red
  • implementación del  código para el 5: Green
  • refactorización
  • caso de prueba para el 17: Red
  • implementación del  código para el 17: Green
  • refactorización para generalizar y eliminar duplicidades
  • etc…

encuentro que es un ejemplo ideal para explicar como hacer TDD y sus bondades, creo que quedaron convencidos que es una técnica interesante de diseño y no solo una forma de tener test unitarios para poder hacer refactorizaciones sin morir en el intento.

Unos días después estos mismos compañeros estaban leyendo un libro sobre ASP.NET MVC3 y se pusieron a codificar su primer proyecto MVC3 siguiendo el ejemplo y intentando aplicar TDD. En esto que uno de ellos me comento: “Ei, yo ya se que usar dependency injection es una buena decisión de diseño en una aplicación ASP.NET MVC3, pero ¿puedo llegar a esta conclusión mediante un enfoque TDD?” Ostras, la pregunta tiene miga, si la rerformulamos de forma un poco más genérica:

¿nos va a “empujar” TDD a tomar decisiones de diseño “correctas” como el uso de DI o este tipo de decisiones no pueden “emerger” del diseño basado en tests y deben tomarse a priori?

Esta reflexión despertó dos de las preguntas que me hago cada vez que explico/aplico TDD:

  • ¿hasta que punto el diseño “emerge”?
  • ¿hay decisiones de diseño a las que nunca podremos llegar por mucho TDD que hagamos?

el objetivo del post es intentar responder a estas dos cuestiones; para ello me centraré en el ejemplo concreto del uso de DI en una aplicación MVC3 analizando si TDD nos lleva de forma natural a esta decisión, o, por el contrario, TDD nunca nos empujará a tomar una decisión de este tipo.

¿Qué queremos hacer?

La aplicación que usaremos como ejemplo es muy, muy simple: queremos hacer una aplicación ASP.NET MVC3 para mostrar un listado de las películas que hay en cartelera ordenadas por número de espectadores que la han visto. Supongamos que disponemos de un servicio remoto IMoviesService que nos proporciona este listado ordenado y que, al ser un servicio remoto, la consulta de películas puede ser bastante lenta.

Primera iteración: Red, Green, Refactor

Como vamos a desarrollar esta mini aplicación bajo un enfoque TDD lo primero que debemos hacer es crear una prueba para la acción de listado (en esta prueba, para no complicar el ejemplo, simplemente vamos a comprobar que la acción deja en el modelo la colección de películas que devuelve el servicio):

[TestClass]
public class MovieControllerTest
{
    [TestMethod]
    public void ListMoviesPutAllMoviesInModel()
    {
        // Arrange
        var movieController = new MovieController();
        // Act
        var movies = ((IEnumerable<Movie>)movieController.List().Model).ToArray();
        // Verify
        Assert.AreEqual(movies.Length, 5);
        Assert.AreEqual(movies[0].Title, "X-Men");
        Assert.AreEqual(movies[4].Title, "Batman");
    }    
}

Nota: sabemos que el número de películas en cartelera para esta semana es de 5, que hoy la película más vista es “X-Men” y la menos vista “Batman”.


Ejecutamos la prueba y esta ni compila! Red! Evidente, no hemos creado ni el controlador! El siguiente paso es pues crear el controlador y implementar la acción List para que pase la prueba unitaria.

public class MovieController : Controller
{
    public ViewResult List()
    {
        var movieService = new MovieService();
        return View(movieService.AllMovies());
    }   
}

Ejecutamos el test y Bingo! Green!


Refactor: Ya esta ¿no?, nuestro caso de prueba ya pasa  y yo no veo que pueda refactorizar el código por ningún lado… Llegados a este punto podríamos concluir que TDD NO ha hecho emerger la necesidad de usar dependency injection! pero nos olvidamos de algunos detalles importantes:



  • Nuestros tests muy lentos: estamos atacando a la implementación real del servicio y esto es lento.
  • Los tests no son repetibles, dependen del resultado que nos proporcione el servicio. Mañana posiblemente cambie el número de espectadores que han visto las películas y la próxima semana las películas en cartelera.
  • El SUT (Subject Under Test) no es el servicio si no el método List del controller!):



Segunda iteración: introducimos un doble para el servicio


Si queremos que nuestros tests sean rápidos (condición indispensable para que se ejecuten con regularidad) y repetibles tenemos que atacar a un doble del servicio y no a la implementación real. Fijaros que este requerimiento no emerge del proceso normal de TDD (Red, Green, Refactor) ya que los test creados en la primera iteración NO eran correctos.


Necesitamos poder trabajar con dobles des de los test unitarios y con la implementación real cuando se ejecute la aplicación. Tenemos que cambiar el new MovieService() por algo configurable que nos permita usar tanto la implementación real como un doble. La teoría nos dice que podemos hacer esto aplicando un patrón Service Locator (bien sea con una factoría propia o usando un contenedor de IoC), para el ejemplo escogemos la opción de usar una factoría de servicios propia con un método GetService<T> para resolver un servicio y un método RegisterService<T> para registrar servicios (obviamos la creación de esta factoría también lo haríamos siguiendo un enfoque TDD).


Refactorizamos el código de nuestro test para usar la factoría y lo dejamos así:

[TestClass]
public class MovieControllerTest
{
    [TestMethod]
    public void ListMoviesPutAllMoviesInModel()
    {
        // Arrange
        Mock<IMovieService> mock = new Mock<IMovieService>();
        Movie[] movies = new Movie[] 
        {
            new Movie() { Title = "X-Men" },
            new Movie() { Title = "X" },
            new Movie() { Title = "Y" },
            new Movie() { Title = "Z" },
            new Movie() { Title = "Batman" }
        };
        mock.Setup(m => m.AllMovies()).Returns(movies);
        IoCFactory.RegisterService<IMovieService>(mock.Object);
        var movieController = new MovieController();
        // Act
        var movies = ((IEnumerable<Movie>)movieController.List().Model).ToArray();
        // Verify
        Assert.AreEqual(movies.Length, 5);
        Assert.AreEqual(movies[0].Title, "X-Men");
        Assert.AreEqual(movies[4].Title, "Batman");
    }
}

Nota: Usamos Moq para crear un doble del servicio de cartelera, tenéis mas información sobre Moq aquí.


Ejecutamos: Red!


Modificamos el código de la acción List para que obtenga el servicio de nuestra factoría de servicios:

public class MovieController : Controller
{    
    public ViewResult List()
    {
        var movieService = IoCFactory.GetService<IMovieService>();
        return View(movieService.AllMovies());
    }
}

Ejecutamos el test: Green!


Ahora si que ya lo tenemos! Pero tampoco hemos llegado a la necesidad de usar dependency injection! Normalmente nos quedaríamos aquí y no le daríamos mas vueltas pero estamos olvidando la etapa de Refactor! En esta etapa tenemos que refactorizar el código para que, a parte de pasar los test unitarios, nuestro código cumpla los principios de diseño orientado a objetos.


Si analizáis con detenimiento el código generado veréis que no cumple algunos de estos principios:



  • No cumple el principio SOLID de responsabilidad única: El método List tiene dos responsabilidades claras, proporcionar un listado de películas a la vista y gestionar la resolución del servicio mediante la factoría. 
  • Las dependencias de nuestro controlador no están claras, al tener acceso completo a la factoría sus métodos pueden acceder a cualquier objeto que esté registrado en esta.

Nota: otro factor que nos empujaría a refactorizar el código una vez avancemos en el desarrollo es que estaríamos repitiendo la instrucción IoCFactory.GetService<IMovieService>() en todas las acciones del controlador y esto viola el principio DRY. Esto no lo podríamos ver ahora, pero conforme fuéramos implementando acciones se pondría de manifiesto.


Tercera iteración: Necesitamos dependency injection!


Para resolver los problemas anteriores (detectados en la fase de refactoring) tendríamos que poder pasar al controlador la implementación del servicio y usar esa implementación en todas sus acciones, el código de nuestro test debería quedar así:

[TestClass]
public class MovieControllerTest
{
   [TestMethod]
    public void ListMoviesPutAllMoviesInModel()
    {
        // Arrange
        Mock<IMovieService> mock = new Mock<IMovieService>();
        Movie[] movies = new Movie[] 
        {
            new Movie() { Title = "X-Men" },
            new Movie() { Title = "X" },
            new Movie() { Title = "Y" },
            new Movie() { Title = "Z" },
            new Movie() { Title = "Batman" }
        };
        mock.Setup(m => m.AllMovies()).Returns(movies);        
        var movieController = new MovieController(mock.Object);
        // Act
        var movies = ((IEnumerable<Movie>)movieController.List().Model).ToArray();
        // Verify
        Assert.AreEqual(movies.Length, 5);
        Assert.AreEqual(movies[0].Title, "X-Men");
        Assert.AreEqual(movies[4].Title, "Batman");
    }
}

Para hacer este refactoring tenemos que saber que ASP.NET MVC3 nos permite cambiar el resolvedor de dependencias por una implementación propia que use un contenedor de IoC para poder pasar objetos al constructor del controlador y configurar en este contenedor de IoC los servicios que necesitemos. Vemos que el enfoque TDD nos lleva a esto pero debemos tener el conocimiento suficiente de la tecnología con la que trabajamos para ver que la solución es viable.


Nota: Fijaros que como efecto colateral hemos eliminado la necesidad de configurar la factoría de servicios (ni ningún contenedor de IoC) en los test unitarios, creamos el doble en el test y se lo pasamos al controlador!


Ejecutamos: Red!


Modificamos el código del controlador para cambiar el contenedor de IoC por una implementación del servicio y la acción List para que use este servicio:

public class MovieController : Controller
{
    private IMovieService movieService;
    
    public MovieController(IMovieService service)
    {
        this.movieService = service;
    }
    public ViewResult List()
    {        
        return View(this.movieService.AllMovies());
    }
}

Ejecutamos: Green!


Refactor: parece que el código de la acción List no incumple ninguno de los principios de diseño OO y los test se ejecutan correctamente => END!


Conclusión


En esta entrada he intentado explicar mediante un ejemplo concreto una de las dudas que me asaltan con mas frecuencia cuando desarrollo siguiendo un enfoque TDD: ¿hasta que punto TDD nos lleva a hacer “buenos” diseños?


Yo creo que algunas decisiones arquitectónicas de alto nivel se deben tomar inicialmente (por ejemplo, en nuestro caso, el hecho de usar ASP.NET MVC3) pero otras cuestiones de diseño pueden aflorar de una manera mas o menos clara siempre y cuando se cumplan algunas premisas:



  • Conocer las características de un buen test unitario (rápido, repetible, claros, testean solo el SUT, etc…), sin esto nos hubiéramos quedado en la primera iteración y el test hubiera fallado al cabo de un par de días!
  • Alto grado de dominio de la tecnología que estemos usando (en el ejemplo no hubiéramos podido hacer la tercera iteración sin conocer a fondo las capacidades que brinda ASP.NET MVC)
  • Hacer siempre la fase de refactor asumiendo que, a parte de que los casos de prueba pasen, es importantísimo respetar los principios de diseño OO (tampoco hubiéramos llegado el tercer paso sin esto)

Me gustaría saber que opináis al respecto:



  • ¿Creéis que la deducción está muy “cogida con pinzas”?
  • ¿Creéis que la implementación de la acción simple List bajo un enfoque TDD nos lleva de forma natural a deducir que necesitamos DI?
  • ¿Llegaríamos a ella sin tener asumido, a priori, que DI es una buena solución?
  • ¿Dónde está la frontera entre lo que puede aflorar y lo que no?

Saludos, Josep Maria

26 agosto 2011

Javascript no es el demonio (creo)!

Hola a tod@s,

la verdad es que si hace 6 o 7 años alguien me hubiera dicho que estaría escribiendo un post sobre JavaScript que no fuera una crítica salvaje le hubiera tratado de loco. La verdad es que la idea que tenia en mi cabeza sobre JavaScript era la de un lenguaje de scripting para páginas HTML que, básicamente, les servía a los diseñadores gráficos para hacer “guarradas”  sobre el HTML y que convertía la interfaz de usuario en la parte mas oscura, inmantenible y “jodida” de modificar de las aplicaciones web. En la mayoría de aplicaciones acababas con cientos de funciones sueltas, spaggetti code con mucho JavaScript mezclado con el HTML, variables de ámbito global, inexistencia de tests unitarios, reutilización nula o prácticamente nula => Mi máxima siempre había sido: cuanto menos JavaScript tengamos que poner mejor porqué JavaScript = PROBLEMAS!

A todo esto cabe añadir también que nunca he sido muy amante del desarrollo de interfaces gráficas, básicamente por mi prácticamente nula capacidad artística (si, si, ahora ya se que no queda muy bien un título verde sobre un fondo rojo!) y siempre intentaba que fuera el equipo de UI el que lidiara con el JavaScript y enfrentarme a el lo mínimo posible.

A raíz de tener que implementar la UI en un proyecto MVC3 y con el objetivo de conseguir una interfaz agradable y, sobre todo, usable decidí usar JQuery (en MVC3 ya lo tenemos por defecto) para realizar validaciones en cliente, actualizaciones asíncronas de la interfaz y manipulaciones del DOM. Esto combinado con las capacidades de HTML5 y CSS3 (esto último mas para ver una pincelada de las “nuevas” tendencias en interfaces de usuario para aplicaciones web que por necesidad) me permitirían conseguir una UI agradable, potente y actual para mi aplicación web.

La primera decisión pues fue usar JQuery como framework para realizar la validaciones en cliente, gestionar las peticiones AJAX e interactuar con el DOM de las páginas HTML. Primera reflexión: JQuery es un framework de JavaScript => SHIT, me toca lidiar con el dichoso JavaScript!

Llegados a este punto tenia dos opciones:

  • Pasar de puntillas, es decir, coger un manual de JQuery, aprender las capacidades que proporciona para hacer las cuatro cosas que requería mi proyecto, cerrar los ojos e intentar no “enguarrar” demasiado mi UI.
  • Coger el toro por los cuernos y, dado que JQuery es un framework JavaScript, aprender JavaScript para ver si es posible realizar una UI “limpia” y mantenible con él.

Dado que uno de los objetivos del proyecto es experimentar un poco con diferentes tecnologías decidí elegir la segunda opción y darle una oportunidad a JavaScript. 

En el post voy a enumerar las características que me han sorprendido (ya sea para bien o para mal) en esta primera toma de contacto con Mr. JavaScript y introducir brevemente conceptos que nos pueden ayudar a resolver los problemas de los que adolecen muchas UI’s basadas en JavaScript. No esperéis encontrar en él temas avanzados de JavaScript (de hecho el primer título que le había puesto era JavaScript for dummies) ni una guía completa de las diferentes características del lenguaje. La idea del post es que os sirva como índice introductorio, todos los conceptos se presentaran de forma muy concisa (en un párrafo) y, para algunos de ellos, intentaré escribir entradas en el blog para verlos con mas profundidad.

Entre los puntos candidatos a tener, a priori, su propia entrada tenemos:

  • Objetos, funciones, clausuras y ámbitos.
  • Prototipos.
  • Duck typing (#cerveza gratis para @eiximenis por la palabreja).
  • Patrones de diseño.
  • OO clásica frente al enfoque prototípico.
  • Alternativas a la resolución de la herencia clásica en un lenguaje basado en prototipos.
  • Testing, TDD y JavaScript.
  • Proyectos ASP.NET MVC3, ¿cómo gestionamos la parte de JavaScript?.

Si ya conocéis JavaScript y lo usáis de una forma “correcta” posiblemente veáis el post como un refrito de obviedades. En la red hay muchísima literatura sobre JavaScript, muchas de las características las introduciré con una frase y os remitiré a algún enlace para que podáis profundizar en el tema.

Antes de entrar en materia un último apunte: el post esta escrito des del punto de vista de un desarrollador de aplicaciones de servidor acostumbrado a trabajar con lenguajes OO puros fuertemente tipados como Java y C# y con poca experiencia en interfaces de usuario, lenguajes de scripting y lenguajes funcionales.

¿Qué es JavaScript?

Básicamente podemos ver JavaScript cómo un lenguaje de scripting orientado a objetos, basado en prototipos, con funciones como entidades de primera clase y con tipado débil.

A partir de esta definición ya podemos extraer unas pocas conclusiones y abrir bastantes “cajas de pandora!”:

  • JavaScript es un lenguaje orientado a objetos => Debe posibilitar muchas de las características que soportan la mayoría de lenguajes OO: encapsulación, herencia, polimorfismo, etc… Ummmm! Interesante! parece que podremos hacer algo mas que definir conjuntos inconexos de variables globales y funciones!
  • JavaScript es un lenguaje basado en prototipos => En el lenguaje NO existe el concepto de clase sino el de prototipo: pero, perdonad la ignorancia de un triste programador Java/C#, ¿cómo podemos crear objetos con determinados atributos y propiedades sin definir la clase de la que será instancia? pues lo haremos en base al prototipo que todo objeto tiene!  Y este prototipo además nos permitirá hacer herencia por delegación y, por consiguiente, reutilizar código.
  • Las funciones son entidades de primera clase => Vale, bien, ¿y? ¿esto que implica? Pues implica que las funciones se tratan como cualquier otro tipo: se pueden asignar a variables, se pueden pasar como parámetros a métodos, ser devueltos por métodos, etc… ¿Os suena el concepto de puntero a función de C o de delegate en C#? Pues las funciones de JavaScript pueden funcionar de la misma manera. Además, al ser las funciones entidades de primera categoría nos lleva a pensar en JavaScript como un lenguaje candidato a usar una aproximación funcional para el desarrollo. 
  • JavaScript es un lenguaje de tipado débil => Ufff! Ya está, ya se pq no me gustaba JavaScript, lo de poder asignar peras a gatos y que no me avise el compilador de que la pera no puede maullar no me va mucho! Pero, un momento, si desarrollamos usando un enfoque ágil y una metodología orientada al test tendríamos que tener una prueba (fallida por supuesto) en la que le pidiéramos a la pera que maullara… Ummmm otra vez! Igual el hecho de seguir un enfoque dirigido al test hace menos importante las verificaciones de tipos en tiempo de compilación.

Funciones como entidades de primera clase…

El hecho de que las funciones sean entidades de primera clase permite:

  • Asignar funciones a variables.
  • Pasar funciones como argumentos de un método.
  • Devolver funciones como tipo de retorno de un método.
  • Desconectar la definición de la función de su contexto de ejecución y esto, junto con el concepto de clausura, nos ofrecerá unas capacidades importantes.
  • Usar una aproximación de lenguaje funcional al desarrollo.

Ya veremos que el hecho de que las funciones sean entidades de primer nivel nos proporcionará numerosas ventajas y nos permitirá usar una aproximación muy cercana a la programación en lenguajes funcionales aprovechando toda la potencia de estos.

¿Dónde están las variables locales? ¿y la encapsulación, reutilización, mantenibilidad y testabilidad de mi código?

En JavaScript solo tenemos dos ámbitos, el global y el local a una función => toda variable que no esté declarada con la palabra reservada var es global. Esto realmente es una deficiencia del lenguaje ya que nos induce a una mala práctica de programación como son las variables globales (creo que en eso estaremos todos de acuerdo!). Bueno, la primera en la frente! El problema de JavaScript no es que permita el uso de variables globales (casi todos los lenguajes las permiten, public static … en java por ejemplo) sino que JavaScript prácticamente obliga al uso de variables globales. Otro fallo relacionado con las variables globales es que cualquier variable que no se defina con var automáticamente es una variable global (con todos los errores y problemas que esto puede comportar). JavaScript tampoco proporciona ámbito de bloque y esto también nos puede llevar a errores difíciles de detectar.

La parte buena es que, aunque el lenguaje nos empuje a la definición de variables globales, existen técnicas y patrones para minimizar o eliminar el uso de variables globales en nuestros desarrollos, encapsular funcionalidades, ocultar miembros privados y proporcionar una alto grado de reutilización, mantenibilidad y testabilidad de nuestro código JavaScript.

En Techniques, Strategies and Patterns for Structuring JavaScript Code tenéis tres patrones de estructuración de código que os permitirán alcanzar los objetivos anteriores, fijaros como se puede pasar de una aplicación “spaggetti code” a una aplicación bastante estructurada, legible, mantenible y testeable simplemente con la aplicación de uno de los patrones indicados.

¿Y mis clases?

Como ya hemos comentado antes JavaScript es un lenguaje basado en prototipos, en un lenguaje de programación orientado a prototipos NO existen las clases y la herencia se basa en la clonación/copia de objetos existentes y la extensión de sus funcionalidades extendiendo el prototipo del objeto clonado/copiado.

Podéis obtener más información sobre la programación basada en prototipos comparada con la programación tradicional basada en clases en la wikipedia: Programación basada en prototipos y en este artículo de Pedro Cuesta (Universidad de Vigo). Encuentro especialmente interesante la reflexión sobre cómo influye este hecho en el enfoque del modelo de desarrollo que adoptamos, incitando a un desarrollo basado en ejemplos (¿os suena de algo?… metodologías ágiles, TDD, etc…) en vez de crear primero las abstracciones.

Nota: fijaros que el debate entre prototipos y clases es muy antiguo, la mayor parte de referencias son del siglo XX ;-)

Ostras, y puedo añadir comportamiento a los objetos dinámicamente!

Precisamente una de las características presentes en muchos lenguajes de programación basados en prototipos es la capacidad de extender dinámicamente el comportamiento de los objetos en tiempo de ejecución: dado que los objetos se crean por un proceso de copia es fácil modificar en tiempo de ejecución el comportamiento y la estructura de los objetos individuales. JavaScript es un lenguaje dinámico.

Esta muy chulo, si señor! Pero, ¿sirve de algo añadir comportamiento dinámico a nuestros objetos? Bueno pues esto nos lleva a la eterna discusión entre lenguajes dinámicos versus estáticos. No es mi intención posicionarme en este ni en un sentido ni en otro, tenéis mucha literatura en la web, lo que si parece claro es que los lenguajes estáticos cada vez están incorporando mas características de los dinámicos. Por ejemplo, .NET 4.0 incorpora los tipos dinámicos aunque sea básicamente para interoperar con lenguajes dinámicos (tenéis un buen artículo sobre Objetos dinámicos en .NET 4.0: ExpandoObject en el blog de José Manuel Alarcon)

Yo se muchas cosas de OO, ¿las puedo aplicar en JavaScript?

JavaScript es un lenguaje orientado a objetos, y yo estoy harto de trabajar con lenguajes orientados a objeto como Java y C#, entonces debo poder aplicar las buenas prácticas de programación OO en JavaScript, ¿verdad? Bueno pues la respuesta creo que es “si puedes, con un poco de esfuerzo, pero la pregunta realmente interesante es: ¿debo aplicar estas buenas prácticas tal y como lo haría en un lenguaje de programación basado en clases?

Pensad que JavaScript proporciona un modelo de herencia basado en prototipos muy diferente al que proporcionan Java y C# y, posiblemente, se puedan obtener los mismos beneficios pero la forma de hacerlo puede que sea diferente y mucho mas natural para un lenguaje basado en prototipos.

Tenéis un artículo buenísimo, Transitioning from Java Classes to JavaScript Prototypes, donde hay un ejemplo paso a paso de como implementar el patrón Observer en Java y en JavaScript. En él podréis ver que, efectivamente, se puede implementar este patrón tal y como lo haríamos en Java (o en C#) pero que resulta mucho más efectivo y elegante usar una aproximación que se aproveche del hecho que en JavaScript las funciones son entidades de primer nivel.

Oye, lo estas pintando todo muy de color de rosa, ¿es que no hay cosas mal resueltas en JavaScript?

Evidentemente, y bastantes, por enumerar solo algunas:

  • Dependencia de las variables de ámbito global.
  • Inexistencia del ámbito de bloque.
  • Sintaxis muy enrevesada para hacer cosas muy simples (leed JavaScript is Dead. Long Live JavaScript! para ver algunas de las propuestas de mejora de la sintaxis).
  • Uso del operador + tanto para añadir como para concatenar.
  • with y eval.
  • false, null, undefined, NaN.
  • etc…

Entonces, ¿recomiendas el uso de JavaScript?

En este post solo hemos visto unas breves pinceladas de JavaScript y con esto no podemos evaluar si es una buena opción o no, dependerá de mil factores: tipo de proyecto, tecnologías, alcance, equipo, etc…

Hay un hecho importante a tener muy en cuenta y que ha sido el que me ha hecho decantar por el uso de JavaScript en mi proyecto:  es la única opción si queremos programación en cliente para las aplicaciones web! Si os encontráis en este caso y tenéis que usarlo lo que si os recomiendo es que invirtáis algo de tiempo en entender la idiosincrasia del lenguaje e intentéis adaptaros a esta en vez de intentar que el lenguaje se adapte a vuestra manera de trabajar.

JavaScript tiene cosas malas pero también muchas cosas buenas, evitad las malas prácticas y centraros en aprovechar las bondades del lenguaje, que, aunque a estas alturas todavía me estén sorprendiendo, son bastantes. Y, sobre todo, intentad conocerlo antes de usarlo (como dice Douglas Crockford, JavaScript es de los pocos lenguajes que la gente cree que puede usar sin haberlo estudiado)!

Bien y con esta última recomendación lo dejamos por hoy, espero haberos abierto el apetito (o no haberos aburrido en exceso) y que leáis los siguientes artículos donde intentaré profundizar un poco más en algunos de estos temas. Podéis dejar cualquier sugerencia sobre temas de los que os gustaría hablar en los comentarios del post.

Saludos a tod@s! Josep Maria

Otras referencias

08 agosto 2011

Dependency Injection en aplicaciones N-Layer

Hola a tod@s,

Hace unos días publique un post publiqué un post sobre como realizar IoC usando DI o bien usando SL, en este post llegamos a la conclusión que es mucho mas efectivo hacer DI para conseguir IoC. Yo me quede convencido que IoC es una buena opción para mis proyectos y que DI era la mejor alternativa pero NO vimos como implementarlo, en este post vamos a bajar a las trincheras y veremos como podemos hacer IoC usando DI en una aplicación N-Layer de forma práctica.

Para ello imaginemos que queremos hacer una aplicación multicapa con la siguiente arquitectura:

Architecture

  • La aplicación simplemente publica un servicio que, dado un nombre, nos devuelve un saludo. Por ejemplo, si le pasamos “josep maria” el servicio nos devolverá “Hola Josep Maria!”
  • La aplicación se divide en 4 capas, presentación, servicios distribuidos, aplicación y dominio.
  • En la capa de presentación tenemos un cliente web y una aplicación WCF que van a consumir el servicio de la capa de aplicación Greeting.
  • La capa de servicios distribuidos expone mediante WCF el servicio Greeting de la capa de aplicación para que este pueda ser consumido por clientes remotos.
  • La capa de aplicación expone un servicio Greeting que, simplemente, devuelve un saludo personalizado al usuario. El servicio Greeting de la capa de aplicación usa un servicio de la capa de dominio (Capitalize) para poner en mayúsculas las primeras letras del nombre del usuario.
  • Los clientes web acceden directamente al servicio Greeting de la capa de aplicación.
  • Los clientes WCF acceden a una adaptador del servicio Greeting en la capa de servicios distribuidos.

La aplicación en si es una chorrada y, como veis, esta un poco/un mucho “sobrearquitecturada” (¿solo un poco? Vaya tela de tio!) Su pretensión es hacer una prueba de concepto para mostrar como se pueden inyectar los servicios de aplicación y/o de dominio a los controladores de la capa de presentación MVC y a los servicios distribuidos WCF sin hacer muchas cosas raras, dejando que sea la infraestructura de MVC y de WCF la que inyecte estos servicios. Los principios que aplicamos a esta aplicación “chorra” se pueden extrapolar a cualquier aplicación N-Layer compleja donde seguro que tendrán mucho mas sentido.

Como la literatura no es lo mi fuerte os pongo el código que queremos que tenga nuestra aplicación en cada una de las capas:

Capa de presentación:

Slide2

Capa de servicios distribuidos:

Slide3

Capa de servicios de aplicación:

Slide4

Capa de servicios del dominio

Slide5

Resumiendo, lo que queremos lograr es:

  • Conseguir IoC por medio de DI con inyección de dependencias en el constructor en toda la aplicación.
  • Registrar los dos servicios (Greeting y Capitalize) en un contenedor de IoC (Unity en nuestro caso) des de un único punto para toda la aplicación.
  • Conseguir que la capa de presentación web, implementada mediante ASP.NET MVC3, use Unity como contendor de IoC para resolver las dependencias. Definir una dependencia en el constructor del controlador web al servicio Greeting de la capa de aplicación (que a su vez tiene otra dependencia con el servicio Capitalize de la capa de dominio) y que sea la infraestructura de MVC la que las resuelva.
  • Conseguir que la capa de servicios remotos, implementada mediante WCF, use Unity como contendor de IoC para resolver las dependencias. Definir una dependencia en el constructor del servicio remoto al servicio Greeting de la capa de aplicación (que a su vez tiene otra dependencia con el servicio Capitalize de la capa de dominio) y que sea la infraestructura de WCF la que las resuelva.
  • No hacer ningún Resolve explícito des de la aplicación.

Dependency injection en la capa de presentación con ASP.NET MVC 3

El código del controlador que queremos evitar seria similar a este:

    public class HomeController : Controller
    {
        private IGreetingService greetingService;
        
        public HomeController(IUnityContainer container)
        {
            this.greetingService = container.Resolve<IGreetingService>();
        }
        
        public ActionResult Index()
        {
            ViewBag.Message = greetingService.SayHello(Request.Params["name"]);
            return View();
        }        
    }


fijaros que con este código estaríamos haciendo IoC pero mediante SL y no mediante DI (consultad el post para ver porqué se prefiere el uso de DI al uso de SL).



Afortunadamente ASP.NET MVC3 está muy preparado para usar un contendor de IoC para resolver las dependencias, y hay mucha información en la red explicando paso a paso como hacer-lo. Básicamente y de forma resumida, los pasos a realizar serian los siguientes:





  1. Crear nuestro UnityDependencyResolver que utilice Unity para resolver los tipos extendiendo de IDependencyResolver.

  2. Crear el contenedor de Unity.

  3. Registrar todos los controladores de la aplicación en este contenedor.

  4. Registrar todos los tipos que deba resolver la aplicación en este contenedor.

  5. Indicar a MVC3 que use nuestro UnityDependencyResolver para resolver todas las dependencias.


Podemos hacer estos pasos manualmente pero en el ejemplo me he decantado por usar el package Unity.Mvc3 de Paul Hiles que ya nos proporciona muchas de estas tareas:





  • Nos proporciona una extensión de Unity para registrar todos los controllers de la aplicación en el contenedor de IoC.

  • Añade una clase Bootstrapper al proyecto web que se encarga de crear el contenedor de Unity, registrar los controladores (mediante la extensión), configurar Unity como dependency resolver de MVC y registrar los tipos de nuestra aplicación. Esta clase Bootstrapper se llama des de Application_Start() del Global.asax


el código de la clase Bootstrapper generada por Unity.Mvc3 tiene el siguiente aspecto:

    public static class Bootstrapper
    {
        public static void Initialise()
        {
            var container = BuildUnityContainer();
            DependencyResolver.SetResolver(new UnityDependencyResolver(container));
        }
        private static IUnityContainer BuildUnityContainer()
        {
            IUnityContainer container = new UnityContainer();           
            container.RegisterControllers();
            IoCComponentsRegistration.RegisterApplicationTypes(container);
            
            return container;
        }
    }


para hacer la configuración del proyecto MVC3 usando esta librería hemos seguido los pasos descritos en Integrating The Unity.Mvc3 1.1 NuGet Package From Scratch con la única salvedad que hacemos el registro de nuestros tipos en el método estático IoCComponentsRegistration.RegisterApplicationTypes en una librería de clases independiente y no en el Bootstrapper directamente, con esto conseguimos centralizar este registro de tipos y no tener dependencias en nuestro proyecto MVC con todos los proyectos de la aplicación:

    public class IoCComponentsRegistration
    {
        public static void RegisterApplicationTypes(IUnityContainer container)
        {
            container.RegisterType<IGreetingService, GreetingService>();
            container.RegisterType<ICapitalizeService, CapitalizeService>();
        }
    }


Nuestro controlador quedará así:

    public class HomeController : Controller
    {
        private IGreetingService greetingService;
        
        public HomeController(IGreetingService service)
        {
            this.greetingService = service;
        }
        
        public ActionResult Index()
        {
            ViewBag.Message = greetingService.SayHello(Request.Params["name"]);
            return View();
        }        
    }


con esto ya tenemos Unity configurado y listo para resolver todas la dependencias de la aplicación! Fijaros que se están resolviendo todas las dependencias con Unity, DI y inyección de dependencias en el constructor que es el objetivo que perseguimos.



Nota: Unity.Mvc3 también proporciona un Dependency Resolver de Unity para registrar los tipos que implementan IDisposable (por ejemplo los contextos de Entity Framework), tenéis más información en Introducing The Unity.Mvc3 NuGet Package To Reconcile MVC3, Unity and IDisposable.



Dependency injection en la capa de servicios remotos con WCF



Igual que para el caso de los controladores de la capa web, el código del servicio remoto que queremos evitar es este:

    public class GreetingService : IGreetingService
    {
        private ApplicationServices.IGreetingService greeting;
        public GreetingService(IUnityContainer container)
        {
            this.greeting = container.Resolve<IGreetingService>();
        }
        public string SayHello(string name)
        {
            return this.greeting.SayHello(name);
        }
    }


ya que con este código estaríamos usando SL y no DI. Para hacerlo vamos a usar los puntos de extensión que nos proporciona WCF.



Primero tenemos que definir un proveedor de instancias que utilice Unity para resolver los tipos. Para esto creamos una clase que implementa la interfaz IInstanceProvider de WCF y que devolverá las instancias configuradas en Unity cuando WCF necesite resolver un tipo:

    public class UnityInstanceProvider : IInstanceProvider
    {
        private readonly Type serviceType;
        private IUnityContainer container;
        public UnityInstanceProvider(Type serviceType)
        {
            this.serviceType = serviceType;
            this.container = new UnityContainer();
            IoCComponentsRegistration.RegisterApplicationTypes(container);
        }
        public object GetInstance(InstanceContext instanceContext, Message message)
        {
            return this.container.Resolve(serviceType);
        }
        public object GetInstance(InstanceContext instanceContext)
        {
            return this.GetInstance(instanceContext, null);
        }
        public void ReleaseInstance(InstanceContext instanceContext, object instance)
        {
            this.container.Teardown(instance);            
        }
    }


Fijaros que estamos llamando al mismo método (IoCComponentsRegistration.RegisterApplicationTypes) que en el caso de la capa de presentación para registrar las instancias en el contenedor de Unity!



Una vez hecho esto debemos configurar WCF para que use nuestro proveedor de instancias en vez del proveedor de instancias por defecto, para ello crearemos un nuevo “comportamiento” (service behavior) para nuestros servicios implementando la interfaz IServiceBehavior de WCF:

    public class UnityServiceBehavior : Attribute, IServiceBehavior
    {
        public void ApplyDispatchBehavior(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
        {
            foreach (var item in serviceHostBase.ChannelDispatchers)
            {
                var dispatcher = item as ChannelDispatcher;
                if (dispatcher != null) 
                {
                    dispatcher.Endpoints.ToList().ForEach(endpoint =>
                    {
                        endpoint.DispatchRuntime.InstanceProvider = new UnityInstanceProvider(serviceDescription.ServiceType);
                    });
                }
            }
        }
        public void AddBindingParameters(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase, Collection<ServiceEndpoint> endpoints, BindingParameterCollection bindingParameters)
        {
        }
       
        public void Validate(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
        {            
        }        
    }
}


Básicamente este comportamiento insta a WCF a usar nuestro proveedor de instancias para todos los Endpoints de todos los canales.



Una vez hecho esto tenemos que asociar este comportamiento nuestro servicio distribuido, esto lo podemos hacer mediante atributos, mediante un host de servicio propio o mediante configuración. Si lo hacemos mediante atributos debemos crear la clase que implementa el servicio distribuido decorada con el atributo [UnityServiceBehavior], la implementación del servicio WCF queda así:

    [ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall)]
    [UnityServiceBehavior]
    public class GreetingService : IGreetingService
    {
        private ApplicationServices.IGreetingService greeting;
        public GreetingService(ApplicationServices.IGreetingService greeting)
        {
            this.greeting = greeting;
        }
        public string SayHello(string name)
        {
            return this.greeting.SayHello(name);
        }
    }


Lo último que nos queda es crear un host propio que registre el comportamiento definido al hacer un Open:

    public class UnityServiceHost : ServiceHost
    {        
        public UnityServiceHost(Type serviceType, params Uri[] baseAddresses)
            : base(serviceType, baseAddresses)
        {
        }
        protected override void OnOpening()
        {
            base.OnOpening();
            if (this.Description.Behaviors.Find<UnityServiceBehavior>() == null)
            {
                Description.Behaviors.Add(new UnityServiceBehavior());
            }            
        }
    }


crear la factoría de hosts que nos devolverá la instancia de host del tipo UnityServiceHost:

    public class UnityServiceHostFactory : ServiceHostFactory
    {
        public ServiceHost CreateServiceHost(Type serviceType, string baseAddress)
        {
            return CreateServiceHost(serviceType, new[] { new Uri(baseAddress) });
        }
        protected override ServiceHost CreateServiceHost(Type serviceType, Uri[] baseAddresses)
        {
            return new UnityServiceHost(serviceType, baseAddresses);
        }
    }


y configurar el servicio remoto Greeting para que use esta factoría de hosts:

<%@ ServiceHost Language="C#" 
Debug="true" Service="DistributedServices.GreetingService" CodeBehind="GreetingService.svc.cs" 
Factory="DistributedServices.UnityServiceHostFactory"
%>


y listos, nuestra capa de servicios WCF estará usando Unity para resolver todas las dependencias!



Fijaros, por último, que también aquí se están resolviendo todas las dependencias con Unity, DI y inyección de dependencias en el constructor: el servicio Greeting de la capa de aplicación tiene una dependencia con el servicio Capitalize de la capa de dominio.



Nota: esta solución se basa en el post Integrating StructureMap with WCF de Jimmy Bogard adaptado al caso en que usemos Unity como contenedor de IoC. En el blog de Johan Danforth también tenéis una entrada interesante que explica como hacer test unitarios de vuestros servicios WCF usando Unity: Integration Testing WCF Services with Unity



Resumen



En el post hemos visto una prueba de concepto para hacer IoC mediante DI y inyección de dependencias en el constructor en aplicaciones que sigan una arquitectura N-Layer. Es importante notar que solo realizamos la configuración del contenedor de IoC en los puntos de entrada de la aplicación: los servicios distribuidos y la aplicación web y dejamos a la infraestructura de MVC y WCF la responsabilidad de resolver las dependencias => NO accedemos al contenedor de IoC en ningún punto de la aplicación.



Saludos, Josep Maria