Despedida del programa Microsoft MVP

Después de 13 años como Microsoft MVP, este año me despido del programa. Y quiero hacerlo dando las gracias a todos, a la propia Microsoft y -sobre todo- a la gente que he conocido en este periodo: empleados de la propia Microsoft, toda la gente del programa MVP o de las comunidades, etc.

Al fin y al cabo, dejando a un lado los reconocimientos, conocer a toda esta gente ha sido lo mejor y más importante de este periodo, hasta el punto de poder decir que a algunos de mis mejores amigos los he conocido aquí. Y eso es mucho decir.

A decir verdad desde hace un par de años ya le había comentado a mamá Cristina (la gran madre de todos los MVP) mi intención de dejar el programa por diversos motivos, pero al final siempre me terminaba convenciendo para seguir por un tiempo…  que grande eres Cris y que razón tenías, muchas gracias por todo!

Entre estos motivos, destacaría el hecho de que hace tiempo que: ya no creo que por méritos propios merezca estar entre los reconocidos. Y esto es básicamente porque yo mismo elegí cambiar y hacer menos pequeñas contribuciones diarias (o casi) y centrarme en hacer dos o tres más grandes al año.

Ya no tengo ni el mismo tiempo ni -porque no decirlo- las mismas ganas que hace unos años… y sinceramente, hay gente que contribuye de ese modo mucho mejor que yo. Así que decidí que donde puedo aportar más, es por ejemplo en los eventos grandes tipo DotNetConference o organizando el GAPAND anual, que de momento seguirá.

Claro que no es el único motivo, siempre hay cosas en las que uno no está 100% de acuerdo, pero ahora no es el momento ni el lugar para hablar de ello. En este post sólo quiero, como he dicho al principio, dar las gracias a todos y decir que me lo he pasado pipa durante este tiempo. Siempre recordaré este periodo con muchísimo cariño!

Yo por mi parte bajaré el próximo día 5/6 de Octubre al Tech Summit en Madrid y aprovecharé para despedirme de todos los que me encuentre, ya que aprovecharé la excusa y me pillaré un tiempo sabático de todo esto, que ya me toca :P

Gracias a todos y ahora que sigan otros tirando del carro :D #NewBlood

L

Había pensado en esperar al 1 de Octubre para escribir esto, pero al final he decidido hacerlo ahora para no coincidir con la alegría de todos los nuevos (o renovados) MVP. Buen trabajo y felicidades, chicos! :D

ends

 

GAPAND 2016 is over

IMG_20160702_140840

BUENO…

Otro año ha pasado, y otra edición más del GAPAND a la saca. No, si al final esto va a convertirse en un clásico y todo… bueno, el tiempo lo dirá. Lo que si os puedo asegurar es que ha sido la mejor edición hasta la fecha, ya que el feedback de la gente (que al fin y al cabo es la única métrica que me interesa) es, a falta de una palabra más ‘fisna’: COJONUDO :D

Y eso no se paga con nada, sabéis? Porque vale, si, seguro que ya os imagináis que organizar un evento como este es un currazo. Y vaya si lo es! Lleva meses de trabajo duro, de coordinarse con mucha gente, de lidiar con 1000 temas distintos, de solucionar un montón de problemillas sobre la marcha, y todo por un día… un mísero día al año. Como nos gusta complicarnos la vida, eh? ;)

Pero es que todo eso no es nada cuando ves el ambientazo que se respira ese día. Cuando tienes la oportunidad de volver a ver a viejos amigos, y de hacer otros nuevos. Porque lo bueno del GAPAND (como en tantos otros eventos 100% comunidad) no está sólo en las sesiones, está en el contacto con la gente, y en el buen ambiente que se respira.

 

GRACIAS

Así que desde aquí quiero daros las gracias a todos los que en mayor o menos medida habéis ayudado a que este evento hay sido posible: GRACIAS! GRACIAS! Y MUCHAS GRACIAS! :D

A todos, a los colaboradores porque sin ellos no tendríamos un sitio en el que hacer el evento (Universitat d’Andorra), ni desayuno (Sant Eloi), ni comida (DevsDNA), ni camisetas para los ponentes (Eset) y para la gente del staff (Semic), ni camisetas de regalo (Microsoft), ni cervezas (Hack & Beers), ni cosas para sortear (Caldea, Andorra Turisme, etc.).

A los ponentes, porque además de ser unos cracks hacen el esfuerzo de prepararse contenido súper interesante para crear una agenda de los más chula. Y todo eso lo hacen sin recibir nada a cambio… es más, incluso tienen que costearse su hotel! Así que imaginaros su compromiso con la comunidad! Si eso no es amor y pasíon por lo que te gusta, no se qué puede serlo. Un aplauso enorme… sois muy grandes!

Y cómo no, a todos los que habéis asistido al evento… sin vosotros esto no tendría sentido. Me alegra especialmente haber visto este año a bastante gente joven (venga, que los viejos necesitaremos el relevo, más pronto que tarde :D), estudiantes de la propia universidad, y gente que ha venido de bastante lejos a pasar un día con nosotros en este pequeño país… GRACIAS!

Mención aparte para mi colega Jordi, que ha tenido la paciencia de aguantarme otro año, y de tirar del carro cuando era menester. Ah! Y de buscarse la vida como nadie, y hasta de hacer de Community Manager. Thx mate! ;)

Os dejo con algunas fotos del evento. Si tenéis algunas fotos chulas por favor contactad con nosotros para ampliar el álbum de recuerdos… gracias! :)

 

Y un resumen en forma de Timeline, con algunos tweets del #gapand2016 :D

https://twitter.com/eltitular_es/status/749158636593750017

Video de mi charla en la #dotNetSpain2016

Hola de nuevo,

Lo prometido es deuda, he subido a Channel9 un video sobre mi sesión de ‘async Best practices’ de la pasada #DotNetSpain2016 :)

https://channel9.msdn.com/Blogs/channel9spain/Async-best-practices-por-Llus-Franco

s1

El vídeo dura una hora y veinte minutos aproximadamente y trata todos los contenidos de la sesión y la última demo con un poco más de profundidad.

Espero que os guste. Lo podéis ver online o descargar para más tarde.

Muchas gracias Isa por haber insistido, y al resto por el buen feedback! ;)

Materiales++ de mi sesión ‘async best practices’

Hola de nuevo,

Durante los últimos días me ha contactado bastante gente haciéndome preguntas sobre mi sesión de la pasada DotNet Spain Conference.

Aquí van un par de ellas con sus respuestas, por si son de vuestro interés ;)

“Las demos eran un proyecto de consola, pero qué consola era esa? No es el clásico cmd de Windows, verdad?”

Pues no, desde hace tiempo he sustituido el cmd por la estupenda ConEmu, que permite abrir distintos shells (PowerShell, PuTTY, mintty, GViM, etc) y distribuirlos como tabs o mosaicos.

Podéis descargarla desde: https://conemu.github.io/

m1

En lugar de partir de cero para configurarla, os paso también mis settings por si queréis utilizarlas de punto de partida. Basta con ir a ‘Settings’/’Import’ y posteriormente ‘Save’ :)

ConEmu Settings (XML): http://1drv.ms/1VV4cwp

Y si no os gustan siempre podéis hacer un ‘Reset’ y empezar de cero :P

“En la última demo (la de cancelaciones a la BD) mostraste trazas en el SQL Profiler. Dijiste que tenías una plantilla creada para eso? La podrías compartir si no te importa?”

Of course! Esta plantilla básicamente muestra los eventos Starting y Completed de cada vez que se ejecuta un SQL statement (en este caso un Stored Procedure que tarda unos 5 segundos en completarse). Lo más interesante es que gracias a esta plantilla podemos ver si las peticiones terminan con éxito o han sido canceladas por el usuario, amén de la duración, que también nos puede indicar si ha terminado con éxito o no.

m2

SQL Profiler template: http://1drv.ms/1p43ti6

Para instalar la plantilla en tu SQL Profiler basta con descargarla y hacer doble click. Se abrirá el profiler y os informarà de que la plantila se ha importado con éxito.

A partir de aquí, cada vez que queráis usar esta plantilla de traza, basta con usarla como las que vienen ‘out of the box’:

m3

Intentaré ir ampliando este post con aquellas que crea que pueden ser de interés general. Si tenéis alguna pregunta, ya sabéis :)

Nos vemos,

 

DotNet Spain Conference 2016… I was there!

_1

El pasado miércoles se celebró en Madrid el mayor evento del año en tecnologías de desarrollo Microsoft. Un evento al que han asistido más de 1700 personas de forma presencial y unos cuantos miles más en streaming por Internet.

Y sólo puedo decir una cosa: ha sido una experiencia cojonuda a todos los niveles.

Me he rencontrado con viejos amigos y he conocido otros nuevos, he podido asistir a algunas sesiones ‘pata negra’ de otros colegas, he visto y oído al gran jefe Satya Nadella, y para rematarlo he tenido la oportunidad de poner mi granito de arena con una sesión sobre ‘async best practices’ la cual, por el feedback recibido parece ser que ha gustado a mucha gente, así pues… ¿qué más se puede pedir?

Como bastante gente me ha preguntado, aquí os dejo las slides de mi sesión, así como el código con las demos y la demo sorpresa final:

Slides on Slideshare

Code on GitHub

https://github.com/lluisfranco/AsyncBestPracticesDemos2016

_b

https://github.com/lluisfranco/AsyncDatabaseCancellationDemo

La verdad es que hacía bastantes años que no hacía una sesión para tanta gente, y os tengo que confesar que los 5 minutos antes de empezar fueron ‘complicadillos’. La ventaja es que al fin y al cabo todos los frikis somos como una gran familia, de modo que al empezar la sesión y empezar a hablar de nuestras cositas los nervios desaparecieron desde el minuto cero y todo fue como una seda.

Felicitaciones

Un 10 para la organización. Después de haber podido organizar unos cuantos eventos por mi cuenta y saber lo complicado que es, no quiero ni imaginarme lo que tiene que ser montar un evento de este calibre… chavales, lo habéis bordado. Os podéis tomar unos días de merecidas vacaciones :D

Creo poder decir sin lugar a dudas que ha sido el mejor evento al cual he asistido en España. Felicidades a todos!

Y como al fin y al cabo este es mi blog, me voy a dar un poco de autobombo, que coño! ;)

Aquí van algunos tuits, gracias a todos por el buen feedback!

 

 

DotNet Spain Conference 2015

Este fin de semana he tenido la oportunidad de participar en el mayor evento de la comunidad .NET en España hasta la fecha.

Se ha realizado en la Universidad de Alcalá, con record de asistentes. Cosa que no me extraña viendo la cantidad de charlas y hands on lab que se han realizado en varios tracks en paralelo. La verdad es que ha sido un éxito a todos los niveles, y sólo puedo decir que va a ser difícil superarlo en futuras ediciones. Se ha puesto el listón muy alto! :D

dotnetspain

En lo que respecta a mi, tuve la gran suerte de presentar -y que me aprobaran- una charla conjunta con mi colega Alex Casquete, sobre buenas prácticas sobre async, algo que precisamente no es mainstream pero que curiosamente ha tenido una aceptación muy buena. De hecho ha sido mejor de la que yo pensaba que podía tener en un principio, así que muchas gracias a todos por tanto feedback positivo!

Os dejo aquí las slides de la charla y las demos que utilizamos, ya que -para mi sorpresa- me las ha pedido bastante gente:

Sin embargo, en un evento como este no todo son sesiones técnicas. Lo mejor de todo es que he tenido la oportunidad de volver a encontrarme con un montón de viejos conocidos, con los que compartir buenos momentos y algunas cervezas, de modo que el networking ha sido… fantástico!

Os dejo con algunas fotos del eventazo. Gracias a todos! :D

Serializar listas genéricas en aplicaciones WinRT

andorraenamora

Edit (11/03/2013): Gracias a una sugerencia del colega MVP Javier Torrecilla se ha modificado el código para especificar el Encoding (UTF8Encoding) y así evitar problemas. Thx dude! :)

 

Hola de nuevo,

Rompiendo un poco con la serie de posts sobre las ‘Parallel Series’, hoy quiero escribir acerca de algo totalmente distinto. Y es que ando haciendo mis pinitos con mi primera aplicación Windows Store, y me estoy encontrando con bastantes cosas que no conozco, y que desde mi absoluto desconocimiento de la plataforma, encuentro bastante tediosas de realizar.

Hoy por ejemplo estaba tratando de almacenar ciertos datos en local -ya que para esta aplicación no quiero depender de ninguna base de datos porque en realidad son cuatro datos- y no he encontrado una forma directa de persistir listas genéricas en el sistema de ficheros local.

Si que es cierto que las herramientas están ahí para ser usadas ‘a mano’, pero he echado en falta una forma más sencilla de hacerlo (que no quiere decir que no exista), de modo que he creado una clase para facilitarme el proceso.

Su propósito es muy específico, pero básicamente permite guardar y leer cualquier lista genérica List<T> a un fichero, que puede ser guardado en la carpeta Local, Temporal o de Roaming.

La clase es la siguiente (aunque supongo que es muy mejorable):

using System;
using System.Collections.Generic;
using System.IO;
using System.Threading.Tasks;
using System.Xml.Serialization;
using Windows.Storage;

namespace MySampleApp.Domain
{
    public class LocalStorage<T>
    {
        public List<T> Data { get; set; }
        public string Filename { get; set; }
        public StorageFolder StorageFolder { get; set; }

        public LocalStorage(string filename)
        {
            Filename = filename;
            Data = new List<T>();
            StorageFolder = ApplicationData.Current.LocalFolder;
        }

        public async Task SaveAsync()
        {
            if (!await fileExistAsync(Filename))
            {
                await StorageFolder.CreateFileAsync(
                    Filename, CreationCollisionOption.ReplaceExisting);
            }
            await saveToLocalStorageAsync();
        }

        public async Task<List<T>> LoadAsync()
        {
            if (await fileExistAsync(Filename))
            {
                return await loadFromLocalStorageAsync();
            }
            else
            {
                await StorageFolder.CreateFileAsync(Filename);
                return null;
            }
        }

        public async void DeleteAsync()
        {
            try
            {
                if (await fileExistAsync(Filename))
                {
                    var file = await StorageFolder.GetFileAsync(Filename);
                    if (file != null) await file.DeleteAsync();
                }
            }
            catch (Exception)
            {
                throw;
            }
        }

        private async Task<bool> fileExistAsync(string fileName)
        {
            try
            {
                await StorageFolder.GetFileAsync(fileName);
                return true;
            }
            catch
            {
                return false;
            }
        }

        private async Task saveToLocalStorageAsync()
        {
            var sessionFile = await StorageFolder.CreateFileAsync(
                Filename, CreationCollisionOption.ReplaceExisting);
            using (var sessionRandomAccess = await sessionFile.OpenStreamForWriteAsync())
            {
                var serializer = new XmlSerializer(typeof(List<T>), new Type[] { typeof(T) });
                serializer.Serialize(new StreamWriter(sessionStream, new UTF8Encoding()), Data);
                await sessionStream.FlushAsync();
            }
        }

        private async Task<List<T>> loadFromLocalStorageAsync()
        {
            var sessionFile = await StorageFolder.CreateFileAsync(
                Filename, CreationCollisionOption.OpenIfExists);
            if (sessionFile == null) return null;
            using (var sessionInputStream = await sessionFile.OpenReadAsync())
            {
                var reader = XmlReader.Create(new StreamReader(
                    await sessionFile.OpenStreamForReadAsync(), new UTF8Encoding()));
                var serializer = new XmlSerializer(typeof(List<T>), new Type[] { typeof(T) });
                Data = (List<T>)serializer.Deserialize(reader);
                return Data;
            }
        }
    }
}

Y para utilizarla basta con disponer de una lista de objetos de un tipo T:

var customers = new List<Customer>();
customers.AddRange(getSampleCustomers());

Y posteriormente crear una instancia de LocalStorage:

var storage = new MySampleApp.Domain.LocalStorage<Customer>("customers.xml");
//Opcionalmente podemos cambiar la carpeta de destino (por defecto es LocalStorage)
storage.StorageFolder = Windows.Storage.ApplicationData.Current.RoamingFolder;
//Añadimos los datos a persistir
storage.Data.AddRange(customers );
//Guardar los datos al fichero customers.xml
await storage.SaveAsync();
//Recuperar los datos del fichero customers.xml
await storage.LoadAsync();
//Eliminar el fichero customers.xml
storage.DeleteAsync();

Si alguien tiene alguna sugerencia o mejora que no dude en escribir un comentario.

Nos vemos! :)

Problemas de concurrencia

Why concurrent collections?

En un mundo en el que los procesos ya no son secuenciales sino paralelos, es cada vez más posible encontrarnos con problemas de concurrencia al acceder a recursos compartidos. Conceptualmente hablando, esto es algo a los que los desarrolladores ya estamos acostumbrados cuando trabajamos con gestores de bases de datos como Oracle o SQL Server, ya que varios usuarios pueden acceder o modificar la información al mismo.

Sin embargo, la gran mayoría de los desarrolladores pocas veces hemos tenido que lidiar con bloqueos en colecciones en menoria, ya que no todo el mundo crea aplicaciones en las que varios threads acceden a recursos compartidos. De hecho, si alguna vez has lo tenido que hacer sabrás perfectamente que antes de la aparición de la TPL era una de las disciplinas más complejas dentro del desarrollo de software. Algo que favorece la calvície :)

Sin embargo, desde la aparición de la TPL en el .NET Framework 4.0 es mucho más sencillo desarrollar aplicaciones que ejecuten procesos en paralelo o de forma asíncrona, pero esto conlleva que en ocasiones nos olvidemos que hay algunos threads que se ejecutan al mismo tiempo, y esto podría llevar a producir efectos no deseados cuando se trata de acceder a recursos compartidos, como una colección de elementos en memoria.

Por ejemplo: supongamos un escenario en el que tenemos una lista de clientes en memoria y un par de tareas (Task) que acceden a esa colección. La primera tarea podría estar verificando si todos los clientes cumplen una condición X, y si no la cumplen eliminar el cliente de la colección. Mientras tanto la segunda tarea podría estar actualizando alguna propiedad de los clientes, como la edad.

Un escenario real

Encierra este escenario algún peligro? A priori podemos pensar que no. Basta con que la segunda tarea verifique si el cliente existe en la colección antes de actualizarlo. Seguro? Pues no. Al menos no basta si la colección que estamos usando no es una de las nuevas definidas dentro del namespace System.Collections.Concurrent. Y para verlo mejor, hagamos un pequeño ejemplo con código, que es lo que nos gusta a todos.

1 – Partiremos de una clase base Customers con un método que crea n objetos de ejemplo:

public class Customer
{
    public int CustomerId { get; set; }
    public string Name { get; set; }
    public int Age { get; set; }

    public static List<Customer> GetSampleCustomers(int n)
    {
        Random r = new Random(Guid.NewGuid().GetHashCode());
        List<Customer> customers = new List<Customer>();
        for (int i = 0; i < n; i++)
        {
            customers.Add(new Customer()
            {
                CustomerId = i,
                Name = string.Format("Customer {0}", i),
                Age = r.Next(20, 80)
            });
        }
        return customers;
    }
}

2 – A continuación en un formulario declararemos e inicializaremos una colección de tipo Dictionary para almacenar estos objetos cliente:

Dictionary<int, Customer> dic1 = new Dictionary<int,Customer>();

3 – Y en el constructor la rellenamos con 100.000 clientes de ejemplo:

public Form1()
{
    InitializeComponent();
    dic1 = Customer.GetSampleCustomers(100000).ToDictionary(p => p.CustomerId);
}

4 – Ahora, vamos a complicar un poco más el ejemplo y crearemos dos métodos que simulen el borrado y la actualización de los objetos que contiene la colección. Luego llamaremos a éstos métodos para 100 objetos aleatorios de forma paralela para ver que efectos se producen:

private void deleteItem1(int id)
{
    if (dic1.ContainsKey(id) && dic1[id].Age < 30) dic1.Remove(id);
}

private void updateItem1(int id)
{
    if (dic1.ContainsKey(id)) dic1[id].Age++;
}

private void button1_Click(object sender, EventArgs e)
{
    for (int i = 0; i < 100; i++)
    {
        Random r = new Random(Guid.NewGuid().GetHashCode());
        int id = r.Next(1, dic1.Count);
        Task.Factory.StartNew(() => deleteItem1(id));
        Task.Factory.StartNew(() => updateItem1(id));
    }
}

Ejecutamos la aplicación y cuendo pulsemos el botón puede pasar que obtengamos un bonito error como este:

image

Concretamente en la línea que incrementa la edad del cliente:

image

Y digo que puede pasar, pero no es seguro. Tal vez tengamos que repetir el proceso varias veces, y es que en un entorno en el que varios threads acceden a un recurso compartido nada nos asegura que se produzca el error. A veces pasa a la primera y a veces a la cuarta, pero hay que tener presente que cuando esté en producción siempre pasará en viernes por la tarde cinco minutos antes de empezar el fin de semana ;)

Analicemos el porqué del error, por que ¿cómo es posible que no encuentre el elemento en la colección si precisamente en la línea anterior verificamos su existencia? Pues ahí está la gracia, que lo verificamos en la línea anterior. A nosotros -pobres developers- nos parece que la línea anterior en la que verificamos si existe y la línea actual en la que lo emininamos van seguidas una detrás de otra, pero realmente en un entorno asíncrono hay todo un mundo entre ambas. Y eso es porque ambas líneas se ejecutan de forma separada, sin ningún tipo de bloqueo, no existe Transaccionalidad al estilo de las bases de datos, de modo que mientras el primer thread verifica que existe ese elemento en la colección y lo borra, llega el segundo thread y… ZASCA! Lo elimina.

image

El nuevo ConcurrentDictionary

Para estos casos (y muchos otros) aparecen en escena un nuevo conjunto de colecciones especializadas en entornos multithreading. Una de las más populares es una variación del clásico Dictionary, el ConcurrentDictionary. Esta clase proporciona una série de métodos alternativos para agregar, modificar o eliminar elementos llamados TryAdd, TryUpdate o TryRemove. La ventaja de éstos métodos es que son transaccionales y proporcionan Atomicidad. Es decir, garantizan que en caso de que se invoquen, se ejecuten totalmente: O bien se añade/modifica/elimina el elemento de la colección o bien se devuelve el valor False porque no se ha podido realizar la operación. También proporciona un método TryGetValue que intenta obtener un elemento de la colección. Todos estos métodos implementan en su interior bloqueos (lock), para asegurar que nadie más accede al elemento mientras se realiza la operación solicitada.

Un ejemplo real que no falla ;)

Vamos a modificar el ejemplo anterior usando esta nueva colección, para observar su comportamiento en el entorno anterior.

1 – Agregaremos un ConcurrentDictionary después de la declaración del anterior:

ConcurrentDictionary<int, Customer> dic2 =
    new ConcurrentDictionary<int, Customer>();

2 – Lo rellenamos en el constructor, al igual que hacíamos antes. Aquí podemos ver la primera diferencia, ya que usamos uno de los nuevos métodos TryXXX:

Customer.GetSampleCustomers(100000).ForEach(c => dic2.TryAdd(c.CustomerId, c));

3 – A continuación vamos a crear los métodos equivalentes para eliminar y modificar el elemento en la colección:

private void deleteItem2(int id)
{
    Customer c;
    if(!dic2.TryRemove(id, out c)) Console.WriteLine("Error deleting!");
}

private void updateItem2(int id)
{
    Customer c;
    if (!dic2.TryGetValue(id, out c))
    {
        Console.WriteLine("Error getting value");
    }
    else
    {
        Customer newc = new Customer() { CustomerId = c.CustomerId, Name = c.Name, Age = c.Age };
        newc.Age++;
        if (!dic2.TryUpdate(id, newc, c)) Console.WriteLine("Error updating!");
    }
}

En el borrado usamos el método TryRemove que necesita el id del elemento a eliminar, y en caso que lo elimine con éxito, devuelve True y el objeto eliminado en el segundo parámetro out (de salida) del método. En caso que no lo elimine devuelve False y el valor default del objeto a eliminar en el segundo parámetro.

La actualización es un poco más compleja, ya que primero debemos asegurarnos de que el elemento a modificar existe en la colección mediante el método TryGetValue, que básicamente funciona igual que el método TryDelete anterior. Una vez hemos comprobado que dicho objeto existe en la colección creamos una réplica del cliente, modificamos su edad y llamamos al método TryUpdate, el cual se encarga de la modificación.

Es interesante notar que para que la modificación se realice correctamente debemos informar de la clave del objeto en la colección, el nuevo valor del objeto (en este caso la réplica del cliente a la que hemos modificado la edad) y un tercer parámetro que es el valor original del objeto, que es usado para comparar.

4 – Probemos los nuevos métodos en otro botón:

private void button2_Click(object sender, EventArgs e)
{
    for (int i = 0; i < 100; i++)
    {
        Random r = new Random(Guid.NewGuid().GetHashCode());
        int id = r.Next(1, dic1.Count);
        Task.Factory.StartNew(() => deleteItem2(id));
        Task.Factory.StartNew(() => updateItem2(id));
    }
}

Ejecutamos y si vamos a la ventana de consola podremos observar el resultado:

Error getting value
Error getting value
Error getting value
Error getting value
Error updating!
Error getting value
Error getting value
Error getting value

En la mayoría de los casos, obtenemos un error de lectura porque el elemento ya ha sido eliminado de la colección, pero en algunos casos el error se producirá en el método TryUpdate. Eso significa que la llamada a TryGetValue encuentra el elemento, pero cuando lo vamos a modificar éste ya no existe en la colección. Perfecto! :)

Conclusión

La ventaja de usar colecciones específicas en entornos multithreading es clara: Garantizan que el acceso a los recursos compartidos sea transaccional, al más puro estilo de las bases de datos. De acuerdo que su programación sea un poco más compleja, pero no tiene nada que ver con lo que se tenía que hacer antiguamente cuando no existía la TPL.

Por otro lado, el uso de estas colecciones debe hacerse sólo en aquelos casos en los que se accede a recursos compartidos, ya que si no, por un lado estamos complicando nuestro codigo y por otro lado un ConcurrentDictionary no es tan eficiente como lo és un Dictionary, sobre todo en entornos más de escritura que de lectura. Tenéis un post muy detallado al respecto del gran James (aka Black Rabbit) respecto a la diferencia de performance:

http://geekswithblogs.net/BlackRabbitCoder/archive/2010/06/09/c-4-the-curious-concurrentdictionary.aspx

Espero sacar tiempo para otro post en el que explicar otras colecciones de este namespace, como las ‘BlockingCollection’ o las ‘’ConcurrentBag’, que son colecciones más especializadas. La primera está optimizada para escenarios dónde el mismo thread produce y consume objetos, mientras que la segunda ha sido especialmente diseñada para escenarios de productor-consumidor.

Aquí tenéis un pequeño proyecto de ejemplo con el código:

https://www.dropbox.com/s/ej3u3s1v55ltb30/TPL04_Concurrency.zip

Nos leemos! :D

Volver al índice de contenidos

Entrevista para el MVP Site (versión completa)

MVPPartySeattle2011

Ayer me publicaron una entrevista en el sitio internacional del programa MVP:

http://mvp.microsoft.com/es-ES/Paginas/default.aspx (spanish)

Sin embargo, no es la versión completa. Ésta la publico aquí, sin cortes. Espero que os guste ;)

Entrevista a Lluís Franco

Nacido en Barcelona y con 20 años de experiencia en el sector del desarrollo de software, Lluís Franco posee varias certificaciones MCP y MCTS y ha sido reconocido como Microsoft MVP durante los últimos 10 años, principalmente por haber sido colaborador activo y moderador en los grupos de noticias y en los foros MSDN de Microsoft desde 1997.

Actualmente trabaja como responsable de desarrollo de proyectos en FIMARGE una empresa del sector financiero situada en Andorra. En 2007 fundó AndorraDotNet, el primer grupo de usuarios y en 2010 la asociación virtual de informáticos del país. Escribe en varios blogs, y es organizador y ponente habitual en los eventos de los grupos de usuarios de la región. También colabora con un periódico local escribiendo artículos para su sección tecnológica.

En lo personal vive en Andorra desde hace más de una década, está felizmente casado con una mujer encantadora y es padre de las dos niñas más guapas del mundo.

1. Que significa ser MVP para ti?

Algo mucho más importante ahora que cuando recibí mi primera nominación, ya que por aquel entonces no era consciente de toda la gente que iba a conocer ni de todo lo que iba a suceder en los próximos 10 años. Y con esto no me refiero sólo al nivel técnico de este colectivo -que lo tiene, y mucho- sino a la calidad humana, porque a muchos de mis mejores amigos actuales los he conocido a través del programa MVP.

2. Cómo empezaste a colaborar en la comunidad?

Sinceramente? Pues de casualidad. La verdad es que como muchos otros profesionales, un día hace unos cuantos años necesitaba ayuda para resolver una duda, y buscando me encontré los ya desaparecidos grupos de usuarios, en los que me ayudaron a resolver la mayoría de mis dudas. Eso me encantó y poco a poco decidí devolver el buen trato recibido ayudando también a otros. Después empecé con una web, un blog, otro blog, a hablar en pequeños eventos, luego también a organizarlos… y mira. Hasta hoy :)

3. Si pudieras preguntarle a Steve Ballmer una pregunta, que te gustaría preguntar?

Ufff… lo primero que me viene a la cabeza es preguntarle por la estrategia a largo plazo de algunas de las líneas de negocio. Aunque pensándolo mejor, creo que todo el mundo debe preguntarle ese tipo de cosas, así que mejor le preguntaría por los viejos tiempos: Así que Steve, si me estás oyendo… ¿cuál crees que ha sido el hecho más importante en la historia de Microsoft? Me refiero a algún punto de inflexión que según tu opinión -y no la de un libro o película- sea lo que ha hecho de Microsoft lo que es hoy en día.

4. Cual crees que ha sido el mejor Software de la historia?

Soy un enamorado de C#. Para mí es, sin ningún lugar a dudas el lenguaje más bello, completo y potente jamás creado, así que por extensión VS2012 es el mejor IDE de la historia (o al menos de los que he usado, que son unos cuantos). En cuanto a sistemas operativos, para mí tampoco no hay duda: Windows 8 con mucha diferencia sobre el segundo. Y que conste que no siempre he trabajado con productos de Microsoft, y algunos me gustan mucho, pero a día de hoy ésta es mi opinión.

5. Si tú fueras el responsable de C# qué cambio te gustaría hacer?

Seguir implementando características de la programación funcional. En las últimas versiones, la aparición de genéricos, el manejo de delegados, LINQ y sobretodo las expresiones lambda han convertido C# en el lenguaje que siempre había soñado. ¡Créeme si te digo que hace muy divertido el desarrollar! Sin embargo todavía faltan cosas, y aunque no son imprescindibles (como las Nested functions) sí que harían -como dicen unos buenos amigos míos- que en C# las funciones fueran consideradas ciudadanos de primer nivel, y así dejarían de darme la paliza. Ah! Y permíteme agregar también otra cosa: Aligerar un poco el Framework y el IDE. Porque después de tantas versiones hay ciertos objetos y unas cuantas colecciones que deberían ser eliminadas… y perder unos Kb nunca viene mal.

6. Cuál fue el último libro que has leído?

Suelo ser un lector compulsivo de libros técnicos, fantasía y ciencia ficción, así que no esperes que te diga que un superventas. A ver, mi último libro ha sido ‘Ready Player One’, una novela llena de referencias de los años 80: Hay videojuegos clásicos, música, películas, rol, comics y hasta juguetes. Si bien el estilo es un poco juvenil, no deja de ser una perla para cualquier freak nacido en los 70, porque al fin y al cabo nos hemos criado en esa época. También suelo tener en mi mesilla de noche algún libro técnico del cuál ojeo fragmentos de vez en cuando y cómo no, mi biblia particular: El Silmarillion.

7. Que CD de música recomiendas?

Uno solo? Entonces supongo que me quedaría con el ‘Ok Computer’ de Radiohead. Lo encuentro un disco redondo dentro del género alternativo y como banda me encantan, sobre todo los primeros discos. Con todo, mi criterio musical va desde Bach hasta el buen Metal, pasando por mucho Jazz, así que no se si mi criterio es el más fiable.

8. Que hace que tú seas un excelente MVP?

No soy un excelente MVP, eso lo tengo clarísimo. Verás, déjame matizar lo que para mí significa ser un MVP: Un profesional con un cierto nivel técnico pero que destaca por querer contribuir a la comunidad, ayudando a otros como antes lo ayudaron a él. Y para eso la actitud es básica, y debe ser más importante que las cualidades técnicas. De modo que si alguna vez veis a alguien decir “Ves? Soy mejor que tú porque soy MVP”, pensar que esta persona no merece formar parte del programa. Es más, tenéis mis datos arriba. Poneros en contacto conmigo, ok? No bromeo.

9. Que contiene tu “Computer Bag”?

Cada vez menos software y más hierro. Y con la proliferación de pequeños dispositivos cada vez llevo más adaptadores, cargadores, conectores universales para los viajes y por supuesto una reliquia de mis primeros días de MVP: Una navaja suiza con el logo del programa MVP que contiene un montón de herramientas. No la he usado nunca, pero no pierdo la esperanza.

10. Cuál es la mejor cosa que te ha pasado desde que eres MVP?

La fama, las mujeres, el dinero… es difícil. Podría decirte que ser escogido como C# MVP of the year, ya que es un premio que se otorga una vez ya eres MVP por parte de tus propios compañeros. O mi primer viaje a Seattle, que también fue algo apoteósico. Pero si tengo que escoger una única cosa me quedo con la gente. Ya lo he dicho antes, pero me ha permitido conocer profesionales como la copa de un pino, que además son gente muy maja y dispuesta a ayudar a la comunidad sin reservas. Y lo mejor de todo es que la gran mayoría son unos geeks como yo. No hay nada como un buen geeks & beers…

11. Cuál es tu lema?

Me encantaría poder soltaros una frase molona, pero la verdad es que mi lema es bastante corriente: Intentar ser mejor persona y alguien en quién mis dos hijas se puedan identificar cuando crezcan. No pretendo cambiar la sociedad, con lo anterior ya tengo trabajo de sobras.

12. Quien es tu héroe?

Sheldon Cooper. Yoda. Spock. Frodo. Cálico. Fuckowsky de ‘Memorias de un ingeniero’, y algún otro que se me olvida. Pero supongo que si debo elegir me quedo con Tony Stark: Un tío que es un genio en varios campos, playboy y que viste su propia armadura de combate… ¡Venga ya! ¿A quién no le gustaría? Sin embargo en el mundo real un héroe es algo mucho más difícil: Alguien que hace lo correcto a pesar de complicadas que están las cosas y sin que nadie lo obligue, un niño con una enfermedad grave dando ánimos a sus padres… Eso si que son héroes!

13. Que significa el éxito para ti?

¡Trabajar de algo que te gusta! Fíjate que en realidad son dos cosas: La primera trabajar, que con la que está cayendo por todos lados, es casi un lujo. Y la segunda, encima, hacer algo que realmente te apasiona. Porque al fin y al cabo es algo que vas a tener que hacer durante muuuuchos años, y si no te apasiona estás perdido, ya que la pasión es el motor que va a hacer que evoluciones con los años. Intentad no perderla!

14. Mencione un proyecto que desearía cumplir este año.

Ya he ido a Seattle al MVP Summit, y también he organizado el primer Geek-a-paloozaaa en Andorra, así que a nivel de trabajo me gustaría terminar una larga serie de posts y videos sobre programación paralela que empecé hace unos meses y la he pausado temporalmente por falta de tiempo. He recibido mucho feedback pidiéndome que la continúe, y eso es lo que voy a hacer. Por otro lado a nivel más personal me gustaría no trabajar tanto, pasar más tiempo con mis seres queridos y no ser tan gruñón a veces. Por pedir que no quede!

Nos vemos! :-D

MVP por décimo año (Frodo, voy a por tí)

MVP_BlueOnly

:-)
Hola a todo el mundo!

Pues eso, que me acaba de llegar EL CORREO. Y a diferencia de otros años, la verdad es que no me acordaba de que hoy era el día D, el día en el que se nombran o renuevan a los MVPs de Octubre… y la verdad es que me he ahorrado algunos nervios. Bueno, al menos hasta hace 2 ó 3 horas, porque la inefable Pilar (que también es de Octubre) me lo ha recordado… Gracias por los nervios! Te debo una! :D

Sin embargo, al final ha llegado:

Estimado/a Lluis Franco i Montanyes,
Enhorabuena. Nos complace presentarle el programa de nombramiento MVP de Microsoft® de 2012. Este nombramiento se concede a los líderes excepcionales de la comunidad técnica que comparten de forma activa su experiencia de alta calidad y de la vida real con otras personas. Le agradecemos especialmente la contribución que ha realizado en las comunidades técnicas en el área de Visual C# a lo largo del pasado año.

La verdad es que este año me hace especial ilusión porque se trata de mi 10º año perteneciendo al programa, y caramba, y eso es una jartá de tiempo! Además, este año toca un anillo especial (como cada 5 años) así que cuando llegue ya os pondré una foto… aunque yo hubiese preferido un jamón ;)

No quiero ponerme sentimental, pero si quiero agradecer a quién sea (nadie sabe exactamente como funciona esto de las nominaciones) el que hay pensado que  merezco pertenecer a este grupo de monstruos. Y quiero decirlo así: Monstruos, porque la gente que pertenece al programa son unos verdaderos cracks técnicos, pero además -salvo raras excepciones- son gente realmente cojonuda. Lo que se llama buena gente, vamos… No es extraño que a muchos de mis mejores amigos los haya conocido aquí.

Dicho esto, como no quiero hacer un post que sea un tocho, os dejo algunos enlaces a los posts de antiguas renovaciones, en los que podréis ver desde fotos de lo mal que lo pasamos cuando nos juntamos, hasta algún video de los bautizos de los nuevos.

MVP Award 2011

MVP Award 2010

MVP Award 2009

MVP Award 2008

Muchas gracias a todos! :D