lunes, 9 de diciembre de 2013

Implementando el servicio de navegación usando MVVM

Uno de los retos básicos al tratar de hacer una buena arquitectura cross platform consiste en que la navegación en cada plataforma es diferente, si han intentado desarrollar en Windows Phone y Windows 8 van a notarlo facilmente, en Windows Phone por ejemplo el NavigationService es una clase que solo podemos usar a nivel de un proyecto de UI, así que, si recuerdan, nuestras Vistas Modelo en el proyecto que tenemos, están ubicadas en un proyecto diferente, persiguiendo el tema de ser lo más cross platform posible. Ese es un problema, además de que el NavigationService de Windows Phone de nada serviría compartido.

Para dejarles opciones quiero compartirles los enlaces que encontré con propuestas parar el tema, y en el transcurso de este post, explicaré la que elegí y como la incluí en CongresoVisible
  1. Alejandro Campos : Ejemplo de una implementación del patrón MVVM
  2. Sara Silva: Adding Navigation Service
  3. Josue Yeray: Cualquier código autogenerado por App Studio
La solución que elegí a este problema la plantea Nick Randolph, en su artículo Estados, Navegación y Testing en Clases Portables, allí pueden encontrarlo además de explicado detalladamente, libre de toda la arquitectura que estamos trabajando, por que ella nos pone en ciertas situaciones al intentar agregarla. Eso sí lo más importante es entenderla de forma básica, por que en nuestro proyecto quedará bastante dispersa.

Lo que más me gustó de esta solución es su sencillez pero que a la vez deja ser a cada plataforma lo que es sin complicarse demasiado y teniendo una estructura apta para test.

La primera parte que vemos de esta implementación es el Contrato del INavigationService


Es así de sencilla por que de hecho lo único que pretendemos reemplazar es justamente la opción de navegar, igual si tuviesemos otros tipo de necesidades en este lugar las añadiremos posteriormente.

Según nuestra arquitectura, esperaríamos que haya en el proyecto Services y en FakeServices alguien que implemente esta interfaz pero ahí viene la diferencia, como ya lo dijimos al ser un problema puntual de cada plataforma, esta clase se va a implementar en cada plataforma. Sin embargo el FakeService si puede implementarse para los test.


La implementación concreta propuesta para Windows Phone es la siguiente:


Esta es la implementación que cambiará para cada plataforma. Si intentamos entender este código, veremos como la ruta a la que se pretende navega es el nombre de una clase, esa clase serán nuestras vistas modelo, y claramente nuestras páginas no van a llamarse como nuestras vistas modelo, sin embargo, la propuesta de Nick si es hacerlas algo similares. Ella consiste en ubicar las páginas en una carpeta y nombralas según la Vista Modelo que representa su contexto.


Para que esta indicación cobre sentido, debemos continuar las instrucciones, la que sigue consiste en crear un Uri Mapper con una estrategia particular que Nick describe en otro de sus artículos.


Si observamos con detenimiento este UriMapper nos damos cuenta que se está usando una parte del nombre de la VistaModelo para ser mapeada contra una página, así es bastante sencillo de entender, claro está nos va a forzar a tener una Vista Modelo por cada vista a la que queramos navegar, pero eso no está tan mal, es más o menos lo típico. Para que esto termine de encajar debemos cambiar una línea en App.xaml.cs para establecer nuestro UriMapper en plena inicialización.


Ahora bien, si lo han estado notando, acompañando al NavigationService hay una clase más que teniamos pendiente por implementar para nuestras apps y es un Locator. Si recuerdan nuestros Test, en ellos la misma clase de Test inicializaba las vistas modelos, pues bien para teminar la implementación de nuestro ServiceLocator, necesitamos un Locator local que sirva como contexto a nuestras vistas, es aquí donde diferimos de la implementación que hace Nick en el artículo, debido a que nosotros tenemos un manejo de dependencias a través de nuestro ServiceLocator.

Pues bien, nuestro Locator quedaría implementado de la siguiente manera

Si analizamos la implementación vemos que este Locator es el responsable de inicializar las instancias particulares de los servicios y de las vistas modelo. ¿Pero como es que esta clase inicializa todo para la app? ¿En que momento lo hace?

Pues bien, el momento es cuando empieza a ejecutarse la aplicación, ya que si lo pasaron por alto, pueden observar que el Locator está definido como recurso de la aplicación en el App.xaml


Pero además siguiendo el patrón Service Locator, debemos hacer que cada una de nuestras vistas tenga como DataContext a este Locator que es un recurso, así:


Para terminar con nuestra implementación de navegación y si son lo suficientemente curiosos habrán notado que cuando el Locator instancia cada una de las vistas modelo y las registra en el Service Locator, además inicializa su Navigator.

Pues bien cada una de las VistaModelo que requiera usar el navigator ahora implementa la interfaz INavigateViewModel, con la que además hice un ajuste en el proyecto de contratos


Así pues de acuerdo a las capacidades que requieran las interfaces de nuestras vistas modelo tendrán que implementar estas interfaces


Pero entendiendo que las implementaciones concretas de estas son comunes a todas las vistas modelos, dejamos la implementación concreta en BindableBase de la cual tenemos certeza es heredada por todas nuestras vistas modelo


Estoy del desacople es literal como juga con legos. Ahora lo que queriamos ver desde el inicio es la navegación, estando todo listo para que pueda darse, ahora navegar desde nuestras vistas modelo es tan sencillo como esto.


Bastante bonito ¿eh? Para completar nuestra implementación haremos algo que Nick muestra en su post y es crear un proyecto de Test de Windows Phone, esto solo por el mero ejercicio ya que como saben tenemos nuestra estructura de pruebas listas para hacer lo mismo.

Lo primero que debemos hacer es crear un proyecto de Pruebas Unitarias para Windows Phone.


Como van a ver en el test que se implementa, no tiene nada particular como para dejarlo en un Test de este tipo, pero como les mencionaba en ese post, si su arquitectura no está tan segmentada como la mía, bien valdria la pena ver que tienen a la mano este tipo de herramientas.

Nuestro test usando comandos sería:


Incluí este test en nuestro proyecto de test general así:


Para quienes recién empiezan con los test observen como en cada uno de los que tenemos hasta ahora hay dos estrategias diferentes, uno es con un Callback y el otro con un contador, cada uno puede hacerlo como mejor lo entienda, lo importante es hacer los test.

Ese es el fin del ejercicio, espero no haber olvidado poner ningun paso, sin embargo el código está publicado. Estamos a punto de llegar al momento donde nuestra aplicación por fín hace algo y si que hemos trabajado. :)

sábado, 7 de diciembre de 2013

Creando prototipos funcionales usando Blend

Bien, una de mis partes favoritas de hacer apps es montar el diseño, con el fin de que no me vean pasar de cero a cien en la app, les daré una pequeña muestra de como crear sus prototipos funcionales usando como base todo lo que ya tenemos para nuestro proyecto de Congreso Visible.

Lo que veremos aquí aplica a Windows Phone y Windows 8.1, en Windows 8 por alguna razón que desconozco no se encontraba disponible el Sample Data con Blend.

Con Blend tenemos una gran herramienta para hacer prototipos funcionales y ver como quedarán nuestras apps, aun sin tener el código que se ejecutará finalmente, vamos a recordar nuestro diseño


Bien vamos a intentar diseñar en este post la primera de las columnas. Como ven en la estructura de mi proyecto que presento a continuación simplemente tengo un panorama y tres panorama items.


Ahora vamos a crear los datos de ejemplo que nos permitirán crear nuestro diseño. Como ven en las opciones hay varias formas de crear datos de ejempo. Yo tipicamente lo creo a partir de una clase y selecciono la clase principal MainViewModel, sin embargo esto tiene sus implicaciones, como que los datos no sirven para hacer prototipos funcionales por que no se ven en tiempo de ejecución y que cada que agregamos propiedades serviría refrescar el DataSource y enlazarlo de nuevo.

Bueno, para evitarnos esas complicacipnes y lograr lo de tener prototipos funcionales en este ejercicio usaré la opción New Sample Data, que crea basicamente un archivo XAML con datos de ejemplo que se cargan en tiempo de diseño si así lo queremos.


Después de seleccionar la opción New Sample Data, Blend nos pide colocar un nombre. Ya que vamos a crear un Sample Data que tiene la estructura del Main View Model sugiero en nombre que ven en la siguiente imagen.


Después de creado el Sample Data podemos empezar a agregar propiedades, como ven las hay de tres tipos, datos simples, propiedad compleja (para simular una clase) o propiedad colección (para simular una lista)


Los que debemos hacer por tanto es simular la mis estructura que tiene el MainViewModel, esto con el fin de que cuando lo asignemos como contexto de nuestra vista encaje como un guante. Sin embargo en el Sample Data solo pondremos los datos que sean necesarios para generar efectos gráficos, en nuestro ejemplo simplemente para visualizar data.


Miren como la estructura del Data Source coincide exactamente con los nombres de las propiedades de la clase MainViewModel


Para verificar los tipos de datos es bueno que se pasen por el API y así puedan ver que tipos de datos obtendrán y cuales quieren dibujar en su diseño, por ejemplo miren el género, no se confien de los nombres en el API en esta como en otras APIs puede pasar que les toque hacer recomendaciones.


Las propiedades de los Sample Data en Blend pueden establecerse de varios tipos: String, Boolean, Numeric e Image. El string tiene algo particular y es que tiene un formato que nos ofrece varias alternativas para la generación de los datos de ejemplo, como generar nombres, telefonos, direcciones, esto con el ánimo de que los prototipos funcionales queden realistas.


La propiedad imagen nos permite tomar una carpeta donde tengamos imagenes y usarlas como datos de ejemplo, con el mismo objetivo de lo anterior, crear prototipos funcionales realistas.


No olviden que cuando quieren que los datos esten disponibles o no en tiempo de ejecución, pueden activar o desactivar.


Muy bien, después de configurar nuestro Sample Data, arrastramos la colección que configuramos hasta el primer panorama y la soltamos allí. Veremos como automáticamente se crea un ListBox con los datos de ejemplo, que inicialmente no vemos por que tienen la letra blanca.


En este punto debemos editar la plantilla para poder cambiar el color de la letra y ademas acomodar los datos como los queremos ver. No olviden borrar la plantilla que queda en el archivo local XAML por el efecto de haber arrastrado la colección. Dando clic derecho sobre el ListBox editamos la plantilla a través de las siguientes opciones.


Le ponemos un nombre a la plantilla que vamos a crear y observen bien la guardamos en un diccionario de recursos.


Editamos la plantilla colocando los datos que queremos en la posición correspondiente, usando los contenedores de XAML que necesitemos. Observen la jerarquía de esta plantilla.


Al salir de la edición de la plantilla veremos una bonita lista.


Usar un botón en los items de nuestras listas, nos permitirá usar facilmente su propiedad Command para hacer alguna función cuando el usuario haga tap sobre el item. El problema es que tenemos que tener en cuenta lo siguiente:

video

Como ven la lista provoca que el color de acento del teléfono se vea al presionar el botón y obviamente si como en nuestro caso no estamos trabajando en los estilos por defecto, eso no va a gustarnos mucho. Pues bien, para solucionarlo debemos editar de nuevo la plantilla y esta vez editar el estilo del botón.


No se olviden de asignarle un nombre acorde


Allí tendremos la posibilidad de editar lo que sucede en los Visual States del botón, y de observar el efecto que vimos en el video


Pues bien, seleccionamos el ButtonBackground y ponemos el color que deseamos y el efecto es este:

video

Genial, simple y fácil. Incluso sin haber hecho nada de los post anteriores este post puede resultar útil a diseñadores. Espero les haya gustado y bueno luego voy a sorprenderlos con el avance del diseño.

Actualización 17 de Febrero
Quería compartirles como se ve el panorama después de un tiempo y lo bonito de trabajar con Blend, y ver nuestros diseños sin dejarlos a la imaginación, más bien observandolos en tiempo de diseño.

video


Preparando nuestro proyecto para pruebas unitarias (TDD)

Parece que hasta ahora hemos dado montones de vueltas antes de empezar a hacer nuestra app, y creanme aun no terminamos, y es que así es más parecido a la realidad.

Hoy vamos a iniciar entendiendo un tema útil y hasta de moda. Como vieron en el anterior post, la estructura de nuestra solución tiene un proyecto de test unitarios y la arquitectura necesaria para poder usarlos. Pues bien antes de eso y para los que no conocen hay que mencionar que es TDD (Test Driven Development)

TDD es una técnica para diseñar software que se centra en tres pilares fundamentales:

  • La implementación de las funciones justas que el cliente necesita y no más.
  • La minimización del número de defectos que llegan al software en fase de producción.
  • La producción de software modular, altamente reutilizable y preparado para el cambio.
Los invito a conocer en detalle sobre el tema con el libro de Carlos Blé, Diseño Ágil con TDD
Ahora bien, hacer TDD no es hacer pruebas como lócos es hacer pruebas con sentido, que ayuden a proteger a nuestro código  de cambios no inápropiados y a estar seguros que al menos cierta parte del mismo funciona correctamente.
Hay que entender que este tema es opcional pero es una buena práctica que vale la pena comentar y aplicar si trabajamos en equipos ágiles. Veamos como lo estamos aplicando en nuestro proyecto de Congreso Visible.

En mi óptica las Vistas Modelo deben quedarse intáctas y no deben tener mocks, los mocks son de fuentes externas o servicios de plataforma especificos tales como settings o caracteristicas del teléfono o tableta, que no estarían disponibles al ejecutar las pruebas unitarias, por esta razón el punto de partida es pensar que tipos de servicios tendremos y por tanto cuales son las interfaces de estos.

Confieso que me demoré más de lo que pensaba montando la estructura de todo esto, la parte positiva es que además de que quedo listo y super desacoplado, ustedes ya lo pueden descargar, verlo y explorarlo. Tenemos solo con un test case inicialmente, pero quedará super listo para ensamblar los demás. Vamos a ver si logro describir las cosas que tuve que hacer.

Lo primero que hice fue definir todas las interfaces de servicios que creo voy a utilizar.


Como ven además definí interfaces para las vistas modelos. Esto pudo perfectamente ser opcional, pero en la idea de intentar desacoplarme de todo fue un buen ejercicio que espero tenga algún proposito más que solo complicarme la implementación, ya que como claramente lo deben intuir las interfaces de las vistas modelos las debe implementar cada una de las vistas modelo que teniamos definidas, por lo que fue necesario trasladar todas las propiedades a las interfaces para que esten disponibles en los test cases y por supuesto realizar la implementación de las propiedades así:


Una interfaz que espero esten notando y se pregunten que es es IBindableServiceLocator. Si recuerdan la el post donde definimos la arquitectura, BindableBase que es quien implementan todas las VistasModelos, tiene un método que recupera del Services Locator, las instancias del servicio a usar. Pues bien, debido a mi uso de interfaces por aquí por allá debemos implementar una interfaz con este método para que así los test unitarios puedan reconocerlo pero recuperando el servicio falso.


Tenga en cuenta por lo tanto que nuestras interfaces de las Vistas Modelo ahora tendrán que implementar tambien IBindableServiceLocator.


Todo esto es un poco pesado al inicio para el esquema mental de quienes apenas están comenzando, pero tengan en mente que algún día lo comprenderán facilmente. Bien, por supuesto espero que sobre decir que además fue necesario crear todos los servicios Fake que probaremos y para eso era el proyecto de FakeServices.


Para entender un poco más por que todas estas complicaciones desde hace ya 5 post, vamos a ver el test case que implementé aquí. Para ello tenemos que conocer la nueva clase TestContainer que implementé dentro del proyecto de test, esto como ensayo no más, en el futuro espero tener varios TestContainer de acuerdo a grupos de pruebas que quiera hacer.


Por el momento, esta clase será la responsable de instanciar las Vistas Modelo y además de registrar los servicios falsos para las pruebas unitarias.


Ahora vamos a realizar la implementación del comando en nuestra Vista Modelo de ejemplo para crear el Test ShareProfile. En este punto está la magía y lo bonito del desacomplamiento, como ven nadie conoce a nadie, solo se usan interfaces. Por lo demás es solo la implementación de un comando, si no lo tienen claro, les recomiento como siempre ver los videos del maestro Josue Yeray explicando MVVM


Por último el lugar donde queríamos llegar es el test case o prueba unitaria. Empecemos por hacer un test que falle. Veamos ¿Por qué falla este test?


Espero que lo hayas adivinado, simple, por que no hay un enlace para compartir, así que al ejecutar los testcase el resultado es...


Usar un contador es una de las estrategias para hacer test, tambien podemos usar Callbacks y de hecho lo veremos en post más adelante pues será la estrategia con la que continuaremos haciendo TDD en nuestro proyecto.

Ahora como manda, hagamos funcionar el test


Y entonces después de todo este trabajo tenemos un bonito "Test case passed!", y la alegría que eso produce es solo apta para geeks! ;)


Si observaron con detenimiento, los mocks los implemento a nivel de Servicios solamente. ¿Por qué entonces hacer interfaces de las vistas modelo? Diría que es un tema de gusto por perseguir el desacople, si analizan o intentan eliminar las interfaces, se darán cuenta que el proyecto de Contratos, quedaría acoplado al de Vistas Modelo y bueno este a su vez estará acoplado al de servicios, así que nó, no es eso lo que persigo :)

Para no perdernos del contexto de nuestra app, aquí les dejo el Modelo de Paquetes actualizado. Sorpréndanse de todo lo que hemos creado y solo es infraestructura.


Entiendo que algunos de ustedes pueden necesitar hacer TestCases sin tener una arquitectura tan elaborada así que no olviden visitar MSDN para saber como ejecutar test incluso cuando los tienen al interior de la app de Windows Phone.

Actualización: He creado un post donde se usa un Test en un proyecto Windows Phone Unit Test para probar la navegación del NavigationService no olviden pasar a verlo, está al final y necesita de lo creado en ese post para ensamblarlo y entenderlo.

viernes, 6 de diciembre de 2013

Definiendo la arquitectura base de nuestro proyecto

Actualización Febrero 2014: La arquitectura propuesta aquí se refino en el post numero 10 de la serie.

Continuando con nuestro desarrollo, después de pensar un rato en esto, terminé la definición de la distribución de componentes según sus responsabilidades dentro de mi solución. Mi decisión fue no usar controles de terceros y evitar al máximo usar frameworks o librerias externas, con excepcion de SQLite y el Toolkit de Windows Phone, vamos a ver como nos va con esa decisión.

La solución quedó estructurada de la siguiente manera:


Para entender mejor la relación entre los proyectos, les dejo un diagrama de paquetes. Allí se puede observar donde quedaron los modelos que usaremos para consumir los datos vía Json como se explicó en otro post y también las Vistas Modelo que definimos en el post antenior.

* El diagrama está actualizado al 15 de Diciembre con el post 9.


Como ven, el trabajo que tenemos es bastante, aun no se si nos mantedremos así hasta el final, pero lo intentaremos.
Como pueden observar quiero en este ejercicio lograr que la clase de infraestructura sea lo más reutilizable posible, por lo que aprendiendo del mejor maestro Josue Yeray y sus ejemplos, tengo varias clases reusables, incluida una implementación de un Service Locator, que no usa frameworks externos, espero que cuando empecemos la app de Android y iPhone el hecho de no usar más que código C# nos traiga grandes ventanas.
A veces tiendo a exagerar con la separación por assemblies pero les aseguro que estuve pensando en esto un buen rato y por el momento estoy conforme, las librerías todas son portables con este soporte:


Si necesitas conocer que es una Librería Portable (PCL) sus ventajas y limintaciones en MSDN encuentras la explicación en español. Los demás proyectos son una aplicación panorama Windows Phone 8, una aplicación Hub Windows 8, y un proyecto de Test.

No olviden que para entender las decisiones de esta estructura deben tener idea y conceptos al menos básicos de XAML y MVVM razón por la que nuevamente les comparto la diapositiva de intro y no se olviden de ver la explicación en video de Josue Yeray del patrón MVVM.


Ahora, si bien esa es la estructura de nuestra solución, vale la pena detenernos en esas 3 clases en particular de infraestructura, que con suerte son las que nos van a ayudar a trabajar una buena aplicación cross platform, puede que no de la manera más óptima pero si de la más transparente y bajo nuestro control.

La primer clase es BindableBase, tomada tal cual de la plantilla de Windows 8, y adecuada con el Service Locator, es la clase que va a permitir a nuestras Vistas Modelos ser escuchadas por las Vistas cuando realicen un cambio, todo gracias a INotifyPropertyChanged.


La segunda clase interesante es el DelegateCommand en su implementación seguro más sencilla, nos va a permitir enlazar comandos de nuestras Vistas Modelos con nuestras Vistas sin usar Code Behind.


La última pero no menos importante es la clase ServiceLocator que nos permitirá obtener las instancias de las clases que son el contexto de nuestra aplicación desacoplando las vistas de estas clases y a la vez de facilitándonos hacer TestCases pues también tendrá una referencia a los servicios que usamos siempre disponible.


Mi lectura recomendada está en MSDN, aunque no está en contexto de apps móviles de manera general explican el patrón Services Locator.



El Service Locator es una versión especializada del patrón de Inversión de Control (IoC). La inyección de dependencias resuelve el mismo problema que el Service Locator pero usa una implementación diferente, para hacer inyección de dependencias podemos usar componentes como Unity que está disponible vía Nuget para nuestras aplicaciones de forma gratuita y que es provisto por Microsoft Patterns and Practices.
Como ven, las clases descritas cumplen propósitos generales, y si todo sale bien sencillamente podrían ser usadas tal cual en otras aplicaciones.

Actualización 11 de Diciembre: Lo más bonito del conocimiento es cuando se multiplica, les comparto la explicación de Emerson Perdomo sobre Inversion de Control e Inyección de Dependencias. Mil gracias por compartirlo :)


Nota: Veo que este post ha tenido muchas visitas, y no tanto así el de pruebas unitarias, mi invitación es a que se pasen por allá tambien, puesto que al intentar crear las pruebas unitarias para congreso visible, se añadieron más cosas a la arquitectura que deben ser entendidas y tomadas en cuenta.

Actualización 15 de Diciembre: En el post 9 este era nuestro diagrama de dependencias, para entenderlo no pueden olvidar seguir la serie de Congreso Visible para ver de que manera evolucionamos hasta aquí. La parte negativa y a la vez positiva de todo esto es que al hacer este análisis logré identificar que algo estaba mal.


Como pueden ver, el proyecto de insfraestructura tiene una relacion indeseada con Congreso Visible ¿Por qué indeseada? pues bien este proyecto debia ser transportable a otros proyectos sin ser tocado, así que en este punto entre a resolver la situación. Quitando los proyectos de test el nuevo diagrama luce asi:


El cambio interno fue que las interfaces que necesitaban de infraestructura se movieron a ese proyecto y fue bastante transparente, es decir, nuestro proyecto de infraestructura quedaría asi:


* He actualizado el diagrama de paquetes del inicio de este post a la fecha.