martes, 24 de septiembre de 2013

Iteraciones, valor y el nuevo San Mamés

El mundo de desarrollo de Software tiene su propia velocidad. Las ideas van y vienen, se crean tendencias, se testean nuevos enfoques y se descartan otros. Pero en otras áreas de la ingeniería en las que la responsabilidad civil es mayor, los cambios en los procesos tienen otros ciclos. Esto implica que no siempre es fácil ver como se plasman ideas consideradas axiomas por el agilismo.

Hoy os quería comentar un ejemplo relacionado con esto. Como los más futboleros sabéis, el Athletic Club de Bilbao ha creado un nuevo estadio de futbol, el Nuevo San Mamés (ni media vuelta al nombre)

Este proyecto tenia ciertas restricciones:

  • El nuevo estadio ocuparía parcialmente el área del anterior.
    Esto en el mundo del software sería algo parecido a tener código legacy. ;)
  • El equipo debe empezar a jugar la liga en este nuevo estado tan pronto como sea posible. (Las dos primeras jornadas en "casa" se jugaron en el estadio de la Real Sociedad)

Revisando la planificación del mismo, podemos observar que se dividieron los hitos a cubrir en tres fases:

Fase Operación Fecha fin
Inicio Primera piedra. 26 de mayo de 2010.
  Inicio de las obras. 25 de junio de 2010.
Fase 1 Construcción de las tribunas laterales y norte. Verano 2013.
  Primeros partidos. Temporada 2013/14.
Fase 2 Demolición del antiguo San Mamés. Temporada 2013/14.
Fase 3 Construcción de la tribuna sur. Verano 2014.
  Fin total de las obras. Temporada 2014/15.

Y este me ha parecido un muy buen ejemplo de buenas prácticas aplicadas a la obra civil.

Si nos fijamos:

  • Se hace un tratamiento especial sobre el hito principal del proyecto que ataca la restricción anteriormente citada (Jugar los primeros partidos en el estadio tan pronto como sea posible) dentro de la Fase 1.
  • Cada una de las fases tienen un claro objetivo y aportan valor.
    En todas se define un entregable (medible) que funciona y sobre el cual se iterará para dar más valor al cliente.

Este es el cometido de realizar nuestro trabajo en iteraciones, liberar valor lo antes posible. Esto también nos permite recoger feedbak lo antes posible para poder corregirlo (Creo que algún espectador le tocaron goteras ;)) y rebajar la presión sobre el proyecto general.

Además las entregas (siempre que cumplan las expectativas del cliente) generan confianza y crean una relación de colaboración que mejora la relación entre las partes y hace más fácil que el proyecto llegue a buen puerto.

Esta forma de desarrollar el proyecto, junto con la reducción de costes sobre lo originalmente planificado (también de capacidad), puede ser un buen caso de éxito de las técnicas de sentido común agilidad fuera del ámbito del Software.

viernes, 15 de febrero de 2013

Más allá del misterio: Asignando valores con el Revealing Module Pattern

Un patrón bastante extendido cuando desarrollamos código en JavaScript es el Revealing Module Pattern para poder establecer ámbito sobre ciertas partes de nuestro módulo. Quien más quien menos que desarrolle en JavaScript (y no esté en una cueva) ha oído hablar de él así que no vamos a hacer un análisis en detalle sobre el mismo.
Por otro lado, es bastante común exponer un objeto con los nombre de las propiedades que coincidentes con los métodos y propiedades que exponemos y aquí viene el punto propenso a errores que quiero mitigar con este post.
Imaginemos este código:
   1:  var Person = function () {
   2:      var name,
   3:          sayHello = function () {
   4:              alert('Hi, my name is ' + name);
   5:          };
   6:      return {
   7:          name: name,
   8:          sayHello: sayHello,
   9:      }
  10:  }
  11:   
  12:  var andoni = new Person();
  13:  andoni.name = 'andoni';
  14:  andoni.sayHello();



Si yo os pregunto que mostrará la función sayHello por pantalla, que me diríais?
Pues aunque no os lo creáis un bonito mensaje: "Hi, my name is undefined"
Ahora es cuando viene lo de:

“¿Pero que ha pasado? Si yo he asignado el name a "Andoni"!!!

Esto seguro que es por lo del this, o lo del lexical scope … JavaScript es un mierda y que porque no nos habremos quedado en la era de COBOL...”

Que no cunda el pánico, vamos a entender que ha pasado antes de pegarle fuego a V8, Chakra y a todo lo que se mueva...

Tened en cuenta que si aplicamos el patrón, la función nos devuelve otro objeto con dos propiedades (name y sayHello). Cada una de ellas apunta a los objetos reales que está revelando. El código que hemos visto arriba recibe ese objeto y lo que está haciendo es cambiar a que apunta la propiedad name del objeto revelado, que obviamente, no es lo que esperábamos... (recordad los punteros)

Revisemos nuestro código problemático con una modificación:

   1:  var Person = function () { 
   2:      var name, 
   3:          setName = function(nameToSet){ 
   4:              name = nameToSet; 
   5:          }, 
   6:          sayHello = function () { 
   7:              alert('Hi, my name is ' + name); 
   8:          }; 
   9:      return { 
  10:          name: name, 
  11:          setName: setName, 
  12:          sayHello: sayHello, 
  13:      } 
  14:  }
  15:   
  16:  var andoni = new Person(); 
  17:  andoni.setName('andoni'); 
  18:  andoni.sayHello();



Ahora si que recibiremos el mensaje esperado, debido a que la modificación se esta realizando sobre el mismo objeto y no sobre la propiedad del proxy que nos está siendo revelado.

Es un problema sutil y en ocasiones difícil de corregir así que espero que les sea de utilidad.

Un saludo desde Seattle!!

Andoni Arroyo

viernes, 30 de noviembre de 2012

[Off-Topic] Javascript – Desde cero hacia las mejores prácticas (Materiales de la charla)


El pasado día 29 de noviembre tuve el placer de dar una charla en el comité sobre JavaScript con el título “Javascript – Desde cero hacia las mejores prácticas”

Aquí os dejo los materiales de la charla por si os pueden resultar de interés.

Descargar materiales

Un saludo

Andoni Arroyo

lunes, 23 de julio de 2012

Como desarrollar con Javascript y no morir (ni matar) en el intento – III


En JavaScript el concepto de Objeto representa un papel clave. Si tenemos en cuenta que no existe el concepto de clase que manejamos en otros lenguajes, es el objeto sobre el que recae la responsabilidad de definir el modelo y almacenar el valor de la instancia.

Una vez interiorizado este concepto, (superado el shock…) debemos tener en cuenta que en JavaScript disponemos de cinco tipos primitivos por valor que son: number, string, boolean, null, y undefined. Todo lo demás son objetos (más o menos especializados)

Estos tipos por valor (exceptuando null y undefined) poseen lo que se conoce como primitive wrapper objects. Los objetos wrapper pueden ser creados utilizando los constructores predefinidos Number(), String(), y Boolean()

Veamos este código al respecto:

   1:          //// number (primitivo)
   2:          var n = 100;
   3:          console.log(typeof n); // "number"
   4:          // objeto Number 
   5:          var nobj = new Number(100);
   6:          console.log(typeof nobj); // "object"

Estos objetos exponen una serie de métodos que nos ayudan a trabajar con la naturaleza de los datos a los que representan. Por ejemplo el objeto Number expone métodos como toFixed() o toExponential o el objeto String los métodos substring(), charAt() o toLowerCase().

Como hemos comentado alguna vez JavaScript es muy propenso a interpretar de la mejor manera que pueda el código e intentar hacer que funcione, con resultados algunas veces imprevistos.

¿Que os parece si os digo que estos métodos pueden ser aplicados también sobre los métodos primitivos por valor?

Pues en principio lo menos que os puede parecer es raro… Bueno, lo que esta ocurriendo detrás de la escena es que JavaScript promociona puntualmente el tipo primitivo a su correspondiente objeto, ejecuta el método y a continuación descarta el objeto creado. Lo dicho, buenas intenciones pero si no conocemos este comportamiento, puede provocar más de un dolor de cabeza…

Por ejemplo, como se nos ocurra la idea de aumentar un tipo primitivo, el interprete de JavaScript no nos arrojará ningún error, puesto que desde el punto de vista sintáctico todo está correcto, pero la propiedad incluida lo será sobre el objeto que se descartará automáticamente con lo que mal negocio hemos hecho.

Veamos un código que ilustra este ejemplo:

 
   1:          // string primitivo
   2:          var enterprise = "Plain Concepts";
   3:          // El primitivo es convertido a un objeto con el fin
   4:          // de ejecutar el método split()
   5:          console.log(enterprise.split(' ')[0]); // "Plain"
   6:          // Si intentamos aumentar un tipo primitivo no es un 
   7:          // error
   8:          enterprise.CIF = "XXXXXXXXXX";
   9:          // pero como el objeto es decartado automaticamente después de
  10:          // la promoción, la propiedad se pierde...
  11:          console.log(enterprise.CIF); // "undefined"​​





Este comportamiento, no ocurriría si instanciamos un objeto del tipo concreto (String(), Number(), Boolean()… ), por lo que si estamos pensando en aumentar el objeto creado no es buena idea usar los primitivos. 

También podríamos usar el constructor Object que incluye cierta lógica para crear el tipo derivado apropiado en base al valor recibido. (Una especie de factory)
 
Por ejemplo:
 

   1:           var n = new Object(3);
   2:           console.log(n instanceof Number); // True


 
Esta característica es un arma de doble filo puesto que nos puede llevar a errores o comportamientos inesperados cuando empleamos tipos dinámicos, por lo que en general se desaconseja su empleo siendo mas aconsejable (por sencilla y certera) emplear la notación literal.
 


 

miércoles, 18 de julio de 2012

Como desarrollar con Javascript y no morir (ni matar) en el intento – II


Cuando trabajamos con JavaScript una de las características que más quebraderos de cabeza nos pueden dar es el ámbito de las variables. Así como en otros lenguajes tenemos la capacidad de definir un ámbito dentro de varios elementos (por ejemplo en C# dentro de una clase, método, usign…) en JavaScript el único elemento que nos permite definir ámbito es el objeto function. (Y digo objeto porque en JavaScript una función es un Objeto, es decir puede tener propiedades y métodos…)

Hoy vamos a analizar un efecto conocido como Hoisting. Este efecto ocurre porque en JavaScript podemos dispersar las declaraciones de nuestras variables a lo largo de nuestra aplicación.

Veamos el siguiente código:

   1:          var name = "global name";
   2:          // global variable 
   3:          function func() 
   4:          {    
   5:              console.log ('name value: ' + name);   // undefined   
   6:              var name = "local name";    
   7:              console.log('name value after assign value: ' + name);  
                                                          //local name
   8:          };
   9:          func(); 

Como podéis ver en este código tenemos una variable “name” con el mismo nombre en el ámbito global y dentro de la función. Como hemos comentado antes, la función nos permite definir ámbito de variables, por lo que la variable “name” es diferente dentro y fuera de la misma.
Si analizamos el código anterior podemos observar que en la línea 5 se accede a la variable “name”. Sería lógico espera que dicha variable tenga el valor “global name” pero aquí entra en juego la característica de JavaScript llamada Hosting

Con este nombre, JavaScript nos permite colocar múltiples “var” en cualquier punto de la función de tal manera que ellos funcionen como si hubiesen sido declarados al principio de la función.

Lo que tenemos que tener en cuenta es que la declaración de la variable se promociona al tope de la función (como si “var name” se colocase antes de la fila 5) pero la inicialización de la misma se ejecuta en el punto definido (la línea 6 en el código anterior). Es por eso que ocurre el efecto comentado anteriormente, es decir, en la línea 5 la variable “name” de la función (“var name”) se ha ejecutado pero no la inicialización de la misma. (Por eso el valor undefined)

Una vez entendido como funciona y con el fin de evitar errores un tanto confusos que disparen el coste de mantenimiento, un buen hábito es asumir la convención de definir todas las variables que vamos a usar al principio de la misma.

martes, 17 de julio de 2012

[Material del evento] Porque debería automatizar mis pruebas?

Os he dejado en mi skydrive el material del evento Porque debería automatizar mis pruebas? que vimos en el Centro de Innovación Social de Bilbao.

Espero que os resulte interesante, un saludo.

Como desarrollar con Javascript y no morir (ni matar) en el intento


Cada día son más las aplicaciones que cuentan con JavaScript como lenguaje de programación.
El motivo de este éxito anunciado es, entre otro, la ubicuidad de este lenguaje, y es que correr en “casi” todos los navegadores instalados a lo largo y ancho del mundo no es poca cosa.

La Web actual requiere cada vez una mayor carga de programación en cliente, hace un uso cada vez más intensivo de las capacidades del mismo (manejo del DOM, AJAX, Almacenamiento en local…) Además existen otros tipos de escenarios donde tradicionalmente JavaScript no tenía presencia (las aplicaciones nativas para Windows, aplicaciones para dispositivos móviles…) que también van convirtiéndose en terreno abonado para JavaScript.
Un claro ejemplo de este cambio ha sido confirmado con la aparición de Windows 8 y su Interfaz Metro. En él, JavaScript se presenta como un lenguaje de cliente de primera clase para desarrollar aplicaciones. Esto lo hace comparable a los hasta ahora intocables lenguajes manejados como C# o VB presentes en WPF o Silverlight.

Este cambio ha sido posible gracias en gran medida a incluir ciertas características que antes formaban  parte de .NET a nivel del Sistema Operativo y, por lo tanto, consumible desde un entorno no manejado como en el que se ejecuta JavaScript. (Internet Explorer)

Además de Metro, en las aplicaciones móviles también JavaScript es bastante común para conseguir reutilización entre plataformas, contando con ciertas artistas invitados como Phonegap

Y es por todo esto que las comunidades de desarrolladores muy versadas en entornos muy avanzados de programación (como la gente de .NET o Java) van aterrizando en JavaScript y en la mayoría de ocasiones su primera sensación viene a resumirse en la muy común frase “vaya m***** es JavaScript”

Bueno pues la realidad es que sin estar al nivel de los lenguajes y marcos de trabajo modernos tampoco es tan malo como al principio creemos. Lo que si es necesario es realizar el esfuerzo de entender las aproximaciones con las que JavaScript afronta algunos de los problemas comunes. Esta tarea es la que vamos a realizar en esta serie de entradas ayudándonos a encajar los conceptos básicos.
Una de las primeras cosas que debemos tener en cuentas es:

“El problema con las variables globales”

Las variables globales (como su nombre indica) son compartidas a través de todo el código de tu aplicación JavaScript o página Web. Esto quiere decir que la superficie de colisión de dichas  variables es sencillamente: toda tu aplicación, con lo cual es relativamente probable definir diferentes variables globales con el mismo nombre pero diferentes propósitos.

Para entender este problema debemos ser conscientes de que JavaScript es esencialmente propenso a ayudar a que nuestra aplicación funcione a costa de no ser (a veces excesivamente) riguroso en sus validaciones (algo mejorado con el uso del strict)

Se dan dos características para la propensión a este problema:
  • En JavaScript podemos utilizar una variable que no hayamos definido
  • Cualquier variable que no hayamos declarado se convierte automáticamente en la propiedad del objeto global
Veamos un ejemplo:

(Tened en cuenta que en JavaScript el unico elemento que nos permite definir ámbito es el objeto fuction)

   1:   
   2:          function sum(x, y) {
   3:              result = x + y;
   4:              return result;
   5:          }
   6:          console.log(sum(2, 4));  // 6
   7:          console.log(result);  // 6

Como podemos observar aunque el ámbito de la variable result se desea limitar a la function sum en la que se emplea sigue viva fuera de la misma.
La regla de oro es aplicar siempre la palabra reservada var. Este mismo código declarando resutl con un var por delante nos daría un bonito:

Uncaught ReferenceError: result is not defined al ejecutar el código de la línea 7

Sencillo ¿verdad?

Veamos otro código muy similar al anterior pero incluyendo el var que aun  así no funciona como esperamos:

   1:          function foo() 
   2:          {    
   3:              var a = b = 0;
   4:          }
   5:          foo();
   6:          console.log(b);

En este caso lo que está ocurriendo es que solo se aplica el var a la variable a, que se está inicializando con el resultado de la asignación de b = 0. Pero con b nos está ocurriendo lo mismo que en el ejemplo anterior, la estamos usando antes de declararla por lo tanto es un variable global
Hay muchos aspectos sobre los que podemos ir comentando particularidades de JavaScript así que estad atentos.

jueves, 12 de abril de 2012

Evento: Porque debería automatizar mis pruebas?


El próximo día 17 de Abril a las 19:00 tengo el placer de dar una charla con el título ¿Porque debería automatizar mis pruebas? dentro del marco de actividades del grupo WebDev Bilbao en el Centro de Innovación Social de Bilbao.

En la misma hablaremos, entre otras cosas, sobre:

  • Cuales son los aspectos más importantes a la hora de automatizar nuestras pruebas.
  • Que podemos aspirar a conseguir con dicha automatización.
  • Candidatos a la automatización.
  • Porque automatizar las pruebas es más que una técnica.
  • Terminología del mundo de las pruebas.
  • Economía de la automatización de pruebas.
  • ROI.
  • Características del buen test.
  • Problemas comunes.
  • Como organizar nuestros tests.
  • Métodos de diseño de tests.
  • Tipos de tests (que no solo existen test unitarios!!)
  • Estrategias de verificación.

Vamos, de todo un poco sobre un tema tan interesante como es el de la automatización de nuestras pruebas.

Os espero por ahí para hacer el evento lo más interesante posible.

lunes, 6 de febrero de 2012

Cambios y expectativas (Plain Concepts +1)

Es tiempo de cambios para mí. Dejo de trabajar en Panda Security para comenzar una nueva etapa en Plain Concepts.

Haciendo balance de mi paso por Panda Security, el resultado es francamente positivo. He aprendido mucho, trabajando en equipos formados por gente muy diferente (alemanes, cubanos, americanos…) lo cual me ha permitido evolucionar como profesional y como persona. Tópico, pero verdad…

Entonces, por que cambiar?

Pues porque es mucho lo que espero de mi nueva empresa:

  • Gestión ágil (de verdad), con todo lo que eso implica.
  • Proyectos interesantes, avanzados tecnológicamente y con requerimientos exigentes.
  • Compañeros motivados, capaces de compartir sus conocimientos y estar abiertos siempre a la mejora. Conozco hace tiempo a mucho de ellos de la comunidad, eventos y otro saraos. Son el tipo de gente con el que da gusto trabajar.
  • Conocer un montón de gente interesante de la que aprender, tanto dentro como fuera de la empresa. Trabajando duro para ser el peor, como comentaba Dawn Cannan en su articulo: Be the Worst en Agile Record)

Un sitio definitivamente donde poder trabajar con alta motivación, que me ayude a evolucionar aportando mi esfuerzo y plantee retos que sean beneficiosos para ambas partes.

Estoy seguro que esto y mucho más va a ser lo que voy a encontrar allí.

Estamos en contacto.

martes, 31 de enero de 2012

Invocando un servicio WCF desde una aplicación Metro (desde la misma máquina!!)


El otro día hablábamos de las limitaciones de comunicación entre aplicaciones Metro y Desktop hospedadas en la misma máquina establecidas en Windows 8. De hecho, hablábamos de la “NO” comunicación entre Metro y Desktop. Los pistoleros más rápidos dirán que donde dije Digo ahora digo Diego, pero esperar un poco antes de apedrearme en la plaza pública…

Comentábamos que por diseño, invocar desde una aplicación Metro a un servicio WCF expuesto en la misma máquina, no está permitido. Esto puede ser una restricción demasiado estricta (y totalmente injustificadas) si estamos desarrollando en la misma máquina el servicio y la parte Metro que la consume.

Para este tipo de casos (y no para saltarnos el control, que no tenéis una idea buena...) contamos con una herramienta de línea de comandos llamada CheckNetIsolation. Podemos leer un poco más al respecto aquí http://msdn.microsoft.com/en-us/library/windows/apps/hh452759.aspx

Acorde a dicha restricción, al acceder a dicho servicio, la aplicación Metro (sin ningún tratamiento previo) recibiremos una excepción del tipo EndPointNotFopundException con un mensaje tal que así:

{"There was no endpoint listening at ... that could accept the message. This is often caused by an incorrect address or SOAP action. See InnerException, if present, for more details."}

Ok, a menos de que creas que la gente de Microsoft va de farol, es lo esperado, no?

Ahora viene lo interesante. Para permitir este tipo de comunicación (recuerda que la limitación solo se aplica a la misma máquina) debes seguir estos pasos:

Lo primero que debemos hacer es buscar en el registro la clave de la aplicación Metro con la que deseamos hacer la excepción. Para ello, abrimos el Regedit y buscamos la clave de la aplicación que cuelga de:

HKEY_CURRENT_USER\Software\Classes\Local Settings\Software\Microsoft\Windows\CurrentVersion\AppContainer

Fíjate en el valor de la propiedad displayname para poder identificarla.
Una vez que sepamos la rama concreta, puedes seleccionarla con el botón derecho y copykeyname y selecciona el nombre de la carpeta del mapping (desde S-1-15... hasta el final). Este <keyname> nos permitirá establecer la excepción más adelante.

A continuación, abre el “Developer Command Promp” y escribe “CheckNetIsolation” para acceder a la utilidad. Pégate una leidita el enlace anterior para evaluar un poco mas en detalle las capacidades de la herramienta.

En nuestro caso debemos escribir:

  • Para ver el listado de las aplicaciones ya excluidas del bloqueo de loopback:
    CheckNetIsolation.Exe LoopbackExempt –s
  • Para incluir nuestra aplicación como una excepción:
    CheckNetIsolation.exe LoopbackExempt -a -p=<keyname>
  • Para comprobar que ya ha sido correctamente incluida, pues vuelve a ejecutar el comando anterior (nunca te lo hubieses imaginado, verdad?)
    CheckNetIsolation.Exe LoopbackExempt –s

Una vez hecho esto, ya podremos consumir servicios de la misma máquina sin recibir la excepción comentada al principio del post, comprobado!!

miércoles, 25 de enero de 2012

Windows 8 y la “NO” comunicación entre Metro y Desktop

Windows 8 va cogiendo forma, y lo que vamos viendo nos confirma que la gente de Redmond está haciendo una apuesta muy fuerte por evolucionar su sistema hacia diferentes dispositivos. Un único sistema operativo para ordenadores y tabletas (dejemos los teléfonos de momento…) implica un profundo replanteamiento del mismo, desde sus cimientos.

Por un lado tenemos un gran hito para Windows 8 es la necesidad de correr sobre procesadores ARM. Por otro lado, Microsoft tradicionalmente se aplica en  maximizar la compatibilidad hacia atrás. Este es un compromiso que tradicionalmente le ha diferenciado de la competencia digamos más “intrépida” en sus evoluciones/revoluciones.

El resultado de aplicar este par de fuerzas, en principio opuestas (compatibilidad hacia atrás VS evolución hacia la ligereza) implica casi tener dos sistemas operativos en uno. Es muy interesante la lectura de este post Windows 8 – A Tale of Two Platforms al respecto.

Siempre que se produce un cambio profundo como este, se generan por un lado un buen montón de riesgos a mitigar así como otro montón de oportunidades a aprovechar. Cuando comenzamos a evaluar la posibilidad de que nuestras aplicaciones corran sobre Windows 8 siempre comenzamos a pensar en los componentes que la conforman y en como ir migrándolos hacia la nueva plataforma.

Quien más quien menos ha oído o va a oír al respecto:
“Este servicio lo dejo igual y desde la interfaz metro lo invoco y...”

Pero en esta aproximación hay un demonio escondido: crea un dependencia de la parte de aplicaciones “Metro” hacia la parte “Desktop” y ese no es el camino que Microsoft fomenta. Tengamos en cuenta que si todos los desarrolladores aplican ese proceso, la parte “Metro” de Windows 8 nunca podrá correr sin la parte “Desktop”. Ese es el precio a pagar por dicha dependencia.

Podemos ver esta división en el siguiente gráfico:
image

Comprobamos que no existe un canal de comunicación oficial por encima del Kernel de Windows (que obviamente, comparten) para realizar comunicaciones entre aplicaciones “Metro” y “Desktop”.

La pregunta (muy común y cada vez más) es clara:
¿Como puedo comunicar entre aplicaciones Metro y Desktop?

La respuesta no es tan clara, pero desde luego no es algo que en principio Microsoft fomente.
El modelo de procesamiento en la nube y clientes ligeros es el candidato por todas las grandes a la hora de llegar a diferentes dispositivos y es también es el que Microsoft promociona. Este escenario ha demostrado su éxito en la competencia y algo sabe esta empresa de aprender de los demás.

Una posible solución (por supuesto depende de la naturaleza de cada aplicación) es llevar toda la lógica de tu aplicación a tu proveedor de Cloud (Azure, Amazon, GAE…) y dejar un cliente bien ligero en “Metro” que consuma de manera optimizada dichos servicios. (Debemos tener en cuenta que en Metro solo se ha migrado la parte de cliente de WCF!!).

Obviamente este modelo también tiene su problemática a resolver, como por ejemplo como comportarse en caso de no tener comunicación.
Con el fin de confirmar las limitaciones de comunicación entre aplicaciones “Metro” y “Desktop” podemos leer:

  • Ale Contenti comentaba que la comunicación entre aplicaciones de ambos mundos es a nivel de archivo. (aunque también dice que es muy pronto para confirmarlo)
    http://channel9.msdn.com/Events/BUILD/BUILD2011/TOOL-789C
  • Otra idea podría ser montar un Servicio Web en la parte Desktop:
    Respecto a eso, podemos leer a Jeff Sanders en los foros de soporte de Microsoft:

    “You cannot access a WebService on the same machine. The WebService would need to be external to the machine ... In Metro you cannot use IPC except with Metro Style applications that are in the same package.”Otro día hablamos de CheckNetIsolation.exe, prometido!
  • Pero estas restricciones de comunicación no solo existen a alto nivel. Podemos leer a Pavel Minaev:

    ”… Named pipes aren't there, for example, nor are memory mapped files. There are sockets (including server sockets), but when connecting to localhost, you can only connect to the same app. You could use normal files in one of the shared "known folders" (Documents, Pictures etc), but that is a fairly crude hack that necessitates polling and is visible to the user.”

A buen entendedor pocas palabras bastan. Podemos ver claro que este canal de comunicación no es el deseado. Y esto es comprensible, puesto que si pensamos un poco en los diferentes escenarios sobre los que deseamos corra Windows 8 podemos observar que:
  • PCs Legacy corriendo Windows 8 donde se ejecutarán aplicaciones Legacy pero no van a aprovechar las bondades de las aplicaciones basadas en interfaces táctil (Metro/WinRT)
  • Tabletas x86 donde podrán correr aplicaciones Legacy que por otro lado, si sacaran el máximo a las aplicaciones metro. Eso si, tendremos que tener en cuenta temas como peso, vida de la batería, coste...
  • Tabletas basadas en ARM donde las aplicaciones Legacy (salvo que Microsoft se saque algo de la chistera...) no van a correr, pero sacarán el máximo de Metro.
Resumiendo podemos decir que Windows 8 tiene dos caras, es muy importante comprender esto para poder afrontar las migraciones y nuevos desarrollos con la perspectiva adecuada al nuevo panorama que se nos presenta.

miércoles, 4 de enero de 2012

POCOs con piel de cordero

Reconozcámoslo, automatizar cualquier proceso es gratifícateme pero no siempre es fácil. Todos alguna vez hemos aparcado muy buenos propósitos (como los año nuevo…) debido a los impedimentos encontrados por el camino.

He sufrido este fenómeno recientemente en una empresa que todos conocemos (y no puedo nombrar ;)) hace bien poquito con un intento de aplicar TDD en los equipo de desarrollo debido a los plazos de entrega tan ajustados que se manejaban.

Sintiéndolo mucho, debemos decir que esto es lo normal.

Afortunadamente igual de normal tener el deseo de mejorar y eso nos impulsa hacia caminos que sabemos van a ser ventajosos. Uno de ellos es automatizar las pruebas en nuestros proyectos. En torno a un 40% del tiempo destinado a un proyecto se dedica a probar, así que invertir en este campo parece una apuesta segura.
Centrándome en el propósito del post (que me voy por las ramas) hace poco he estado trabajando con un equipo que tenía algunas dudas frente a como automatizar las pruebas sobre algunas clases de una determinada funcionalidad.

Poco más o menos la queja era:
Tenemos una clase que no podemos desacoplar (como nos has dado la paliza 100 veces) puesto que .NET me obliga a que herede de otra puesto que lee del fichero de configuración...
Por no entrar a demasiado detalle digamos que tenían unas clases que ellos creían POCO, pero que realmente no lo eran, puesto que tenían unos bonitos atributos que se habian pasado por alto.
La solución del problema fue crear un mock la clase directamente (los frameworks de Mock “modernos” nos permiten hacer esto) y mockear de ciertas propiedades que se estaban consumiendo desde el código para conseguir el nivel de aislamiento necesario y poder realizar las prueba unitaria. Por supuesto, desde la prueba unitaria tuvimos que añadir los mismos atributos que tenía el código real y conseguimos que el test funcionara correctamente.
Lo más interesante de todo esto son las conclusiones que podemos extraer de la experiencia:
Cuando en DDD hablamos de que las clases deben ser POCO es por algo. Todo lo demás es infraestructura. La tecnología es infraestructura. En este ejemplo, esos atributos tan inofensivos, son tecnología y hacen que esas clases aparentemente POCO no lo sean. (se mapean de un fichero de configuración!!)
Por eso digo en el título que estos POCO son lobos con piel de cordero.
La siguiente pregunta es ¿Debemos probar el código de infraestructura?
Pues la respuesta es SÍ. Es parte de nuestra aplicación y debemos probarlo, pero probablemente tengamos una política de testeo diferente. Debemos en la medida de lo posible, hacer que dichos “adaptadores” sean lo más sencillos posibles facilitando su testo.

Podemos decidir alcanzar una cobertura menor en pruebas unitarias y realizar un mayor esfuerzo en pruebas de integración.
Como siempre, la clave del éxito radica ajustar la relación del esfuerzo que nos supone desarrollar (y mantener) una batería de pruebas optima para en contexto (Core Business / Infraestructura…) en el que nos encontramos, con el retorno de valor que de la mismas obtenemos.
Por cierto, feliz 2012 ;)

martes, 20 de diciembre de 2011

Certificados, ficheros y claves privadas

Últimamente por motivos relacionados con mi trabajo me he tenido que ir introduciendo cada vez más y más en el mundo de la seguridad informática. Es un campo muy extenso e interesante pero también un tanto oscuro en algunos puntos. (sobre todo si no das con las fuentes de información adecuadas)

En este ecosistema de seguridad, como ya conocemos todos en mayor o menor medida, los certificados de seguridad juegan un papel de lo más importante. ¿Quien no ha oído hablar de los certificados X509?

Windows incluye una herramienta para gestionar los certificados que tenemos instalados en la máquina/máquinas. Más concretamente es un complemento de la Microsoft Management Console (a.k.a. navaja suiza) llamado “Certificates”. Esta herramienta es de lo más conocida y podéis encontrar mucha documentación sobre ella en el MSDN, por ejemplo aquí.

Curioseando con la instalación de los certificados me surgió la pregunta sobre donde Windows almacena la clave privada de los mismos. Leyendo una poco al respecto, encontré una herramienta que nos aporta dicha información llamada Find Private Key Tool.

Dicha herramienta nos permite a través de la línea de comandos, preguntar sobre un determinado certificado ( filtrando por diferentes características como su subject, thumbprint…). En caso de existir un certificado que se adapte a los parámetros solicitados,  nos retornara el nombre del fichero que le da soporte. Esta información nos puede ser necesaria en caso de tener que ajustar los permisos de las acciones que sobre el mismo se deben permitir. El caso más típico es acceder a la clave privada de un certificado (por código) con un usuario con permisos restringidos (por ejemplo el application pool identity de una aplicación ASP.NET)

Según la especificación de la herramienta:

  1: Usage: FindPrivateKey <storeName> <storeLocation> [{ {-n <subjectName>} | {-t <thumbprint>} } [-f | -d | -a]]
  2:        <subjectName> subject name of the certificate
  3:        <thumbprint>  thumbprint of the certificate (use certmgr.exe to get it)
  4:        -f            output file name only
  5:        -d            output directory only
  6:        -a            output absolute file name

Ejemplos de comandos:


Buscar en StoreName “My”  y Store Location “CurrentUser” un certificado con el Subject  CN=TESTCERT (CN es el Common Name, que forma parte del Subject)

  1: FindPrivateKey My CurrentUser -n "CN=TESTCERT"

Buscar en StoreName “My” y Store Location “LocalMachine” un certificado con el Thumbprint pasado por parámetro

  1: FindPrivateKey My LocalMachine -t "40 ee 7b 2f 10 59 38 99 4f 65 9f 8f 92 38 85 a3" –c

En caso de que el certificado solicitado exista, la herramienta nos devolverá algo como:

  1: Private key directory:
  2: C:\ProgramData\Microsoft\Crypto\RSA\MachineKeys
  3: Private key file name:
  4: <GUID>

Siendo el GUID el nombre del fichero asociado que almacena la clave privada. Una vez localizado podemos modificar sus permisos si para alguno de nuestros procesos esto es necesario.

jueves, 21 de julio de 2011

Retrospective [Evento: SCRUM y conceptos ágiles]]


El pasado día 19 de Julio dentro del marco WebDev Bilbao tuve la suerte de dar una charla sobre SCRUM y conceptos ágiles. Me gustaría realizar una pequeña retrospectiva del mismo y sacar algunas conclusiones:

  • Presencia
    Lo primero que me llamó al atención fue la buena acogida del evento en la comunidad. Superó en número todas las expectativas, más teniendo en cuenta, que la charla fue de 19:00 a 21:00 en un día de verano (que cayese el diluvio universal igual ayudó...)
    Se confirma, una vez más, que la inquietud por las metodologías ágiles es grande, la tendencia cada vez mayor.
  • Perfiles
    Entre los asistentes existían diferentes perfiles. Hubo gente con mucha experiencia en gestión y gente más joven. La combinación de todos ellos nos ayudo a completar la foto desde diferentes perspectivas. Comprobamos una vez más, que las bondades de SCRUM lo son tanto para los gestores como para los desarrolladores. A golpe de empatía llegamos rápidamente a acuerdos.

    Aun así, algunos perfiles se echaron de menos. No hubo presencia (al menos hasta donde yo pude comprobar) de ningún Tester o QA. Su integración en los equipos es un punto muy interesante por lo que me hubiera gustado contar con alguien que aportase dicha visión.
    También noté la falta de diseñadores Web o gráficos. Este es un perfil que tiene presencia en WebDev Bilbao y que tiene una integración particular en los equipos de desarrollo. También eché en falta su voz.

    Otra vez será...(o eso espero!)
  • Empresas pequeñas, startups...
    Bilbao es una zona de emprendedores. Combinado con las “facilidades” de nuestro sector la presencia de startups y microempresas es muy significativa en este tipo de actividades. Los profesionales de este tipo de empresas están especialmente sensibilizados con aspectos como el trato al cliente, time to market... Además necesitan más que nadie dedicar su capacidad (más limitada que en empresas más grandes) a los aspectos que realmente aportan valor.

    Por otro lado, también discutimos sobre por dónde empezar en una empresa más grande y como concienciar a los gestores más reaccionarios sobre las bondades de la agilidad.
  • Poco conocimiento previo sobre SCRUM
    Algo que me sorprendió, es que muchos de los profesionales que acudieron no conocían nada o casi nada acerca de SCRUM. Quizás deba ampliar mi circulo de colegas, puesto que mi percepción estaba, me temo, distorsionada...

    Es importante para evitar que la brecha se siga abriendo realizar ciertas acciones de iniciación a las metodología ágiles orientadas a sentar las bases sobre las cuales podamos autoformarnos o elegir el sabor que mejor nos encaje.


Resumiendo, creo que el balance de la actividad es muy positivo. Ha quedado patente el interés que los desarrolladores, manager y demás stakeholder tienen por mejorar a través de la agilidad.
Desde el grupo de Agilidad y gestión de proyectos de WebDev Bilbao tomamos nota y continuaremos trabajando en otras actividades. Con algunas de ellas intentaremos profundizar más en aspectos que ya hemos ido tocando, como por ejemplo, gestión de contratos ágiles, liderazgo, documentación...(sí puede haberla!!)

También intentaremos abrir otras líneas como una introducción al Kanban o confrontar las metodologías ágiles con otras más predictivas, que no solo de SCRUM vive el hombre.

Por supuesto, si eres, trabajas o pasas por Bilbao no dudes en pasarte por el WebDev Bilbao que serás bienvenido!

Por cierto, os podéis descargar la presentación de la charla de aquí (hay más cosas en Prototypes, cotillea al gusto ;))

miércoles, 13 de julio de 2011

Evento: SCRUM y conceptos ágiles

El próximo día 19 de Julio, tengo el placer de dar una charla sobre SCRUM y conceptos ágiles dentro del marco de actividades del grupo WebDev Bilbao. En ella, explicaré algunos conceptos claves sobre agilidad y analizaremos las propuestas de SCRUM sobre como afrontarlos.

A quien va dirigido

  • Gestores de proyectos de desarrollo de Software.
  • Product mangers y Stakeholders interesados en agilidad.
  • Por supuesto, desarrolladores!

Fecha y hora:

  • 19 de Julio de 2011 a las 19:00
  • Eutokia (Centro de Innovación Social de Bilbao)

Nota:
Aunque en principio el acceso a estos eventos está restringido a la gente del grupo de WebDeb Bilbao, si quieres pasarte puedes enviarme un correo electrónico a andoni.arroyo@gmail.com y veremos que podemos hacer ;)

viernes, 8 de julio de 2011

Silverlight y las excepciones no gestionadas

Silverlight nace para cubrir las necesidades de aplicaciones RIA, y como sabemos, las aplicaciones de Internet son exigentes en muchos aspectos. Es debido a dicha concepción, que posee ciertas características muy interesantes para escenarios para los que originalmente no fue creado.

Por ejemplo, la huella en memoria de Silverlight es sensiblemente menor que incuso para el .NET Framework Client Profile. Además el tamaño del instalador es también varias veces menos que dicho (de 28MB a 6MB ). Estos detalles que nos pueden parecer banales, no lo son tanto, si multiplicamos dichas diferencias por muchos millones de descargas o requerimientos de Hardware…

Teniendo en cuenta estas ventajas y que las partes más comunes de WPF se encuentra también presente en Silverlight, este se presenta como un candidato válido para desarrollo de aplicaciones de escritorio. (Ahora que está tan de moda HTML5/JS…)

Este modo de trabajo se conoce como “out of browser” (OOB). Tengamos en cuenta que la misma aplicación puede ejecutarse dentro y fuera del navegador, en principio, en base a que el usuario decida instalarla.

Si deseamos desarrollar aplicaciones de escritorio, podríamos distribuir nuestro .xap como parte del instalador de la aplicación completa, evitando dar la posibilidad de ejecutarla en el navegador (El host va a ser el sllauncher.exe)

Las mayores restricciones en este aspecto están relacionadas con la interacción con el Sistema Operativo y acceso a recursos de la máquina local. Si vuestro conjunto de requisitos de interacción en el puesto cliente no son muy elevadas, es posible que Silverlight pueda ser vuestra tecnología de cliente.

En esta forma de trabajo, debemos evaluar la conveniencia de algunos de los planteamientos del equipo de Microsoft y adaptarlos a nuestras necesidades. La gestión predeterminada de las excepciones no gestionadas que nos propone Visual Studio no está pensada si deseamos crear una aplicación de escritorio.

Si vemos el código que nos propone el Visual Studio al crear el proyecto de Silverlight observamos:

  1:         private void Application_UnhandledException(object sender, ApplicationUnhandledExceptionEventArgs e)
  2:         {
  3:             // If the app is running outside of the debugger then report the exception using
  4:             // the browser's exception mechanism. On IE this will display it a yellow alert 
  5:             // icon in the status bar and Firefox will display a script error.
  6:             if (!System.Diagnostics.Debugger.IsAttached)
  7:             {
  8:
  9:                 // NOTE: This will allow the application to continue running after an exception has been thrown
 10:                 // but not handled. 
 11:                 // For production applications this error handling should be replaced with something that will 
 12:                 // report the error to the website and stop the application.
 13:                 e.Handled = true;
 14:                 Deployment.Current.Dispatcher.BeginInvoke(delegate { ReportErrorToDOM(e); });
 15:             }
 16:         }
 17:
 18:         private void ReportErrorToDOM(ApplicationUnhandledExceptionEventArgs e)
 19:         {
 20:             try
 21:             {
 22:                 string errorMsg = e.ExceptionObject.Message + e.ExceptionObject.StackTrace;
 23:                 errorMsg = errorMsg.Replace('"', '\'').Replace("\r\n", @"\n");
 24:
 25:                 System.Windows.Browser.HtmlPage.Window.Eval("throw new Error(\"Unhandled Error in Silverlight Application " + errorMsg + "\");");
 26:             }
 27:             catch (Exception)
 28:             {
 29:             }
 30:         }

Como vemos se incluye una función para interactuar con el DOM. Esto no tiene sentido si nuestra aplicación va a correr siempre en modo OOB. Además comprueba si no tenemos el depurador adjunto para realizar esta notificación…

Vamos a comenzar a modificar este comportamiento para que se adapte a nuestras necesidades.


Lo primero vamos a hacer es cambiar el código del método Application_UnhandledException y eliminar la función ReportErrorToDOM.

El resultado quedaría algo así:

  1:         private void Application_UnhandledException(object sender, ApplicationUnhandledExceptionEventArgs e)
  2:         {
  3:             e.Handled = true;
  4:             new ExceptionDetailView {DataContext = new ExceptionDetailViewModel(e.ExceptionObject)}.Show();
  5:         }


Sencillo, verdad?


Antes de nada marcamos como tratado el parámetro recibido para notificar que ya ha sido tratada y que no escale más por la pila de excepciones. Además mostramos un mensaje de error por pantalla notificando al usuario que se ha producido un error.

Este sería un punto interesante para guardar en el log de la aplicación la información más detallada de la excepción, que seguro el departamento de soporte nos lo agradecerá.

Si deseáis incluir una buena gestión de log en Silverlight os recomiendo usar el Silverlight Integration Pack for Microsoft Enterprise Library 5.0.


Ahora la pregunta es que es ExceptionDetailView?


Pues no es más que una vista que creamos para mostrar el mensaje de error de manera agradable para el usuario. La particularidad de la misma, es que es una ChildWindow clase que se incluye en Silverlight desde la versión 3.


Esta clase nos permite colocar un control de usuario simulando una ventana modal. Es decir, deshabilita y oscurece el fondo. Este es el comportamiento que deseamos para mostrar nuestra excepción de modo que quede algo como esto:


image


En la implementación de la vista empleamos el patrón MVVM, sobre el cual existen toneladas de información. (y eso en raras ocasiones es bueno…)

Resumiendo podemos decir que disponemos de un ViewModel (ExceptionDetailViewModel.cs) y una vista que se encarga de pintar los datos que ese ViewModel expone por pantalla. (ExceptionDetailView.xaml)

La vista tiene asociada en su DataContext el ViewModel y vía Binding implementamos el conexión entre los datos y su representación gráfica.

Además de los datos es responsabilidad del ViewModel exportar la funcionalidad (vía comandos) que la vista puede invocar. En este caso, nuestro ViewModel expone un comando a la vista (ToggleShowingExceptionDetailCommand) que le permite mostrar u ocultar la información detallada de la excepción, para contentar a los más curiosos…

Pues ya solo queda probar, porque nos encanta probar, verdad??


Y en este caso debemos lanzar una excepción (al gusto, yo me he decantado por una IndexOutOfRangeException) y comprobamos que la aplicación muestra el mensaje de error de manera correcta en vez de quedarse en blanco.


Espero que os resulte interesante la idea y os incluyo el código fuente de la aplicación de ejemplo para que podáis probar su funcionamiento. Podéis consultar este y otros prototipos aquí (el nombre del archivo de esta solución es Andoni.Arroyo.UnhandledException )

sábado, 25 de junio de 2011

Evolución del Thread Local Storage (a.k.a. TLS)

Una de las cosas que más me gusta de .NET es lo rápido y consistente que evoluciona. Cuando cubre alguna funcionalidad, lo hace de manera elegante y bien terminada. Como desarrolladores es un gusto consumir las clases que exponen dicha funcionalidad y la experiencia suele ser de lo mas gratificante.

Nuestra responsabilidad como desarrolladores es conocer lo que nos brinda y aprovechar al máximo las ventajas que dichas evoluciones nos aportan. Esto nos permite centrar nuestros esfuerzos en las tareas que más valor aportan delegando en el framework las tareas más rutinarias y que aun siendo necesarias no dan valor al producto.

Un ejemplo de estas mejoras, incluida en el Framework 4 cubre un escenario más común de lo que parece, como es implementar un thread-local storage, conocido como TLS.

Imaginemos que deseamos realizar ciertas tareas en paralelo. Común, verdad? Además imaginemos que para el correcto procesamiento de esas instrucciones cada uno de los hilos necesita manejar sus datos de manera separada de los demás hilo de procesamiento que ejecuta un mismo código. Esto es, cada hilo en el que se están procesando las instrucciones, dispone de una copia propia y separada de los recursos que necesita para dicho procesamiento.

Esta característica es interesante si por ejemplo exponemos cierta funcionalidad a través de un Singleton (o un conjunto determinado de instancias), pero necesitamos permitir que dicho código pueda ser invocado desde diferentes hilos. También puede ser interesante si trabajamos con algún recurso no manejado que no soporte MTA (como la implementación del COM Interop de Silverlight, por ejemplo…) o si tenemos un código heredado que deseamos modificarlo para soportar ciertas características de procesamiento en paralelo, aplicando los mínimos cambios posibles.

Para cubrir esta funcionalidad desde el .NET Framework 1.1 existe el atributo [ThreadStatic] que brinda una forma elegante de implementarlo.

Veamos con un poco de código:

  1: ...
  2: 
  3: internal class TLSTestClass
  4: {
  5:     private ClassWithHeavyProcess tp;
  6: 
  7:     internal void Test()
  8:     {
  9:         //UI Thread
 10:         tp = new ClassWithHeavyProcess();
 11:         tp.HeavyMethod();
 12: 
 13:         var bw = new BackgroundWorker();
 14:         bw.DoWork += BwDoWork;
 15:         bw.RunWorkerAsync();
 16: 
 17:         var bw2 = new BackgroundWorker();
 18:         bw2.DoWork += Bw2DoWork;
 19:         bw2.RunWorkerAsync();
 20:     }
 21: 
 22:     void BwDoWork(object sender, DoWorkEventArgs e)
 23:     {
 24:         tp.HeavyMethod();
 25:     }
 26: 
 27:     void Bw2DoWork(object sender, DoWorkEventArgs e)
 28:     {
 29:         tp.HeavyMethod();
 30:     }
 31: }
 32: ...

Veamos como implementar la clase ClassWithHeavyProcess.

Como primera aproximación podemos hacer algo así:

  1:  internal class ClassWithHeavyProcess
  2:     {
  3:         [ThreadStatic]
  4:         public static NeededForThreadProcess _neededForThreadProcess;
  5:         
  6:         static ClassWithHeavyProcess()
  7:         {
  8:             _neededForThreadProcess = new NeededForThreadProcess { Name = "Andoni" };
  9:         }
 10: 
 11:         public void HeavyMethod()
 12:         {
 13:             _neededForThreadProcess.Name = "Assigned from the thread with id: " + Thread.CurrentThread.ManagedThreadId;
 14:         }
 15:     }

Uno de los problemas de esta implementación, es que la inicialización de la variable, al estar implementada en el constructor estático solo se ejecuta una vez. Este escenario nos funcionará solo para el primer hilo, puesto que todos los demás accederán a dicha variable con un valor por defecto del tipo (nulo en los tipos por referencia).

Si no tenemos en cuenta esta circunstancia podemos obtener una bonita System.NullReferenceException como la obtiene el código aquí mostrado…


Como a grandes males, grandes remedios, podemos crearnos una propiedad que encapsule el acceso al campo e inicializarlo si está a nulo, es decir, si estamos en un hilo que no posee su propia copia de la variable.

Entonces tendríamos algo así:

  1:  internal class ClassWithHeavyProcess
  2:     {
  3:         [ThreadStatic]
  4:         public static NeededForThreadProcess _neededForThreadProcess;
  5: 
  6:         public NeededForThreadProcess NeededForThreadProcess
  7:         {
  8:             get
  9:             {
 10:                 if (_neededForThreadProcess == null)
 11:                     _neededForThreadProcess = new NeededForThreadProcess();
 12:                 return _neededForThreadProcess;
 13:             }
 14:         }
 15: 
 16:         public void HeavyMethod()
 17:         {
 18:             NeededForThreadProcess.Name = "Assigned from the thread with id: " + Thread.CurrentThread.ManagedThreadId;
 19:         }
 20:     }
Tened en cuenta que cuando un hilo completa su procesamiento es eliminado y liberados sus recursos, incluida la copia de la variable asociada. (Si el GC ha decidido llevárselos al más allá…).

Bueno, esto es así casi siempre…

Recordad que desde el .NET Framework 2.0 existe el ThreadPool. De las optimizaciones que el .NET Framework haga sobre el pool de hilos manejados también nuestras aplicaciones se verán beneficiadas, puesto que si reutilizamos los hilos también sus variables de almacenamiento local. Esto es una mejora en el rendimiento, pero debemos asegurarnos que inicializamos correctamente las variables al inicio del procesamiento, puesto que pueden ser parte de algún hilo reciclado.

Si os preguntáis porque os cuento esto, tened en cuenta que si revisáis la implementación de la clase TLSTestClass podéis comprobar que está empleando objetos BackgroundWorker  que internamente negocian con el ThreadPool de .NET.


Con respecto a este escenario el .NET Framework 4 ha evolucionado para hacernos las cosas aún más fáciles. Se ha incluido la clase genérica ThreadLocal (que ya existía en Java, sí…) que se encarga de encapsular el poco “pipeline” que nos quedaba por hacer a nosotros.

Con ella podemos evitar la propiedad y especificar el constructor que deberá invocar cuando lo necesite.


Con esta clase nuestro código podría quedar tan elegante como este:

  1:  internal class ThreadProcess
  2:     {
  3:         ThreadLocal<NeededForThreadProcess> NeededForThreadProcess = new ThreadLocal<NeededForThreadProcess>(() => new NeededForThreadProcess());
  4: 
  5:         public void HeavyMethod()
  6:         {
  7:             NeededForThreadProcess.Value.Name = "Assigned from the thread with id: " + Thread.CurrentThread.ManagedThreadId;
  8:         }
  9:     }

Realmente elegante!


Si implementáis esta funcionalidad porque desde la clase NeededForThreadProcess gestionáis algún recurso no manejado (uno de los escenarios que comentaba antes), recordad que es responsabilidad vuestra liberad dichos objetos. Esto lo debéis realizar al menos al destruir los objetos (sino antes) que los consumen, pero eso, como el valor en la mili, se os supone..

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.