jueves, 28 de octubre de 2010

“scrum” con minúsculas

Es muy interesante observar como ciertos paradigmas van calando en la comunidad de desarrollo. Raro es ver hoy en día alguien que no defienda un modelo ágil de trabajo, puesto que sus virtudes son evidentes.

Como siempre ocurre, sabemos donde queremos ir, pero en ocasiones el camino no es lo suficientemente claro para avanzar sin dudas. Muchos son los que se pierden por diversos motivos echando a andar sin tener correctamente interiorizados los principales valores innegociables. Una vez conseguidos los mismos, lo demás vendrá solo.

Te puedes quedar, como dice un amigo, “Buscando por donde le entra el agua al coco…”

Si no afrontamos la adopción de una nueva metodología con la importancia que se merece, podemos cometer algunos errores que nos condenen al fracaso, y esto de verdad que minará la posibilidad de mejora para una larga temporada…

Algunos de los errores más comunes que nos pueden llevar a tener un SCRUM sesgado y poco efectivo pueden ser:

  • No integrar los hitos heredados en la planificación del Backlog
    Las empresas (aunque sea a golpe de ASM) hacen cosas en el día y a día. Asumen compromisos que deben cumplir. Un cambio en la metodología es una evolución, no una revolución. Deben contemplarse los hitos anteriores y encajarse en el nuevo modelo de manera natural. De nada (positivo) vale crear un sprint si el día 1 del siguiente mes debemos entregar la “master” y ese trabajo no se contempla en la planificación de Backlog.
  • Jugar con dos barajas con las prioridades
    Las prioridades y urgencias son las mismas con y sin SCRUM. La nueva metodología no va a solventarnos por arte de magia los problemas, solo nos va a dar unas reglas para afrontarlos. De nada vale planificar algo para saltarlo, haciéndonos trampas al solitario y andar como pollo sin cabeza apagando fuegos.
  • Asumir de manera parcial o sesgada las reglas del juego
    Una de las ventajas que tiene SCRUM frente a otras metodologías más predictivas, es su sencillez y empatía con el desarrollador. Estos al fin y al cabo son el motor de cualquier empresa de desarrollo de Software y colocarlos en el centro del tablero es una de los principales aciertos. Eso si, si te decantas por SCRUM implanta al menos las pocas reglas en conjunto para que la mecánica tenga sentido.
  • Presencia de roles satélites o heredados
    Al ganar visibilidad inevitablemente afloraran roles a los que se les verá el cartón. Quedará patente lo poco que aportan a día de hoy y serán grandes enemigos del cambio. Supervivientes hay en todos los sitios y tirar de la manta no les va a hacer ninguna gracia. Debemos identificarlos y recolocarlos si es posible puesto que pueden hacer mucho ruido en contra y comprometer la estabilidad. Siempre es más fácil deshacer que hacer.
  • Permitir implantar la metodología sin conciencia Top-Down
    Asumir una metodología (más siendo ágil) es un cambio profundo para una empresa. Afecta a todos los estratos de la misma y solo triunfará si se asume una conciencia global de la necesidad e implicación necesaria para el éxito. O jugamos todos o rompemos la baraja y no vale ir de farol ;)
  • Establecer un ámbito de actuación de la metodología reducido o para partes de los equipos
    Todo lo que ganemos en agilidad, es un éxito, pero los avances se multiplican y crean sinergias muy positivas cuanto mayor es el dominio se implantación de la misma. Asumirla en equipo muy estancos obliga a realizar un esfuerzo titánico por parte de unos pocos y no fomenta el ROI de las inversiones.
  • Impedimentos de Hardware, limitación de inversiones
    las herramientas no son parte de la metodología en si misma, sino la forma de implementar la misma. Olvídate de reinventar la rueda, existen herramientas muy poderosas que te permitirán a un coste asumible ser muy productivo. Con la aparición del Cloud Computing dichos costes pueden ser todavía más elásticos permitiendo a pymes y empresas con pocos recursos contar con las mismas herramientas que antes solo estaban al alcance de las grandes. SAAS de TFS es un buen ejemplo de este escenario.
  • Intentar implantar todas las best-practices a la vez
    Es mucha la gente que piensa que un conjunto de best-practices relacionadas con el mundo del desarrollo del Software son parte de SCRUM. Esto no es así. Está claro que cuanto mejor desarrollemos, mayor ventaja competitiva tendremos. Esto es independiente de la metodología que empleemos. Tanto en CMMI , RUP o MSF realizar pruebas unitarias, builds automatizadas, patrones de diseño…son prácticas muy valoradas. Es verdad que en aspectos ágiles todavía son más relevantes puesto que el intervalo de entrega se acorta (valor solo entendido como Software potencialmente entregable) pero esto es la guinda del pastel.
  • Falta de paciencia y fe en los resultados
    Como ya hemos comentado, no existe una varita mágica que nos resuelva los problemas. Solo con trabajo y esfuerzo llegarán los frutos. Es un proceso continuo, sin un fin definido. Siempre podremos ir mejorando y adaptándonos a las nuevas realidades que surjan por el camino. Si te decides a implantar SCRUM no esperes que al terminar el primer Sprint tu empresa se otra. Valora si es un poco mejor de lo que lo era antes. Evalúa la tendencia, no (solo) la foto y por supuesto, replantearte continuamente los procesos, identifica las acciones en cascada y disuélvelas con una integración más orgánica.

Estos son algunos de los puntos sobre los cuales debemos poner el foco a la hora de intentar implementar cualquier metodología en una empresa. Aunque son problemas comunes se acentúa aún más cuando deseamos trabajar con metodologías ágiles.

Por cierto, la palabra ágil no está empleada por que sí. Para que el conjunto sea ágil todos los componentes del mismo deben serlo. Esta necesidad nos obliga a identificar los puntos que no lo son y tratarlos como impedimentos (teoría de los cuellos de botella). Este proceso de mejora continua es el que nos permite adquirir agilidad puesto que los valores absolutos no tienen cabida en este marco.

domingo, 22 de agosto de 2010

Cloud Computing, lo tienes claro?

Cada día escuchamos más y más hablar de Cloud Computing. La evolución del mundo del desarrollo marca una clara tendencia debido a las múltiples beneficios que este paradigma aporta. Vamos a revisar los principales conceptos de manera muy sintetizada de tal modo que podamos aprender con las ideas claras.

Una cosa que debemos tener en mente es que el Cloud Computing es un paradigma en evolución. Por lo tanto, sus definiciones se encuentran sujetas a debate por parte de todos los actores implicados. Estos (está de mas decirlo) pretenden arrimar el ascua a su sardina, pero eso es harina de otro costal...

Basándonos en las definiciones del National Institute of Standards and Technology, Cloud Computing es un modelo para habilitar acceso remoto y bajo demanda a un conjunto de recursos computacionales (redes, servidores, almacenamiento, aplicaciones y servicios) que puedan ser rápidamente aprovisionados y liberados con un mínimo esfuerzo de gestión o interacción con el proveedor de servicios.

De manera estandarizada se especifican cinco características esenciales, tres modelos de servicio y cuatro modelos de despliegue. Vamos a revisar esos conceptos para componer una idea más completa.

Carcateristicas:

  • Auto-servicio bajo demanda
    Un cliente puede aprovisionar de manera unilateral las capacidades computacionales en base a las necesidades, sin requerir interacción humana con cada proveedor de servicios.

  • Amplio acceso a la red
    Los recursos están disponibles a través de la red y accedidos a través de mecanismos estándar que propician el uso desde plataformas heterogéneas.

  • Pool de recursos
    Los recursos computacionales del proveedor son sirven a múltiples clientes empleando un modelo multi-tenant, con diferentes recursos físicos y virtuales
    dinamicamente asignados y reasignados en base a las demandas del cliente.

  • Rápida elasticidad
    Los recursos pueden ser rápida y elasticamente aprovisionados, en algunos casos de manera automática. Esta característica permite escalar (aumentar y reducir) rápidamente. Desde el punto de vista del cliente los recursos son ilimitados y pueden ser contratados en cualquier momento y en cualquier cantidad.

  • Medición de servicio
    Los sistemas de Cloud automáticamente controlan y optimizan los recursos.
    El uso de los recursos puede ser monitorizado, controlado y reportado aportando transparencia tanto para el proveedor como el cliente del servicio.

Modelos de despliegue:

  • SaaS (Software as a Service)
    Hace referencia a proveer la capacidad al cliente de utilizar las aplicaciones del proveedor que se están ejecutando en la infraestructura de la nube. Es importante tener en cuenta que el cliente no gestiona (salvo excepciones) la infraestructura subyacente de la nube.
    Este es el modelo principal de Azure.
  • PaaS (Platform as a Service)
    Hace referencia a proveer la capacidad al cliente de desplegar sus aplicaciones sobre la infraestructura de la nube, creadas empleando los lenguajes de programación y herramientas soportadas por el proveedor. El cliente no gestiona la infraestructura subyacente de la nube pero sí que controla el despliegue de las mismas y posiblemente la configuración de los entornos donde estas son albergadas.
    AppEngine de Google es un ejemplo de PasS
  • IaaS (Infrastructure as a Service)
    Hace referencia a proveer la capacidad al cliente de aprovisionar procesamiento, almacenamiento, redes y otros recursos computacionales sobre los cuales tiene la capacidad de desplegar y hacer correr software (puede incluir SO y aplicaciones). El cliente no gestiona la infraestructura subyacente de la nube, pero tiene control sobre el SO, almacenamiento, despliegue y ocasionalmente control (limitado) sobre ciertos componentes de la red. (Por ejemplo firewalls...)
    Amazon AWS es el mayor proveedor mundial de IaaS.

Modelos de despliegue:

  • Nube privada
    La explotación de la infraestructura de la nube es realizada por una única organización. Puede ser gestionada por la organización o por un tercero.
  • Nube comunitarias
    La explotación de la infraestructura de la nube es realizada por varias organizaciones y soporta una comunidad que comparten ciertos aspectos (por ejemplo requisitos de seguridad, políticas...) Puede ser gestionada por las organizaciones o por una tercera parte.
  • Nube pública
    La infraestructura de la nube se encuentra disponible para el publico general o un gran grupo de industrias y es propiedad de una organizativo que comercializa los servicios de la nube.
  • Nube híbrida
    La infraestructura de la nube está compuesta por dos o mas nubes (privada, comunitaria o publica) unidas a través de estándares o tecnología propietaria que habilita la comunicación entre ellas

Espero que este pequeño resumen sirva para aclarar algunos conceptos básicos y genere un poco más de curiosidad.

domingo, 25 de julio de 2010

SOA != Client Server + WCF

El panorama actual en el mundo de desarrollo del software nos brinda más oportunidades de las que nunca habíamos tenido (quizás ni siquiera imaginado). Entre otros escenarios, la aparición de Internet ha propiciado el crecimiento de los sistema distribuidos, la orientación a servicios, el SaaS...

Este nuevo "el dorado" plantea características donde todas las empresas desean desembarcar sus activos. Por supuesto estos destinos son tan interesantes que muchos deciden tomar atajos para llegar a lo que creen el mismo destino, pero cuidado,
que como siempre, no es oro todo lo que reluce.

La formula del título viene a decir eso, se podría leer como:

SOA != Client Server + WCF

No es lo mismo desarrollar Software orientado a servicio que colocar una capa de WCF en una aplicación Cliente Servidor. Definitivamente NO ES LO MISMO...

Pero como ya sabemos las cosas no cambian solas, debemos como desarrolladores hacer un esfuerzo por ser conscientes de las nuevas reglas de juego con las que deseamos que nuestras aplicaciones den la talla.

Revisando mi experiencia el respecto podemos identificar los errores más comunes a la hora de crear Software orientadas a servicios:

  • Los servicios (aunque no te lo creas) no están (solo) para ti.
    Utiliza los recursos del servicio de manera razonable, piensa bien como y cuando realizar las llamadas evitando acaparar los recursos disponibles.
  • Al consumir otros servicios estas realizando una llamada remota, eres consciente?
    No hagas 17 peticiones con sus 17 serializaciones para pintar una pantalla. No me digas que son las clases que usas como DTO y que te van para el pelo para tu ORM...
    Todo el tiempo invertido en optimizar la comunicación tendrá un alto ROI, te lo aseguro.
    Por supuesto recibir 26 millones de objetos (bien serializados) es un problema a nivel de diseño de la aplicación. (consolida la información, pagina, trabaja por bloques pero no tires por ese camino bajo ningún concepto...)
  • Siempre piensa en que la disponibilidad nunca es del 100%
    Eso es así aunque algún comercial se empeñe en decir lo contrario.
    Pregúntate que ocurre si el servicio no está disponible y dota a tu aplicación de la inteligencia necesaria para responder ante tal situación de manera digna. Siempre es interesante valorar la posibilidad de realizar las comunicaciones de manera asíncrona.
    Ten en cuenta que no debes lanzar procesos que comprometan la estabilidad de los servicios, puesto que estos deben estar disponibles para los demás clientes.
    (Recuerda que trabajar por bloques "casi nunca" es opcional y con determinado volumen de datos es obligatorio)
    Piensa en la Alta disponibilidad, como hacer correr varias instancias en paralelo, clúster activo-pasivo antes de que te pille el toro...
  • Diseña un plan de contingencia y déjalo por escrito
    Si no quieres que la gente que mantiene la aplicación te llamen a las 3:00 de la madrugada por que se ha parado el servicio, dales los mecanismos oportunos para que operen con autonomía. Ten un poco de empatía y piensa que ellos no pueden controlar todas las aplicaciones que están en producción como los que lo han desarrollado. 
  • Escalabilidad no es solo una palabra más terminada en …idad
    Creo que está de más decirlo, pero evitar mantener el estado en el servidor entre tus llamadas te permitirá escalar mejor. Tomate la molestia de planificar mecanismos de escalabilidad vertical y horizontal si no quieres morir de éxito. Corregir este tipo de problemas a posteriori siempre es traumático.
    Ten en cuenta que todos los recursos son limitados, hasta el disco donde escribes el log se acaba si no tienes políticas de reciclaje. Piensa en que los servicios están diseñados para ejecutarse 24x7 y 365 días al año, en estos detalles debemos hacer especial énfasis.
  • La correcta gestión de excepciones te puede salvar la vida
    En relación con la disponibilidad, es crítico gestionar de manera lo más eficiente posible las excepciones. La tecnología está ahí hace tiempo solo debes esforzarte en aplicarla correctamente. Una excepción en un servicio debe gestionarse correctamente para que no comprometa su estabilidad y disponibilidad. Trabajar sobre ello puede mejorar mucho la QoS y reducir el coste de mantenimiento.
  • Invierte tiempo en pensar bien tus contratos
    Es importante ajustar el equilibrio entre la cohesion de los servicios y los clientes. Cuando desarrollamos orientado a servicio no debemos hacerlo ad-hoc a un cliente en particular. El servicio debe exponer una serie de funcionalidades bien definidas. Extendiendo esta característica conseguimos el correcto grado de cohesión.
    Ahora tampoco hagas que usar tus servicios sea un infierno...
  • Piensa bien cual es la mejor manera de establecer la comunicación con tus servicios
    La serialización y transporte de los objetos es una parte muy significativa del tiempo de procesamiento consumido. Piensa cuidadosamente la manera de exponer tus servicios al mundo. expón los endpoints que sean necesarios y afina los behaviors de los mismos para evitar matar moscas a cañonazos.

Como siempre, se hace camino al andar, así que la resolución de los problemas presentes en este tipo de escenarios también tenderá a converger (para estandarizarse más adelante) mientras todos maduraremos en el proceso.

Por supuesto surgirán nuevos problemas relacionados con llevar el mundo del desarrollo de software más allá, que para algo estamos aquí, no?

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...