Saltar al contenido principal
Inicio
CES Digital
  
Introduce tu búsqueda aquí:
Iniciar la búsqueda

Imagen de la barra de título de página de elementos Web
cesblog

 Entradas de blog

Windows Azure DataMarket: el multiuso de los datos

Últimamente mi trabajo ha derivado hacia temas fuera de lo técnico por lo que lamentablemente tengo poca capacidad para “tocar código” de la que he podido disfrutar hasta ahora, pero aunque este tema me pille un poco más de “refilón” me ha parecido lo suficientemente interesante para conocerlo y, ya puesto, explicarlo.

Microsoft, dentro de su estrategia de servicios para la nube de Internet denominad Windows Azure, ha incluido una plataforma de consumo y publicación de datos a través de OData llamada DataMarket.

image

DataMarket es una plataforma que realmente define en su nombre de qué se trata: “simplemente” es un mercado de datos. Y digo simplemente porque toda la complejidad técnica que esconde detrás de la fachada es admirable: cualquier empresa, institución o incluso persona puede exponer sus datos para consumo y uso por parte de un tercero en cualquier lugar de Internet, de una manera establecida o no, sin que esto suponga carga de proceso para el proveedor y con la posibilidad o no de conseguir beneficios económicos de esta “venta de datos”; pero es que también cualquier empresa, institución o persona puede disponer de manera inmediata de datos digitales de los que puede hacer uso como le plazca (salvo excepciones estipuladas en cada licencia de uso de los datos) en sus propias aplicaciones o mediante aplicaciones de terceros como Microsoft Excel PowerPivot, de manera gratuita o con un coste estipulado por uso (ojo con esto: es preciso comprobar cuál es el coste de los datos que usemos y bajo qué condiciones se nos tarifica por su uso ya que por ejemplo puede haber conjuntos de datos que por cada consulta, y esto incluye las previsualizaciones, nos cobre un acceso… – en general, esto es un consejo recomendable para cualquier uso en Windows Azure: ¡mucho ojo con la tarificación!).

Lo que esto nos proporciona básicamente es el poder acceder a datos y por tanto información que nunca antes hubiéramos podido usar. Esto nos permite pensar aplicaciones nuevas, completar las existentes… en definitiva: innovar, que ya es hora :) Además, al hacer uso de estándares reconocidos como OData, Microsoft esta vez nos ofrece un producto realmente “open” para Internet, que puede emplearse en cualquier plataforma y aplicación. Y, aunque muchos de los conjuntos de datos que se ofrecen en DataMarket son de pago, también hay otros muchos que son gratuitos y que podemos emplear ya, como el que veremos a continuación en el ejemplo que proviene de Naciones Unidas. Por cierto, sería de agradecer que Microsoft añadiera un filtro a su buscador de datos para mostrar sólo los gratuitos… aunque me imagino que eso va contra sus objetivos de ventas ;)

Vamos pues a entrar en arena con un pequeño ejemplo. Lo primero que hemos de hacer es acceder a la página de DataMarket y registrarnos con una Windows Live Id en https://datamarket.azure.com/ 

Una vez dentro tenemos varias pestañas en la parte superior que nos ayudarán a realizar nuestra labor:

  • Learn: aprender, que nos proporciona información sobre cómo desarrollar aplicaciones para Windows Azure DataMarket . En Microsoft se han tomado mucho esfuerzo en intentar que sepamos fácilmente cómo desarrollar aplicaciones para su plataforma, es algo que se ve en todo el portal de DataMarket y que es de agradecer.

image

  •  Browse: para buscar fuentes de datos y la verdad es que hay muchísimas y cada día más! Eso sí, sobre todo norteamericanas pero es de esperar que esto poco a poco vaya mejorando para los habitantes del viejo continente (por ejemplo, empieza a disponerse de muchas fuentes europeas y de Gran Bretaña, a las que seguramente seguirán alemanes y franceses).

image

  Aquí podemos buscar la/s fuente/s de datos que nos interese, o simplemente como es mi caso acceder a aquellas de organismos internacionales de carácter público ya que estos suelen ser gratuitos en un 95% de los casos (por ejemplo, los de United Nations).

  • Partners es la zona donde los socios que proporcionan datos en DataMarket se anuncian de manera pública además de donde podemos encontrar la información de los pasos a seguir si tenemos datos que queremos “vender en el mercado”.

image

  • My Data, aquí es donde está el “meollo” de la cuestión, donde encontraremos la lista de las fuentes de datos a las que nos hayamos subscrito, y desde esta lista acceder a la información sobre su uso (licencia, costes…), tipos de consultas que ofrece (fijas o flexibles) y clave de acceso. En mi caso estoy suscrito a una fuente de datos de UNData, la sección de datos de Naciones Unidas, que proporciona información muy interesante a coste 0.

image

  • Help, nuevamente una sección muy completa de ayuda sobre cualquier cosa que necesitemos en DataMarket, o para pedir ayuda si echamos algo de menos.

image

Vale, ahora vamos a ver cómo podemos usar estos datos. No me voy a dedicar a mostrar aquí cómo podemos usarlos mediante herramientas como Excel PowerPivot ya que me alargaría demasiado y eso está muy bien explicado en la propia ayuda de DataMarket. Lo que haré será desarrollar una mini aplicación para mostrar lo fácil que es acceder a estos datos mediante Visual Studio y OData.

Lo primero es volver al tab de “My Data”, donde haciendo drill down en el enlace al conjunto de datos que nos interesa podremos acceder a más información sobre ellos:

image Desde aquí podemos tener acceso tanto a la exploración de una vista previa de los datos (recordar que en este caso esto no tiene coste!) como a los enlaces para ver los datos con otras herramientas como Excel PowerPivot o TableauSoftware. imagePero en enlace que nos interesa es el de abajo “Learn How To Use This Data In Visual Studio“ que nos lleva a una sección en MSDN dedicada al desarrollo de soluciones para Windows Azure DataMarket muy completa.

image

Bien, manos a la obra. Lo primero que tenemos que hacer es averiguar si nuestro conjunto de datos es de tipo Flexible Query o Fixed Query. La diferencia es que los primeros nos permiten pasar una serie de parámetros y/o condiciones para la consulta de manera que los datos que esta devuelva sean flexibles, mientras que en el segundo caso el vendedor establece unos datos fijos que devolverá según una serie de consultas establecidas por él de antemano. Estos datos los podremos luego usar nosotros como queramos, pero siempre serán los que nos vengan dados.

En nuestro caso, si volvemos a la página de información de nuestro conjunto de datos, bajando un poco en la misma vemos que indica que se trata de una Flexible Query (acepta parámetros):

imageEn este caso lo que tenemos que hacer es crear una aplicación en VisualStudio a la que añadiremos una Service Reference para el acceso a los datos en Azure. Vamos a hacer lo más sencillo, una aplicación de consola, ya que una vez conseguido hacer este acceso bien modificar el UI para usar Windows Forms, WPF, Silverlight, ASP.Net o lo que queramos será una cosa simple.

Abrimos VS2010 y creamos un nuevo proyecto .NET Framework 4.0 (obligatoriamente) de tipo Aplicación de consola, que en nuestro caso será en C#, y nombraremos TestDataMarket.

image A continuación, tal y como indica la ayuda de MSDN, para crear una aplicación de tipo Flexible Query, http://msdn.microsoft.com/en-us/library/gg312152.aspx, añadimos la Service root URL a nuestro proyecto, que es la que tenemos en la página de información de nuestro conjunto de datos que hemos visto anteriormente. A continuación en nuestro árbol de proyecto, en References, pinchamos con el botón derecho y seleccionamos “Agregar referencia de servicio”. En el menú que nos sale, en Dirección pegamos la Service Root URL, y pulsamos “Ir” para que detecte los servicios disponibles. image

. Le proporcionamos un nombre con sentido y pulsamos Aceptar.Hecho esto, ya tendremos disponible el conjunto de datos para nuestro uso en la aplicación.image En nuestro código añadimos la referencia con una sentencia using que referencia al espacio de nombres de nuestra aplicación seguido del que hemos dado al servicio referenciado. En mi caso:

using TestDataMarket.UNEnergyData;  // Acceso a datos

A continuación hemos de crear una clase pública que nos proporcionará el acceso a los datos.

        public class GetElectricalData
        {
            Uri serviceUri;
            UnitedNationsEnergyContainer context;
 
            public GetElectricalData()
            {
                serviceUri =
                    new Uri("https://api.datamarket.azure.com/Data.ashx/UnitedNations/Energy/");
                context = new UnitedNationsEnergyContainer(serviceUri);
                context.Credentials = new NetworkCredential(" ", <CLAVE DE ACCESO>);
            }
 
            public IList<Values> getStats()
            {
                IEnumerable<Values> query;
 
                query = from c in context.Values
                        where c.CountryName == "Spain"
                        select c;
                return query.ToList();
            }
        }

Esta clase la he hecho muy básica, porque sólo quiero comprobar el acceso. Se trata de una query LINQ que devuelve una lista de enumerables que recuperan los valores de nuestra fuente de datos para España. Lo podríamos complicar todo lo que queramos, dentro de los valores permitidos por los datos, tal y como se hace en las consultas SQL de toda la vida. Destacar únicamente que donde indica <CLAVE DE ACCESO> habremos de introducir nuestra Account Key de DataMarket, que podremos obtener en la pantalla “My Data” (o “My Accounts” en la parte superior, es lo mismo), en la sección “Account Keys”. 

Finalmente, en nuestro main mostramos los resultados por pantalla para ver que funciona:

        static void Main(string[] args)
        {
            GetElectricalData X = new GetElectricalData();
 
            IList<Values> stats = X.getStats();
 
            foreach (Values v in stats)
            {
                Console.WriteLine(v.Year + " : " + v.CommodityTransactionName + "  -> " + v.Quantity);
            }
            Console.ReadLine();
        }

Como vemos, este código no tiene nada de particular, por lo que no haré comentarios. Y nuestro resultado será este:

image

Como vemos, acceder a semejante volumen de datos y emplearlos en nuestras aplicaciones no tiene ninguna dificultad gracias a Windows Azure DataMarket. Lo siguiente será que vendamos nuestros datos a través de esta plataforma, rentabilizando por tanto de manera adicional nuestras aplicaciones. Una gran plataforma por parte de Microsoft.

Aprovecho para despedirme de las colaboraciones en el boletín de los Centros de Excelencia Software de Navarra, CESDigital, ya que aunque es posible que estos continúen, mi dedicación a este boletín ya no es prioritaria por tanto dudo mucho que vuelva a publicar nada en él. Eso sí, mi blog ha de seguir adelante.

Y, finalmente, ¡muy feliz 2011 a todos! Ojalá que podamos olvidarnos de este año 2010 en el que sólo han salido ganando los impresentables de siempre y ha traído tan poca alegría a la gente normal. Urte berri on!

Gestión de proyectos ágil con herramientas opensource (7/7): Express

Terminamos el año y los artículos de la serie con la última herramienta, Express: http://agileexpress.sourceforge.net/

A juzgar por la escasa documentación, parece ser proyecto reciente y según su roadmap, todavía tiene mucho camino que recorrer:

  • 0.7 (current) - Backlog management, Virtual Wall, Acceptance Criteria, basic impediment management.
  • 0.8 - Full Impediment Management for tasks and stories with list views by Iteration and Project.
  • 0.9 - Detailed reporting: developer velocity, advanced burndown y project burnup.
  • 1.0 - Defect, Risk, & Issue management.

Puede que actualmente esté un poco verde, contiene errores de funcionamiento (ej: asignación de impedimentos a tareas no visualizados, componentes gráficos de edición no presentes en determinados momentos, etc.) y resulta bastante compleja de instalar, así que quizás convenga esperar a que madure.

Versiones / licencias

No hay información de las licencias. El código no está disponible con lo que apunta a que por el momento no es Open Source o están decidiendo aún su licenciamiento.

Entorno

  • JDK
  • Contendor de servlets: Tomcat 6.0.20, Jetty.
  • Base de datos: Postgres (defecto), MySQL, HSQL.
  • Servidor de correo (SMTP): parece necesitarse para el proceso de confirmación de registro de los usuarios en la plataforma.

Idioma

Sólo está disponible el inglés.

Vida

Aparentemente comenzaron con la versión 0.7.1 en noviembre del 2009, en el momento de analizar esta aplicación, la última versión era de marzo del 2010, la 0.7.5. Han sacado 4 versiones en 4 meses aproximadamente, un buen ritmo si no sería porque desde marzo no habían avanzado nada.

Documentación

Escasa, tan solo hay un documento de instalación y configuración que, de hecho, sirve de poco.

Comunidad

No existe.

Soporte comercial

No existe.

Funcionalidades gestor de proyectos

Se puede gestionar múltiples proyectos aunque no permite la agrupación de los mismos o identificación por áreas lo que puede acabar por convertirse en un saco inmanejable de proyectos.

Se trata de un gestor de proyectos expresamente enfocado a la gestión ágil así que dentro de este apartado no mucho reseñable, salvo quizás, la forma de acceder.

Para tener acceso a la aplicación existe un proceso de registro, por el cual la aplicación verifica tu dirección de correo electrónico. Así pues, es imprescindible configurar el uso de un servidor de correo. (una solución provisional consiste en alterar la base de datos)

Gestión de incidencias

No hay gestión de incidencias.

Ampliación y adaptación

No hay información sobre algún posible sistema de plugins y, aparte, al no disponer de las fuentes en el momento de redactar esta valoración, tampoco se puede modificar para adaptarlo.

Funcionalidades propias de Scrum

La aplicación está claramente orientada a la gestión de proyectos con Scrum, así que implementa los conceptos y artefactos más comunes:

  • Project - Es el nivel más alto, define un proyecto sólo con fecha de inicio, no de fin y en el se indica como se va a medir el esfuerzo de las historias de usuario (puntos, días u horas).
    • Iteration - El sprint con fecha de inicio y de fin.
      • Story – Son historias de usuario, se definen de la manera habitual. Si el proyecto se ha definido el esfuerzo en puntos, las historias de usuario tienen puntos para el valor de negocio y para el esfuerzo. Pueden estar asociadas a un tema (funcionalidad).
        • Tasks – Cada historia de usuario tendrá una o más tareas asociadas. Estas tareas se definen en horas.

Existe, dos backlog consistente en sendas listas de las historias de usuario, por una parte las que no están asignadas a ningún Sprint y las que si están asignadas al Sprint. Existe una vista en la cual se muestran ambas listas y que soporta el drag & drop permitiendo pasar historias de usuario del backlog general (del proyecto) al backlog del sprint.

Cuenta con una pizarra visual por sprint donde se ven las historias de usuario y sus tareas asociadas con 4 estados posibles no modificables: abierta, en progreso, test y hecha. También cuenta con la funcionalidad de drag & drop. Se pueden incluir impedimentos, que se identifican en la tarea como una marca roja existiendo la posibilidad de añadir un responsable de subsanar dicho impedimento. En cada tarea aparece el responsable de la misma, el cual es único aunque cualquier otra persona puede tomar el control cuando quiera auto-asignándosela. No hay medidas de carga y no hay forma de limitar el trabajo que puede hacer una persona.

También tiene una gráfica en la cual se visualizan los puntos (velocidad) conseguidos por iteración y un Burndown Chart por iteración pero que no aporta mucha información.

Los roles existentes no son los de Scrum, hay un el rol de propietario del proyecto y de la iteración. El resto de usuarios puede solicitar entrar en un proyecto, y será el propietario del proyecto el que les permita entrar. Cuando el acceso es aceptado, al usuario le llega un correo confirmándolo.

Cuadro resumen

Express

URL

http://agileexpress.sourceforge.net/

Licencia / versiones

Desconocida

Entorno

JDK

Contendor de servlets: Tomcat 6.0.20, Jetty.

Base de datos: Postgres (defecto), MySQL, HSQL.

Servidor de correo (SMTP)

Idioma

Inglés

Vida

Reciente, proyecto inmaduro. 4 versiones en 4 meses. Actualmente no ha tenido mucha evolución.

Documentación

Escasa, solo de instalación.

Comunidad

No existe

Soporte comercial

No existe

Funcionalidades gestor de proyectos

Proyectos

Multi-proyecto

Gestión de incidencias

No

Ampliación y adaptación

No

Funcionalidades propias Scrum

Backlog

Si, general y por Sprint actual

Historias y Tareas Si
Roles Roles propios de la aplicación, no de Scrum.

Pizarra visual

Sí, pizarra con 4 estados: abierta, en progreso, test y hecha

Burdown Chart Si

Kanban

No

Sincronización contactos y calendario Outlook con Windows Phone 7

Windows Phone 7 sincroniza tanto tus contactos como tu calendario a través de una cuenta compatible con Exchange ActiveSync (Protocolo de sincronización utilizado por Microsoft).

El problema que se me ha planteado es sincronizar contactos y calendario de Outlook con Windows Phone 7. El gestor de correo no es compatible con los requerimientos mencionados con anterioridad.

La solución, exportar tus contactos y citas del calendario a Hotmail a través de una cuenta Windows Live ID.

Los pasos a seguir serán los siguientes:

Exportar desde Outlook

  • En cuanto a contactos se refiere, comenzamos accediendo a Outlook 2003,07 o 10, para realizar la exportación de los contactos en un archivo de extensión .csv (contactos separados por comas, el más común).
  • Accedemos al menú Archivo->Importar y Exportar(2003-2007).
  • Seguidamente hacemos clic en exportar a un archivo y, a continuación, haga clic en siguiente.
  • Luego presionamos sobre Valores separados por comas (Windows) y, a continuación, hacemos clic en siguiente.
  • En la lista de carpetas, haga clic en la carpeta de contactos y, a continuación, haga clic en siguiente.
  • Desplácese hasta la carpeta donde desea guardar los contactos como un archivo. CSV.
  • Escriba un nombre para el archivo exportado y, a continuación, haga clic en Aceptar.
  • Haga clic en siguiente.
  • Haga clic en Finalizar

  • En la versión 2010 accedemos a Archivo->Abrir->Importar.

1

  • En la ventana emergente elegimos exportar a un archivo

2

  • Elegimos el tipo de archivo Valores separados por comas(Windows)

3

  • Elegimos el tipo de datos que queremos exportar, en este caso los contactos.

4

  • Por último asignamos el nombre y la ubicación de los datos a exportar como hemos vistos en las versiones 2003 y 2007.

Importar desde Windows Live Hotmail

  • Accedemos desde nuestro terminal con Windows Phone 7, a Windows Live Hotmail.
  • Iniciamos sesión.
  • Accedemos a la sección Contactos.
  • Hacemos clic sobre Agregar personas.

5

  • Seguidamente podemos ver los diferentes medios desde donde podemos realizar la importación de nuestros contactos(Facebook,My Spaces,Outlook,etc..)

6

  • Seleccionamos lógicamente Outlook. Para más tarde seleccionar el archivo que hemos exportado desde Outlook.

7

  • Una vez importados para realizar la sincronización con Windows Phone 7. Nos situamos en Configuración->Cuentas de correo electrónico. Presionamos sobre nuestra cuenta Windows Live Hotmail y aparecerá la opción Sincronizar en la pantalla del terminal.

Conseguido!!!

Exportar citas del Calendario de Outlook

  • Nos situamos en la sección Calendario de Outlook, seguidamente vamos a guardar el calendario que nos convenga sincronizar con Windows Phone 7. Presionamos sobre Archivo->Guardar Calendario. Finalmente otorgamos el nombre y la ubicación que deseemos, pero el formato a de ser .ics (formato que soporta Windows Live Hotmail).

8

  • Aparecerá un mensaje para seleccionar las fechas de las citas del calendario que queremos exportar.

11

  • Para exportar el calendario completo debemos seleccionas las opciones Calendario Completo y Detalles Completos.

12

Importar Calendario desde Windows Live Hotmail

  • Abrimos la sesión de Windows Live Hotmail, accedemos a la sección Calendario.
  • Presionamos sobre el apartado Suscribirse.

9

  • Elegimos la opción Importar de un archivo ICS. Seleccionamos el archivo exportado desde outlook y nombramos el calendario que vamos a importar.

10

Y tendremos el calendario importado, ahora realizamos la sincronización de el calendario en el terminal. Nos situamos en Configuración->Cuentas de correo electrónico. Presionamos sobre nuestra cuenta Windows Live Hotmail y aparecerá la opción Sincronizar en la pantalla del terminal.

De esta forma podemos utilizar nuestros contactos y citas de Outlook desde Windows Phone 7 utilizando como pasarela Windows Live Hotmail.

Gestión de proyectos ágil con herramientas Open Source (6/7): ScrumFactory

Quiero terminar este año que desde los Centros de Excelencia hemos dedicado a las metodologías ágiles con un último artículo dedicado a otro gestor de proyectos ágiles.  Esta vez nos vamos hasta Brasil para encontrar ScrumFactory:

http://www.scrum-factory.com/

http://thescrumfactory.codeplex.com/

Es una arquitectura cliente-servidor. Existe un instalador para servidor y otro para cliente, que tienen diferentes versiones lo que parece implicar que llevan diferentes ritmos de desarrollo. Existe, además, un plugin para soportar subversion como control de versiones dentro de la herramienta.

Licencia / versiones

Microsoft Reciprocal License (Ms-RL)

Entorno

  • Mínimo Windows XP Service Pack 2
  • .Net framework 3.5
  • Internet Information System 4.0
  • SQL Express 2005

Tiene problemas para instalarse en Windows Server 2008 y en Windows 7, posiblemente porque se han cambiado las políticas de seguridad.  Si se instala sobre Windows Server 2003 hay que tener cuidado con las actualizaciones que se metan porque deja de funcionar.  Es mejor no actualizar el Windows Server 2003.

Es necesario instalar aplicaciones cliente (en los distintos puestos de trabajo) y una aplicación servidor.

Si se producen errores debido a que no se encuentra ADODB, la solución está en comentar esa línea de código en la página web que se carga.  Una vez hecho esto, parece funcionar.  Este error dará si no se le indica donde se encuentra el servidor de correo Exchange.

Idioma

Inglés

Vida

El proyecto es muy reciente, del 14 de marzo del 2010, y se encuentra en versión beta, con lo que su trayectoria ha sido muy corta. Comenzaron con la versión V1 y actualmente, se hallan en la V1a de servidor, de abril, con la corrección de algunos errores.  Desde entonces no se han publicado más versiones.

Documentación

Toda la documentación que se ha encontrado consiste en una sección de FAQ (llamada “How do I”) en la página del proyecto principal que debería ampliarse más porque cubre muy pocos aspectos y de manera muy escueta.

Comunidad

Hay una página dedicada a la comunidad, http://thescrumfactory.codeplex.com/, donde existe un sistema de foros y una gestión de incidencias para informar sobre errores. El foro tiene muy poco contenido aunque las respuestas son bastante rápidas y hay muy pocas peticiones de errores posiblemente se deba a que el proyecto es muy joven (14 de marzo del 2010) y la gente no lo está empleando.

Soporte comercial

No existe soporte comercial. Sin embargo, se da soporte a través de un foro, del sistema de seguimiento de bugs y a través del siguiente correo: support@scrum-factory.com.

Funcionalidades de gestor de proyectos

El gestor de proyectos es multi-proyecto, permite crear varios proyectos y se puede ver la lista de todos y cambiar de uno a otro, aunque sólo el Scrum Master puede crear proyectos.  Para dar de alta un proyecto, debe tener al menos un cliente asociado. Se piden datos de nombre de proyecto, cliente, descripción, ciclo de vida del proyecto (actualmente sólo de tipo ágil), plataforma del proyecto, tipo de proyecto, nombre del directorio en red del proyecto. Además se da una fecha de inicio y una fecha de debería finalizar en.

Los proyectos una vez comenzados se pueden pausar, cerrar o cancelar.  Además un proyecto puede ser hijo de otro.

Gestión de incidencias

Los bugs son tareas dentro del proyecto y se manejan como tales. Hay dos tipos de bugs: corrección de errores y corrección de errores una vez que la aplicación está en producción. Además también se tienen en cuenta las tareas de controles de calidad.

Ampliación e integración con otros sistemas

Existe disponibilidad del código y, por tanto, de su posible adaptación. Por otro lado, la existencia de un plugin para subversión hace pensar que puedan crearse plugins para extender las funcionalidades.

Funcionalidades propias de Scrum

Hay varios roles dentro de la herramienta (Scrum Master, Developer, Product Owner, Commercial Guy y Team).

Tiene diagrama de burndown. Tiene también gestión de riesgos, propuesta y pagos. Además en la página inicial del proyecto, se pueden ver una serie de indicadores del mismo. En la parte de miembros del equipo, se puede gestionar quién puede trabajar en él (sólo los miembros o cualquiera). Además en todo momento se puede ver el esfuerzo del equipo realizado en el proyecto mediante una barra que lo contabiliza (esta barra puede ser desactivada en el apartado de configuración).

El proyecto puede conectarse con un repositorio en subversion mediante un plugin.

La estructura de “artefactos” de la herramienta es la siguiente:

  • Proyecto: Puede ser hijo de otro proyecto.
    • Iteración: Es el sprint
      • Item: Son las historias de usuario (Pueden tener 4 estados Required, Working, Done y Canceled). Además deben verificarse por el equipo de calidad y validarse por el cliente.
        • Tasks: Son las tareas.

Por otra parte, tiene función de autoplanificación de los sprints. El backlog es por sprint, aunque se pueden ver varios sprints seguidos. Se puede exportar a un archivo xml. Las historias de usuario se planifican en puntos (estos puntos están predefinidos y tienen un valor de referencia de a qué pueden corresponderse). Cada historia de usuario, debe verificarse por el equipo de calidad y validarse por el product owner. Además pueden cambiar su posición dentro del backlog del sprint.

Tiene una pizarra visual muy sencilla con funcionalidad de drag & drop. Tiene 3 estados, To Do, Working, Done. No pueden modificarse los estados. Es en este punto donde se crean las tareas asociadas a las historias de usuario del sprint. Hay 4 tipos de tareas, tareas en desarrollo, tareas de control de calidad, corrección de errores y corrección de errores en producción. Cualquier tarea, puede pasar a ser uno de esos tipos. Además, también existe la opción de que sean impedimentos. Entonces cambia su color a rojo. Si las tareas son de corrección de errores, aparece un dibujito de una mariquita o de un escarabajo para indicar que son errores.

Se puede ver la carga de trabajo del cada miembro del equipo mediante la opción Team Allocation del menú superior. Además, en este mismo menú también se puede sacar el esfuerzo en horas de los miembros del equipo.

Cuadro resumen

ScrumFactory
URL

http://www.scrum-factory.com/

http://thescrumfactory.codeplex.com/

Licencia / versiones

Microsoft Reciprocal License (Ms-RL)

Entorno

Mínimo Windows XP Service Pack 2

.Net framework 3.5

Internet Information System 4.0

SQL Express 2005

Idioma

Inglés.

Vida

9 meses de vida con 1 versión y una actualización.

Documentación

Poca, tan solo un FAQ (“How do I”)

Comunidad

Pequeña

Soporte comercial

No.

Funcionalidades gestor de proyectos
Proyectos

Multi-proyecto.

Gestión de incidencias

Sí.

Ampliación y adaptación

Si (disponibilidad de código y existencia de un plugin).

Funcionalidades propias Scrum
Backlog

Sí, por Sprint. Se pueden ver varios seguidos. 

Historias y Tareas

Sí, una “item” (historia) puede tener entre 0 y N “Tasks” (Tareas).

Roles

Tiene varios roles definidos (Scrum Master, Developer, Product Owner, Commercial Guy y Team) y una persona puede pertenecer a uno o varios.

Pizarra visual

Sí, pero con tan sólo 3 estados fijos.

Burdown Chart

Sí.

Kanban

No.

Gestión de PFCs con Scrum.
Introducción

Cuando hablamos de usar metodologías agiles para la gestión de proyectos, en lo primero que pensamos es en un proyecto de desarrollo software, con un equipo de trabajo multidisciplinar .En este artículo vamos a ver un caso diferente, en concreto, como se pueden aplicar este tipo de metodologías para la gestión de un PFC de desarrollo, en el que el equipo es una única persona. Hasta hace poco, la gestión de un PFC de desarrollo se realizaba mediante el modelo clásico conocido como “en cascada”.  Las distintas etapas por las que pasa un desarrollo siguiendo esta metodología son las siguientes:

  • Análisis y definición de requerimientos: Se definen en detalle los servicios, restricciones y
    funcionalidades en forma de especificaciones del sistema. Por lo general, estas especificaciones se mantienen invariables hasta el final del desarrollo.
  • Diseño del sistema y del software: Se diseña el sistema y se definen los requerimientos hardware y software. A nivel hardware se establece la arquitectura del sistema. A nivel software se identifica y describe las abstracciones del sistema y sus relaciones.
  • Implementación y prueba de unidades: Se programa el diseño del software como un conjunto de subsistemas de software. Se testea cada subsistema para asegurar que se cumplen sus especificaciones.
  • Integración y prueba del sistema: Se integran y se prueban los subsistemas de software como un sistema completo para asegurar que se cumplen los requerimientos del software. Después de las pruebas, el sistema software se entrega al cliente.
  • Funcionamiento y mantenimiento: Se instala y se pone en funcionamiento el sistema. El mantenimiento implica corregir errores no descubiertos en las etapas anteriores del ciclo de
    vida, mejorar la implementación de las unidades del sistema e implementar nuevas características una vez que se descubren nuevos requerimientos.

En la siguiente figura se puede ver un esquema del proceso descrito:

image

Por su parte, las metodologías ágiles reconocen que la indefinición y los cambios son factores
inevitables en la gestión de proyectos y que por tanto es más efectivo refinar los requisitos y diseño de los mismos a lo largo del desarrollo, introduciendo los cambios de forma evolutiva. Es decir, siguiendo las metodologías agiles, lo que hacemos es sustituir los ciclos de vida clásicos por un sistema iterativo en el que las mismas actividades se suceden de forma cíclica en periodos cortos de tiempo. Por ejemplo en scrum el proceso de desarrollo esta formado por las siguientes etapas:

  • Análisis del sistema: se obtiene una descripción de la arquitectura del sistema, una visión general del producto, y un catálogo de requisitos ordenados por prioridad(product backlog).
  • Diseño de los requisitos: se describen, detalladamente, las funcionalidades que debe cumplir el producto
  • Iteraciones de desarrollo (sprint):
    • implementación de requisitos, según orden de prioridad (sprint backlog)
    • pruebas por parte de los usuarios y despliegue. Se reportan incidencias revisando el conjunto de requisitos y funcionalidades.

*se añade la resolución de incidencias reportadas en iteraciones anteriores

image

 

Aplicación

Ya que en cein se ha desarrollado un itinerario formativo de metodologías agiles a lo largo de 2010, nos pareció interesante aplicar este tipo de metodologías a la gestión de los PFCs que se desarrollaron dentro de los Centros de Excelencia Software, como un ejercicio de aproximación a las mismas. A través de este artículo, me gustaría mostrar cuales son las prácticas que resultan más complicadas de llevar a cabo en la implementación de scrum, y las conclusiones que sacamos de ello.

1. Es más difícil, que un proyecto normal, estimar el valor de las historias de usuario. Esto se debe a que no se cuenta con un equipo multidisciplinar de trabajo. Se cuenta con una única persona, que por lo general tiene conocimientos básicos de la tecnología o sistemas que va a utilizar para el desarrollo del mismo.

2. No se realiza scrum diario, ya que el equipo es unipersonal. Pero aún así la persona encargada de desarrollar el proyecto debe ser capaz de preguntarse cada día:

  • ¿Qué he hecho desde ayer?
  • ¿Qué voy a hacer para mañana?
  • ¿He encontrado algún problema que no me deje avanzar con mi trabajo?

Y en función de ello debe ser constante a la hora de actualizar el scrum board, para que este sea lo más realista posible.

3. En nuestro caso, se fusionan la reunión de retrospectiva del sprint, y planificación (siguiente sprint). Además se realiza una reunión semanal (revisión) que nos ayuda a ver y realizar los cambios necesarios que van surgiendo a lo largo del desarrollo del proyecto, aportándonos de esta forma gran flexibilidad. 

4. Los roles con los que se ha contado, son algo diferentes a los habituales:

  • No hay equipo multidisciplinar –> es una única persona.
  • Product Owner ->tutor de la universidad
  • Scrum Manager –>tutor en la empresa
  • *Supervisor-> persona responsable de chequear el trabajo hecho y de ayudar al desarrollador

Por ejemplo, en este caso, son el Product Owner y el Scrum Manager, los que definen los requisitos que debe cumplir el producto, cuando en realidad sólo el Product Owner es el que se encarga de esta labor.

5. La documentación (memoria del proyecto), consiste principalmente en detallar el proceso scrum que se ha utilizado:

  • Objetivos –>Análisis del sistema
  • Plataforma (Equipos)
  • Descripción –> Diseño de los requisitos + Iteraciones de desarrollo
    • Definición de las historias de usuarios (funcionalidades de la aplicación)
    • Definición de los Sprints:
      • ¿que historias de usuario se han tomado en cada sprint?¿se han acabado o no?
      • problemas que se han encontrado
      • feedback (que ha ido mal, que ha ido bien, y que es mejorable)  
    • Conclusiones
  • Bibliografía

Si actualizamos habitualmente el scrum board seremos capaces de obtener toda la información necesaria para la memoria a partir del mismo. Por lo que el proceso de documentación se simplifica bastante.

Por último, decir que las conclusiones que hemos obtenido mediante el uso de scrum para la gestión de los PFCs, en general, son buenas, aunque vemos que estas metodologías exigen gran disciplina y metodología de trabajo por parte del desarrollador:

- Ayuda a la organización y distribución del tiempo de la persona encargada de realizar el proyecto. Esto lleva consigo una notable mejora de la productividad. Pero exige:

- Autocontrol: mayor responsabilidad sobre lo que se hace, en que tiempo, y gusto por el trabajo que se realiza.
- Capacidad de autosuperación: ser capaz de evaluar, analizar y mejorar las soluciones en el tiempo establecido.

- Permite ajustar los tiempos de dedicación para las distintas historias de usuario y tareas a medida que vamos viendo las necesidad o los cambios a realizar. Pero exige:

- Compromiso: en los plazas de entrega de las sub-aplicaciones

- Calidad: las sub-aplicaciones deben cumplir todos los requisitos establecidos

- Permite ver en que estado se encuentra el proyecto en cada momento, a través del panel de scrum (Scrum Board). Esto aporta una visión motivadora y retadora del trabajo que se esta haciendo (…o puede tener el efecto contrario). Pero para que la información que nos da el panel sea real, es necesario ser constante en la actualización del mismo.

- Hace que “desaparezca”, o minimiza, la fase de mantenimiento. Ya que se obtienen pequeñas aplicaciones funcionales que se pueden implementar de forma independiente. Lo que significa que conseguimos mejorar la calidad del producto y reducir los errores al mínimo. Esto exige (o sería recomendable):

- Uso pruebas unitarias, para comprobar el correcto funcionamiento de cada una de las sub-aplicaciones. *Esto exige, a su vez, un buen conocimiento del uso de las mismas.

En resumen, estas metodologías se pueden aplicar a la gestión de distintos tipos de proyectos, pero es necesario que tengamos en cuenta que no todos los aspectos propios de dichas metodologías se van a poder implementar siguiendo “las normas generales”, como hemos visto en el caso anterior. Por lo tanto debemos evaluar si es posible ajustar las metodologías a nuestros proyectos o, si en realidad, no es posible el uso de las mismas. Guiño

 

Blog: http://geeks.ms/blogs/gortigosa

Twitter : http://twitter.com/goreorti

Lectura recomendada: Flexibilidad con Scrum

Gestión de proyectos ágil con herramientas opensource (5/7): retrospectiva

La herramienta a valorar esta vez es Restrospectiva: http://retrospectiva.org/ y http://github.com/dim/retrospectiva/

Es un sistema que se centra en el uso de blog, wiki y tickets para el desarrollo compartido de un proyecto. Tiene un sabor parecido a Trac y Redmine aunque parece provenir de un proyecto llamado Collaboa (https://www.ohloh.net/p/3827) que ya no existe.

La gestión ágil la proporciona un plugin, AgilePM.

Versiones / licencias

Licencia MIT.  Retrospectiva 2.0.  La licencia MIT también se aplica a las partes del código tomadas literalmente de la herramienta Collaboa creada por Johan Sorensen.

Entorno

La aplicación está pensada para ser instalada en sistemas Linux y Unix aunque también se puede ejecutar en Windows (no se recomienda para producción) y requiere de:

  • Ruby
  • RubyGems
  • Rails
  • MySQL / Sqlite3

Idioma

Inglés aunque hay varias traducciones en curso, entre ellas, una traducción parcial a Español. Además, existe documentación que explica como añadir las traducciones que se deseen (http://retrospectiva.org/wiki/Translations).

Vida

El proyecto tiene una trayectoria corta, deriva de un proyecto llamado Collaboa. Sacó su primera versión (1.0) en enero del 2007, y durante ese año se trabajó en una versión evolutiva y correctiva de errores. El 2008 fue un año sin actualizaciones, quizás debido a algún cambio interno fuerte de la aplicación. La última versión (2.0), enero del 2010, parece haberse desarrollado durante el 2009. En definitiva, les ha costado 3 años sacar una nueva versión, aunque dejando de lado el año de sequía 2008, ha habido aparentemente bastante movimiento. Actualmente están trabajando en la versión 2.1 y en una versión "futura" donde parecen echar posibles funcionalidades futuras.

Documentación

Existe bastante documentación en la wiki de la página web del proyecto sobre la instalación y configuración, que por otro lado, parece sencilla. También, hay documentación sobre como extender vistas, crear plugins, traducir, etc. No es excesivamente extensa pero cubre lo imprescindible.

Comunidad

La página web del proyecto está soportada por la propia herramienta (como sucede en proyectos como Trac y Redmine). Es por eso que la forma de reclamar funcionalidades y errores sobre el proyecto consiste en el mismo sistema que tiene la herramienta, un gestor de tickets que funciona a modo de soporte. Es cómodo en el sentido de que es una especie de foro donde introduces directamente tu petición y los responsables actúan sobre la misma, incluyendo posibles comentarios de otros usuarios, aunque no parece estar pensado para la aclaración de dudas. Tampoco hay una separación entre consultas de usuarios de la herramienta y desarrolladores de la misma. Quizás no tiene sentido porque no parece haber colaboradores (aunque hay agradecimientos al equipo de Collaboa). Es un sistema que parece tener bastantes usuarios, pero al estar soportado por una única persona las respuestas pueden tardar en llegar de 3 días a 3 meses. Te puedes registrar libremente en la herramienta para generar tickets pero no es necesario. Además, hay una lista de correo (http://rubyforge.org/mail/?group_id=2685) en la que existe un goteo constante de mensajes de 2007 a 2009 durante casi todos los meses del año con una respuesta más o menos rápida (1-8 días), pero en 2010 desaparecen. A partir de esta fecha, parece que migraron a otra lista (http://groups.google.com/group/retrospectiva-general) donde hay una frecuencia menor de mensajes y las respuestas parecen también más dilatadas. No queda claro la diferencia de utilidad entre esta lista de correo y el sistema de tickets de la propia página web. Quizás la lista de correos sea para dudas y el sistema de tickets para la resolución de incidencias y petición de funcionalidades.

Soporte comercial

No hay soporte comercial, todo se realiza mediante el sistema de tickets y la llista de correo.

Funcionalidades gestor de proyectos

Es multi-proyecto, consecuentemente, aunque no permite catalogarlos de algún modo para su distinción. Otra curiosidad es que te permite marcar un proyecto como cerrado.

Tampoco se pueden agrupar los proyectos, pero existe una forma de crear grupos de permisos sobre grupos de proyectos, algo parecido a equipos que se asignan a usuarios individuales.

Existe un sistema de grupos que viene a equivaler a los equipos. A estos grupos se les da unos permisos sobre ciertos proyectos y los miembros del equipo se asignan a dichos grupos con lo que heredan los permisos.

Gestión de incidencias

Existe una gestión de incidencias mediante tickets (sirven para notificar bugs y solicitar mejoras), aunque funciona de manera independiente con respecto, por ejemplo, a las historias de usuario, lo cual resulta bastante desconcertante.

Ampliación y adaptación

Puedes mantener la aplicación siempre actualizada a través del repositorio alojado en GIT aparentemente de forma sencilla (http://retrospectiva.org/wiki/Upgrading). A parte de poder disponer del código fuente para modificarlo al gusto, tiene un sistema de plugins para añadir nuevas funcionalidades. Es el caso del módulo "Ágil", AgilePM. Existe uno propuesto pero que está a la espera de recursos relacionado con Kanban.

Funcionalidades propias de Scrum

Toda la parte "ágil" de la herramienta reside en un plugin de la misma: AgilePM (http://retrospectiva.org/wiki/AgilePM).

La estructura en la que se organiza la información es básicamente la siguiente:

  • Proyecto(s).
    • Milestone(s).
      • Sprint(s).
        • Goal(s) = funcionalidades con una prioridad que no parece configurable.
          • Storie(s) (módulo específico del plugin AgilePM) = historias de usuario. Se estiman en horas, pero es simplemente cuestión de nomenclatura. Parece que no se asignan a ningún responsable, posiblemente se haga de forma automática cuando alguien las  seleccione para su comienzo.
      • Tickets = al igual que en Trac y Redmine, engloba cualquier tipo de petición: tarea, bug, funcionalidad, etc. Son independientes de las historias de usuario. Se define una prioridad (configurable y diferente a la de Goal)

No parecen existir roles de scrum, tan solo permisos.

Existe un Backlog por Sprint que tiene una vista bastante interesante, a mitad de camino entre un BurnDownChart y una pizarra visual. Se visualizan las historias de usuario para un Sprint y un panel cuadriculado con todos los días que incluye ese Sprint donde se observa por cada día el remanente de horas (o puntos) que restan para terminar una historia de usuario. También se aprecia visualmente que historias están activas.

Los estados de las historias de usuario parecen configurables aunque habría que estudiar mejor el plugin de AgilePM para verificar si pueden existir otras: active, pending, complete.

Tampoco puede limitarse el máximo número de puntos (historias de usuario) a trabajar de forma simultánea para controlar la capacidad.

Cuadro resumen

 

Retrospectiva

URL

http://retrospectiva.org/

http://github.com/dim/retrospectiva/

Licencia / versiones

MIT / Retrospectiva 2.0

Entorno

Ruby, RubyGems, Rails, MySQL y Sqlite3

Idioma

Inglés, Español en curso, etc

Vida

Reciente y no muy extensa. tiene 3 años y 2 versiones.

Documentación

Suficiente pero no extensa.

Comunidad

Pequeña

Soporte comercial

No

Funcionalidades gestor de proyectos

Proyectos

Multi-proyecto.

Gestión de incidencias

Si, tickets

Ampliación y adaptación

Si (plugins y disponibilidad del código)

Funcionalidades propias Scrum

Backlog

Si

Historias y Tareas Si
Roles Roles normales, no de Scrum

Pizarra visual

No

Burdown Chart No

Kanban

Plugin en desarrollo

Crear controles dinámicos mediante jQuery en aplicaciones ASP.NET MVC

En el último artículo que escribí, ya hace un tiempo por cierto, vimos como podemos interactuar con Ajax para conseguir interfaces de usuario más potentes. En esta ocasión vamos a ver una aplicación que tiene el mismo objetivo, pero utilizando jQuery para ello. Como ya hemos visto en alguna ocasión jQuery ofrece una amplia gama de posibilidades para animar objetos y crear efectos dentro de nuestras páginas web, pero también aporta otro tipo de funcionalidades. En este caso vamos a ver cómo podemos crear controles dinámicos, haciendo uso de esta biblioteca que viene integrada dentro del propio Framework MVC, evitando de esta forma el uso de postbacks.Para ello vamos a ver un pequeño ejemplo de como implementar interfaces de usuario enriquecidas mediante el uso de jquery. 

Inicialmente, creamos un proyecto llamado jQueryApp de tipo ASP.NET MVC 2 Web Application:

image  image

Dentro de dicha aplicación, abrimos el controlador HomeController que se crea por defecto, y creamos una acción llamada Tema, que se encargará de serializar nuestro objeto a un elemento de tipo Json, para que podamos mostrarlo a través de una vista específica. Este presentará el siguiente código:

  1. public JsonResult Tema(int TemaID)
  2.         {
  3.             var list = new object[] { };
  4.             switch (TemaID)
  5.             {
  6.                 case 1:
  7.                     
  8.                     list = new object[] {
  9.                         new { value = 1, name = "Los pilares de la tierra" },
  10.                         new { value = 2, name = "La catedral del mar" },
  11.                         new { value = 3, name = "Millenium 1" }
  12.                     };
  13.                     break;
  14.                 case 2:
  15.                     list = new object[] {
  16.                         new { value = 1, name = "Ciencia divulgativa:del ábaco a Intenet" },
  17.                         new { value = 2, name = "Hacker" },
  18.                     };
  19.                     break;
  20.             };
  21.             return Json(list,JsonRequestBehavior.AllowGet);
  22.         }

A continuación pasamos a modificar la vista Index existente (o podemos crear una vacía), que será donde definiremos nuestros elementos. En primer lugar,  es necesario configurar la vista para poder usar jquery en ella.  Para ello arrastramos el archivo jquery-1.4.1.js de forma que se crea el código de referencia del script:

  1. <script src="../../Scripts/jquery-1.4.1.js" type="text/javascript"></script>

En segundo lugar añadimos una tabla para definir los elementos a mostrar, que en nuestro caso serán dos desplegables. El primero de ellos se cargará a partir de una serie de datos introducidos manualmente y nos permitirá seleccionar la temática de nuestros libros. Y el segundo se actualizará en función del elemento seleccionado en el primero de los desplegables y nos mostrará una serie de libros en función del tipo de temática seleccionada, tal y como lo hemos definido a través de nuestro objeto.

 

  1. <table>
  2.         <tr>
  3.             <th>Temática:</th>
  4.             <td><select id="theme">
  5.             <option> -- Selecciona una temática -- </option>
  6.             <option value="1">Novela</option>
  7.             <option value="2">Informática</option>
  8.             </select></td>
  9.         </tr>
  10.         <tr>
  11.             <th>Libros:</th>
  12.             <td><select id="books"></select></td>
  13.         </tr>
  14.     </table>

A continuación añadimos el código javascript que se encargará de ejecutar la función específica, para ello añadimos una etiqueta <script> en nuestra vista donde colocaremos todo el código necesario:

 

  1. <script type="text/javascript">
  2.         $(document).ready(function () {
  3.             $("#theme").change(function () {
  4.                 $.post("/Home/Tema/", { TemaID: $(this).val() }, function (data) {
  5.                     populateDropdown($("#books"), data);
  6.                 });
  7.             });
  8.         });
  9.         function populateDropdown(select, data) {
  10.             select.html('');
  11.             $.each(data, function (id, option) {
  12.                 select.append($('<option></option>').val(option.value).html(option.name));
  13.             });
  14.         }
  15.     </script>

La primera de las funciones comprueba el cambio de valor en el selector #theme, y en función de ello realiza un post a la acción Tema del controlador, para lanzar la función populateDropDown, teniendo en cuenta los valores obtenidos a partir del atributo TemaID.

La funcion populateDropdown, se encarga de cargar el contenido del desplegable inferior en función del elemento que es seleccionado en el desplegable superior. Para ello, la función recibe dos parámetros, el dropbox a rellenar, que en este caso es “books”, y los valores del mismo que son leídos a partir de nuestro objeto, y que son mapeados como elementos de nuestro desplegable a través de la etiqueta de definición <option>.

Si compilamos nuestra aplicación y navegamos hasta /Home/Tema, vemos cómo se va actualizando el desplegable inferior en función de lo que seleccionamos en el superior

image

Aunque esto es sólo un ejemplo básico del uso que se le puede dar a jquery para la creación de interfaces de usuario enriquecidas, es suficiente para ver parte de la potencia que ofrece jquery para el desarrollo de este tipo de aplicaciones… y todo ello de manera “relativamente sencilla”.

Blog: http://geeks.ms/blogs/gortigosa/default.aspx

Twitter: http://twitter.com/goreorti

“Enrutamiento con Bing Maps y Silverlight”

Quién más o quien menos alguna vez a dedicado un espacio de tiempo ha localizar un local,un lugar, un punto de interés o a preparar una ruta a la hora de viajar. Por otro lado son cada vez más las empresas que utilizan la geolocalización como instrumento de trabajo, es por este motivo que planteo la segunda parte de las opciones que nos ofrece el API de Bing Maps. En este artículo vamos a utilizar por un lado la geolocalización que he especificado en artículos anteriores y además vamos aprovechar el servicio de enrutamiento que pone a disposición de los desarrolladores Microsoft. De este modo podemos realizar una ruta entre los respectivos puntos que hemos geolicalizado previamente.

Para empezar deberéis asociar una cuenta Live ID y la URL de la página en la que vamos a utilizar la API de Bing Maps. Podéis ver los pasos que tenéis que seguir para disfrutar del API de Bing Maps aqui.

Una vez realizada la asociación, vamos a crear una una nueva aplicación Silverlight desde Visual Studio 2010. Para ello elegimos la plantilla Silverlight Businees Application, elegimos el nombre que queremos para dicho proyecto así como la ubicación del mismo como podemos ver a continuación:

image

Abrimos la página que se carga por defecto en el marco de trabajo de dicha aplicación(Home.Xaml), esta se encuentra ubicada dentro de la carpeta Views del lado del cliente.

Lo primero vamos añadir el servicio de geolocalización a nuestro proyecto. Para ello presionamos con el botón derecho sobre la carpeta Refereces. Elegimos Add Service Reference. En la ventana emergente, debemos introducir en la sección Address la siguiente URL del servicio de Geolocalización (http://dev.virtualearth.net/webservices/v1/geocodeservice/GeocodeService.svc). Presionamos sobre el botón Go para comprobar que la comunicación con el servicio se realiza de forma correcta. El servicio lo identificaremos con el nombre GeocodeService que debemos introducirlo en el apartado NameSpace:

image

Presionamos en OK y ya tenemos preparado el servicio para su posterior utilización.

Seguidamente vamos añadir los credenciales de la API de Bing Maps en los recursos de aplicación y sobre el propio objeto Map.

Abrimos App.xaml, dentro de la etiqueta <ResourceDictionary>

introducimos <sys:String x:Key="MisCredenciales">Clave Cuenta Bing Maps</sys:String>

siendo el resultado final de dicho archivo el siguiente:

  1.    <Application
  2. x:Class="Rutas.App"
  3. xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  4. xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  5. xmlns:app="clr-namespace:Rutas"
  6. xmlns:sys="clr-namespace:System;assembly=mscorlib"
  7. Startup="Application_Startup"
  8. UnhandledException="Application_UnhandledException">
  9.  
  10.     <Application.Resources>
  11.         <ResourceDictionary>
  12.             <ResourceDictionary.MergedDictionaries>
  13.                 <ResourceDictionary Source="Assets/Styles.xaml"/>
  14.                 <ResourceDictionary>
  15.                     <app:ResourceWrapper x:Key="ResourceWrapper" />
  16.                     <app:NotOperatorValueConverter x:Key="NotOperatorValueConverter" />
  17.                     <sys:String x:Key="MisCredenciales">Clave Cuenta Bing Maps</sys:String>
  18.                 </ResourceDictionary>
  19.             </ResourceDictionary.MergedDictionaries>
  20.                         </ResourceDictionary>
  21.     </Application.Resources>
  22.  
  23. </Application>

Más adelante utilizaremos dichos credenciales en el objeto Map como un recurso del proyecto.

Ahora vamos a centrarnos en la interfaz de usuario, primeramente vamos referenciar las librerías de Bing Maps( que previamente hemos añadido, puedes ver aquí donde encuentran las misma) para poder realizar las diferentes acciones de Geocodificación. Dentro de la etiqueta <Page> introducimos la referencia:

  1. xmlns:navigation="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Navigation"

Seguidamente, vamos a definir la estructura de los diferentes objetos que incluiremos dentro de la interfaz de usuario de Home.xaml, para ello añadimos el siguiente fragmento de código:

  1. <Grid x:Name="LayoutRoot">
  2.         <Grid.ColumnDefinitions>
  3.             <ColumnDefinition Width="271*"/>
  4.             <ColumnDefinition Width="100*"/>
  5.         </Grid.ColumnDefinitions>
  6.         <Grid.RowDefinitions>
  7.             <RowDefinition Height="255*"/>
  8.             <RowDefinition Height="45*"/>
  9.         </Grid.RowDefinitions>
  10.         <map:Map x:Name="mapa" Center="40.225,-1.794" ZoomLevel="6" Mode="Road" Grid.Row="0" Grid.ColumnSpan="2">
  11.             <map:Map.CredentialsProvider>
  12.                 <map:ApplicationIdCredentialsProvider ApplicationId="{StaticResource MisCredenciales}"/>
  13.             </map:Map.CredentialsProvider>
  14.         </map:Map>
  15.         <TextBox x:Name="txbPI" Grid.Row="1" Grid.Column="0" Margin="10" BorderBrush="Black" FontSize="21.333" FontFamily="Verdana"/>
  16.         <Button x:Name="btnGeocode" Content="Añadir Localizador" Grid.Row="1" Grid.Column="1" Margin="5" Click="btnGeocode_Click"/>
  17.     </Grid>

Como podéis observar hemos añadido el objeto Map que se encargará de representar el mapa donde se localizarán los diferentes puntos que el usuario busque. También hemos añadido un TextBox para que el usuario pueda introducir los lugares ha buscar y un botón que se encargará de realizar las diferentes acciones para representar los diferentes lugares en el objeto Map. Para generar el evento del botón btnGeocode, presionamos doble click cobre el mismo. De este modo nos desplazaremos al código Behin de la aplicación (Home.xaml.cs). Dentro de dicho evento debemos introducir el siguiente fragmento de código:

  1. private void btnGeocode_Click(object sender, System.Windows.RoutedEventArgs e)
  2.         {
  3.             GeocodeService.GeocodeServiceClient geocodeClient = new GeocodeService.GeocodeServiceClient
  4.  
  5. ("CustomBinding_IGeocodeService");
  6.  
  7.             GeocodeService.GeocodeRequest resquest = new GeocodeService.GeocodeRequest();
  8.             resquest.Query = txbPI.Text;
  9.             resquest.Credentials = new Microsoft.Maps.MapControl.Credentials();
  10.             resquest.Credentials.ApplicationId = App.Current.Resources["MisCredenciales"] as string;
  11.  
  12.             geocodeClient.GeocodeCompleted += new EventHandler<GeocodeService.GeocodeCompletedEventArgs>(geocodeClient_GeocodeCompleted);
  13.             geocodeClient.GeocodeAsync(resquest);
  14.  
  15.         }

Por otro lado debemos de referenciar las librería de Bing Maps dentro del código Behind para aprovechar su funcionalidad, para ello añadimos la siguiente directiva:

  1. using Microsoft.Maps.MapControl;

Como podemos observar creamos un objeto GeocodeServiceClient, que nos permite comunicar la aplicación con el servicio GeocodeService. Dicho servicio requiere del Objeto GeocodeRequest que envía la petición de un nuevo localizador a través del texto introducido en el TextBox. Pero este acceso al servicio no sería posible si no enviaríamos los credenciales de la cuenta Bing Maps. Por último la petición al servicio se ha de realizar de forma asíncrona, cuando la petición regresa la controlamos a través del controlador de eventos geocodeClient_GeocodeCompleted.

Ahora vamos a introducir el  evento citado con anterioridad. En el, obtenemos un array con una serie de coincidencias con el texto introducido en el TextBox. Como solo nos interesa el primer elemento, a través de LINQ obtenemos ese primer elemento. Tomamos la longitud y latitud de ese elemento, creamos en la interfaz de usuario un nuevo localizador. El último paso es ofrecer la mejor vista de ese localizador por lo que el objeto mapa realizará un Zoom sobre dicho punto de interés a fin de mejorar la experiencia de usuario.

  1. private void geocodeClient_GeocodeCompleted(object sender, GeocodeService.GeocodeCompletedEventArgs e)
  2.         {
  3.             GeocodeService.GeocodeResponse response = e.Result;
  4.             if (response.Results.Count > 0)
  5.             {
  6.                 GeocodeService.GeocodeResult result = response.Results.First();
  7.                 if (result.Locations.Count > 0)
  8.                 {
  9.                     Pushpin pushpin = new Pushpin();
  10.                     Location location = new Location(result.Locations.First().Latitude, result.Locations.First().Longitude);
  11.                     pushpin.Location = location;
  12.                     mapa.Children.Add(pushpin);
  13.                     mapa.SetView(result.BestView);
  14.                     
  15.                 }
  16.             }
  17.         }

Ejecutamos la aplicación, accedemos a la sección Logística desde el menú de Navegación. Introducimos en el TextBox por ejemplo Cein, Navarra y el resultado es el siguiente:

 

image

En esta parte del articulo vamos desarrollar la realización de rutas entre lo diferentes puntos que interesen al usuario.Empezamos haciendo clic con el botón derecho sobre la carpeta Reference, elegimos Add Service Reference.En la ventana emergente, debemos introducir en la sección Address la siguiente URL del servicio de enrutamiento (http://dev.virtualearth.net/webservices/v1/routeservice/routeservice.svc ). Presionamos sobre el botón Go para comprobar que la comunicación con el servicio se realiza de forma correcta. El servicio lo identificaremos con el nombre RouteService que debemos introducirlo en el apartado NameSpace:

image

Seguidamente vmos a crear una clase con los parámetros que necesita el servicio para su correcto funcionamiento. Realizamos clic con el botón derecho sobre nuestro proyecto del lado del cliente. Elegimos Añadir->Nuevo elemento, de las plantillas que Visual Studio 2010 nos ofrece por defecto, elegimos Clase, nombrándola como UbicacionEntrega.cs.

image

Dentro de la misma incluiremos el siguiente código:

  1. using System;
  2. using System.Net;
  3. using System.Windows;
  4. using System.Windows.Controls;
  5. using System.Windows.Documents;
  6. using System.Windows.Ink;
  7. using System.Windows.Input;
  8. using System.Windows.Media;
  9. using System.Windows.Media.Animation;
  10. using System.Windows.Shapes;
  11. using Microsoft.Maps.MapControl;
  12.  
  13. namespace SilverlightBusinessApplication
  14. {
  15.     public class UbicacionEntrega
  16.     {
  17.         public string Address { get; set; }
  18.  
  19.         public Location Location { get; set; }
  20.  
  21.     }
  22. }

El siguiente paso que vamos a dar, es la actualización del interfaz de usuario. Tenemos que introducir nuevos elemento y cambiar la distribución de los anteriores. El resultado de la nueva interfaz de usuario es la siguiente:

 

  1. <Grid x:Name="LayoutRoot">
  2.         <Grid.ColumnDefinitions>
  3.             <ColumnDefinition Width="271*"/>
  4.             <ColumnDefinition Width="100*"/>
  5.         </Grid.ColumnDefinitions>
  6.         <Grid.RowDefinitions>
  7.             <RowDefinition Height="188*"/>
  8.             <RowDefinition Height="67*"/>
  9.             <RowDefinition Height="45*"/>
  10.         </Grid.RowDefinitions>
  11.         <map:Map x:Name="mapa" Center="40.225,-1.794" ZoomLevel="6" Mode="Road" Grid.RowSpan="2">
  12.             <map:Map.CredentialsProvider>
  13.                 <map:ApplicationIdCredentialsProvider ApplicationId="{StaticResource MisCredenciales}"/>
  14.             </map:Map.CredentialsProvider>
  15.             <map:MapLayer x:Name="routeLayer"/>
  16.         </map:Map>
  17.         <TextBox x:Name="txtAddress" Grid.Row="2" Margin="10,10,10,68" BorderThickness="3" Background="White" />
  18.         <Button x:Name="btnGeoCode" Content="Añadir Localizador" Grid.Row="2" Grid.Column="1" Margin="5" Click="btnGeocode_Click"/>
  19.         <TextBlock HorizontalAlignment="Left" VerticalAlignment="Top" Text="Entregas" TextWrapping="Wrap" Grid.Column="1" />
  20.         <ListBox x:Name="lbxDestinations" Margin="5,20,8,7" Grid.Column="1" Grid.RowSpan="1">
  21.             <ListBox.ItemTemplate>
  22.                 <DataTemplate>
  23.                     <StackPanel>
  24.                         <TextBlock Text="{Binding Address}" TextWrapping="Wrap"/>
  25.                         <StackPanel Orientation="Horizontal">
  26.                             <Button Content="Subir" Tag="{Binding}" x:Name="ButtonUp" Click="ButtonUp_Click"/>
  27.                             <Button Content="Bajar" Tag="{Binding}" x:Name="ButtonDown" Click="ButtonDown_Click"/>
  28.                             <Button Content="Borrar" Tag="{Binding}" x:Name="ButtonRemove" Click="ButtonRemove_Click"/>
  29.                         </StackPanel>
  30.                     </StackPanel>
  31.                 </DataTemplate>
  32.             </ListBox.ItemTemplate>
  33.         </ListBox>
  34.         <StackPanel Grid.Column="1" Grid.Row="1" Orientation="Vertical" d:LayoutOverrides="Height">
  35.             <CheckBox x:Name="cbxTraffic" Content="Evitar Tráfico"/>
  36.             <Button x:Name="btnCalculateRoute" Click="btnCalculateRoute_Click" Height="22" Content="Calcular Ruta" Margin="5,5,5,0"/>
  37.             <TextBlock x:Name="txtTotalTime" Text="Tiempo Total:" Margin="5,15,5,0" TextWrapping="Wrap"
  38.                        FontSize="13.333" HorizontalAlignment="Center" Width="337" Height="49" />
  39.            
  40.         </StackPanel>
  41.     </Grid>

Hemos empezado por un cambio de la distribución de los elementos dentro del <Grid> principal. Luego hemos añadido un objeto ListBox, dentro del mismo hemos definido una plantilla para cada elemento que se agregue al ListBox. Dicha plantilla se compone del nombre de la Localización (que es obtenido directamente de una colección de elementos)y tres botones. Dos para desplazar el localizador entre los diferentes Items del ListBox y el tercero para borrar el localizador.

También hemos añadido un objeto CheckBox para que el usuario pueda evitar los atascos de tráfico que pueda haber en la ruta elegida. Un botón que será el disparador de las acciones de cálculo de ruta. El último objeto es un TextBlock quese encarga de mostrar al usuario el tiempo que va tardar en realizar la ruta entre los diferentes localizadores que previamente ha seleccionado.

Un elemento que hemos introducido y que no he nombrado pero si destacado es <map:MapLayer x:Name="routeLayer"/>. Dicho elemento nos permitirá la representación de la ruta, sin tener que añadir esta como un hijo del objeto Map. Esto otorga una independencia a la hora de mostrar, ocultar o actualizar la ruta. Ya que si el usuario realiza una serie de comportamientos la ruta se redibuja nuevamente y no confunde al usuario.

 

El siguiente paso es añadir las nuevas funciones del botón Añadir Localizador. Para ello añadimo dentro del constructor de logistica.xaml.cs una colección que es del tipo UbicacionEntrega y un miembro que guarda la respuesta del servicio.

  1. private ObservableCollection<UbicacionEntrega> _locations = new ObservableCollection<UbicacionEntrega>();
  2.         private RouteService.RouteResponse _currentRoute;

También añadimos la siguiente referencia:

  1. using System.Collections.ObjectModel;

Dentro del evento click del Botón que realiza la inclusión de nuevos localizadores, vamos a incluir el borrado de la capa de la que hemos hablado con anterioridad, debido a que se va dibujar una nueva cada vez que añadimos un nuevo localizador. También hemos añadido la cultura con la que se va mostrar la interfaz de usuario. Por último pasamos los credenciales para todos los objetos incluidos en Map. El resultado final del evento click del botón es el siguiente:

  1. private void btnGeocode_Click(object sender, RoutedEventArgs e)
  2.         {
  3.             routeLayer.Children.Clear();//borra el hijo que en ese momento esta representado en la capa
  4.  
  5.             GeocodeService.GeocodeServiceClient geocodeClient = new GeocodeService.GeocodeServiceClient
  6.  
  7.             ("CustomBinding_IGeocodeService");
  8.  
  9.             GeocodeService.GeocodeRequest resquest = new GeocodeService.GeocodeRequest();
  10.             resquest.Culture = mapa.Culture;//otorga la cultura del S.O. al mapa
  11.             resquest.Query = txtAddress.Text;
  12.             resquest.Credentials = new Microsoft.Maps.MapControl.Credentials();//pasamos los credenciales
  13.             resquest.Credentials.ApplicationId = App.Current.Resources["MisCredenciales"] as string;
  14.  
  15.             geocodeClient.GeocodeCompleted += new EventHandler<GeocodeService.GeocodeCompletedEventArgs>(geocodeClient_GeocodeCompleted);
  16.             geocodeClient.GeocodeAsync(resquest);
  17.         }

En el controlado de eventos creamos una variable del tipo de la clase con los parámetros obtenidos en la interfaz de usuario. A la etiqueta del localizador le introducimos los valores introducidos con anterioridad. Por último añadimos el localizador a la colección. Siendo este el aspecto final:

  1. private void geocodeClient_GeocodeCompleted(object sender, GeocodeService.GeocodeCompletedEventArgs e)
  2.         {
  3.             GeocodeService.GeocodeResponse response = e.Result;
  4.             if (response.Results.Count > 0)
  5.             {
  6.                 GeocodeService.GeocodeResult result = response.Results.First();
  7.                 if (result.Locations.Count > 0)
  8.                 {
  9.                     Pushpin pushpin = new Pushpin();
  10.                     Location location = new Location(result.Locations.First().Latitude, result.Locations.First().Longitude);
  11.                     pushpin.Location = location;
  12.                     mapa.Children.Add(pushpin);
  13.                     mapa.SetView(result.BestView);
  14.                     UbicacionEntrega dl = new UbicacionEntrega() { Address = this.txtAddress.Text, Location = location };
  15.                     //Creamos una variable con los parametros de la clase obtenidos de los objetos de la
  16.                     //interfaz de usuario
  17.                     pushpin.Tag = dl;//introducimso el valor de la etiqueta del localizador
  18.                     this._locations.Add(dl);//añadimos el localizador a la colección de localizadores
  19.                 }
  20.             }
  21.         }

Vamos a trabajar con los tres botones que pueden tener cada elemento que se añade al Listbox.

Los botones de desplazamiento (Subir, Bajar) del localizador tienen el mismo comportamiento, salvo la posición que ha de ocupar el elemento cuando presionamos alguno de los citados botones.

 

  1. private void ButtonUp_Click(object sender, RoutedEventArgs e)
  2.         {
  3.             Button btnSender = sender as Button;
  4.             UbicacionEntrega dl = btnSender.Tag as UbicacionEntrega;
  5.             SubirLocalizador(dl);
  6.  
  7.         }
  8.  
  9.         private void ButtonDown_Click(object sender, RoutedEventArgs e)
  10.         {
  11.             Button btnSender = sender as Button;
  12.             UbicacionEntrega dl = btnSender.Tag as UbicacionEntrega;
  13.             BajarLocalizador(dl);
  14.         }

En el evento click de los botones, creamos una variable de tipo botón para obtener todo su contenido a través de la propiedad etiqueta. Finalmente enviamos a los respectivos métodos la variable como UbicacionEntrega.

 

  1. private void SubirLocalizador(UbicacionEntrega dl)
  2.         {
  3.             MoverLocalizador(dl, -1);
  4.         }
  5.         private void BajarLocalizador(UbicacionEntrega dl)
  6.         {
  7.             MoverLocalizador(dl, 1);
  8.         }
  9.         private void MoverLocalizador(UbicacionEntrega dl, int direction)
  10.         {
  11.             BorrarRuta();
  12.             if (this._locations.Count > 1)
  13.             {
  14.                 int origIndex = this._locations.IndexOf(dl);
  15.                 this._locations.Remove(dl);
  16.                 this._locations.Insert(origIndex + direction, dl);
  17.             }
  18.         }
  19.         private void BorrarRuta()
  20.         {
  21.             this._currentRoute = null;
  22.             routeLayer.Children.Clear();
  23.             this.txtTotalTime.Text = "";
  24.         }

En función de si queremos subir o bajar el localizador en el Listbox, llamaremos a un método u otro. Ambos métodos llaman a su vez a MoverLocalizador. Primeramente borra la ruta que hay reflejada en el mapa, así como el tiempo en que se tarda en realizar la ruta. Seguidamente se comprueba que haya más de un elemento en la colección. Si es así, borra el elemento de la lista y sitúa la copia del elemento que está en memoria en la posición correspondiente.

Ahora vamos con el botón de eliminación de un localizador. En el evento click de botón a eliminar en primera instancia elimina la ruta dibujada sobre el mapa. Seguidamente borra el localizador de la colección. Finalmente busca el localizador en el objeto Mapa y es borrado de la interfaz de usuario.

  1. private void ButtonRemove_Click(object sender, RoutedEventArgs e)
  2.         {
  3.             Button btnSender = sender as Button;
  4.             UbicacionEntrega dl = btnSender.Tag as UbicacionEntrega;
  5.             BorrarRuta();//elimina la ruta de la Interfaz de Usuario
  6.             //quitar elemento de la colección
  7.             this._locations.Remove(dl);
  8.             //buscar el marcador
  9.             var pushpinsToDelete = mapa.Children.OfType<Pushpin>().Where(x => x.Location == dl.Location);
  10.             //borrar el marcador de la interfaz usuario
  11.             pushpinsToDelete.ToList().ForEach(x => mapa.Children.Remove(x));
  12.         }

 

Por último vamos a calcular y representar la ruta en la interfaz de usuario.Empezando por generar el evento clic del botón “Calcular Ruta”, para ello realizamos doble clic sobre este en el área de diseño de Logistica.xaml.

Nos situamos en el evento click del botón que se encarga de calcular las diferentes rutas del departamento de logística situado en Logistica.xaml.cs. La primera parte del código que vamos a introducir en el mencionado evento, es esencialmente igual, que la que hemos utilizado para el botón que añade localizadores. La única diferencia es que en vez de usar el servicio GeocodeService utilizamos el servicio RouteService

  1. private void btnCalculateRoute_Click(object sender, RoutedEventArgs e)
  2.         {
  3.  
  4.             routeLayer.Children.Clear();
  5.  
  6.  
  7.             RouteService.RouteServiceClient routeServiceClient = new RouteService.RouteServiceClient("CustomBinding_IRouteService");
  8.             routeServiceClient.CalculateRouteCompleted += new EventHandler<RouteService.CalculateRouteCompletedEventArgs>(routeServiceClient_CalculateRouteCompleted);
  9.  
  10.             RouteService.RouteRequest routeRequest = new RouteService.RouteRequest();
  11.             routeRequest.Culture = mapa.Culture;
  12.             routeRequest.Credentials = new Credentials();
  13.             routeRequest.Credentials.ApplicationId = App.Current.Resources["MisCredenciales"] as string;
  14.  
  15.            
  16.  
  17.         }

Inmediatamente después del evento click con el que hemos trabajado vamos a implementar en controlador de eventos routeServiceClient_CalculateRouteCompleted, añadiendo el siguiente fragmento de código:

 

  1. private void routeServiceClient_CalculateRouteCompleted(object sender, RouteService.CalculateRouteCompletedEventArgs e)
  2.         {
  3.             if (e.Error == null)
  4.             {
  5.                 long timeInSeconds = e.Result.Result.Summary.TimeInSeconds;
  6.                 //obtiene el tiempo de la ruta del servicio
  7.                 TimeSpan t = new TimeSpan(0, 0, int.Parse(timeInSeconds.ToString()));
  8.                 this.txtTotalTime.Text = string.Format("Tiempo Estimado: {0}", t.ToString());
  9.                 //da formato a la variable del tiempo de la ruta y lo incluye en el objeto
  10.                 //que lo mostrará en la Interfaz de Usuario
  11.                 DrawRoute(e);
  12.                 //llamada al método que dibuja la ruta
  13.  
  14.                 this._currentRoute = e.Result;
  15.             }
  16.         }

Volvemos al evento clic del botón de cálculo de ruta. En el introducimos las opciones de cálculo de ruta que vamos a pedir al servicio. Esta petición va a ser para que la ruta se calcule a través de puntos (Localizadores).

 

  1. routeRequest.Options = new RouteService.RouteOptions();
  2.             routeRequest.Options.RoutePathType = RouteService.RoutePathType.Points;
  3.  
  4.             routeRequest.ExecutionOptions = new RouteService.ExecutionOptions();
  5.             routeRequest.ExecutionOptions.SuppressFaults = true;

Seguidamente, vamos a contemplar la opción del control de tráfico, que en el interfaz de usuario ofrecemos al usuario final. Introducimos el siguiente código dentro del evento click del botón:

 

  1. if (this.cbxTraffic.IsChecked.Value)
  2.             {
  3.                 routeRequest.Options.TrafficUsage = RouteService.TrafficUsage.TrafficBasedRouteAndTime;
  4.             }
  5.             else
  6.             {
  7.                 routeRequest.Options.TrafficUsage = RouteService.TrafficUsage.None;
  8.             }

Ahora que tenemos todas las opciones en nuestro objeto RouteRequest, es momento de añadir los localizadores como puntos para realizar el cálculo de la ruta(todo ello dentro del evento clic usado con anterioridad). El siguiente código establece las propiedades de los puntos de la ruta como una ObservableCollection de puntos. Además usa LINQ para recorrer todos los elementos contenidos en la lista _locations (que hemos definido en el constructor). Finalmente pasaremos todos los elementos al método GeocodeResultToWaypoint.

 

  1. routeRequest.Waypoints = new System.Collections.ObjectModel.ObservableCollection<RouteService.Waypoint>();
  2.             this._locations.ToList().ForEach(x => routeRequest.Waypoints.Add(GeocodeResultToWaypoint(x)));

El último fragmento de código que vamos a incluir en el evento click del botón, es la llamada asíncrona al método RouteRequest del servicio de cálculo de ruta de Bing Maps pasándole el objeto routeRequest, como podemos observar a continuación:

  1. routeServiceClient.CalculateRouteAsync(routeRequest);

El siguiente paso es crear el método GeocodeResultToWaypoint que convierte el objeto UbicacionEntrega en el objeto Waypoint, que son los puntos necesarios para crear y calcular una ruta:

 

  1. private RouteService.Waypoint GeocodeResultToWaypoint(UbicacionEntrega deliverylocation)
  2.         {
  3.             RouteService.Waypoint waypoint = new RouteService.Waypoint();
  4.             waypoint.Description = deliverylocation.Address;
  5.             waypoint.Location = new Location();
  6.             waypoint.Location.Latitude = deliverylocation.Location.Latitude;
  7.             waypoint.Location.Longitude = deliverylocation.Location.Longitude;
  8.             return waypoint;
  9.         }

El último método que nos queda por implementar es el que se encarga de dibujar en la capa del objeto mapa la ruta para los diferentes localizadores. Añadimos el siguiente fragmento de código:

  1. private void DrawRoute(SilverlightBusinessApplication.RouteService.CalculateRouteCompletedEventArgs e)
  2.         {
  3.             if (e.Result.Result.Legs.Count > 0)
  4.             {
  5.                 //creamos un objeto MapPolyline llamado routeLine
  6.                 //y establecemos sus propiedades visuales
  7.                 Color routeColor = Colors.Blue;
  8.                 SolidColorBrush routeBrush = new SolidColorBrush(routeColor);
  9.                 MapPolyline routeLine = new MapPolyline();
  10.                 routeLine.Locations = new LocationCollection();
  11.                 routeLine.Stroke = routeBrush;
  12.                 routeLine.Opacity = 0.65;
  13.                 routeLine.StrokeThickness = 5.0;
  14.  
  15.                 double distance = e.Result.Result.Summary.Distance;
  16.                 long seconds = e.Result.Result.Summary.TimeInSeconds;
  17.  
  18.                 TimeSpan time = new TimeSpan(0, 0, int.Parse(seconds.ToString()));
  19.  
  20.                 //el mapa recupera una serie de puntos entre los localizadores
  21.                 //y los representa como una linea
  22.                 foreach (Location p in e.Result.Result.RoutePath.Points)
  23.                 {
  24.                     routeLine.Locations.Add(new Location(p.Latitude, p.Longitude));
  25.                 }
  26.                 //la linea es dibujada en la capa del mapa
  27.                 routeLayer.Children.Add(routeLine);
  28.                 //centramos el mapa acorde a la ruta, creando un rectangulo delimitador
  29.                 LocationRect rect = new LocationRect(routeLine.Locations[0], routeLine.Locations[routeLine.Locations.Count - 1]);
  30.  
  31.                 //definimos la vista de mapa utilizando los límites del rectángulo anterior
  32.                 mapa.SetView(rect);
  33.             }
  34.  
  35.         }

Por último en el evento de carga de la página vamos establecer el origen de los elementos del ListBox como la colección _locations, aunque previamente tenemos que generarlo en logística.xaml como podemos observar en la siguiente imagen:

 

image

En el código Behind del citado evento incluiremos el siguiente fragmento de código:

 

  1. private void Page_Loaded(object sender, RoutedEventArgs e)
  2.         {
  3.             this.lbxDestinations.ItemsSource = this._locations;
  4.  
  5.         }

Ejecutamos la aplicación ( F5 ), introducimos los diferentes puntos de entrega que queremos añadir a la ruta.

image 

Presionamos sobre calcular Ruta y podemos ver como la ruta se dibuja en el mapa y calcula el tiempo estimado de la misma.

image

Podemos personalizar las diferentes rutas con las opciones que ofrecemos al usuario final.

Podéis ver todo el material de este tutorial aquí (recordar debereis incluir el ID de Bing Maps en App.xaml, para que funcione de forma correcta objeto Mapa).

Gestión de proyectos ágil con herramientas Open Source (4/7): Redmine

Siguiendo la estela del mes pasado, vuelvo a comentar un gestor de proyectos, en este caso el francés Redmine: http://www.redmine.org/

Este proyecto empezó como una aplicación sencilla sobre ruby on rails y ha tenido una gran aceptación y apoyo.  En sí, es un gestor de proyectos normal, pero ha habido una serie de colaboradores que han desarrollado varios plugins que permiten adaptarlo a la gestión de proyectos ágiles.  Las características más destacables del mismo son:

  • Soporte multi-proyecto
  • Control de acceso flexible basado en roles
  • Sistema flexible de seguimiento de peticiones
  • Gráficas de Gantt y calendario
  • Gestión de noticias, documentos y archivos
  • Feeds & notificaciones de email
  • Wiki por proyecto
  • Foros por proyecto
  • Time tracking
  • Campos personalizados para peticiones, entradas temporales, proyectos y usuarios
  • Integración con sistemas de versiones (SVN, CVS, Git, Mercurial, Bazaar and Darcs)
  • Creación de peticiones por email
  • Soporte de autenticación LDAP múltiple
  • Soporte de auto-registro de usuarios
  • Soporte multilenguaje
  • Soporte de múltiples bases de datos

Una petición está asociada a una persona, sin embargo, puede tener varios seguidores. Estos seguidores pueden actualizarla. Por otra parte, varias peticiones pueden estar relacionadas entre sí. Se pueden definir flujos de trabajo para los distintos roles de usuarios y peticiones.

Licencia / versiones

GNU General Public License v2 (GPL)

Entorno

    Sistema operativo: Unix, Linux, Mac y Windows.

    Ruby & Ruby on Rails:

     

    Versión de Redmine

    Versiones de Ruby soportadas

    Versión requerida de Rails

    Versión requerida de Rack

    current trunk

    ruby 1.8.6, 1.8.7

    Rails 2.3.5

    Rack 1.0.1

    trunk from r2493 to r2886

    ruby 1.8.6, 1.8.7

    Rails 2.2.2

    trunk before r2493

    ruby 1.8.6, 1.8.7

    Rails 2.1.2

    0.9.x

    ruby 1.8.6, 1.8.7

    Rails 2.3.5

    Rack 1.0.1

    0.8.x

    ruby 1.8.6, 1.8.7

    Rails 2.1.2

    0.7.x

    ruby 1.8.6

    Rails 2.0.2

    Notas:

    · Ruby 1.9 no está soportado. Hay que usar Ruby 1.8.x.

    · Se require RubyGems 1.3.1 o superior

    · Se require Rake 0.8.3 o superior

    Base de datos:

    • MySQL 5.0 o superior (es la base de datos recomendada) con C bindings para Ruby
    • PostgreSQL (se recomienda usar la versión 8.4.2)
    • SQLite 3

    Opcional:

    • Binarios SCM (eg. svn) para la integración con sistemas de control de versiones
    • RMagick (para la exportación de Gantt a imagen png)
    • Ruby OpenID Library (para soporte OpenID)

Idioma

Inglés, Español (tiene traducciones a bastantes idiomas, en el caso de que no esté soportado el que se busca, se puede hacer la traducción de manera sencilla, pues la configuración de idiomas va por ficheros).

Vida

Empezaron con la versión 0.7 en el 2008 y desde entonces han sacado 3 versiones menores y una mayor.  Dentro de la 1.0.x, ya van por la 1.0.3 que fue liberada el 31 de octubre, más o menos sacan una versión por año. Dentro de cada versión existen diversas actualizaciones de corrección de errores habitualmente. Por tanto, es un proyecto con bastante vida y que ha madurado mucho desde sus comienzos.

Documentación

Existe mucha documentación en formato wiki dentro de la página web del proyecto y es documentación de bastante calidad. Existe una traducción a español de parte de la documentación. Por otra parte, existe una página de preguntas frecuentes (http://www.redmine.org/wiki/redmine/FAQ).

Comunidad

Cuenta con un apartado (http://www.redmine.org/projects/redmine/boards) donde existen 4 foros, uno no muy utilizado para los desarrolladores, otro dedicado a los plugins con mayor movimiento y 2 más dirigidos a usuarios de la herramienta donde se concentra casi toda la actividad. En general, las respuestas son bastante rápidas. Además, cuentan con un chat IRC (irc://redmine@chat.freenode.net). En todo este tiempo muchos proyectos están haciendo uso de redmine (http://www.redmine.org/wiki/redmine/WeAreUsingRedmine) como por ejemplo, Lighttpd (http://redmine.lighttpd.net/) y el sistema de incidencias de Ruby (http://redmine.ruby-lang.org/).

Soporte comercial

No existe soporte comercial.  Es posible que empresas externas se dediquen a temas de soporte y consultoría sobre redmine.

Funcionalidades de gestor de proyectos

El gestor de proyectos es multi-proyecto, permite crear varios proyectos y se puede ver la lista de todos y cambiar de uno a otro.   Un proyecto puede depender de otro.  Por otra parte se pueden crear varias versiones del mismo proyecto (Roadmap). Así mismo, se puede crear un campo para decir que ciertos proyectos pertenecen a un grupo de proyectos o a un área determinada.  Estas dos últimas posibilidades son debidas a que existe la posibilidad de crear campos personalizados que se apliquen a distintos niveles (proyecto, versión…). 

Gestión de incidencias

Sí, está integrada dentro de la aplicación. Cuando se crea una petición se puede decir que sea de tipo bug.

Ampliación e integración con otros sistemas

Existe disponibilidad del código y, por tanto, de su posible adaptación. Por otro lado, existen múltiples plugins que añaden funcionalidades y también una guía que da información sobre cómo desarrollarlos.  En esta página http://www.redmine.org/wiki/redmine/Plugins se puede encontrar toda la información relacionada con ellos, desde la lista de los mismos con sus funcionalidades hasta tutoriales de cómo realizarla.

Funcionalidades propias de Scrum

La estructura de la información es básicamente la siguiente:

  • Proyecto(s) = es multiproyecto y un proyecto puede ser padre de otros.
    • Milestone(s) = versiones con un marco temporal. Se corresponderían con los Sprints.
      • Peticiones / Issues = engloba cualquier tipo de petición: tarea, bug, funcionalidad, etc, que son configurables. Podría haber un tipo de petición que fuesen las historias de usuario.
        • Categorías: se puede asignar una categoría a cada petición configurable por proyecto. Podrían ser los temas de las historias de usuario.

Estas funcionalidades ágiles, ya sean de scrum o de kanban se pueden adquirir mediante el uso de plugins.  A continuación, se analizan una serie de plugins que las aportan.  Además de estos existen otras posibilidades, el listado completo de plugins se puede ver aquí.

Nota: Los plugins solo están, por defecto, visibles para el administrador. Posteriormente, hay que dar permisos al resto de usuarios para que puedan acceder y trabajar con estos plugins desde la opción de Roles dentro del menú de Administración general. Así mismo, también los usuarios administradores deberán darse permisos para usarlos, aunque puedan verlos.

Nota 2: Estos plugins sólo están disponibles a día 8 de octubre de 2010 para la versión 0.9.x de Redmine dentro de repositorios git.  Necesitan ser retocados para ser compatibles con la versión 1.0.x

Kanban

http://www.redmine.org/wiki/redmine/PluginKanban

Licencia: GNU General Public License v2 (GPL)

Idioma: Inglés, francés y alemán

Añade una entrada nueva en el menú global con lo que engloba a todos los proyectos.

Se trata de un panel kanban donde se muestran las peticiones de cada proyecto en los siguientes grupos de paneles:

  • Incoming: aquellas peticiones que están a la espera de ser introducidas en el “Backlog”, generalmente peticiones con estado nuevo, aunque es configurable.
  • Backlog: peticiones que van al backlog. Se organizan por prioridad.
  • Quick Tasks: peticiones del “Backlog” que no tienen una estimación de tiempo, parecen ser peticiones que no tienen horas asignadas.
  • Selected requests: peticiones del “Backlog” seleccionadas para trabajar. Parece redundante porque replica las que aparecen en el “Backlog” aunque puedes coger una de la lista “Incoming” y pasarla a “Selected requests” y está no aparece en el “Backlog”.
  • Panel kanban propiamente dicho donde se visualizan las peticiones por cada usuario (asignadas a él) con los siguientes estados:
    • Active
    • Testing
    • Finished Requests
    • Cancel Requests

Tiene un apartado de configuración propio donde se indica que estado de petición es visible en cada panel. Puesto que los estados de las peticiones de Redmine son configurables, permite una gran adaptabilidad. Además permite configurar el número máximo de ítems por estado.

Las peticiones se muestran en diferentes colores según la información introducida en el detalle de la petición pero cuesta entender la lógica:

  • Amarillo cuando la petición no tiene el mínimo de la información introducida.
  • Naranja cuando la petición tiene un mínimo de información introducida.
  • Verde cuando la petición tiene toda la información introducida.

El panel kanban permite drag and drop que actualiza:

  • El estado de la petición.
  • La persona a la cual es asignada la petición.

Interesante la opción de tener una visualización conjunta de todos los proyectos pero cuesta entender la lógica.

ScrumDashboard

http://www.redmine.org/boards/3/topics/5808

Licencia: GNU General Public License v2 (GPL)

Idioma: Inglés, portugués/brasileño, coreano y noruego

Añade un nuevo módulo dentro del menú propio del proyecto, es decir, es una pizarra visual por proyecto.

Muestra por milestone, todas las peticiones o solamente las asignadas al usuario.

La pizarra muestra tantas columnas como estados permitiendo el drag and drop entre ellas que actualiza los estados de cada petición.

La visualización es, quizás, demasiado sencilla aunque el tooltip muestra información más detallada.

Tanto los tipos de petición (tracker) como estos estados son configurables por Redmine y en este plugin se indica cuales de estos se van a emplear. Además se puede asignar un color según el tipo de petición (tracker).

Plugin limitado por tratarse de una pizarra visual solamente por milestone pero sencillo y configurable.

Charts plugin

Licencia: GNU General Public License v2 (GPL)

Idioma: Español, inglés, polaco y otros

http://www.redmine.org/wiki/redmine/PluginCharts

Es un módulo que se añade a cada proyecto. En cada uno de ellos hay distintas opciones de gráficos a mostrar, en total 6 distintas

    • Burndown
      • Línea temporal con horas estimadas, imputadas y las que faltan. Se puede filtrar por grupos y condiciones y desplazarte temporalmente aunque esto no funciona muy bien.
    • Burndown with velocity
      • Burndown (horas que faltan) con velocidad. El gráfico muestra los datos para versiones dadas desde la fecha de creación de la versión hasta la fecha actual de la versión.
    • Logged hours ratio
      • Número de horas imputadas proporcionales a un total, agrupadas y filtradas por usuarios, peticiones, actividades, categorías, versión, prioridades o trackers.
    • Logged hours timeline
      • Línea temporal con horas imputadas, agrupadas y filtradas por usuarios, peticiones, actividades, categorías, versión, prioridades y trackers.
    • Logged hours deviations
      • Ratio de horas imputadas y restantes a horas estimadas por cada petición estimada.
    • Issues ratio
      • Ratio de peticiones según estado.

No acabamos de entender su funcionamiento.

Stuff To Do

http://www.redmine.org/wiki/redmine/PluginStuffToDo

Licencia: GNU General Public License v2 (GPL) o siguientes versiones.

Idioma: Español, inglés, italiano, francés, japonés y otros.

Da conflictos con ScrumDashBoard.

Añade 1 entrada de menú en el menú global con lo que engloba a todos los proyectos.

Esta muestra 3 listas que se pueden actualizar mediante drag and drop con las tareas asignadas al usuario logeado.

Las listas son:

  • Qué estoy haciendo ahora: aparecen las 5 como máximo que has elegido para hacer ahora,
  • Qué voy a hacer después: aparecen las que has elegido para hacer una vez has terminado con las que estás haciendo ahora según el orden de prioridad que has elegido o que el manager ha elegido para ti,
  • Qué está disponible: aparecen todas las que están asignadas a ti.

Si no has incluido 5 tareas en la lista "Qué estoy haciendo ahora", no se pueden añadir tareas a "Qué voy a hacer después", aunque permite ordenarlas en todo momento.

No parece existir relación entre las listas y el estado de la tarea a excepción del estado “closed” que la hace desaparecer de las listas.

Dependiendo del rol que tengas, podrás ver y priorizar las listas de otros usuarios. Además hay varias opciones a la hora de filtrar la lista de tareas que están disponibles (por proyecto, por usuario, por estado...). El administrador del proyecto (project manager), además puede definir un umbral de número de tareas recomendadas a partir del cual se le informe por medio de un correo electrónico que se han incluido tareas en esa lista. Se pueden definir, separadas mediante comas, varias direcciones de correo electrónico.

Además existe un calendario, opcional, que parece recoger las horas por cada día de una semana.

Cuadro resumen

Redmine

URL

http://www.redmine.org/

Licencia / versiones

GPL v2

Entorno

Ruby 1.8.x, Rails 2.x, Rack 1.0.1, Ruby gems 1.3.1, Rake 0.8.3, MySQL 5.0+ (recomendada) o PostgreSQL 8.4.2 o SQLite3, opcionalmente binarios SCM, RMagick (para la exportación de Gantt a imagen png) y Ruby OpenID Library (para soporte OpenID)

Idioma

Español e inglés.

Vida

Desde 2008.

Documentación

Wiki de la página web, abundante y completa.

Comunidad

Foros bastante activos, canal IRC.

Soporte comercial

No hay.

Funcionalidades gestor de proyectos
Proyectos

Multi-proyecto.

Gestión de incidencias

Sí.

Ampliación y adaptación

Disponible código fuente y plugins (guía de cómo desarrollarlos).

Funcionalidades propias Scrum
Backlog

Sí, en plugins, depende del plugin elegido.

Historias y Tareas

Sí, se pueden definir distintos tipos de issues para cubrir esto.

Roles

Depende de plugins.

Pizarra visual

Depende de plugins.

Burdown Chart

Depende de plugins.

Kanban

Existe un plugin que aporta esta funcionalidad.

Gestión de proyectos ágil con herramientas Open Source (3/7): AgileFant

Este mes yo también me uno a la moda de la gestión de proyectos ágiles con herramientas Open Source.  Yo os voy a hablar de un proyecto finlandés.  AgileFant: http://www.agilefant.org/

Este proyecto, está respaldado por la Helsinki University of Technology y SoberIT (Laboratorio de Software de Negocio asociado a la universidad).  Su página web ha cambiado recientemente y ahora la información que se muestra es más reducida que la que se podía encontrar antes.  Posiblemente haya que registrarse para poder acceder a más información.

Tiene una demo online.

Licencia / versiones

Licencia de Agilefant (se basa en la licencia del MIT).

Entorno

  • Mozilla Firefox 3 y 3.5, Google Chrome y Safari de Apple
  • JRE 1.5 o JRE 1.6 (preferiblemente de Sun),
  • JDK 1.5 o JDK 1.6 (preferiblemente de Sun para desarrollo de la herramienta)
  • Tomcat 5.5 o 6
  • MySQL 5 (con InnoDB activado)

Parece ser que ya no sólo Mozilla Firefox 3 va a ser el único navegador soportado activamente en el futuro, ahora también lo prueban sobre Google Chrome y Safari.  Intentan también que sea compatible con Internet Explorer 7 y 8, aunque esto no lo aseguran.  La nueva interfaz de usuario (desde Agilefant 1.4.7) funciona más rápido con Firefox 3 que con versiones anteriores.

Es necesaria la JRE versión 5 o 6 para hacer funcionar el servidor.  Para desarrollo es necesaria la JDK versión 5 (1.5) o 6 (1.6).  Además se recomienda que sean las de Sun.

Se recomienda utilizar Apache Tomcat 5.5 o 6.  Agilefant puede trabajar con otros servidores J2EE y versiones de Tomcat, pero han sido informados de errores con Glassfish.

Se requiere MySQL 5 (con el motor InnoDB).  Agilefant puede personalizarse para funcionar con otros servidores-SQL, sin embargo no existe ni documentación ni soporte.

Idioma

Inglés

Vida

Al menos desde 2007 (última fecha que aparece en página de descargas) Versión 1.2.0. Desde entonces => En 2009 la versión 1.6.2 y a día de hoy (Octubre de 2010) están por la versión 2.0.4. Las versiones 2.0.x se empezaron a publicar en junio de 2010 y desde entonces a septiembre de 2010 que fue cuando se liberó la versión 2.0.4 ha habido 5 versiones (2.0.0 a 2.0.4).

Documentación

Sólo existe una guía de instalación en inglés.  Las preguntas frecuentes se limitan a una serie de diapositivas haciendo un quick tour y las que puedas encontrar o preguntar en los foros.

Comunidad

Foros activos, los desarrolladores suelen contestar en el día o a lo sumo al día siguiente, canal IRC.  Además de esto tienen unos cuantos contribuidores.

Soporte comercial

De momento no hay.  Es posible que a futuro lo pongan.  De momento el único soporte que se da es en el foro (los desarrolladores suelen responder en el día).

Funcionalidades de gestor de proyectos

El gestor de proyectos es multi-proyecto, permite crear varios proyectos y se puede ver la lista de todos y cambiar de uno a otro.  Los proyectos se pueden priorizar y formar parte de un producto mayor mediante el concepto de proyecto - producto.  Un producto puede tener uno o varios proyectos asociados.  Por otra parte, no existe forma de diferenciar proyectos por áreas, aunque a las historias de usuario sí que se le pueden asignar distintas temáticas.

Gestión de incidencias

No tiene.  Se debe usar otro sistema.

Ampliación e integración con otros sistemas

No tiene.  Se pueden solicitar nuevas funcionalidades o desarrollarlas directamente.

Funcionalidades propias de Scrum

Las tareas se planifican en horas, las historias de usuario permite planificarlas introduciendo manualmente los puntos.

Sólo existe el rol de usuario.

Tiene diagrama de burndown por iteración y de burnup por proyecto.

Tiene un informe sobre horas dedicadas a distintas tareas por distintos desarrolladores que se puede exportar a excel (es el único informe que ofrece).  Permite obtener el informe por proyecto, elegir un intervalo de tiempo y los desarrolladores.

Se pueden crear equipos de personas.  Pueden estar en varios proyectos.

Todo el mundo puede tocar todas las opciones administrativas, puesto que no hay permisos por usuario.

Relaciones entre conceptos utilizados en la herramienta:

Componentes agilefant

En el backlog se muestran las historias de usuario.  Estas historias de usuario pueden depender de otras.  También tienen tareas asociadas.  Se puede ver por proyecto y por sprint.  También se puede ver la lista de proyectos que forman parte de un producto.  Se puede priorizar mediante el posicionamiento de los objetivos de la iteración.

No tiene pizarra visual.  Tiene 6 estados (no modificables) por ítem.

 

Estado

Color

Significado

Sin empezar

gris

El trabajo en este item no ha comenzado todavía

Empezado

naranja

El trabajo en este item ha empezado

Pendiente

azul

No se puede proceder, pero se sabe que esperando el obstáculo desparecerá

Bloqueado

rojo

No se puede proceder, y se sospecha que hay que hacer algo para quitar el obstáculo

Implementado

verde claro

Alcanzará la definición de hecho tras ser revisado en la próxima reunión.

Hecho

verde oscuro

Ha alcanzado la definición de hecho

Existe una medida de carga por persona (Load), depende de las horas semanales de trabajo y de las horas estimadas en las tareas.

Cuadro resumen

Agilefant

URL

http://www.agilefant.org/

Licencia / versiones

Licencia de Agilefant / AgileFant 2.0 Beta 1.

Entorno

Mozilla Firefox 3 y 3.5, Google Chrome y Safari de Apple, JRE 1.5 y/o JRE 1.6 (preferiblemente la 1.6 y de Sun), Tomcat 5.5 o 6, MySQL 5 (con InnoDB activado).

Idioma

Inglés.

Vida

Desde 2007.

Documentación

No mucha, parte en finlandés y parte sin terminar.

Comunidad

Activa.  Foro, IRC.

Soporte comercial

No hay todavía.

Funcionalidades gestor de proyectos
Proyectos

Multi-proyecto.

Gestión de incidencias

No.

Ampliación y adaptación

Sí, mediante solicitud de funcionalidades / desarrollo de la aplicación.

Funcionalidades propias Scrum
Backlog

Sí, por Proyecto y Sprint.

Historias y Tareas

Sí, una “story” (historia) puede tener entre 0 y N “Tasks” (Tareas).

Roles

Sólo tiene el rol de usuario.

Pizarra visual

No tiene.

Burdown Chart

Sí, por iteración.  Por proyecto tiene un burnup chart.

Kanban

No.

1 - 10 Siguiente
© 2008 CEIN - Centro Europeo de Empresas e Innovación de Navarra. Aviso Legal.
Polígono Industrial Mocholi 31110 Noáin (Navarra) Tel: 848 425500 - Fax: 948 312631
GPS:: Lat:42º45´21155´´, Long: 1º 38´9538´´