viernes, 7 de febrero de 2014

Refinando la arquitectura de nuestro proyecto - Usando Autofac y Moq (1/2)

Después de algunos días retomo la serie de Congreso Visible, y no precisamente por que haya estado detenida en su totalidad, más bien estuve en el proceso de resolver algunos escenarios para el tema de acceso local a la base de datos, lo cual al momento es un post pendiente, pero que no quiero continuar sin antes aplicar al proyecto todas las mejoras que tengo planeadas a nivel de arquitectura, ya que espero llegar un día a una que pueda ser seguida como ejemplo por ustedes y además ofrecer alternativas.

Diré que el ejercicio hasta el momento me dejo demasiados aprendizajes, pero sobre todo una alta comprensión de lo que suponen cada uno de los escenarios que vimos, ya que estuvo complejo resolver de forma manual cada uno de los retos:
  • Tener codigo compartido por todas las plataformas
  • Tener codigo especifico para cada plataforma sin salirse del esquema general.
  • Aplicar pruebas unitarias a los dos escenarios anteriores bajo el mismo esquema.
  • Disminuir el acomplamiento entre las vistas y las vista modelo. Además de usar la menor cantidad de CodeBehind posible.
Todo esto fue una grata experiencia ya que evitamos al máximo usar librerías de terceros, lo que nos hizo tener un mayor entendimiento de la solución dada a cada escenario, sin embargo hoy después de ese proceso considero que podemos con mayor conciencia y aprovechar las ventajas que nos dan al crear código más limpio. En el repositorio quiero conservar los tags tanto a los intentos de no usar librerias como al cambio que realizaré a partir de este momento.
Al empezar este post pensé que podría mostrarles paso a paso el cambio, pero fue tan grande que ahora solo me queda enumerarles los cambios y compartirles los modelos actualizados y el código.

En este primer refinamiento vamos a usar las librerías Autofac para Injección de Dependencias y Moq para Mocking o creación de objetos dummy para los Test Unitarios.

Recuerden que cualquiera de estas librerías se instala en el proyecto que sea necesario a través del menú contextual Manage Nuget Package en la cabecera de sus proyectos.


Se consulta la librería que se desea añadir en las librerías en línea y se da Instalar


Ahora bien veamos cada uno de los cambios de este primer paso. Los cambios más evidentes se resumen en 3:

La eliminación de los servicios fake

Esto fue de los temas más interesantes debido a que comparar los test implementados con Moq versus los Test implementados a mano con Callbacks y Variables adicionales, se nota como el trabajo con Moq hace los Test menos mecanicos y más pensandos, es decir de verdad se necesita saber lo que se está haciendo para ensamblar los Mocks usando Moq


Espero que esten notando claramente la diferencia con la forma de crear Mocks, antes, si nó aquí les comparto una imagen del post en que iniciamos con TDD



De hecho si analizamos detenidamente en una línea haciamos la inyección de dependencias de la instancia de un Fake. Ahora vemos como hacemos la instancia usando Mocks. ¿Y la inyección de dependencias? Pues bien eso es el siguiente punto, por ahora veamos como se ven nuestros Test con Moq.



Si me permiten decirles, bastante bonitos, si desean ver los anteriores dirijanse al post en que iniciamos el montaje de los Test y verán la gran diferencia.

Actualización 10 de Febrero de 2013: Algo muy útil que encontré como compañero de Moq fue una librería adicional llamada Autofixture la cual nos permite añadir datos Fake para las pruebas. Si observa el tercer test de la tabla anterior en el tengo un DataTestHelper en el que uso Autofixture para generar datos y espero que les sea útil conocerlo. Para instalarlo en conjunto con Moq deben seleccionar el paquete correcto.


Luego de esto estarán listos para genera su Helper de generacion de datos Dummy, aquí un pequeño ejemplo, mejorado por mi amigo @HernanDgr


Cambio del manejo manual de dependencias

En este punto se implementó Autofac como contenedor de dependencias. Me hubiese gustado usar Unity, lastimosamente aun no tiene soporte para clases portables como si lo tiene Autofac.

Bien, Al mirar los test vemos como la inyección de dependencias cambió, ahora en vez de registrar una nueva instancia de un Fake, registramos el objeto que Moq crea.

Quisiera resaltar la última línea de la inicialización ya que esta es la manera como decidi resolver el acoplamiento entre las VistasModelo y el contenedor. Siendo que todas las Vistas Modelos heredan de la misma clase padre, dicha clase ahora tiene una referencia al contenedor haciendo que todas tengan la posibilidad de resolver correctamente las dependencias sin saber directamente de donde ellas provienen.

Otra cosa importante es ver como quedó en la aplicación implementado, cambiaron pocas cosas pero son importantes. Antes de mirar el cambio les mostraré que separé el ServiceLocator de las clases de Servicios creadas por ser propias de la plataforma.

En el futuro veremos cuan importante es tener en mente la estructura del proyecto, incluso el hecho de que por ejemplo estos servicios y el Service Locator compartan namespaces con los servicios que estan fuera de las clases. En Windows 8 tendremos que crear la mistra estructura Adicionar como Link el Service Locator y re implementar los servicios propios de la plataforma. Si en un futuro parte de estos servicios se vuelve común, será tan sencillo como implementarlo y pasarlo al assembly de servicios compartidos.
Por lo pronto conocer la reubicación de estas clases es importante debido a que para inicializar las dependencias en la app, es el ServiceLocator quien además de registrar las clases concretas, inicializa el contenedor de Autofac y observen la diferencia con como registramos las dependencias en los Test


Aquí vemos como en vez de registrar una instancia de Moq, registramos las clases concretas. Ahora bien la clase de infraestructura BindableBase quedó igual que antes responsable del contenedor pero esta vez del contenedor de Autofac.



El contenedor de Autofac se usa por las VistaModelo en el constructor, cuando se inicializan los servicios que dicha VistaModelo necesite


Es necesario decir que con este esquema los servicios podemos inicializarlos en el constructor o particularmente en los métodos que los usemos, finalmente siempre se recuperan del mismo contenedor de dependencias y se inicializarán solo una vez ya que solo existe una instancia de la Vista Modelo en el Service Locator. ¿Bonito eh? ¡Muy bonito!

Refactorización general

Se realizaron muchos cambios en nombres de clases, eliminación de interfaces innecesarias y reacomodación de clases en los assemblies. Hoy definitivamente valio la pena la pausa, aprender y pensar en mejores formas de hacer las cosas. Finalmente todos los cambios y el mismo proceso de ajustar el código ha quedado reflejado en el repositorio, un ejercicio interesante puede ser bajar los dos tags hasta el momento y observar las diferencias.

Por el momento en el solo modelo de paquetes, las diferencias son obvias.

Para finalizar quise dejar una reflexión sobre el por que intentar realizar tanto trabajo manual en los 9 post anteriores para no dejar demasiado texto al inicio, sin embargo como siempre me gusta compartirles mis posiciones.
Básicamente lo que más me inquieta de algunos de los devs Windows Phone que conozco son dos temas: Uno, no usan en absoluto ninguna buena práctica de MVVM y tienen vacios enormes a nivel de Programación Orientada a Objetos, o dos usan todas las buenas prácticas a través de librerías, sin entender lo que hacen, lo cual no redunda más que en lo mismo de los primeros, una falencia enorme de conceptos. 
Es importante entender que esto no es una crítica, es un llamado de atención. Como desarrolladores cada día deberiamos preocuparnos por mejorar nuestras habilidades para crear mejor código, todos aprendemos cada día, y deberíamos querer mejorar y avanzar, en la ruta correcta.

No hay comentarios: