domingo, 18 de abril de 2010

Controlando el cierre de sesión desde nuestra aplicación WPF

En numerosas ocasiones hemos hablado de las características básicas que debe poseer cualquier aplicación profesional de software que desarrollemos. Una de las fijas en todos los listados es la estabilidad. Cuando valoramos dicha cualidad debemos ser conscientes de que nuestras aplicaciones no se ejecutan solas ni son independientes de los devenires del los usuarios a nivel del Sistema Operativo.

Revisando las posibilidades que manejamos a la hora de mantener nuestra aplicación siempre en un estado controlado nos podemos alegrar una vez más de contar con un framework estable y maduro como es .NET.

Imaginemos el siguiente escenario:

El usuario trabaja con nuestra aplicación editando una serie de datos de un determinado registro. Por otro lado, el Sistema Operativo comienza a descargar e instalar unas actualizaciones que obligan a reiniciar. El usuario acepta el reinicio sin darse cuenta que no ha salvado los datos… (improbable, verdad? ;))

Si no contemplamos este tipo de casuísticas en nuestra aplicación, esta se cerrará y la modificación no se reflejará en el sistema de almacenamiento subyacente (base de datos, archivos…) y se terminó la historia. Otro debate es si la culpa de la pérdida es nuestra o no, pero lo que es seguro, es que existen entornos en los que esta respuesta no es aceptable…

Para controlar cosas como estas (está todo pensado…) debemos trabajar con las posibilidades que nos brinde la  clase Application de .NET. Entre otras características, esta clase nos brinda la oportunidad de interactuar con un cierre de sesión a través de un método sobrescribible o suscribiéndonos a un evento.

Vamos a ver este código:

   1: public partial class App : Application



   2:     {



   3:         private bool _editing = true;



   4:  



   5:         protected override void OnSessionEnding(SessionEndingCancelEventArgs e)



   6:         {



   7:             base.OnSessionEnding(e);



   8:             if (_editing)



   9:             {



  10:                 e.Cancel = true;



  11:                 MessageBox.Show("You can´t " + e.ReasonSessionEnding.ToString() + " with unsaved data.");



  12:             }



  13:         }



  14:     }




Estableciendo en este punto nuestras políticas, podemos determinar de una manera muy sencilla si el estado de nuestra aplicación permite realizar el cierre sin comprometer su estabilidad o datos almacenados en memoria. Si os interesa conocer el motivo del cierre de la sesión podéis consultar el valor de la propiedad ReasonSessionEnding de la clase SessionEndingCancelEventArgs



A veces cuesta muy poco dar superar lo estrictamente obligado, con lo que transmitimos una mayor sensación de esmero y profesionalidad.

viernes, 12 de marzo de 2010

Sinergia D&T (developer + tool)

Siempre es importante aprender de los demás (sobre todo de los buenos ;)) pero en aspectos como la organización y la metodología lo básico está inventado. Nuestra tarea como desarrollador consiste, básicamente, en aplicar esas buenas ideas a nuestra realidad y hacer que se ajuste a la misma como un guante.

Por supuesto, esta idea es más sencilla de decir que de poner en practica. Se deben tener en cuenta muchos aspectos, sin descuidar ni uno solo de ellos, si queremos tener un “Jelled Team” como lo califican en Peopleware. En el proceso ALM podemos observar que contar con un buena herramientas nos puede facilitar mucho el proceso.

Cuando comenzamos con una metodología, la herramienta seleccionada nos brinda una gran ayuda poniendo a nuestra disposición todo el know-how analizado y sintetizado para generarla. Y esto no es poco. Nos ayuda a encauzar la energía y optimizar los esfuerzos sin dispersarnos en decidir como comenzar a caminar en la organización básica del complicado mundo del desarrollo del software.

En este punto es donde, ante el Team Foundation Server hay que quitarse el sombrero. Para ser una herramienta relativamente moderna ha sabido encajar las piezas con mucho acierto abriendo los puntos claves a diferentes metodologías para elegir nuestro sabor preferido. (MSF, SCRUM…)

Como muestra un botón. Cuando en el TFS2010 reportas un bug sobre un proyecto, el formulario correspondiente (y la Web del Team Web Access !!) nos aparece un botón con la leyenda Tools. Al desplegarlo, tenemos entre otras opciones, la de mostrar el diagrama de estados de la gestión de bugs definida por la guía de proceso seleccionada.

Dicho elemento se ve así con el SCRUM de Cochango:


State Diagram

Cualquier desarrollador de Software se puede dar cuenta que poco tenemos que inventar al respecto. Como mucho, tendrás que hacer algún ajuste personalizado para tus particularidades. Ahora imaginaros la cantidad de horas y energía que podíamos malgastar en intentar crear una gestión de bugs como esta desde cero (más el tiempo en crear el diagrama y mandarlo al departamento de calidad ;)). Aspectos como este, transmiten madurez por parte de la herramienta, generan confianza en su uso y crean una sinergia entre los desarrolladores y la herramienta que nos ayudan a ser lo más eficientes posible.

A ver quien se vuelve al Source Safe ;)

lunes, 18 de enero de 2010

El misterioso caso de LINQ to SQL y 0=1…

Como ya más o menos todos conocéis LINQ to SQL implementa una política de concurrencia optimista. Esta característica parte de la premisa de no realizar ningún bloqueo sobre los registros con los que estamos trabajando. Este modo es el recomendado, y en ocasiones el único aceptable, sobre todo en entornos de alta escalabilidad como son por ejemplo las aplicaciones Web.

Cuando nos creamos el modelo de nuestra aplicación a partir de la base de datos, generamos un fichero dbml. Es importante tener en cuenta que, entre otras propiedades, podemos especificar como queremos que el contexto gestione el UpdateCheck de cada columna. (Always, WhenChanged, Never).

Esto nos permite, en base a la naturaleza de la información de un campo, afinar la política de comprobación de la concurrencia que deseamos aplicar. Por ejemplo, podemos sobrescribir siempre la descripción detallada de un producto (sin importarnos si otro usuario la ha modificado desde que leímos ) pero puede no ser aceptable para, por ejemplo, el Stock asociado al mismo. Esta característica junto con el RowVerison nos permite detectar los problemas de concurrencia y automatizar su resolución en la medida de lo posible.

Hablando con un equipo de desarrollo me contaban que tenían problemas al borrar un registro. Revisándolo con ellos, me comentaban que pasaban por parámetro clave primaria del registro que deseaban eliminar. El código que empleaban era similar a este:

using (xxxDataContext ctx = new xxxDataContext())
{
      Table1 t1 = new Table1 { Id = id };
        ctx.Table1s.Attach(t1);
        ctx.Table1s.DeleteOnSubmit(t1);
        ctx.SubmitChanges();
}

Y el error que percibían era que no se eliminaba el registro asociado en la base de datos pero no sabían exactamente porqué...

Al revisar la política de UpdateCheck de las columnas de la entidad, me di cuenta que estaban definidos en el modelo con su valor predeterminado. (Always). Por lo que la cosa estaba clara, Linq To SQL estaba creando la consulta que lanzaba al proveedor subyacente concatenándole el valor original y al no encontrar dicho registro en la base de datos no eliminaba nada…

Al comprobar mi teoría veo que la sentencia que genera Linq To SQL para el borrado incluye una clausula where del estilo ...

DELETE FROM [dbo].[Table1] WHERE 0 = 1

¿¿0=1??

Para darles respuesta les comenté el problema y la solución fue tan simple como cambiar el UpdateCheck a Never puesto que este escenario les cuadraba para dicha tabla, pero yo ya me había quedado mosca con el tema del 0=1...

Leyendo un poco descubro que es una optimización generada por el equipo de ADO.net puesto que determinan que nunca se cumple la condición. Y la condición que nunca se cumple es la siguiente:

En la base de datos existe un campo Name que esta definida como NOT NULL, por lo tanto nunca puede almacenar un valor NULL (obvio, no?). En .Net el tipo de la propiedad que mapea a dicho campo es de tipo String y por la naturaleza del mismo este puede almacenar un NULL. De hecho es los que almacena si nos fijamos en el código superior.

Como LINQ To SQL observa que en el objeto el valor es un NULL y en la definición del esquema de la base de datos este valor no puede estar presente, determina que no va a coincidir por lo que optimiza con el 0=1...

Bueno dicho (y comprendido) queda...

viernes, 4 de diciembre de 2009

Scrum:IGTD (Scrum implementa el interfaz GTD)

Cada día están más en auge las metodologías orientadas a la productividad personal. Todos y cada uno de nosotros gestionamos recursos, al menos nuestro tareas en el tiempo, y es recomendable, por no decir necesario, organizar dichas tareas para ser los más productivos posible.

El ámbito de aplicación GTD no se limita al entorno profesional sino que cubre también los aspectos de organización personales, permitiendo aplicar pautas a todos los aspectos de nuestro comportamiento. Existen en la red toneladas de material al respecto y discutir las bondades de la metodología GTD y las implementaciones de las mismas quedan fuera de la intención de este post. Sin embargo, me gustaría analizar la relación que existe entre dos mundos íntimamente relacionados (aunque no de manera explicita) como son GTD y las metodologías ágiles. Como representante de dichas metodologías estudiaremos Scrum.

Si consideramos GTD como un interfaz o contrato, llamémosle IGTD, sus puntos serian:

  • Recopilar
  • Procesar
  • Organizar
  • Revisar
  • Hacer

Veamos como SCRUM implementa cada uno de los mismos…

  • Recopilar
    El objetivo en GTD se define como “sacar” todo de nuestra mente y recogerlo en alguno de los elementos de almacenamiento para luego procesarlos.

    Scrum define exactamente esta tarea identificando un rol para cubrirla, el responsable de producto o Product Owner. Entre las responsabilidades principales de dicho rol se encuentran la de identificar los puntos que más valor aportan al producto servicio que desarrolla el proyecto. Dicha recolección se realiza escuchando y tratando con los diferentes stakeholders. Este punto común de acceso permite crear una capa de protección y homogenización para el resto del equipo.
    Otra tarea muy importante y a la vez menos visible que recae sobre esta figura, es la de rechazar las propuestas de los stakeholders que no interesa avancen por el flujo puesto que no son interesantes para el producto. Esto permite al equipo centrarse en lo que realmente aporta valor.

  • Procesar
    Por supuesto, el trabajo de un buen Product Owner, no se limita a transcribir todo lo que escucha a los diferentes stakeholders. Debe realizar un proceso de análisis y diseño cuyo resultado se muestra como un conjunto de historias de usuario o Product Backlog. Dichas historias deben mantenerse consensuadas, consistentes y priorizadas puesto que conforman el material sobre las cuales trabajará la “apisonadora” que es el equipo.

    Una buena regla para saber si tienes un buen Product Owner en tu equipo es preguntarse cuanto disminuiría la rentabilidad del producto si lo sustituyes por una regla de redirección de correo…
  • Organizar
    El equipo, liderado por el Scrum Master y contando con la disponibilidad del Responsable de Producto, comienza en el Sprint Planning Meeting a digerir y desmenuzar ese producto Backlog. El resultado de dicho procesamiento son las tareas necesarias para cubrir las historias de usuario que el Product Owner ha recopilado.
  • Revisar
    Scrum da gran importancia al proceso de revisión. En base al grano deseado realiza la tarea de revisión en dos maneras.

    Todo el equipo se reúne una vez al día en el Daily Scrum comenta lo que ha realizado, lo que va a realizar en el día y los impedimentos que se ha encontrado por el camino. La verdad es que no se me ocurre una mejor forma de aplicar el concepto de revisión a grano fino.

    Por otro lado, al finalizar cada sprint se realiza una revisión del mismo, Sprint Retrospective que permite a nivel de todo lo realizado en el Sprint, evaluar los aspectos positivos para potenciarlos y negativos para mejorarlos.

    En GTD también existen dos tipos de revisiones, las diarias y las semanales (por Sprint para Scrum) así que en este punto la cosa encaja como un guante.
  • Hacer
    Una vez que tenemos claro lo que hay que hacer el equipo lo desarrolla, lo mismo que en GTD. Ambas metodologías hacen hincapié en la satisfacción de hacer las cosas y poder marcarlas como hechas, quitándolas de la primera línea de batalla y permitiendo centrarnos en lo que falta por hacer.

La conclusión que podemos obtener de este análisis, es que ambos metodologías son recomendablemente compatibles. Encajan porque se basan en patrones comunes, haciendo hincapié en centrarse en lo importante, reducir el stress, simplificar el día a día.

Además son especialmente cuidadosas con evitar el cambio de contexto y fomentar la concentración, GTD vía controlando las interrupciones internas y externas y Scrum blindando a los equipo de los cambios durante los Sprints.

lunes, 30 de noviembre de 2009

Instanciando objetos en Silverlight: Code VS XAML

Si os pregunto que manera de instanciar los objetos es más rápida, por código o vía el parser de XAML ¿Cual sería vuestra respuesta?
Pues la mayoría de los desarrolladores dirían que por código, pero obviamente la cosa tiene trampa…

En la mayoría de los casos el parser de XAML es más rápido. La razón de esta característica es el resultado de una serie de optimizaciones realizadas en tiempo de ejecución por Silverlight. El parser de XAML no crea los API objects que se emplean para interactuar con los elementos, sino que solo crea una representación interna de los mismos. Cuando desde código comenzamos a interactuar con esos objetos es cuando Silverlight crea los API objects necesarios. Esta característica se hace especialmente patente en inicializaciones de gran cantidad de objetos, aunque hay entra nuestra labor de diseño para evitar crear vistas inmanejables…

Teniendo esta particularidad en mente y valorando las facilidades de integración diseñadores/desarrolladores que nos da escribir UI en XAML es recomendable dejar la creación de objetos por código para los escenarios en los que realmente es necesario.