<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/rss2full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><rss xmlns:atom="http://www.w3.org/2005/Atom" xmlns:openSearch="http://a9.com/-/spec/opensearch/1.1/" xmlns:georss="http://www.georss.org/georss" xmlns:gd="http://schemas.google.com/g/2005" xmlns:thr="http://purl.org/syndication/thread/1.0" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" version="2.0"><channel><atom:id>tag:blogger.com,1999:blog-31098559</atom:id><lastBuildDate>Sat, 11 Feb 2012 23:33:21 +0000</lastBuildDate><category>Personal</category><category>Certificación Microsoft</category><category>Visual Studio</category><category>Emprender</category><category>Metro</category><category>MVVM</category><category>Windows 8</category><category>Lógica</category><category>.NET Framework 4.0</category><category>Escritores</category><category>Metodología</category><category>Threads</category><category>OOB</category><category>.NET Framework 3.5</category><category>SOA</category><category>Excepciones</category><category>Base de datos</category><category>Test</category><category>Tradeoff</category><category>Windows.Forms</category><category>Curiosidades</category><category>Inteligencia Artificial</category><category>Pruebas unitarias</category><category>Ágil</category><category>Kanban</category><category>Eventos</category><category>WTF</category><category>Matemática</category><category>WWF</category><category>Humor</category><category>DDD</category><category>Globalización</category><category>Cine</category><category>Cloud computing</category><category>Negocio</category><category>Capa de Datos</category><category>.NET Framework 3.0</category><category>OffTopic</category><category>Arquitectura del Software</category><category>Informática</category><category>Trabajo</category><category>Internet</category><category>Museos</category><category>Criptografía</category><category>Capa de Presentación</category><category>Lectura</category><category>TFS</category><category>UnitTest</category><category>Física</category><category>WebDevBilbao</category><category>Ciencia</category><category>Cerebro</category><category>SCRUM</category><category>GTD</category><category>Cultura</category><category>WCF</category><category>Revolución Vapor</category><category>POCO</category><category>Religión</category><category>Agilidad</category><category>Seguridad</category><category>TLS</category><category>Rendimiento</category><category>WPF</category><category>Desarrollo de Software</category><category>Entity Framework</category><category>.NET</category><category>Silverlight</category><category>C# 4.0</category><title>Blog de Andoni Arroyo</title><description>Andoni Arroyo es básicamente un informático...(creo que con eso se explica todo)</description><link>http://andoni-arroyo.blogspot.com/</link><managingEditor>noreply@blogger.com (Andoni Arroyo)</managingEditor><generator>Blogger</generator><openSearch:totalResults>121</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/rss+xml" href="http://feeds.feedburner.com/andoniarroyo" /><feedburner:info uri="andoniarroyo" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><item><guid isPermaLink="false">tag:blogger.com,1999:blog-31098559.post-5239014662759219295</guid><pubDate>Mon, 06 Feb 2012 07:00:00 +0000</pubDate><atom:updated>2012-02-06T08:00:02.914+01:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">Trabajo</category><category domain="http://www.blogger.com/atom/ns#">Personal</category><category domain="http://www.blogger.com/atom/ns#">OffTopic</category><title>Cambios y expectativas (Plain Concepts +1)</title><description>&lt;p&gt;Es tiempo de cambios para mí. Dejo de trabajar en &lt;a href="http://www.pandasecurity.com/" target="_blank"&gt;Panda Security&lt;/a&gt; para comenzar una nueva etapa en &lt;a href="http://www.plainconcepts.com/" target="_blank"&gt;Plain Concepts&lt;/a&gt;.&lt;/p&gt; &lt;p&gt;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…&lt;br&gt;&lt;br&gt;Entonces, por que cambiar?&lt;/p&gt; &lt;p&gt;Pues porque es mucho lo que espero de mi nueva empresa:&lt;/p&gt; &lt;ul&gt; &lt;li&gt;Gestión ágil (de verdad), con todo lo que eso implica. &lt;br&gt; &lt;li&gt;Proyectos interesantes, avanzados tecnológicamente y con requerimientos exigentes.&lt;br&gt; &lt;li&gt;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.&lt;br&gt; &lt;li&gt;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 &lt;a href="http://www.agilerecord.com/" target="_blank"&gt;Agile Record&lt;/a&gt;)&lt;br&gt;&lt;/li&gt;&lt;/ul&gt; &lt;p&gt;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.&lt;/p&gt; &lt;p&gt;Estoy seguro que esto y mucho más va a ser lo que voy a encontrar allí.&lt;/p&gt; &lt;p&gt;Estamos en contacto.&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/31098559-5239014662759219295?l=andoni-arroyo.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/andoniarroyo/~4/sfwDIOEsM4o" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/andoniarroyo/~3/sfwDIOEsM4o/cambios-y-expectativas-plain-concepts-1.html</link><author>noreply@blogger.com (Andoni Arroyo)</author><thr:total>0</thr:total><feedburner:origLink>http://andoni-arroyo.blogspot.com/2012/02/cambios-y-expectativas-plain-concepts-1.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-31098559.post-4430155430703318892</guid><pubDate>Tue, 31 Jan 2012 07:00:00 +0000</pubDate><atom:updated>2012-01-31T08:00:04.351+01:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">Arquitectura del Software</category><category domain="http://www.blogger.com/atom/ns#">Windows 8</category><category domain="http://www.blogger.com/atom/ns#">WCF</category><title>Invocando un servicio WCF desde una aplicación Metro (desde la misma máquina!!)</title><description>&lt;p&gt;&lt;br&gt;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 &lt;a href="http://geeks.ms/blogs/aarroyo/archive/2012/01/25/windows-8-y-la-no-comunicaci-243-n-entre-metro-y-desktop.aspx" target="_blank"&gt;“NO” comunicación entre Metro y Desktop&lt;/a&gt;. 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…&lt;/p&gt; &lt;p&gt;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.&lt;/p&gt; &lt;p&gt;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 &lt;em&gt;CheckNetIsolation&lt;/em&gt;. Podemos leer un poco más al respecto aquí &lt;a href="http://msdn.microsoft.com/en-us/library/windows/apps/hh452759.aspx"&gt;http://msdn.microsoft.com/en-us/library/windows/apps/hh452759.aspx&lt;/a&gt;&lt;/p&gt; &lt;p&gt;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 &lt;em&gt;&lt;strong&gt;EndPointNotFopundException&lt;/strong&gt;&lt;/em&gt; con un mensaje tal que así:&lt;br&gt;&lt;br&gt;&lt;em&gt;&lt;font color="#666666"&gt;&lt;strong&gt;{"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."}&lt;/strong&gt;&lt;/font&gt;&lt;/em&gt;&lt;/p&gt; &lt;p&gt;Ok, a menos de que creas que la gente de Microsoft va de farol, es lo esperado, no? &lt;/p&gt; &lt;p&gt;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:&lt;/p&gt; &lt;p&gt;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 &lt;em&gt;Regedit&lt;/em&gt; y buscamos la clave de la aplicación que cuelga de:&lt;br&gt;&lt;br&gt;&lt;em&gt;&lt;font color="#666666"&gt;&lt;strong&gt;HKEY_CURRENT_USER\Software\Classes\Local Settings\Software\Microsoft\Windows\CurrentVersion\AppContainer&lt;/strong&gt;&lt;/font&gt;&lt;/em&gt;&lt;/p&gt; &lt;p&gt;Fíjate en el valor de la propiedad &lt;em&gt;displayname&lt;/em&gt; para poder identificarla.&lt;br&gt;Una vez que sepamos la rama concreta, puedes seleccionarla con el botón derecho y &lt;em&gt;copykeyname&lt;/em&gt; y selecciona el nombre de la carpeta del mapping (desde S-1-15... hasta el final). Este &amp;lt;&lt;em&gt;keyname&lt;/em&gt;&amp;gt; nos permitirá establecer la excepción más adelante.&lt;/p&gt; &lt;p&gt;A continuación, abre el “&lt;em&gt;Developer Command Promp&lt;/em&gt;” y escribe “&lt;em&gt;CheckNetIsolation&lt;/em&gt;” para acceder a la utilidad. Pégate una leidita el enlace anterior para evaluar un poco mas en detalle las capacidades de la herramienta. &lt;/p&gt; &lt;p&gt;En nuestro caso debemos escribir:&lt;/p&gt; &lt;ul&gt; &lt;li&gt;Para ver el listado de las aplicaciones ya excluidas del bloqueo de loopback:&lt;br&gt;&lt;em&gt;&lt;font color="#666666"&gt;&lt;strong&gt;CheckNetIsolation.Exe LoopbackExempt –s&lt;/strong&gt;&lt;br&gt;&lt;/font&gt;&lt;/em&gt; &lt;li&gt;Para incluir nuestra aplicación como una excepción:&lt;br&gt;&lt;em&gt;&lt;font color="#666666"&gt;&lt;strong&gt;CheckNetIsolation.exe LoopbackExempt -a -p=&amp;lt;keyname&amp;gt;&lt;/strong&gt;&lt;/font&gt;&lt;/em&gt; &lt;br&gt; &lt;li&gt;Para comprobar que ya ha sido correctamente incluida, pues vuelve a ejecutar el comando anterior (nunca te lo hubieses imaginado, verdad?)&lt;br&gt;&lt;em&gt;&lt;font color="#666666"&gt;&lt;strong&gt;CheckNetIsolation.Exe LoopbackExempt –s&lt;/strong&gt;&lt;/font&gt;&lt;/em&gt;&lt;/li&gt;&lt;/ul&gt; &lt;p&gt;Una vez hecho esto, ya podremos consumir servicios de la misma máquina sin recibir la excepción comentada al principio del post, comprobado!!&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/31098559-4430155430703318892?l=andoni-arroyo.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/andoniarroyo/~4/aVczyuonAII" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/andoniarroyo/~3/aVczyuonAII/invocando-un-servicio-wcf-desde-una.html</link><author>noreply@blogger.com (Andoni Arroyo)</author><thr:total>0</thr:total><feedburner:origLink>http://andoni-arroyo.blogspot.com/2012/01/invocando-un-servicio-wcf-desde-una.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-31098559.post-1375613804051785699</guid><pubDate>Wed, 25 Jan 2012 09:00:00 +0000</pubDate><atom:updated>2012-01-25T11:12:07.509+01:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">Metro</category><category domain="http://www.blogger.com/atom/ns#">Arquitectura del Software</category><category domain="http://www.blogger.com/atom/ns#">Windows 8</category><title>Windows 8 y la “NO” comunicación entre Metro y Desktop</title><description>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.&lt;br /&gt;
&lt;br /&gt;
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&amp;nbsp; 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.&lt;br /&gt;
&lt;br /&gt;
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 &lt;a href="http://getwired.com/2012/01/12/windows-8-a-tale-of-two-platforms/" target="_blank"&gt;Windows 8 – A Tale of Two Platforms&lt;/a&gt; al respecto.&lt;br /&gt;
&lt;br /&gt;
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. &lt;br /&gt;
&lt;br /&gt;
Quien más quien menos ha oído o va a oír al respecto:&lt;br /&gt;
&lt;em&gt;“Este servicio lo dejo igual y desde la interfaz metro lo invoco y...”&lt;/em&gt;&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
Podemos ver esta división en el siguiente gráfico:&lt;br /&gt;
&lt;a href="http://lh6.ggpht.com/-xCQtiZ57TYc/Tx6ccFmH6qI/AAAAAAAABXQ/fPHlPU_a13g/s1600-h/image%25255B3%25255D.png"&gt;&lt;img alt="image" border="0" height="335" src="http://lh3.ggpht.com/-laz5Uht8B7E/Tx6cd-O5ICI/AAAAAAAABXY/63ozirgVr9Q/image_thumb%25255B1%25255D.png?imgmax=800" style="background-image: none; border-bottom: 0px; border-left: 0px; border-right: 0px; border-top: 0px; display: block; float: none; margin-left: auto; margin-right: auto; padding-left: 0px; padding-right: 0px; padding-top: 0px;" title="image" width="611" /&gt;&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt;
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”. &lt;br /&gt;
&lt;br /&gt;
La pregunta (muy común y cada vez más) es clara: &lt;br /&gt;
&lt;strong&gt;¿Como puedo comunicar entre aplicaciones Metro y Desktop?&lt;/strong&gt;&lt;br /&gt;
&lt;br /&gt;
La respuesta no es tan clara, pero desde luego no es algo que en principio Microsoft fomente. &lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
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!!). &lt;br /&gt;
&lt;br /&gt;
Obviamente este modelo también tiene su problemática a resolver, como por ejemplo como comportarse en caso de no tener comunicación.&lt;br /&gt;
Con el fin de confirmar las limitaciones de comunicación entre aplicaciones “Metro” y “Desktop” podemos leer:&lt;br /&gt;
&lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="http://channel9.msdn.com/Events/Speakers/ale+contenti" target="_blank"&gt;Ale Contenti&lt;/a&gt; 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)&lt;br /&gt;&lt;a href="http://channel9.msdn.com/Events/BUILD/BUILD2011/TOOL-789C"&gt;http://channel9.msdn.com/Events/BUILD/BUILD2011/TOOL-789C&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Otra idea podría ser montar un Servicio Web en la parte Desktop:&lt;br /&gt;Respecto a eso, podemos leer a Jeff Sanders en los &lt;a href="http://social.msdn.microsoft.com/Forums/en-AU/winappswithcsharp/thread/735b0f24-6273-42d3-a2a4-19ef17a45b66" target="_blank"&gt;foros de soporte de Microsoft&lt;/a&gt;:&lt;br /&gt;&lt;br /&gt;&lt;em&gt;&lt;span style="color: #a5a5a5;"&gt;“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.”&lt;/span&gt;&lt;span style="color: #666666;"&gt;Otro día hablamos de CheckNetIsolation.exe, prometido!&lt;/span&gt;&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;Pero estas restricciones de comunicación no solo existen a alto nivel. Podemos leer a &lt;a href="http://www.linkedin.com/in/int19h" target="_blank"&gt;Pavel Minaev&lt;/a&gt;:&lt;br /&gt;&lt;br /&gt;&lt;em&gt;&lt;span style="color: #a5a5a5;"&gt;”… 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.”&lt;/span&gt;&lt;/em&gt; &lt;/li&gt;
&lt;/ul&gt;
&lt;br /&gt;
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:&lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;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)&lt;/li&gt;
&lt;li&gt;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...&lt;/li&gt;
&lt;li&gt;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.&lt;/li&gt;
&lt;/ul&gt;
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.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/31098559-1375613804051785699?l=andoni-arroyo.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/andoniarroyo/~4/vMvV5ad0GPc" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/andoniarroyo/~3/vMvV5ad0GPc/windows-8-y-la-no-comunicacion-entre.html</link><author>noreply@blogger.com (Andoni Arroyo)</author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://lh3.ggpht.com/-laz5Uht8B7E/Tx6cd-O5ICI/AAAAAAAABXY/63ozirgVr9Q/s72-c/image_thumb%25255B1%25255D.png?imgmax=800" height="72" width="72" /><thr:total>0</thr:total><feedburner:origLink>http://andoni-arroyo.blogspot.com/2012/01/windows-8-y-la-no-comunicacion-entre.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-31098559.post-7683395183400235037</guid><pubDate>Wed, 04 Jan 2012 08:30:00 +0000</pubDate><atom:updated>2012-01-04T09:30:01.187+01:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">UnitTest</category><category domain="http://www.blogger.com/atom/ns#">POCO</category><category domain="http://www.blogger.com/atom/ns#">DDD</category><category domain="http://www.blogger.com/atom/ns#">Test</category><title>POCOs con piel de cordero</title><description>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. &lt;br /&gt;&lt;br /&gt;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.&lt;br /&gt;&lt;br /&gt;Sintiéndolo mucho, debemos decir que esto es lo normal.&lt;br /&gt;&lt;br /&gt;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.&lt;br /&gt;
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. &lt;br /&gt;&lt;br /&gt;Poco más o menos la queja era:&lt;br /&gt;
&lt;blockquote&gt;
&lt;em&gt;&lt;span style="color: #a5a5a5;"&gt;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...&lt;/span&gt;&lt;/em&gt;&lt;/blockquote&gt;
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.&lt;br /&gt;
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.&lt;br /&gt;
Lo más interesante de todo esto son las conclusiones que podemos extraer de la experiencia:&lt;br /&gt;
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!!)&lt;br /&gt;
Por eso digo en el título que estos &lt;strong&gt;POCO son lobos con piel de cordero&lt;/strong&gt;.&lt;br /&gt;
La siguiente pregunta es ¿Debemos probar el código de infraestructura?&lt;br /&gt;
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. &lt;br /&gt;&lt;br /&gt;Podemos decidir alcanzar una cobertura menor en pruebas unitarias y realizar un mayor esfuerzo en pruebas de integración. &lt;br /&gt;
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 (&lt;em&gt;Core Business / Infraestructura&lt;/em&gt;…) en el que nos encontramos, con el retorno de valor que de la mismas obtenemos.&lt;br /&gt;
Por cierto, feliz 2012 ;)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/31098559-7683395183400235037?l=andoni-arroyo.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/andoniarroyo/~4/MNk2a1SS4e0" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/andoniarroyo/~3/MNk2a1SS4e0/pocos-con-piel-de-cordero.html</link><author>noreply@blogger.com (Andoni Arroyo)</author><thr:total>0</thr:total><feedburner:origLink>http://andoni-arroyo.blogspot.com/2012/01/pocos-con-piel-de-cordero.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-31098559.post-8520739340754638912</guid><pubDate>Tue, 20 Dec 2011 07:00:00 +0000</pubDate><atom:updated>2011-12-20T08:00:10.206+01:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">Criptografía</category><category domain="http://www.blogger.com/atom/ns#">Seguridad</category><title>Certificados, ficheros y claves privadas</title><description>&lt;p&gt;Ú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)&lt;/p&gt; &lt;p&gt;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 &lt;a href="http://es.wikipedia.org/wiki/X.509" target="_blank"&gt;certificados X509&lt;/a&gt;? &lt;/p&gt; &lt;p&gt;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 &lt;a href="http://technet.microsoft.com/en-us/library/bb727068.aspx" target="_blank"&gt;aquí&lt;/a&gt;.&lt;/p&gt; &lt;p&gt;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 &lt;a href="http://msdn.microsoft.com/en-us/library/ms732026.aspx" target="_blank"&gt;Find Private Key Tool&lt;/a&gt;.&lt;/p&gt; &lt;p&gt;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,&amp;nbsp; 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)&lt;/p&gt; &lt;p&gt;Según la especificación de la herramienta:&lt;/p&gt;&lt;pre style="border-bottom: #cecece 1px solid; border-left: #cecece 1px solid; padding-bottom: 5px; background-color: #fbfbfb; min-height: 40px; padding-left: 5px; width: 662px; padding-right: 5px; height: 176px; overflow: auto; border-top: #cecece 1px solid; border-right: #cecece 1px solid; padding-top: 5px"&gt;&lt;pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 10px"&gt;  1: Usage: FindPrivateKey &amp;lt;storeName&amp;gt; &amp;lt;storeLocation&amp;gt; [{ {-n &amp;lt;subjectName&amp;gt;} | {-t &amp;lt;thumbprint&amp;gt;} } [-f | -d | -a]]&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #f8f8f8; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 10px"&gt;  2:        &amp;lt;subjectName&amp;gt; subject name of the certificate&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 10px"&gt;  3:        &amp;lt;thumbprint&amp;gt;  thumbprint of the certificate (use certmgr.exe to get it)&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #f8f8f8; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 10px"&gt;  4:        -f            output file name only&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 10px"&gt;  5:        -d            output directory only&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #f8f8f8; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 10px"&gt;  6:        -a            output absolute file name&lt;/pre&gt;&lt;/pre&gt;&lt;br /&gt;&lt;p&gt;Ejemplos de comandos:&lt;/p&gt;&lt;br /&gt;&lt;p&gt;Buscar en StoreName “My”&amp;nbsp; y Store Location “CurrentUser” un certificado con el Subject&amp;nbsp; CN=TESTCERT (CN es el Common Name, que forma parte del Subject)&lt;/p&gt;&lt;pre style="border-bottom: #cecece 1px solid; border-left: #cecece 1px solid; padding-bottom: 5px; background-color: #fbfbfb; min-height: 40px; padding-left: 5px; width: 666px; padding-right: 5px; height: 61px; overflow: auto; border-top: #cecece 1px solid; border-right: #cecece 1px solid; padding-top: 5px"&gt;&lt;pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 10px"&gt;  1: FindPrivateKey My CurrentUser -n "&lt;span style="color: #8b0000"&gt;CN=TESTCERT&lt;/span&gt;"&lt;/pre&gt;&lt;/pre&gt;&lt;br /&gt;&lt;p&gt;Buscar en StoreName “My” y Store Location “LocalMachine” un certificado con el Thumbprint pasado por parámetro&lt;/p&gt;&lt;pre style="border-bottom: #cecece 1px solid; border-left: #cecece 1px solid; padding-bottom: 5px; background-color: #fbfbfb; min-height: 40px; padding-left: 5px; width: 671px; padding-right: 5px; height: 79px; overflow: auto; border-top: #cecece 1px solid; border-right: #cecece 1px solid; padding-top: 5px"&gt;&lt;pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 10px"&gt;  1: FindPrivateKey My LocalMachine -t "&lt;span style="color: #8b0000"&gt;40 ee 7b 2f 10 59 38 99 4f 65 9f 8f 92 38 85 a3&lt;/span&gt;" –c&lt;/pre&gt;&lt;/pre&gt;&lt;br /&gt;&lt;p&gt;En caso de que el certificado solicitado exista, la herramienta nos devolverá algo como:&lt;/p&gt;&lt;pre style="border-bottom: #cecece 1px solid; border-left: #cecece 1px solid; padding-bottom: 5px; background-color: #fbfbfb; min-height: 40px; padding-left: 5px; width: 678px; padding-right: 5px; height: 139px; overflow: auto; border-top: #cecece 1px solid; border-right: #cecece 1px solid; padding-top: 5px"&gt;&lt;pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 10px"&gt;  1: Private key directory:&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #f8f8f8; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 10px"&gt;  2: C:\ProgramData\Microsoft\Crypto\RSA\MachineKeys&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 10px"&gt;  3: Private key file name:&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #f8f8f8; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 10px"&gt;  4: &amp;lt;GUID&amp;gt;&lt;/pre&gt;&lt;/pre&gt;&lt;br /&gt;&lt;p&gt;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.&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/31098559-8520739340754638912?l=andoni-arroyo.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/andoniarroyo/~4/cJ6bCQzqfek" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/andoniarroyo/~3/cJ6bCQzqfek/certificados-ficheros-y-claves-privadas.html</link><author>noreply@blogger.com (Andoni Arroyo)</author><thr:total>1</thr:total><feedburner:origLink>http://andoni-arroyo.blogspot.com/2011/12/certificados-ficheros-y-claves-privadas.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-31098559.post-7506846815266324949</guid><pubDate>Thu, 21 Jul 2011 14:00:00 +0000</pubDate><atom:updated>2011-07-21T16:00:09.023+02:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">Eventos</category><category domain="http://www.blogger.com/atom/ns#">Metodología</category><category domain="http://www.blogger.com/atom/ns#">SCRUM</category><category domain="http://www.blogger.com/atom/ns#">Agilidad</category><title>Retrospective [Evento: SCRUM y conceptos ágiles]]</title><description>&lt;p&gt;&lt;br&gt;El pasado día 19 de Julio dentro del marco &lt;a title="http://webdevbilbao.com/" href="http://webdevbilbao.com/" target="_blank"&gt;WebDev Bilbao&lt;/a&gt; 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:&lt;br&gt; &lt;ul&gt; &lt;li&gt;Presencia&lt;br&gt;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ó...)&lt;br&gt;Se confirma, una vez más, que la inquietud por las metodologías ágiles es grande, la tendencia cada vez mayor.&lt;br&gt;&lt;/li&gt;&lt;/ul&gt; &lt;ul&gt; &lt;li&gt;Perfiles&lt;br&gt;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.&lt;br&gt;&lt;br&gt;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.&lt;br&gt;También noté la falta de diseñadores Web o gráficos. Este es un perfil que tiene presencia en &lt;a title="http://webdevbilbao.com/" href="http://webdevbilbao.com/" target="_blank"&gt;WebDev Bilbao&lt;/a&gt; y que tiene una integración particular en los equipos de desarrollo. También eché en falta su voz.&lt;br&gt;&lt;br&gt;Otra vez será...(o eso espero!)&lt;br&gt; &lt;li&gt;Empresas pequeñas, startups...&lt;br&gt;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.&lt;br&gt;&lt;br&gt;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.&lt;br&gt; &lt;li&gt;Poco conocimiento previo sobre SCRUM&lt;br&gt;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...&lt;br&gt;&lt;br&gt;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.&lt;/li&gt;&lt;/ul&gt; &lt;p&gt;&lt;br&gt;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.&lt;br&gt;Desde el grupo de Agilidad y gestión de proyectos de &lt;a title="http://webdevbilbao.com/" href="http://webdevbilbao.com/" target="_blank"&gt;WebDev Bilbao&lt;/a&gt; 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!!)&lt;br&gt;&lt;br&gt;También intentaremos abrir otras líneas como una introducción al &lt;a href="http://geeks.ms/blogs/aarroyo/archive/2009/08/12/kanban.aspx" target="_blank"&gt;Kanban&lt;/a&gt; o confrontar las metodologías ágiles con otras más predictivas, que no solo de SCRUM vive el hombre.&lt;br&gt;&lt;br&gt;Por supuesto, si eres, trabajas o pasas por Bilbao no dudes en pasarte por el &lt;a title="http://webdevbilbao.com/" href="http://webdevbilbao.com/" target="_blank"&gt;WebDev Bilbao&lt;/a&gt; que serás bienvenido!&lt;/p&gt; &lt;p&gt;Por cierto, os podéis descargar la presentación de la charla de &lt;a href="https://skydrive.live.com/redir.aspx?cid=f81337c1ad08b635&amp;amp;resid=F81337C1AD08B635!1126" target="_blank"&gt;aquí&lt;/a&gt; (hay más cosas en &lt;em&gt;Prototypes&lt;/em&gt;, cotillea al gusto ;))&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/31098559-7506846815266324949?l=andoni-arroyo.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/andoniarroyo/~4/bTRkNpp7pJo" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/andoniarroyo/~3/bTRkNpp7pJo/retrospective-evento-scrum-y-conceptos.html</link><author>noreply@blogger.com (Andoni Arroyo)</author><thr:total>0</thr:total><feedburner:origLink>http://andoni-arroyo.blogspot.com/2011/07/retrospective-evento-scrum-y-conceptos.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-31098559.post-2043427767031377825</guid><pubDate>Wed, 13 Jul 2011 19:12:00 +0000</pubDate><atom:updated>2011-07-13T21:12:53.023+02:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">Eventos</category><category domain="http://www.blogger.com/atom/ns#">WebDevBilbao</category><category domain="http://www.blogger.com/atom/ns#">Metodología</category><category domain="http://www.blogger.com/atom/ns#">SCRUM</category><category domain="http://www.blogger.com/atom/ns#">Agilidad</category><title>Evento: SCRUM y conceptos ágiles</title><description>&lt;p&gt;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 &lt;a title="http://webdevbilbao.com/" href="http://webdevbilbao.com/" target="_blank"&gt;WebDev Bilbao&lt;/a&gt;. En ella, explicaré algunos conceptos claves sobre agilidad y analizaremos las propuestas de SCRUM sobre como afrontarlos. &lt;br&gt;&lt;br&gt;A quien va dirigido&lt;/p&gt; &lt;ul&gt; &lt;li&gt;Gestores de proyectos de desarrollo de Software.&lt;/li&gt; &lt;li&gt;&lt;a href="http://es.wikipedia.org/wiki/Product_manager" target="_blank"&gt;Product mangers&lt;/a&gt; y Stakeholders interesados en agilidad.&lt;/li&gt; &lt;li&gt;Por supuesto, desarrolladores!&lt;/li&gt;&lt;/ul&gt; &lt;p&gt;Fecha y hora:&lt;/p&gt; &lt;ul&gt; &lt;li&gt;19 de Julio de 2011 a las 19:00&lt;/li&gt; &lt;li&gt;&lt;a href="http://eutokia.org/" target="_blank"&gt;Eutokia&lt;/a&gt; (Centro de Innovación Social de Bilbao)&lt;/li&gt;&lt;/ul&gt; &lt;p&gt;Nota:&lt;br&gt;Aunque en principio el acceso a estos eventos está restringido a la gente del grupo de &lt;a href="http://webdevbilbao.com/" target="_blank"&gt;WebDeb Bilbao&lt;/a&gt;, si quieres pasarte puedes enviarme un correo electrónico a &lt;a href="mailto:andoni.arroyo@gmail.com"&gt;andoni.arroyo@gmail.com&lt;/a&gt; y veremos que podemos hacer ;)&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/31098559-2043427767031377825?l=andoni-arroyo.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/andoniarroyo/~4/kM4ub6S1LLQ" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/andoniarroyo/~3/kM4ub6S1LLQ/scrum-y-conceptos-agiles.html</link><author>noreply@blogger.com (Andoni Arroyo)</author><thr:total>0</thr:total><feedburner:origLink>http://andoni-arroyo.blogspot.com/2011/07/scrum-y-conceptos-agiles.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-31098559.post-5114428839774367017</guid><pubDate>Fri, 08 Jul 2011 06:00:00 +0000</pubDate><atom:updated>2011-07-08T08:00:08.904+02:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">MVVM</category><category domain="http://www.blogger.com/atom/ns#">.NET</category><category domain="http://www.blogger.com/atom/ns#">Informática</category><category domain="http://www.blogger.com/atom/ns#">Excepciones</category><category domain="http://www.blogger.com/atom/ns#">Visual Studio</category><category domain="http://www.blogger.com/atom/ns#">Silverlight</category><category domain="http://www.blogger.com/atom/ns#">Desarrollo de Software</category><category domain="http://www.blogger.com/atom/ns#">OOB</category><title>Silverlight y las excepciones no gestionadas</title><description>&lt;p&gt;Silverlight nace para cubrir las necesidades de aplicaciones &lt;a href="http://es.wikipedia.org/wiki/Rich_Internet_Applications" target="_blank"&gt;RIA&lt;/a&gt;, 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.&lt;br /&gt;&lt;br /&gt;Por ejemplo, la huella en memoria de Silverlight es sensiblemente menor que incuso para el &lt;a href="http://msdn.microsoft.com/es-es/library/cc656912.aspx" target="_blank"&gt;.NET Framework Client Profile&lt;/a&gt;. 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…&lt;br /&gt;&lt;br /&gt;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…)&lt;br /&gt;&lt;br /&gt;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.&lt;br /&gt;&lt;br /&gt;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)&lt;br /&gt;&lt;br /&gt;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.&lt;br /&gt;&lt;br /&gt;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.&lt;/p&gt; &lt;p&gt;Si vemos el código que nos propone el Visual Studio al crear el proyecto de Silverlight observamos:&lt;/p&gt;&lt;pre style="border-bottom: #cecece 1px solid; border-left: #cecece 1px solid; padding-bottom: 5px; background-color: #fbfbfb; min-height: 40px; padding-left: 5px; width: 639px; padding-right: 5px; height: 399px; overflow: auto; border-top: #cecece 1px solid; border-right: #cecece 1px solid; padding-top: 5px"&gt;&lt;pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 10px"&gt;  1:         &lt;span style="color: #0000ff"&gt;private&lt;/span&gt; &lt;span style="color: #0000ff"&gt;void&lt;/span&gt; Application_UnhandledException(&lt;span style="color: #0000ff"&gt;object&lt;/span&gt; sender, ApplicationUnhandledExceptionEventArgs e)&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #f8f8f8; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 10px"&gt;  2:         {&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 10px"&gt;  3:             &lt;span style="color: #008000"&gt;// If the app is running outside of the debugger then report the exception using&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #f8f8f8; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 10px"&gt;  4:             &lt;span style="color: #008000"&gt;// the browser's exception mechanism. On IE this will display it a yellow alert &lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 10px"&gt;  5:             &lt;span style="color: #008000"&gt;// icon in the status bar and Firefox will display a script error.&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #f8f8f8; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 10px"&gt;  6:             &lt;span style="color: #0000ff"&gt;if&lt;/span&gt; (!System.Diagnostics.Debugger.IsAttached)&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 10px"&gt;  7:             {&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #f8f8f8; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 10px"&gt;  8:&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 10px"&gt;  9:                 &lt;span style="color: #008000"&gt;// NOTE: This will allow the application to continue running after an exception has been thrown&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #f8f8f8; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 10px"&gt; 10:                 &lt;span style="color: #008000"&gt;// but not handled. &lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 10px"&gt; 11:                 &lt;span style="color: #008000"&gt;// For production applications this error handling should be replaced with something that will &lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #f8f8f8; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 10px"&gt; 12:                 &lt;span style="color: #008000"&gt;// report the error to the website and stop the application.&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 10px"&gt; 13:                 e.Handled = &lt;span style="color: #0000ff"&gt;true&lt;/span&gt;;&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #f8f8f8; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 10px"&gt; 14:                 Deployment.Current.Dispatcher.BeginInvoke(&lt;span style="color: #0000ff"&gt;delegate&lt;/span&gt; { ReportErrorToDOM(e); });&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 10px"&gt; 15:             }&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #f8f8f8; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 10px"&gt; 16:         }&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 10px"&gt; 17:&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #f8f8f8; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 10px"&gt; 18:         &lt;span style="color: #0000ff"&gt;private&lt;/span&gt; &lt;span style="color: #0000ff"&gt;void&lt;/span&gt; ReportErrorToDOM(ApplicationUnhandledExceptionEventArgs e)&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 10px"&gt; 19:         {&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #f8f8f8; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 10px"&gt; 20:             &lt;span style="color: #0000ff"&gt;try&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 10px"&gt; 21:             {&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #f8f8f8; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 10px"&gt; 22:                 &lt;span style="color: #0000ff"&gt;string&lt;/span&gt; errorMsg = e.ExceptionObject.Message + e.ExceptionObject.StackTrace;&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 10px"&gt; 23:                 errorMsg = errorMsg.Replace('"&lt;span style="color: #8b0000"&gt;', '\'').Replace(&lt;/span&gt;"\r\n"&lt;span style="color: #8b0000"&gt;, @&lt;/span&gt;"\n"&lt;span style="color: #8b0000"&gt;);&lt;br /&gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre style="background-color: #f8f8f8; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 10px"&gt; 24:&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 10px"&gt; 25:                 System.Windows.Browser.HtmlPage.Window.Eval("&lt;span style="color: #8b0000"&gt;throw new Error(\"Unhandled Error in Silverlight Application &lt;/span&gt;" + errorMsg + "&lt;span style="color: #8b0000"&gt;\");&lt;/span&gt;");&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #f8f8f8; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 10px"&gt; 26:             }&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 10px"&gt; 27:             &lt;span style="color: #0000ff"&gt;catch&lt;/span&gt; (Exception)&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #f8f8f8; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 10px"&gt; 28:             {&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 10px"&gt; 29:             }&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #f8f8f8; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 10px"&gt; 30:         }&lt;/pre&gt;&lt;/pre&gt;&lt;br /&gt;&lt;p&gt;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…&lt;br /&gt;&lt;br /&gt;Vamos a comenzar a modificar este comportamiento para que se adapte a nuestras necesidades.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;Lo primero vamos a hacer es cambiar el código del método &lt;em&gt;Application_UnhandledException&lt;/em&gt; y eliminar la función &lt;em&gt;ReportErrorToDOM&lt;/em&gt;.&lt;br /&gt;&lt;br /&gt;El resultado quedaría algo así:&lt;/p&gt;&lt;pre style="border-bottom: #cecece 1px solid; border-left: #cecece 1px solid; padding-bottom: 5px; background-color: #fbfbfb; min-height: 40px; padding-left: 5px; width: 633px; padding-right: 5px; height: 79px; overflow: auto; border-top: #cecece 1px solid; border-right: #cecece 1px solid; padding-top: 5px"&gt;&lt;pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 10px"&gt;  1:         &lt;span style="color: #0000ff"&gt;private&lt;/span&gt; &lt;span style="color: #0000ff"&gt;void&lt;/span&gt; Application_UnhandledException(&lt;span style="color: #0000ff"&gt;object&lt;/span&gt; sender, ApplicationUnhandledExceptionEventArgs e)&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #f8f8f8; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 10px"&gt;  2:         {&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 10px"&gt;  3:             e.Handled = &lt;span style="color: #0000ff"&gt;true&lt;/span&gt;;&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #f8f8f8; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 10px"&gt;  4:             &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; ExceptionDetailView {DataContext = &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; ExceptionDetailViewModel(e.ExceptionObject)}.Show();&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 10px"&gt;  5:         }&lt;/pre&gt;&lt;/pre&gt;&lt;br /&gt;&lt;p&gt;&lt;br /&gt;Sencillo, verdad?&lt;/p&gt;&lt;br /&gt;&lt;p&gt;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.&lt;br /&gt;&lt;br /&gt;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á.&lt;br /&gt;&lt;br /&gt;Si deseáis incluir una buena gestión de log en Silverlight os recomiendo usar el &lt;a href="http://blogs.msdn.com/b/agile/archive/2011/05/11/silverlight-integration-pack-for-microsoft-enterprise-library-5-0-released.aspx" target="_blank"&gt;Silverlight Integration Pack for Microsoft Enterprise Library 5.0&lt;/a&gt;.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;Ahora la pregunta es que es &lt;em&gt;ExceptionDetailView&lt;/em&gt;?&lt;/p&gt;&lt;br /&gt;&lt;p&gt;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 &lt;a href="http://msdn.microsoft.com/es-es/library/system.windows.controls.childwindow(v=vs.95).aspx" target="_blank"&gt;ChildWindow&lt;/a&gt; clase que se incluye en Silverlight desde la versión 3.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;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:&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://lh5.ggpht.com/-tvRWXtskDKA/ThYpoI8eYjI/AAAAAAAABBs/FWkYEWHdPow/s1600-h/image4.png"&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: block; float: none; border-top-width: 0px; border-bottom-width: 0px; margin-left: auto; border-left-width: 0px; margin-right: auto; padding-top: 0px" title="image" border="0" alt="image" src="http://lh5.ggpht.com/-IlmWWvMqlcY/ThYpt_NLykI/AAAAAAAABBw/mo3HIfgD71s/image_thumb2.png?imgmax=800" width="521" height="409" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;En la implementación de la vista empleamos el patrón &lt;a href="http://en.wikipedia.org/wiki/Model_View_ViewModel" target="_blank"&gt;MVVM&lt;/a&gt;, sobre el cual existen toneladas de información. (y eso en raras ocasiones es bueno…)&lt;br /&gt;&lt;br /&gt;Resumiendo podemos decir que disponemos de un &lt;em&gt;ViewModel&lt;/em&gt; (&lt;em&gt;ExceptionDetailViewModel.cs&lt;/em&gt;) y una vista que se encarga de pintar los datos que ese &lt;em&gt;ViewModel&lt;/em&gt; expone por pantalla. (&lt;em&gt;ExceptionDetailView.xaml&lt;/em&gt;)&lt;br /&gt;&lt;br /&gt;La vista tiene asociada en su &lt;em&gt;DataContext&lt;/em&gt; el &lt;em&gt;ViewModel&lt;/em&gt; y vía &lt;em&gt;Binding&lt;/em&gt; implementamos el conexión entre los datos y su representación gráfica.&lt;br /&gt;&lt;br /&gt;Además de los datos es responsabilidad del &lt;em&gt;ViewModel&lt;/em&gt; exportar la funcionalidad (vía comandos) que la vista puede invocar. En este caso, nuestro &lt;em&gt;ViewModel&lt;/em&gt; expone un comando a la vista (&lt;em&gt;ToggleShowingExceptionDetailCommand&lt;/em&gt;) que le permite mostrar u ocultar la información detallada de la excepción, para contentar a los más curiosos…&lt;br /&gt;&lt;br /&gt;Pues ya solo queda probar, porque nos encanta probar, verdad??&lt;/p&gt;&lt;br /&gt;&lt;p&gt;Y en este caso debemos lanzar una excepción (al gusto, yo me he decantado por una &lt;em&gt;IndexOutOfRangeException&lt;/em&gt;) y comprobamos que la aplicación muestra el mensaje de error de manera correcta en vez de quedarse en blanco.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;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 &lt;a href="https://skydrive.live.com/?cid=f81337c1ad08b635&amp;amp;sc=documents&amp;amp;move=F81337C1AD08B635!1063&amp;amp;sid=F81337C1AD08B635!111&amp;amp;iscopy=0&amp;amp;id=F81337C1AD08B635%21144#" target="_blank"&gt;aquí&lt;/a&gt; (el nombre del archivo de esta solución es &lt;em&gt;Andoni.Arroyo.UnhandledException&lt;/em&gt;  ) &lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/31098559-5114428839774367017?l=andoni-arroyo.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/andoniarroyo/~4/UpBQry2LZYA" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/andoniarroyo/~3/UpBQry2LZYA/silverlight-y-las-excepciones-no.html</link><author>noreply@blogger.com (Andoni Arroyo)</author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://lh5.ggpht.com/-IlmWWvMqlcY/ThYpt_NLykI/AAAAAAAABBw/mo3HIfgD71s/s72-c/image_thumb2.png?imgmax=800" height="72" width="72" /><thr:total>0</thr:total><feedburner:origLink>http://andoni-arroyo.blogspot.com/2011/07/silverlight-y-las-excepciones-no.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-31098559.post-3607789179844793821</guid><pubDate>Sat, 25 Jun 2011 17:35:00 +0000</pubDate><atom:updated>2011-06-25T19:35:55.517+02:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">TLS</category><category domain="http://www.blogger.com/atom/ns#">Rendimiento</category><category domain="http://www.blogger.com/atom/ns#">Threads</category><category domain="http://www.blogger.com/atom/ns#">.NET Framework 4.0</category><title>Evolución del Thread Local Storage (a.k.a. TLS)</title><description>&lt;p&gt;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. &lt;br&gt;&lt;br&gt;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.&lt;/p&gt; &lt;p&gt;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 &lt;a href="http://en.wikipedia.org/wiki/Thread-local_storage" target="_blank"&gt;TLS&lt;/a&gt;.&lt;/p&gt; &lt;p&gt;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. &lt;/p&gt; &lt;p&gt;Esta característica es interesante si por ejemplo exponemos cierta funcionalidad a través de un &lt;a href="http://es.wikipedia.org/wiki/Singleton" target="_blank"&gt;Singleton&lt;/a&gt; (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 &lt;a href="http://msdn.microsoft.com/en-us/library/ms693421(v=vs.85).aspx" target="_blank"&gt;MTA&lt;/a&gt; (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. &lt;/p&gt; &lt;p&gt;Para cubrir esta funcionalidad desde el .NET Framework 1.1 existe el atributo &lt;a href="http://msdn.microsoft.com/en-us/library/system.threadstaticattribute.aspx" target="_blank"&gt;[ThreadStatic]&lt;/a&gt; que brinda una forma elegante de implementarlo. &lt;/p&gt; &lt;p&gt;Veamos con un poco de código:&lt;/p&gt;&lt;pre style="border-bottom: #cecece 1px solid; border-left: #cecece 1px solid; padding-bottom: 5px; background-color: #fbfbfb; min-height: 40px; padding-left: 5px; width: 650px; padding-right: 5px; overflow: auto; border-top: #cecece 1px solid; border-right: #cecece 1px solid; padding-top: 5px"&gt;&lt;pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 10px"&gt;  1: ...&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #f8f8f8; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 10px"&gt;  2: &lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 10px"&gt;  3: &lt;span style="color: #0000ff"&gt;internal&lt;/span&gt; &lt;span style="color: #0000ff"&gt;class&lt;/span&gt; TLSTestClass&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #f8f8f8; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 10px"&gt;  4: {&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 10px"&gt;  5:     &lt;span style="color: #0000ff"&gt;private&lt;/span&gt; ClassWithHeavyProcess tp;&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #f8f8f8; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 10px"&gt;  6: &lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 10px"&gt;  7:     &lt;span style="color: #0000ff"&gt;internal&lt;/span&gt; &lt;span style="color: #0000ff"&gt;void&lt;/span&gt; Test()&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #f8f8f8; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 10px"&gt;  8:     {&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 10px"&gt;  9:         &lt;span style="color: #008000"&gt;//UI Thread&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #f8f8f8; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 10px"&gt; 10:         tp = &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; ClassWithHeavyProcess();&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 10px"&gt; 11:         tp.HeavyMethod();&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #f8f8f8; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 10px"&gt; 12: &lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 10px"&gt; 13:         var bw = &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; BackgroundWorker();&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #f8f8f8; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 10px"&gt; 14:         bw.DoWork += BwDoWork;&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 10px"&gt; 15:         bw.RunWorkerAsync();&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #f8f8f8; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 10px"&gt; 16: &lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 10px"&gt; 17:         var bw2 = &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; BackgroundWorker();&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #f8f8f8; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 10px"&gt; 18:         bw2.DoWork += Bw2DoWork;&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 10px"&gt; 19:         bw2.RunWorkerAsync();&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #f8f8f8; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 10px"&gt; 20:     }&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 10px"&gt; 21: &lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #f8f8f8; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 10px"&gt; 22:     &lt;span style="color: #0000ff"&gt;void&lt;/span&gt; BwDoWork(&lt;span style="color: #0000ff"&gt;object&lt;/span&gt; sender, DoWorkEventArgs e)&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 10px"&gt; 23:     {&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #f8f8f8; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 10px"&gt; 24:         tp.HeavyMethod();&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 10px"&gt; 25:     }&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #f8f8f8; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 10px"&gt; 26: &lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 10px"&gt; 27:     &lt;span style="color: #0000ff"&gt;void&lt;/span&gt; Bw2DoWork(&lt;span style="color: #0000ff"&gt;object&lt;/span&gt; sender, DoWorkEventArgs e)&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #f8f8f8; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 10px"&gt; 28:     {&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 10px"&gt; 29:         tp.HeavyMethod();&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #f8f8f8; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 10px"&gt; 30:     }&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 10px"&gt; 31: }&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #f8f8f8; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 10px"&gt; 32: ...&lt;/pre&gt;&lt;/pre&gt;&lt;br /&gt;&lt;p&gt;Veamos como implementar la clase &lt;em&gt;ClassWithHeavyProcess&lt;/em&gt;. &lt;br&gt;&lt;br&gt;Como primera aproximación podemos hacer algo así:&lt;/p&gt;&lt;pre style="border-bottom: #cecece 1px solid; border-left: #cecece 1px solid; padding-bottom: 5px; background-color: #fbfbfb; min-height: 40px; padding-left: 5px; width: 650px; padding-right: 5px; overflow: auto; border-top: #cecece 1px solid; border-right: #cecece 1px solid; padding-top: 5px"&gt;&lt;pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 10px"&gt;  1:  &lt;span style="color: #0000ff"&gt;internal&lt;/span&gt; &lt;span style="color: #0000ff"&gt;class&lt;/span&gt; ClassWithHeavyProcess&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #f8f8f8; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 10px"&gt;  2:     {&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 10px"&gt;  3:         [ThreadStatic]&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #f8f8f8; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 10px"&gt;  4:         &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;static&lt;/span&gt; NeededForThreadProcess _neededForThreadProcess;&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 10px"&gt;  5:         &lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #f8f8f8; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 10px"&gt;  6:         &lt;span style="color: #0000ff"&gt;static&lt;/span&gt; ClassWithHeavyProcess()&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 10px"&gt;  7:         {&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #f8f8f8; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 10px"&gt;  8:             _neededForThreadProcess = &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; NeededForThreadProcess { Name = "&lt;span style="color: #8b0000"&gt;Andoni&lt;/span&gt;" };&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 10px"&gt;  9:         }&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #f8f8f8; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 10px"&gt; 10: &lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 10px"&gt; 11:         &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;void&lt;/span&gt; HeavyMethod()&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #f8f8f8; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 10px"&gt; 12:         {&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 10px"&gt; 13:             _neededForThreadProcess.Name = "&lt;span style="color: #8b0000"&gt;Assigned from the thread with id: &lt;/span&gt;" + Thread.CurrentThread.ManagedThreadId;&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #f8f8f8; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 10px"&gt; 14:         }&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 10px"&gt; 15:     }&lt;/pre&gt;&lt;/pre&gt;&lt;br /&gt;&lt;p&gt;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). &lt;br&gt;&lt;br&gt;Si no tenemos en cuenta esta circunstancia podemos obtener una bonita &lt;a href="http://msdn.microsoft.com/es-es/library/system.nullreferenceexception(v=vs.80).aspx" target="_blank"&gt;System.NullReferenceException&lt;/a&gt; como la obtiene el código aquí mostrado…&lt;/p&gt;&lt;br /&gt;&lt;p&gt;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. &lt;br&gt;&lt;br&gt;Entonces tendríamos algo así:&lt;/p&gt;&lt;pre style="border-bottom: #cecece 1px solid; border-left: #cecece 1px solid; padding-bottom: 5px; background-color: #fbfbfb; min-height: 40px; padding-left: 5px; width: 650px; padding-right: 5px; overflow: auto; border-top: #cecece 1px solid; border-right: #cecece 1px solid; padding-top: 5px"&gt;&lt;pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 10px"&gt;  1:  &lt;span style="color: #0000ff"&gt;internal&lt;/span&gt; &lt;span style="color: #0000ff"&gt;class&lt;/span&gt; ClassWithHeavyProcess&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #f8f8f8; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 10px"&gt;  2:     {&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 10px"&gt;  3:         [ThreadStatic]&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #f8f8f8; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 10px"&gt;  4:         &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;static&lt;/span&gt; NeededForThreadProcess _neededForThreadProcess;&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 10px"&gt;  5: &lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #f8f8f8; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 10px"&gt;  6:         &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; NeededForThreadProcess NeededForThreadProcess&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 10px"&gt;  7:         {&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #f8f8f8; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 10px"&gt;  8:             &lt;span style="color: #0000ff"&gt;get&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 10px"&gt;  9:             {&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #f8f8f8; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 10px"&gt; 10:                 &lt;span style="color: #0000ff"&gt;if&lt;/span&gt; (_neededForThreadProcess == &lt;span style="color: #0000ff"&gt;null&lt;/span&gt;)&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 10px"&gt; 11:                     _neededForThreadProcess = &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; NeededForThreadProcess();&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #f8f8f8; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 10px"&gt; 12:                 &lt;span style="color: #0000ff"&gt;return&lt;/span&gt; _neededForThreadProcess;&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 10px"&gt; 13:             }&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #f8f8f8; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 10px"&gt; 14:         }&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 10px"&gt; 15: &lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #f8f8f8; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 10px"&gt; 16:         &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;void&lt;/span&gt; HeavyMethod()&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 10px"&gt; 17:         {&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #f8f8f8; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 10px"&gt; 18:             NeededForThreadProcess.Name = "&lt;span style="color: #8b0000"&gt;Assigned from the thread with id: &lt;/span&gt;" + Thread.CurrentThread.ManagedThreadId;&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 10px"&gt; 19:         }&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #f8f8f8; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 10px"&gt; 20:     }&lt;/pre&gt;&lt;/pre&gt;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 &lt;a href="http://msdn.microsoft.com/en-us/library/0xy59wtx.aspx" target="_blank"&gt;GC&lt;/a&gt; ha decidido llevárselos al más allá…). &lt;br&gt;&lt;br&gt;Bueno, esto es así casi siempre… &lt;br /&gt;&lt;p&gt;Recordad que desde el .NET Framework 2.0 existe el &lt;a href="http://msdn.microsoft.com/es-es/library/system.threading.threadpool(v=vs.80).aspx" target="_blank"&gt;ThreadPool&lt;/a&gt;. 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. &lt;br&gt;&lt;br&gt;Si os preguntáis porque os cuento esto, tened en cuenta que si revisáis la implementación de la clase &lt;em&gt;TLSTestClass&lt;/em&gt; podéis comprobar que está empleando objetos &lt;em&gt;BackgroundWorker&lt;/em&gt;&amp;nbsp; que internamente negocian con el &lt;em&gt;ThreadPool&lt;/em&gt; de .NET.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;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 &lt;a href="http://msdn.microsoft.com/en-us/library/dd642243.aspx" target="_blank"&gt;ThreadLocal&lt;/a&gt; (que ya &lt;a href="http://download.oracle.com/javase/1.4.2/docs/api/java/lang/ThreadLocal.html" target="_blank"&gt;existía&lt;/a&gt; en Java, sí…) que se encarga de encapsular el poco “&lt;em&gt;pipeline”&lt;/em&gt; que nos quedaba por hacer a nosotros. &lt;br&gt;&lt;br&gt;Con ella podemos evitar la propiedad y especificar el constructor que deberá invocar cuando lo necesite.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;Con esta clase nuestro código podría quedar tan elegante como este:&lt;/p&gt;&lt;pre style="border-bottom: #cecece 1px solid; border-left: #cecece 1px solid; padding-bottom: 5px; background-color: #fbfbfb; min-height: 40px; padding-left: 5px; width: 650px; padding-right: 5px; overflow: auto; border-top: #cecece 1px solid; border-right: #cecece 1px solid; padding-top: 5px"&gt;&lt;pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 10px"&gt;  1:  &lt;span style="color: #0000ff"&gt;internal&lt;/span&gt; &lt;span style="color: #0000ff"&gt;class&lt;/span&gt; ThreadProcess&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #f8f8f8; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 10px"&gt;  2:     {&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 10px"&gt;  3:         ThreadLocal&amp;lt;NeededForThreadProcess&amp;gt; NeededForThreadProcess = &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; ThreadLocal&amp;lt;NeededForThreadProcess&amp;gt;(() =&amp;gt; &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; NeededForThreadProcess());&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #f8f8f8; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 10px"&gt;  4: &lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 10px"&gt;  5:         &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;void&lt;/span&gt; HeavyMethod()&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #f8f8f8; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 10px"&gt;  6:         {&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 10px"&gt;  7:             NeededForThreadProcess.Value.Name = "&lt;span style="color: #8b0000"&gt;Assigned from the thread with id: &lt;/span&gt;" + Thread.CurrentThread.ManagedThreadId;&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #f8f8f8; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 10px"&gt;  8:         }&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 10px"&gt;  9:     }&lt;/pre&gt;&lt;/pre&gt;&lt;br /&gt;&lt;p&gt;Realmente elegante!&lt;/p&gt;&lt;br /&gt;&lt;p&gt;Si implementáis esta funcionalidad porque desde la clase &lt;em&gt;NeededForThreadProcess &lt;/em&gt;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..&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/31098559-3607789179844793821?l=andoni-arroyo.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/andoniarroyo/~4/OWDR7o3MZ_Y" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/andoniarroyo/~3/OWDR7o3MZ_Y/evolucion-del-thread-local-storage-aka.html</link><author>noreply@blogger.com (Andoni Arroyo)</author><thr:total>0</thr:total><feedburner:origLink>http://andoni-arroyo.blogspot.com/2011/06/evolucion-del-thread-local-storage-aka.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-31098559.post-3542080705674346</guid><pubDate>Wed, 27 Oct 2010 23:02:00 +0000</pubDate><atom:updated>2010-10-28T01:02:07.463+02:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">Metodología</category><category domain="http://www.blogger.com/atom/ns#">TFS</category><category domain="http://www.blogger.com/atom/ns#">Pruebas unitarias</category><category domain="http://www.blogger.com/atom/ns#">SCRUM</category><title>“scrum” con minúsculas</title><description>&lt;p&gt;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. &lt;/p&gt;  &lt;p&gt;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.&lt;/p&gt;  &lt;p&gt;Te puedes quedar, como dice un amigo, “Buscando por donde le entra el agua al coco…”&lt;/p&gt;  &lt;p&gt;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…    &lt;br /&gt;    &lt;br /&gt;Algunos de los errores más comunes que nos pueden llevar a tener un SCRUM sesgado y poco efectivo pueden ser:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;&lt;strong&gt;No integrar los hitos heredados en la planificación del Backlog        &lt;br /&gt;&lt;/strong&gt;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.       &lt;br /&gt;&lt;/li&gt;    &lt;li&gt;&lt;strong&gt;Jugar con dos barajas con las prioridades        &lt;br /&gt;&lt;/strong&gt;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.       &lt;br /&gt;&lt;/li&gt;    &lt;li&gt;&lt;strong&gt;Asumir de manera parcial o sesgada las reglas del juego        &lt;br /&gt;&lt;/strong&gt;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.       &lt;br /&gt;&lt;/li&gt;    &lt;li&gt;&lt;strong&gt;Presencia de roles satélites o heredados        &lt;br /&gt;&lt;/strong&gt;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.       &lt;br /&gt;&lt;/li&gt;    &lt;li&gt;&lt;strong&gt;Permitir implantar la metodología sin conciencia Top-Down        &lt;br /&gt;&lt;/strong&gt;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 ;)       &lt;br /&gt;&lt;/li&gt;    &lt;li&gt;&lt;strong&gt;Establecer un ámbito de actuación de la metodología reducido o para partes de los equipos        &lt;br /&gt;&lt;/strong&gt;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.       &lt;br /&gt;&lt;/li&gt;    &lt;li&gt;&lt;strong&gt;Impedimentos de Hardware, limitación de inversiones        &lt;br /&gt;&lt;/strong&gt;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.       &lt;br /&gt;&lt;/li&gt;    &lt;li&gt;&lt;strong&gt;Intentar implantar todas las best-practices a la vez        &lt;br /&gt;&lt;/strong&gt;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.       &lt;br /&gt;&lt;/li&gt;    &lt;li&gt;&lt;strong&gt;Falta de paciencia y fe en los resultados        &lt;br /&gt;&lt;/strong&gt;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.       &lt;br /&gt;&lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;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.    &lt;br /&gt;    &lt;br /&gt;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.&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/31098559-3542080705674346?l=andoni-arroyo.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/andoniarroyo/~4/7M8Zd8UPoTI" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/andoniarroyo/~3/7M8Zd8UPoTI/scrum-con-minusculas.html</link><author>noreply@blogger.com (Andoni Arroyo)</author><thr:total>0</thr:total><feedburner:origLink>http://andoni-arroyo.blogspot.com/2010/10/scrum-con-minusculas.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-31098559.post-3008868575537081705</guid><pubDate>Sun, 22 Aug 2010 20:41:00 +0000</pubDate><atom:updated>2010-08-22T22:41:21.105+02:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">Cloud computing</category><title>Cloud Computing, lo tienes claro?</title><description>&lt;p&gt;Cada día escuchamos más y más hablar de Cloud Computing. La evolución del mundo del desarrollo marca una clara tendencia debido a las múltiples beneficios que este paradigma aporta. Vamos a revisar los principales conceptos de manera muy sintetizada de tal modo que podamos aprender con las ideas claras.    &lt;br /&gt;    &lt;br /&gt;Una cosa que debemos tener en mente es que el Cloud Computing es un paradigma en evolución. Por lo tanto, sus definiciones se encuentran sujetas a debate por parte de todos los actores implicados. Estos (está de mas decirlo) pretenden arrimar el ascua a su sardina, pero eso es harina de otro costal...&lt;/p&gt;  &lt;p&gt;Basándonos en las definiciones del &lt;a href="http://www.nist.gov/index.html" target="_blank"&gt;National Institute of Standards and Technology&lt;/a&gt;, Cloud Computing es un modelo para habilitar acceso remoto y bajo demanda a un conjunto de recursos computacionales (redes, servidores, almacenamiento, aplicaciones y servicios) que puedan ser rápidamente aprovisionados y liberados con un mínimo esfuerzo de gestión o interacción con el proveedor de servicios.&lt;/p&gt;  &lt;p&gt;De manera estandarizada se especifican cinco características esenciales, tres modelos de servicio y cuatro modelos de despliegue. Vamos a revisar esos conceptos para componer una idea más completa.&lt;/p&gt;  &lt;p&gt;&lt;b&gt;Carcateristicas:&lt;/b&gt;&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;     &lt;p&gt;&lt;strong&gt;Auto-servicio bajo demanda&lt;/strong&gt;         &lt;br /&gt;Un cliente puede aprovisionar de manera unilateral las capacidades computacionales en base a las necesidades, sin requerir interacción humana con cada proveedor de servicios.         &lt;br /&gt;&lt;/p&gt;   &lt;/li&gt;    &lt;li&gt;     &lt;p&gt;&lt;strong&gt;Amplio acceso a la red&lt;/strong&gt;         &lt;br /&gt;Los recursos están disponibles a través de la red y accedidos a través de mecanismos estándar que propician el uso desde plataformas heterogéneas.         &lt;br /&gt;&lt;/p&gt;   &lt;/li&gt;    &lt;li&gt;     &lt;p&gt;&lt;strong&gt;Pool de recursos&lt;/strong&gt;         &lt;br /&gt;Los recursos computacionales del proveedor son sirven a múltiples clientes empleando un modelo multi-tenant, con diferentes recursos físicos y virtuales         &lt;br /&gt;dinamicamente asignados y reasignados en base a las demandas del cliente.         &lt;br /&gt;&lt;/p&gt;   &lt;/li&gt;    &lt;li&gt;     &lt;p&gt;&lt;strong&gt;Rápida elasticidad&lt;/strong&gt;         &lt;br /&gt;Los recursos pueden ser rápida y elasticamente aprovisionados, en algunos casos de manera automática. Esta característica permite escalar (aumentar y reducir) rápidamente. Desde el punto de vista del cliente los recursos son ilimitados y pueden ser contratados en cualquier momento y en cualquier cantidad.         &lt;br /&gt;&lt;/p&gt;   &lt;/li&gt;    &lt;li&gt;     &lt;p&gt;&lt;strong&gt;Medición de servicio&lt;/strong&gt;         &lt;br /&gt;Los sistemas de Cloud automáticamente controlan y optimizan los recursos.         &lt;br /&gt;El uso de los recursos puede ser monitorizado, controlado y reportado aportando transparencia tanto para el proveedor como el cliente del servicio.&lt;/p&gt;   &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;&lt;strong&gt;Modelos de despliegue:&lt;/strong&gt;&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;&lt;b&gt;SaaS (Software as a Service)        &lt;br /&gt;&lt;/b&gt;Hace referencia a proveer la capacidad al cliente de &lt;b&gt;utilizar&lt;/b&gt; las &lt;b&gt;aplicaciones del proveedor&lt;/b&gt; que se están ejecutando en la infraestructura de la nube. Es importante tener en cuenta que el cliente no gestiona (salvo excepciones) la infraestructura subyacente de la nube.       &lt;br /&gt;Este es el modelo principal de Azure.       &lt;br /&gt;&lt;/li&gt;    &lt;li&gt;&lt;b&gt;PaaS (Platform as a Service)        &lt;br /&gt;&lt;/b&gt;Hace referencia a proveer la capacidad al &lt;b&gt;cliente&lt;/b&gt; de desplegar &lt;b&gt;sus&lt;/b&gt; &lt;b&gt;aplicaciones&lt;/b&gt; sobre la infraestructura de la nube,&lt;b&gt; creadas empleando los lenguajes de programación y herramientas soportadas por el proveedor&lt;/b&gt;. El cliente no gestiona la infraestructura subyacente de la nube pero sí que controla el despliegue de las mismas y posiblemente la configuración de los entornos donde estas son albergadas.       &lt;br /&gt;AppEngine de Google es un ejemplo de PasS       &lt;br /&gt;&lt;/li&gt;    &lt;li&gt;&lt;b&gt;IaaS (Infrastructure as a Service)        &lt;br /&gt;&lt;/b&gt;Hace referencia a proveer la capacidad al cliente de &lt;b&gt;aprovisionar&lt;/b&gt; procesamiento, almacenamiento, redes y otros recursos computacionales sobre los cuales tiene &lt;b&gt;la capacidad de desplegar y hacer correr software (puede incluir SO y aplicaciones).&lt;/b&gt; El cliente no gestiona la infraestructura subyacente de la nube, pero tiene control sobre el SO, almacenamiento, despliegue y ocasionalmente control (limitado) sobre ciertos componentes de la red. (Por ejemplo firewalls...)       &lt;br /&gt;Amazon AWS es el mayor proveedor mundial de IaaS. &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;&lt;b&gt;Modelos de despliegue:&lt;/b&gt;&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;&lt;b&gt;Nube privada&lt;/b&gt;       &lt;br /&gt;La explotación de la infraestructura de la nube es realizada por una única organización. Puede ser gestionada por la organización o por un tercero.       &lt;br /&gt;&lt;/li&gt;    &lt;li&gt;&lt;b&gt;Nube comunitarias&lt;/b&gt;       &lt;br /&gt;La explotación de la infraestructura de la nube es realizada por varias organizaciones y soporta una comunidad que comparten ciertos aspectos (por ejemplo requisitos de seguridad, políticas...) Puede ser gestionada por las organizaciones o por una tercera parte.       &lt;br /&gt;&lt;/li&gt;    &lt;li&gt;&lt;b&gt;Nube pública&lt;/b&gt;       &lt;br /&gt;La infraestructura de la nube se encuentra disponible para el publico general o un gran grupo de industrias y es propiedad de una organizativo que comercializa los servicios de la nube.       &lt;br /&gt;&lt;/li&gt;    &lt;li&gt;&lt;b&gt;Nube híbrida        &lt;br /&gt;&lt;/b&gt;La infraestructura de la nube está compuesta por dos o mas nubes (privada, comunitaria o publica) unidas a través de estándares o tecnología propietaria que habilita la comunicación entre ellas &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;Espero que este pequeño resumen sirva para aclarar algunos conceptos básicos y genere un poco más de curiosidad.&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/31098559-3008868575537081705?l=andoni-arroyo.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/andoniarroyo/~4/_QTnYrR9Sr0" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/andoniarroyo/~3/_QTnYrR9Sr0/cloud-computing-lo-tienes-claro.html</link><author>noreply@blogger.com (Andoni Arroyo)</author><thr:total>0</thr:total><feedburner:origLink>http://andoni-arroyo.blogspot.com/2010/08/cloud-computing-lo-tienes-claro.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-31098559.post-5784923775861525491</guid><pubDate>Sun, 25 Jul 2010 18:00:00 +0000</pubDate><atom:updated>2010-07-25T20:00:00.551+02:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">SOA</category><category domain="http://www.blogger.com/atom/ns#">Arquitectura del Software</category><category domain="http://www.blogger.com/atom/ns#">Metodología</category><category domain="http://www.blogger.com/atom/ns#">WCF</category><title>SOA != Client Server + WCF</title><description>&lt;p&gt;El panorama actual en el mundo de desarrollo del software nos brinda más oportunidades de las que nunca habíamos tenido (quizás ni siquiera imaginado). Entre otros escenarios, la aparición de Internet ha propiciado el crecimiento de los sistema distribuidos, la orientación a servicios, el SaaS... &lt;/p&gt;  &lt;p&gt;Este nuevo &amp;quot;el dorado&amp;quot; plantea características donde todas las empresas desean desembarcar sus activos. Por supuesto estos destinos son tan interesantes que muchos deciden tomar atajos para llegar a lo que creen el mismo destino, pero cuidado,    &lt;br /&gt;que como siempre, no es oro todo lo que reluce. &lt;/p&gt;  &lt;p&gt;La formula del título viene a decir eso, se podría leer como:    &lt;br /&gt;    &lt;br /&gt;&lt;strong&gt;&lt;em&gt;SOA != Client Server + WCF&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;No es lo mismo desarrollar Software orientado a servicio que colocar una capa de WCF en una aplicación Cliente Servidor. Definitivamente NO ES LO MISMO... &lt;/p&gt;  &lt;p&gt;Pero como ya sabemos las cosas no cambian solas, debemos como desarrolladores hacer un esfuerzo por ser conscientes de las nuevas reglas de juego con las que deseamos que nuestras aplicaciones den la talla. &lt;/p&gt;  &lt;p&gt;Revisando mi experiencia el respecto podemos identificar los errores más comunes a la hora de crear Software orientadas a servicios: &lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;&lt;strong&gt;Los servicios (aunque no te lo creas) no están (solo) para ti.&lt;/strong&gt;       &lt;br /&gt;Utiliza los recursos del servicio de manera razonable, piensa bien como y cuando realizar las llamadas evitando acaparar los recursos disponibles.       &lt;br /&gt;&lt;/li&gt;    &lt;li&gt;&lt;strong&gt;Al consumir otros servicios estas realizando una llamada remota, eres consciente?&lt;/strong&gt;       &lt;br /&gt;No hagas 17 peticiones con sus 17 serializaciones para pintar una pantalla. No me digas que son las clases que usas como DTO y que te van para el pelo para tu ORM...       &lt;br /&gt;Todo el tiempo invertido en optimizar la comunicación tendrá un alto ROI, te lo aseguro.       &lt;br /&gt;Por supuesto recibir 26 millones de objetos (bien serializados) es un problema a nivel de diseño de la aplicación. (consolida la información, pagina, trabaja por bloques pero no tires por ese camino bajo ningún concepto...)       &lt;br /&gt;&lt;/li&gt;    &lt;li&gt;&lt;strong&gt;Siempre piensa en que la disponibilidad nunca es del 100%&lt;/strong&gt;       &lt;br /&gt;Eso es así aunque algún comercial se empeñe en decir lo contrario.       &lt;br /&gt;Pregúntate que ocurre si el servicio no está disponible y dota a tu aplicación de la inteligencia necesaria para responder ante tal situación de manera digna. Siempre es interesante valorar la posibilidad de realizar las comunicaciones de manera asíncrona.       &lt;br /&gt;Ten en cuenta que no debes lanzar procesos que comprometan la estabilidad de los servicios, puesto que estos deben estar disponibles para los demás clientes.       &lt;br /&gt;(Recuerda que trabajar por bloques &amp;quot;casi nunca&amp;quot; es opcional y con determinado volumen de datos es obligatorio)       &lt;br /&gt;Piensa en la Alta disponibilidad, como hacer correr varias instancias en paralelo, clúster activo-pasivo antes de que te pille el toro...       &lt;br /&gt;&lt;/li&gt;    &lt;li&gt;&lt;strong&gt;Diseña un plan de contingencia y déjalo por escrito        &lt;br /&gt;&lt;/strong&gt;Si no quieres que la gente que mantiene la aplicación te llamen a las 3:00 de la madrugada por que se ha parado el servicio, dales los mecanismos oportunos para que operen con autonomía. Ten un poco de empatía y piensa que ellos no pueden controlar todas las aplicaciones que están en producción como los que lo han desarrollado.&amp;#160; &lt;br /&gt;&lt;/li&gt;    &lt;li&gt;&lt;strong&gt;Escalabilidad no es solo una palabra más terminada en &lt;em&gt;…idad&lt;/em&gt;&lt;/strong&gt;       &lt;br /&gt;Creo que está de más decirlo, pero evitar mantener el estado en el servidor entre tus llamadas te permitirá escalar mejor. Tomate la molestia de planificar mecanismos de escalabilidad vertical y horizontal si no quieres morir de éxito. Corregir este tipo de problemas a posteriori siempre es traumático.       &lt;br /&gt;Ten en cuenta que todos los recursos son limitados, hasta el disco donde escribes el log se acaba si no tienes políticas de reciclaje. Piensa en que los servicios están diseñados para ejecutarse 24x7 y 365 días al año, en estos detalles debemos hacer especial énfasis.       &lt;br /&gt;&lt;/li&gt;    &lt;li&gt;&lt;strong&gt;La correcta gestión de excepciones te puede salvar la vida        &lt;br /&gt;&lt;/strong&gt;En relación con la disponibilidad, es crítico gestionar de manera lo más eficiente posible las excepciones. La tecnología está ahí hace tiempo solo debes esforzarte en aplicarla correctamente. Una excepción en un servicio debe gestionarse correctamente para que no comprometa su estabilidad y disponibilidad. Trabajar sobre ello puede mejorar mucho la QoS y reducir el coste de mantenimiento.       &lt;br /&gt;&lt;/li&gt;    &lt;li&gt;&lt;strong&gt;Invierte tiempo en pensar bien tus contratos&lt;/strong&gt;       &lt;br /&gt;Es importante ajustar el equilibrio entre la cohesion de los servicios y los clientes. Cuando desarrollamos orientado a servicio no debemos hacerlo &lt;em&gt;ad-hoc&lt;/em&gt; a un cliente en particular. El servicio debe exponer una serie de funcionalidades bien definidas. Extendiendo esta característica conseguimos el correcto grado de cohesión.       &lt;br /&gt;Ahora tampoco hagas que usar tus servicios sea un infierno...       &lt;br /&gt;&lt;/li&gt;    &lt;li&gt;&lt;strong&gt;Piensa bien cual es la mejor manera de establecer la comunicación con tus servicios        &lt;br /&gt;&lt;/strong&gt;La serialización y transporte de los objetos es una parte muy significativa del tiempo de procesamiento consumido. Piensa cuidadosamente la manera de exponer tus servicios al mundo. expón los &lt;em&gt;endpoints&lt;/em&gt; que sean necesarios y afina los &lt;em&gt;behaviors&lt;/em&gt; de los mismos para evitar matar moscas a cañonazos. &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;Como siempre, se hace camino al andar, así que la resolución de los problemas presentes en este tipo de escenarios también tenderá a converger (para estandarizarse más adelante) mientras todos maduraremos en el proceso. &lt;/p&gt;  &lt;p&gt;Por supuesto surgirán nuevos problemas relacionados con llevar el mundo del desarrollo de software más allá, que para algo estamos aquí, no? &lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/31098559-5784923775861525491?l=andoni-arroyo.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/andoniarroyo/~4/oAnxj9VkNME" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/andoniarroyo/~3/oAnxj9VkNME/soa-client-server-wcf.html</link><author>noreply@blogger.com (Andoni Arroyo)</author><thr:total>0</thr:total><feedburner:origLink>http://andoni-arroyo.blogspot.com/2010/07/soa-client-server-wcf.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-31098559.post-7928676531795735107</guid><pubDate>Sun, 18 Apr 2010 14:23:00 +0000</pubDate><atom:updated>2010-04-18T16:23:41.106+02:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">.NET Framework 3.5</category><category domain="http://www.blogger.com/atom/ns#">WPF</category><title>Controlando el cierre de sesión desde nuestra aplicación WPF</title><description>&lt;p&gt;En numerosas ocasiones hemos hablado de las características básicas que debe poseer cualquier aplicación profesional de software que desarrollemos. Una de las fijas en todos los listados es la estabilidad. Cuando valoramos dicha cualidad debemos ser conscientes de que nuestras aplicaciones no se ejecutan solas ni son independientes de los devenires del los usuarios a nivel del Sistema Operativo.    &lt;br /&gt;    &lt;br /&gt;Revisando las posibilidades que manejamos a la hora de mantener nuestra aplicación siempre en un estado controlado nos podemos alegrar una vez más de contar con un framework estable y maduro como es .NET.     &lt;br /&gt;    &lt;br /&gt;Imaginemos el siguiente escenario:&lt;/p&gt;  &lt;p&gt;El usuario trabaja con nuestra aplicación editando una serie de datos de un determinado registro. Por otro lado, el Sistema Operativo comienza a descargar e instalar unas actualizaciones que obligan a reiniciar. El usuario acepta el reinicio sin darse cuenta que no ha salvado los datos… (improbable, verdad? ;))&lt;/p&gt;  &lt;p&gt;Si no contemplamos este tipo de casuísticas en nuestra aplicación, esta se cerrará y la modificación no se reflejará en el sistema de almacenamiento subyacente (base de datos, archivos…) y se terminó la historia. Otro debate es si la culpa de la pérdida es nuestra o no, pero lo que es seguro, es que existen entornos en los que esta respuesta no es aceptable…&lt;/p&gt;  &lt;p&gt;Para controlar cosas como estas (está todo pensado…) debemos trabajar con las posibilidades que nos brinde la&amp;#160; clase &lt;em&gt;Application&lt;/em&gt; de .NET. Entre otras características, esta clase nos brinda la oportunidad de interactuar con un cierre de sesión a través de un método sobrescribible o suscribiéndonos a un evento.     &lt;br /&gt;    &lt;br /&gt;Vamos a ver este código:&lt;/p&gt;  &lt;div id="codeSnippetWrapper"&gt;   &lt;div style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px" id="codeSnippet"&gt;     &lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum1"&gt;   1:&lt;/span&gt; &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;partial&lt;/span&gt; &lt;span style="color: #0000ff"&gt;class&lt;/span&gt; App : Application&lt;/pre&gt;&lt;br /&gt;&lt;!--CRLF--&gt;&lt;br /&gt;&lt;br /&gt;    &lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum2"&gt;   2:&lt;/span&gt;     {&lt;/pre&gt;&lt;br /&gt;&lt;!--CRLF--&gt;&lt;br /&gt;&lt;br /&gt;    &lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum3"&gt;   3:&lt;/span&gt;         &lt;span style="color: #0000ff"&gt;private&lt;/span&gt; &lt;span style="color: #0000ff"&gt;bool&lt;/span&gt; _editing = &lt;span style="color: #0000ff"&gt;true&lt;/span&gt;;&lt;/pre&gt;&lt;br /&gt;&lt;!--CRLF--&gt;&lt;br /&gt;&lt;br /&gt;    &lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum4"&gt;   4:&lt;/span&gt;&amp;#160; &lt;/pre&gt;&lt;br /&gt;&lt;!--CRLF--&gt;&lt;br /&gt;&lt;br /&gt;    &lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum5"&gt;   5:&lt;/span&gt;         &lt;span style="color: #0000ff"&gt;protected&lt;/span&gt; &lt;span style="color: #0000ff"&gt;override&lt;/span&gt; &lt;span style="color: #0000ff"&gt;void&lt;/span&gt; OnSessionEnding(SessionEndingCancelEventArgs e)&lt;/pre&gt;&lt;br /&gt;&lt;!--CRLF--&gt;&lt;br /&gt;&lt;br /&gt;    &lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum6"&gt;   6:&lt;/span&gt;         {&lt;/pre&gt;&lt;br /&gt;&lt;!--CRLF--&gt;&lt;br /&gt;&lt;br /&gt;    &lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum7"&gt;   7:&lt;/span&gt;             &lt;span style="color: #0000ff"&gt;base&lt;/span&gt;.OnSessionEnding(e);&lt;/pre&gt;&lt;br /&gt;&lt;!--CRLF--&gt;&lt;br /&gt;&lt;br /&gt;    &lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum8"&gt;   8:&lt;/span&gt;             &lt;span style="color: #0000ff"&gt;if&lt;/span&gt; (_editing)&lt;/pre&gt;&lt;br /&gt;&lt;!--CRLF--&gt;&lt;br /&gt;&lt;br /&gt;    &lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum9"&gt;   9:&lt;/span&gt;             {&lt;/pre&gt;&lt;br /&gt;&lt;!--CRLF--&gt;&lt;br /&gt;&lt;br /&gt;    &lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum10"&gt;  10:&lt;/span&gt;                 e.Cancel = &lt;span style="color: #0000ff"&gt;true&lt;/span&gt;;&lt;/pre&gt;&lt;br /&gt;&lt;!--CRLF--&gt;&lt;br /&gt;&lt;br /&gt;    &lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum11"&gt;  11:&lt;/span&gt;                 MessageBox.Show(&lt;span style="color: #006080"&gt;&amp;quot;You can´t &amp;quot;&lt;/span&gt; + e.ReasonSessionEnding.ToString() + &lt;span style="color: #006080"&gt;&amp;quot; with unsaved data.&amp;quot;&lt;/span&gt;);&lt;/pre&gt;&lt;br /&gt;&lt;!--CRLF--&gt;&lt;br /&gt;&lt;br /&gt;    &lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum12"&gt;  12:&lt;/span&gt;             }&lt;/pre&gt;&lt;br /&gt;&lt;!--CRLF--&gt;&lt;br /&gt;&lt;br /&gt;    &lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum13"&gt;  13:&lt;/span&gt;         }&lt;/pre&gt;&lt;br /&gt;&lt;!--CRLF--&gt;&lt;br /&gt;&lt;br /&gt;    &lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum14"&gt;  14:&lt;/span&gt;     }&lt;/pre&gt;&lt;br /&gt;&lt;!--CRLF--&gt;&lt;/div&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Estableciendo en este punto nuestras políticas, podemos determinar de una manera muy sencilla si el estado de nuestra aplicación permite realizar el cierre sin comprometer su estabilidad o datos almacenados en memoria. Si os interesa conocer el motivo del cierre de la sesión podéis consultar el valor de la propiedad &lt;em&gt;ReasonSessionEnding&lt;/em&gt; de la clase &lt;em&gt;SessionEndingCancelEventArgs&lt;/em&gt;&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;A veces cuesta muy poco dar superar lo estrictamente obligado, con lo que transmitimos una mayor sensación de esmero y profesionalidad.&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/31098559-7928676531795735107?l=andoni-arroyo.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/andoniarroyo/~4/Dhb1PHetHbM" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/andoniarroyo/~3/Dhb1PHetHbM/controlando-el-cierre-de-sesion-desde.html</link><author>noreply@blogger.com (Andoni Arroyo)</author><thr:total>0</thr:total><feedburner:origLink>http://andoni-arroyo.blogspot.com/2010/04/controlando-el-cierre-de-sesion-desde.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-31098559.post-8161310777427996577</guid><pubDate>Thu, 11 Mar 2010 23:13:00 +0000</pubDate><atom:updated>2010-03-12T00:13:27.005+01:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">Ágil</category><category domain="http://www.blogger.com/atom/ns#">Metodología</category><category domain="http://www.blogger.com/atom/ns#">TFS</category><category domain="http://www.blogger.com/atom/ns#">SCRUM</category><title>Sinergia D&amp;T (developer + tool)</title><description>&lt;p&gt;Siempre es importante aprender de los demás (sobre todo de los buenos ;)) pero en aspectos como la organización y la metodología lo básico está inventado. Nuestra tarea como desarrollador consiste, básicamente, en aplicar esas buenas ideas a nuestra realidad y hacer que se ajuste a la misma como un guante.    &lt;br /&gt;    &lt;br /&gt;Por supuesto, esta idea es más sencilla de decir que de poner en practica. Se deben tener en cuenta muchos aspectos, sin descuidar ni uno solo de ellos, si queremos tener un “Jelled Team” como lo califican en Peopleware. En el proceso ALM podemos observar que contar con un buena herramientas nos puede facilitar mucho el proceso.     &lt;br /&gt;    &lt;br /&gt;Cuando comenzamos con una metodología, la herramienta seleccionada nos brinda una gran ayuda poniendo a nuestra disposición todo el know-how analizado y sintetizado para generarla. Y esto no es poco. Nos ayuda a encauzar la energía y optimizar los esfuerzos sin dispersarnos en decidir como comenzar a caminar en la organización básica del complicado mundo del desarrollo del software.     &lt;br /&gt;    &lt;br /&gt;En este punto es donde, ante el Team Foundation Server hay que quitarse el sombrero. Para ser una herramienta relativamente moderna ha sabido encajar las piezas con mucho acierto abriendo los puntos claves a diferentes metodologías para elegir nuestro sabor preferido. (MSF, SCRUM…)&lt;/p&gt;  &lt;p&gt;Como muestra un botón. Cuando en el TFS2010 reportas un &lt;em&gt;bug&lt;/em&gt; sobre un proyecto, el formulario correspondiente (y la Web del Team Web Access !!) nos aparece un botón con la leyenda &lt;em&gt;Tools&lt;/em&gt;. Al desplegarlo, tenemos entre otras opciones, la de mostrar el diagrama de estados de la gestión de &lt;em&gt;bugs&lt;/em&gt; definida por la guía de proceso seleccionada.     &lt;br /&gt;    &lt;br /&gt;Dicho elemento se ve así con el SCRUM de Cochango:     &lt;br /&gt;    &lt;br /&gt;    &lt;br /&gt;&lt;a href="http://lh3.ggpht.com/_cDGcKb7l-aU/S5l5ECU94FI/AAAAAAAABAk/vBwE_vQwX0s/s1600-h/State%20Diagram%5B14%5D.png"&gt;&lt;img style="border-bottom: 0px; border-left: 0px; display: block; float: none; margin-left: auto; border-top: 0px; margin-right: auto; border-right: 0px" title="State Diagram" border="0" alt="State Diagram" src="http://lh6.ggpht.com/_cDGcKb7l-aU/S5l5FN8MPQI/AAAAAAAABAo/0hJYVhJh4dM/State%20Diagram_thumb%5B12%5D.png?imgmax=800" width="453" height="293" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;Cualquier desarrollador de Software se puede dar cuenta que poco tenemos que inventar al respecto. Como mucho, tendrás que hacer algún ajuste personalizado para tus particularidades. Ahora imaginaros la cantidad de horas y energía que podíamos malgastar en intentar crear una gestión de &lt;em&gt;bugs&lt;/em&gt; como esta desde cero (más el tiempo en crear el diagrama y mandarlo al departamento de calidad ;)). Aspectos como este, transmiten madurez por parte de la herramienta, generan confianza en su uso y crean una sinergia entre los desarrolladores y la herramienta que nos ayudan a ser lo más eficientes posible. &lt;/p&gt;  &lt;p&gt;A ver quien se vuelve al Source Safe ;)&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/31098559-8161310777427996577?l=andoni-arroyo.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/andoniarroyo/~4/U6UUtawU8kQ" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/andoniarroyo/~3/U6UUtawU8kQ/sinergia-d-developer-tool.html</link><author>noreply@blogger.com (Andoni Arroyo)</author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://lh6.ggpht.com/_cDGcKb7l-aU/S5l5FN8MPQI/AAAAAAAABAo/0hJYVhJh4dM/s72-c/State%20Diagram_thumb%5B12%5D.png?imgmax=800" height="72" width="72" /><thr:total>0</thr:total><feedburner:origLink>http://andoni-arroyo.blogspot.com/2010/03/sinergia-d-developer-tool.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-31098559.post-1462827265933856736</guid><pubDate>Mon, 18 Jan 2010 21:00:00 +0000</pubDate><atom:updated>2010-01-18T22:50:53.371+01:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">Capa de Datos</category><category domain="http://www.blogger.com/atom/ns#">Desarrollo de Software</category><title>El misterioso caso de LINQ to SQL y 0=1…</title><description>&lt;p&gt;Como ya más o menos todos conocéis &lt;a href="http://msdn.microsoft.com/en-us/library/bb425822.aspx" target="_blank"&gt;LINQ to SQL&lt;/a&gt; implementa una política de concurrencia optimista. Esta característica parte de la premisa de no realizar ningún bloqueo sobre los registros con los que estamos trabajando. Este modo es el recomendado, y en ocasiones el único aceptable, sobre todo en entornos de alta escalabilidad como son por ejemplo las aplicaciones Web. &lt;/p&gt;  &lt;p&gt;Cuando nos creamos el modelo de nuestra aplicación a partir de la base de datos, generamos un fichero dbml. Es importante tener en cuenta que, entre otras propiedades, podemos especificar como queremos que el contexto gestione el &lt;a href="http://msdn.microsoft.com/en-us/library/bb425822.aspx" target="_blank"&gt;UpdateCheck&lt;/a&gt; de cada columna. (Always, WhenChanged, Never).     &lt;br /&gt;    &lt;br /&gt;Esto nos permite, en base a la naturaleza de la información de un campo, afinar la política de comprobación de la concurrencia que deseamos aplicar. Por ejemplo, podemos sobrescribir siempre la descripción detallada de un producto (sin importarnos si otro usuario la ha modificado desde que leímos ) pero puede no ser aceptable para, por ejemplo, el Stock asociado al mismo. Esta característica junto con el RowVerison nos permite detectar los problemas de concurrencia y automatizar su resolución en la medida de lo posible. &lt;/p&gt;  &lt;p&gt;Hablando con un equipo de desarrollo me contaban que tenían problemas al borrar un registro. Revisándolo con ellos, me comentaban que pasaban por parámetro clave primaria del registro que deseaban eliminar. El código que empleaban era similar a este: &lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;using (xxxDataContext ctx = new xxxDataContext())     &lt;br /&gt;{      &lt;br /&gt;&lt;font color="#333333" size="2"&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &lt;/font&gt;Table1 t1 = new Table1 { Id = id };      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; ctx.Table1s.Attach(t1);      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; ctx.Table1s.DeleteOnSubmit(t1);      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; ctx.SubmitChanges();      &lt;br /&gt;}&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;Y el error que percibían era que no se eliminaba el registro asociado en la base de datos pero no sabían exactamente porqué...    &lt;br /&gt;    &lt;br /&gt;Al revisar la política de UpdateCheck de las columnas de la entidad, me di cuenta que estaban definidos en el modelo con su valor predeterminado. (Always). Por lo que la cosa estaba clara, Linq To SQL estaba creando la consulta que lanzaba al proveedor subyacente concatenándole el valor original y al no encontrar dicho registro en la base de datos no eliminaba nada…    &lt;br /&gt;    &lt;br /&gt;Al comprobar mi teoría veo que la sentencia que genera Linq To SQL para el borrado incluye una clausula where del estilo ... &lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;&lt;em&gt;DELETE FROM [dbo].[Table1] WHERE 0 = 1&lt;/em&gt;&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;¿¿0=1?? &lt;/p&gt;  &lt;p&gt;Para darles respuesta les comenté el problema y la solución fue tan simple como cambiar el UpdateCheck a Never puesto que este escenario les cuadraba para dicha tabla, pero yo ya me había quedado mosca con el tema del 0=1... &lt;/p&gt;  &lt;p&gt;Leyendo un poco descubro que es una optimización generada por el equipo de ADO.net puesto que determinan que nunca se cumple la condición. Y la condición que nunca se cumple es la siguiente:    &lt;br /&gt;    &lt;br /&gt;En la base de datos existe un campo &lt;em&gt;Name&lt;/em&gt; que esta definida como NOT NULL, por lo tanto nunca puede almacenar un valor NULL (obvio, no?). En .Net el tipo de la propiedad que mapea a dicho campo es de tipo &lt;em&gt;String&lt;/em&gt; y por la naturaleza del mismo este puede almacenar un NULL. De hecho es los que almacena si nos fijamos en el código superior. &lt;/p&gt;  &lt;p&gt;Como LINQ To SQL observa que en el objeto el valor es un NULL y en la definición del esquema de la base de datos este valor no puede estar presente, determina que no va a coincidir por lo que optimiza con el 0=1... &lt;/p&gt;  &lt;p&gt;Bueno dicho (y comprendido) queda... &lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/31098559-1462827265933856736?l=andoni-arroyo.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/andoniarroyo/~4/v1VNNZATtIA" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/andoniarroyo/~3/v1VNNZATtIA/el-misterioso-caso-de-linq-to-sql-y-01.html</link><author>noreply@blogger.com (Andoni Arroyo)</author><thr:total>0</thr:total><feedburner:origLink>http://andoni-arroyo.blogspot.com/2010/01/el-misterioso-caso-de-linq-to-sql-y-01.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-31098559.post-7344993655594120114</guid><pubDate>Fri, 04 Dec 2009 21:00:00 +0000</pubDate><atom:updated>2009-12-04T22:00:00.680+01:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">GTD</category><category domain="http://www.blogger.com/atom/ns#">Ágil</category><category domain="http://www.blogger.com/atom/ns#">Metodología</category><category domain="http://www.blogger.com/atom/ns#">SCRUM</category><title>Scrum:IGTD (Scrum implementa el interfaz GTD)</title><description>&lt;p&gt;Cada día están más en auge las metodologías orientadas a la productividad personal. Todos y cada uno de nosotros gestionamos recursos, al menos nuestro tareas en el tiempo, y es recomendable, por no decir necesario, organizar dichas tareas para ser los más productivos posible.    &lt;br /&gt;    &lt;br /&gt;El ámbito de aplicación &lt;a href="http://es.wikipedia.org/wiki/Getting_Things_Done" target="_blank"&gt;GTD&lt;/a&gt; no se limita al entorno profesional sino que cubre también los aspectos de organización personales, permitiendo aplicar pautas a todos los aspectos de nuestro comportamiento. Existen en la red toneladas de material al respecto y discutir las bondades de la metodología GTD y las implementaciones de las mismas quedan fuera de la intención de este post. Sin embargo, me gustaría analizar la relación que existe entre dos mundos íntimamente relacionados (aunque no de manera explicita) como son GTD y las metodologías ágiles. Como representante de dichas metodologías estudiaremos Scrum.&lt;/p&gt;  &lt;p&gt;Si consideramos GTD como un interfaz o contrato, llamémosle IGTD, sus puntos serian:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;&lt;strong&gt;Recopilar&lt;/strong&gt; &lt;/li&gt;    &lt;li&gt;&lt;strong&gt;Procesar&lt;/strong&gt; &lt;/li&gt;    &lt;li&gt;&lt;strong&gt;Organizar&lt;/strong&gt; &lt;/li&gt;    &lt;li&gt;&lt;strong&gt;Revisar&lt;/strong&gt; &lt;/li&gt;    &lt;li&gt;&lt;strong&gt;Hacer&lt;/strong&gt; &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;Veamos como SCRUM implementa cada uno de los mismos…&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;&lt;strong&gt;Recopilar&lt;/strong&gt;       &lt;br /&gt;El objetivo en GTD se define como “sacar” todo de nuestra mente y recogerlo en alguno de los elementos de almacenamiento para luego procesarlos.       &lt;br /&gt;      &lt;br /&gt;Scrum define exactamente esta tarea identificando un rol para cubrirla, el responsable de producto o &lt;a href="http://en.wikipedia.org/wiki/Scrum_(development)#Roles_2" target="_blank"&gt;Product Owner&lt;/a&gt;. Entre las responsabilidades principales de dicho rol se encuentran la de identificar los puntos que más valor aportan al producto servicio que desarrolla el proyecto. Dicha recolección se realiza escuchando y tratando con los diferentes &lt;a href="http://es.wikipedia.org/wiki/Stakeholder" target="_blank"&gt;stakeholders&lt;/a&gt;. Este punto común de acceso permite crear una capa de protección y homogenización para el resto del equipo.       &lt;br /&gt;Otra tarea muy importante y a la vez menos visible que recae sobre esta figura, es la de rechazar las propuestas de los stakeholders que no interesa avancen por el flujo puesto que no son interesantes para el producto. Esto permite al equipo centrarse en lo que realmente aporta valor.       &lt;br /&gt;      &lt;br /&gt;&lt;/li&gt;    &lt;li&gt;&lt;strong&gt;Procesar&lt;/strong&gt;       &lt;br /&gt;Por supuesto, el trabajo de un buen Product Owner, no se limita a transcribir todo lo que escucha a los diferentes stakeholders. Debe realizar un proceso de análisis y diseño cuyo resultado se muestra como un conjunto de historias de usuario o &lt;a href="http://es.wikipedia.org/wiki/Scrum#Product_backlog" target="_blank"&gt;Product Backlog&lt;/a&gt;. Dichas historias deben mantenerse consensuadas, consistentes y priorizadas puesto que conforman el material sobre las cuales trabajará la “apisonadora” que es el equipo.       &lt;br /&gt;      &lt;br /&gt;Una buena regla para saber si tienes un buen Product Owner en tu equipo es preguntarse cuanto disminuiría la rentabilidad del producto si lo sustituyes por una regla de redirección de correo…       &lt;br /&gt;&lt;/li&gt;    &lt;li&gt;&lt;strong&gt;Organizar&lt;/strong&gt;       &lt;br /&gt;El equipo, liderado por el &lt;a href="http://en.wikipedia.org/wiki/Scrum_(development)#Roles_2" target="_blank"&gt;Scrum Master&lt;/a&gt; y contando con la disponibilidad del Responsable de Producto, comienza en el &lt;a href="http://es.wikipedia.org/wiki/Scrum#Reuni.C3.B3n_de_Planificaci.C3.B3n_del_Sprint_.28Sprint_Planning_Meeting.29" target="_blank"&gt;Sprint Planning Meeting&lt;/a&gt; a digerir y desmenuzar ese producto Backlog. El resultado de dicho procesamiento son las tareas necesarias para cubrir las historias de usuario que el Product Owner ha recopilado.       &lt;br /&gt;&lt;/li&gt;    &lt;li&gt;&lt;strong&gt;Revisar&lt;/strong&gt;       &lt;br /&gt;Scrum da gran importancia al proceso de revisión. En base al grano deseado realiza la tarea de revisión en dos maneras.       &lt;br /&gt;      &lt;br /&gt;Todo el equipo se reúne una vez al día en el &lt;a href="http://es.wikipedia.org/wiki/Scrum#Daily_Scrum" target="_blank"&gt;Daily Scrum&lt;/a&gt; comenta lo que ha realizado, lo que va a realizar en el día y los impedimentos que se ha encontrado por el camino. La verdad es que no se me ocurre una mejor forma de aplicar el concepto de revisión a grano fino.       &lt;br /&gt;      &lt;br /&gt;Por otro lado, al finalizar cada sprint se realiza una revisión del mismo, &lt;a href="http://en.wikipedia.org/wiki/Scrum_(development)#Meetings" target="_blank"&gt;Sprint Retrospective&lt;/a&gt; que permite a nivel de todo lo realizado en el Sprint, evaluar los aspectos positivos para potenciarlos y negativos para mejorarlos.       &lt;br /&gt;      &lt;br /&gt;En GTD también existen dos tipos de revisiones, las diarias y las semanales (por Sprint para Scrum) así que en este punto la cosa encaja como un guante.       &lt;br /&gt;&lt;/li&gt;    &lt;li&gt;&lt;strong&gt;Hacer&lt;/strong&gt;       &lt;br /&gt;Una vez que tenemos claro lo que hay que hacer el equipo lo desarrolla, lo mismo que en GTD. Ambas metodologías hacen hincapié en la satisfacción de hacer las cosas y poder marcarlas como hechas, quitándolas de la primera línea de batalla y permitiendo centrarnos en lo que falta por hacer. &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;La conclusión que podemos obtener de este análisis, es que ambos metodologías son recomendablemente compatibles. Encajan porque se basan en patrones comunes, haciendo hincapié en centrarse en lo importante, reducir el stress, simplificar el día a día.    &lt;br /&gt;    &lt;br /&gt;Además son especialmente cuidadosas con evitar el cambio de contexto y fomentar la concentración, GTD vía controlando las interrupciones internas y externas y Scrum blindando a los equipo de los cambios durante los Sprints.&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/31098559-7344993655594120114?l=andoni-arroyo.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/andoniarroyo/~4/2xZObn8F3f8" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/andoniarroyo/~3/2xZObn8F3f8/scrumigtd-scrum-implementa-el-interfaz.html</link><author>noreply@blogger.com (Andoni Arroyo)</author><thr:total>0</thr:total><feedburner:origLink>http://andoni-arroyo.blogspot.com/2009/12/scrumigtd-scrum-implementa-el-interfaz.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-31098559.post-7172848247849084255</guid><pubDate>Mon, 30 Nov 2009 19:12:00 +0000</pubDate><atom:updated>2009-11-30T20:12:52.514+01:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">Silverlight</category><category domain="http://www.blogger.com/atom/ns#">Desarrollo de Software</category><title>Instanciando objetos en Silverlight: Code VS XAML</title><description>&lt;p&gt;Si os pregunto que manera de instanciar los objetos es más rápida, por código o vía el parser de XAML ¿Cual sería vuestra respuesta?    &lt;br /&gt;Pues la mayoría de los desarrolladores dirían que por código, pero obviamente la cosa tiene trampa…     &lt;br /&gt;    &lt;br /&gt;En la mayoría de los casos el parser de XAML es más rápido. La razón de esta característica es el resultado de una serie de optimizaciones realizadas en tiempo de ejecución por Silverlight. El parser de XAML no crea los API objects que se emplean para interactuar con los elementos, sino que solo crea una representación interna de los mismos. Cuando desde código comenzamos a interactuar con esos objetos es cuando Silverlight crea los API objects necesarios. Esta característica se hace especialmente patente en inicializaciones de gran cantidad de objetos, aunque hay entra nuestra labor de diseño para evitar crear vistas inmanejables…     &lt;br /&gt;    &lt;br /&gt;Teniendo esta particularidad en mente y valorando las facilidades de integración diseñadores/desarrolladores que nos da escribir UI en XAML es recomendable dejar la creación de objetos por código para los escenarios en los que realmente es necesario.&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/31098559-7172848247849084255?l=andoni-arroyo.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/andoniarroyo/~4/bA54WzF2GT8" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/andoniarroyo/~3/bA54WzF2GT8/instanciando-objetos-en-silverlight.html</link><author>noreply@blogger.com (Andoni Arroyo)</author><thr:total>0</thr:total><feedburner:origLink>http://andoni-arroyo.blogspot.com/2009/11/instanciando-objetos-en-silverlight.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-31098559.post-2924984222218438145</guid><pubDate>Sun, 29 Nov 2009 22:56:00 +0000</pubDate><atom:updated>2009-11-29T23:56:52.286+01:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">Ágil</category><category domain="http://www.blogger.com/atom/ns#">Metodología</category><category domain="http://www.blogger.com/atom/ns#">Desarrollo de Software</category><title>Metodología, motivación y otras hierbas…</title><description>&lt;p&gt;No digo nada nuevo al afirmar que las empresas de desarrollo de software cuentan como materia prima para crear sus “productos finales” con la tecnología y conocimiento. Ahora bien, este conocimiento no reside en el aire, sino en las personas.    &lt;br /&gt;    &lt;br /&gt;Los malos modelos directivos valoran los recursos solo en su aspecto cuantitativo sin valorar la calidad de los mismos. He oído a “grandes” gestores del sector de desarrollo de software, sacar pecho al decir que consigue dos “recursos” (por ejemplo programador) al precio de uno. Por supuesto, el cambio implicaba sustituir una persona con diez años de experiencia por dos becarios, pero desde su perspectiva el cambio de 2x1 implicaba el doble de trabajo al mismo coste…&lt;/p&gt;  &lt;p&gt;Este mercado avanza, lentamente y en su proceso madura. Podemos decir que el ritmo al que madura el mundo del desarrollo del software es varias veces más lento que el ritmo al que avanza la tecnología, pero aun así, lo hace. Si hiciéramos un paralelismo con algún otro sector de desarrollo más maduro, supongamos la automoción, nadie se plantearía trabajar sin una metodología definida que permita a todos los miembros de los diferentes equipos conocer las reglas del juego. Aún así hay muchas empresas que no emplean ningún tipo de metodología explicita.&amp;#160; &lt;br /&gt;    &lt;br /&gt;Pensemos un poco sobre como impacta la forma de trabajar en la motivación de los profesionales. Los músicos de una orquesta, por muy buenos que sean, necesitan una partitura compartida para tocar juntos. Es cierto que la partitura ya esta creada por un compositor (en muchas ocasiones genios) y esta no varía. Se repite de idéntica manera miles de veces y no se adapta a las demandas del que la escucha. Nuestra partitura es más compleja. Varía con el tiempo y no es conocida de antemano (aunque las metodologías predictivas se empeñen en decir lo contrario). Al empezar nuestra obra no conocemos la cantidad de violines o tubas que necesitaremos…     &lt;br /&gt;    &lt;br /&gt;Esta complejidad es una razón más para contar con una poderosa herramienta como la metodología que nos guie por el camino. Esta nos aporta:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;Evitar desgastarnos en definir y redefinir procesos implicados en el día a día. &lt;/li&gt;    &lt;li&gt;Aplicar cierta “objetividad” a la forma de trabajar y a la valoración del trabajo de los miembros del equipo. &lt;/li&gt;    &lt;li&gt;Ganar en visibilidad al definir roles y responsabilidades asociadas. &lt;/li&gt;    &lt;li&gt;Alinear los objetivos de los diferentes miembros del equipo. &lt;/li&gt;    &lt;li&gt;Tener una base que adaptar y mejorar para los siguientes proyectos. &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;Cualquiera de estas características son básicas a la hora de motivar a los profesionales, sobre todo a los buenos. He tenido experiencias al respecto y es un autentico fenómeno a estudiar como cambia la aptitud de los miembros de un equipo que trabajan sin ninguna metodología explicita, al implantar una metodología (especialmente las ágiles). Muchos de ellos tienen la sensación de que su trabajo no se valora porque no es visible, lo cual acaba implantando un “comunismo” asesino de la eficiencia.    &lt;br /&gt;    &lt;br /&gt;Podemos decir que los buenos profesionales necesitan visibilidad y que la metodología aporta visibilidad…así que la cosa está clara.&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/31098559-2924984222218438145?l=andoni-arroyo.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/andoniarroyo/~4/LESyQck7Xho" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/andoniarroyo/~3/LESyQck7Xho/metodologia-motivacion-y-otras-hierbas.html</link><author>noreply@blogger.com (Andoni Arroyo)</author><thr:total>0</thr:total><feedburner:origLink>http://andoni-arroyo.blogspot.com/2009/11/metodologia-motivacion-y-otras-hierbas.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-31098559.post-9216795690690241297</guid><pubDate>Wed, 16 Sep 2009 07:17:00 +0000</pubDate><atom:updated>2009-09-16T09:17:03.852+02:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">Ágil</category><category domain="http://www.blogger.com/atom/ns#">Metodología</category><title>¿Que hace un tecnólogo como tú en una crisis como esta?</title><description>&lt;p&gt;Estamos en lo que parece el ecuador de la crisis económica mundial. Los que ya peinamos alguna que otra cana ya hemos pasado por esto antes y probablemente pasaremos por alguna más. Ya conocemos como se comporta el mercado y os apuesto lo que queráis a que, aunque pase la dichosa crisis, el tiempo de reacción de las empresas de tecnología hacia sus currillos (y la de los clientes hacia las empresas) se estirará lo más posible.    &lt;br /&gt;    &lt;br /&gt;Nos guste o no tenemos que mover ficha. De hecho, tenemos que hacer ajustes para corregir un problema que ni hemos creado ni podíamos haber evitado... Con el fin de adecuarnos a la situación, debemos ser especialmente cuidadosos en algunos aspectos de nuestro día a día, sobre todo, con los directamente o indirectamente relacionados con los (escasos) presupuestos que manejamos. &lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;&lt;strong&gt;Ajusta y maximiza más que nunca los recursos&lt;/strong&gt;       &lt;br /&gt;Puede ser un momento interesante para transmitir al cuadro directivo la necesidad de introducir/mejorar la metodología a emplear en los desarrollos. Argumentado las ventajas de la misma, las empresas suelen estar más receptivas a las mejoras, sobre todo si estas implican poca (o nula) inversión. Mantener una buena visibilidad es un aspecto clave para que los stakeholders analicen mejor que nunca en que se invierten los recursos.       &lt;br /&gt;&lt;/li&gt;    &lt;li&gt;&lt;strong&gt;Céntrate en lo importante&lt;/strong&gt;       &lt;br /&gt;No es nada nuevo, lo deberíamos hacer siempre y las metodologías agiles se cansan de repetirlo. El riesgo de que los proyectos se trunquen a medio camino es más alto en época de inestabilidad. Los presupuestos se aprueban para los diferentes ejercicios y puede ocurrir que un proyecto se paralice o cancele.&amp;#160; &lt;br /&gt;Priorizar las funcionalidades que más valor aportan, así como evaluar con detalle aspectos de más difícil &lt;a href="http://en.wikipedia.org/wiki/Rate_of_return" target="_blank"&gt;R.O.I.&lt;/a&gt; (Creación de Frameworks, metalenguajes, diseñadores…) siempre es importante, pero ahora se vuelve crítico.       &lt;br /&gt;&lt;/li&gt;    &lt;li&gt;&lt;strong&gt;Tomate tiempo para apoyar a la fuerza comercial&lt;/strong&gt;       &lt;br /&gt;Vender siempre es difícil, vender Software o servicios de &lt;a href="http://en.wikipedia.org/wiki/Information_technology" target="_blank"&gt;I.T.&lt;/a&gt; siempre es muy difícil, pero es que en épocas duras se convierte en una acción titánica. Los comerciales e ingenieros comerciales involucrados en las acciones de preventa necesitan justificar y explicar más claramente que nunca porque el cliente debe invertir en el servicio que ofrecemos.       &lt;br /&gt;No escatimes en apoyar con argumentos tecnológicos las soluciones ofrecidas, puesto que cada venta es una batalla y todas las justificaciones que tengamos a mano serán muy apreciadas.       &lt;br /&gt;&lt;/li&gt;    &lt;li&gt;&lt;strong&gt;Valora la posibilidad de emplear soluciones estándar        &lt;br /&gt;&lt;/strong&gt;Potencia el &lt;a href="http://en.wikipedia.org/wiki/Rapid_application_development" target="_blank"&gt;R.A.D&lt;/a&gt;. Intenta recortar los tiempos de desarrollo evitando en la medida de los posible los desarrollos a medida desde cero. Probablemente existan soluciones, bien creadas por Microsoft o terceros, para la mayoría de problemas a solucionar. Esto te permite centrarte en la funcionalidad que realmente aporta valor. Es increíble la cantidad de funcionalidad común que está a mano y no empleamos por no tomarnos el tiempo en evaluarla...       &lt;br /&gt;&lt;/li&gt;    &lt;li&gt;&lt;strong&gt;Re-evalúa las infraestructuras        &lt;br /&gt;&lt;/strong&gt;Probablemente el súper C.P.D. diseñado en los momentos de vacas gordas pueda ser sustituido (antes de realizar la inversión a poder ser ;)) por un sistema en &lt;a href="http://es.wikipedia.org/wiki/Computaci%C3%B3n_en_nube" target="_blank"&gt;Cloud&lt;/a&gt; que reduzca el coste total del proyecto de manera significativa. O quizás explicando en detalle el coste que supone cierto grado de disponibilidad de una funcionalidad, esta no le parezca tan importante al cliente…       &lt;br /&gt;&lt;/li&gt;    &lt;li&gt;&lt;strong&gt;Revisar aquella certificación para la que nunca tenias tiempo&lt;/strong&gt;       &lt;br /&gt;Si tienes un poco más de tiempo de lo habitual, ten en mente que las crisis no son eternas, pasan y cuando se levante el telón los mejor preparados podrán aprovechar el tirón para reclamar los mejores puestos que vuelva a ofrecer el mercado. &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;Lo que nunca debemos hacer es caer en el desanimo, estamos en esto porque es nuestra profesión y además porque nos gusta, que se note!&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/31098559-9216795690690241297?l=andoni-arroyo.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/andoniarroyo/~4/vdqVa2lmGFk" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/andoniarroyo/~3/vdqVa2lmGFk/que-hace-un-tecnologo-como-tu-en-una.html</link><author>noreply@blogger.com (Andoni Arroyo)</author><thr:total>0</thr:total><feedburner:origLink>http://andoni-arroyo.blogspot.com/2009/09/que-hace-un-tecnologo-como-tu-en-una.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-31098559.post-7639852922062012596</guid><pubDate>Thu, 10 Sep 2009 23:56:00 +0000</pubDate><atom:updated>2009-09-11T01:56:45.522+02:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">Ágil</category><category domain="http://www.blogger.com/atom/ns#">Metodología</category><title>La historia del zapatero de Ikea y la perspectiva del proyecto</title><description>&lt;p&gt;La historia que os voy a contar está basada en hechos reales. Aprovechando que tengo unos días libres antes de salir de viaje me he dispuesto a acabar con la fila india de zapatos que tengo por casa. Así que ni corto ni perezoso me fui al Ikea y me cogí un zapatero de esos tan apañado que te montas en casa.    &lt;br /&gt;    &lt;br /&gt;Me puse manos a la obra y decidí seguir las instrucciones que tan amablemente incluyen los suecos a modo de &lt;em&gt;”paso a paso”&lt;/em&gt;. Tras una revisión previa combinada con mis nulos conocimientos en bricolaje y ebanistería, me decidí a seguir los pasos indicados al pie de la letra. El resultado, os lo podréis imaginar, un zapatero impresionante con una de las tablas del frontal colocada al revés, es decir, un precioso acabado en madera virgen…&lt;/p&gt;  &lt;p&gt;Me ha dado por pensar los motivos de este pequeño desastre y la analogía de los mismos en los proyectos de desarrollo de Software. Podemos decir que yo he sido el programador currillo que he recibido una serie de pequeñas tareas bien definidas. Estas tareas fueron creadas por un gran analista sueco como resultado de un diseño basado en el análisis de la funcionalidad a cubrir. &lt;/p&gt;  &lt;p&gt;Por supuesto, no tengo ninguna duda de que el señor analista sueco creó las tareas de manera correcta en su contexto y en su momento. Lamentablemente en el proceso de “codificación” de mi zapatero se han dado algunas circunstancias inesperadas. &lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;&lt;strong&gt;Errores humanos&lt;/strong&gt;       &lt;br /&gt;Tras comprobar de nuevo las instrucciones observo que no se especifica explícitamente el lado que debe dar hacia el frontal y cual no. Obviamente mi decisión no fue la correcta. &lt;/li&gt;    &lt;li&gt;&lt;strong&gt;Falta de comunicación&lt;/strong&gt;       &lt;br /&gt;La verdad es que el analista sueco no me pillaba lo suficientemente a mano para completar las dudas que me surgían sobre el manual mientras avanzaba el desarrollo del proyecto. &lt;/li&gt;    &lt;li&gt;&lt;strong&gt;Falta de perspectiva e interiorización del alcance global del proyecto&lt;/strong&gt; He depositado mi confianza en el manual, sin llegar a interiorizar los componentes del proyecto. Si lo hubiese comprendido como un conjunto, me hubiera dado cuenta de que ese madero en el frontal dado la vuelta no encaja bien, pero para cuando&amp;#160; comprendí que eso era el frontal ya era demasiado tarde….       &lt;br /&gt;&lt;/li&gt;    &lt;li&gt;&lt;strong&gt;Falta de revisiones&lt;/strong&gt;       &lt;br /&gt;Una pequeña revisión al finalizar cada paso o conjunto de pasos podría haber evitado la desviación. Esto me habría limitado la cantidad de pasos a deshacer para recolocar el maldito madero y por lo tanto, el esfuerzo (dinero en proyectos reales) malgastado en problemas que yo mismo me he buscado. &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;En el mundo del Software tanto las especificaciones como los entregables son más abstractos. Si no comprendemos bien las necesidades del cliente, (las que nos transmite y las que ni él mismo ha identificado aún!) podemos llegar a las oficinas del cliente con un software que le produzca mas enfado que satisfacción. Dichas necesidades en la mayoría de ocasiones nos son totalmente ajenas y desconocidas puesto que no conocemos profundamente el sector del cliente (Al menos en los primeros proyectos tipo!).&lt;/p&gt;  &lt;p&gt;Sin trabajar este proceso de interiorización apoyado en la empatía, podemos entregar el zapatero al cliente sin enterarnos de que tenemos el madero al revés aunque lo estemos mirando con todo detalle...&lt;/p&gt;  &lt;p&gt;Así que dicho queda, me voy a por la caja de herramientas de nuevo…&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/31098559-7639852922062012596?l=andoni-arroyo.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/andoniarroyo/~4/91PGF1jfOkY" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/andoniarroyo/~3/91PGF1jfOkY/la-historia-del-zapatero-de-ikea-y-la.html</link><author>noreply@blogger.com (Andoni Arroyo)</author><thr:total>0</thr:total><feedburner:origLink>http://andoni-arroyo.blogspot.com/2009/09/la-historia-del-zapatero-de-ikea-y-la.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-31098559.post-9014089405314917559</guid><pubDate>Sun, 30 Aug 2009 20:00:00 +0000</pubDate><atom:updated>2009-08-30T22:06:58.898+02:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">Ágil</category><category domain="http://www.blogger.com/atom/ns#">Metodología</category><category domain="http://www.blogger.com/atom/ns#">Pruebas unitarias</category><title>Desarrollador con calidad vale por dos (o más...)</title><description>&lt;p&gt;Las metodologías ágiles nos recomiendan centrar nuestros esfuerzos en aportar valor al cliente. Dicho valor se traslada a través de los entregables que el equipo va liberando en las diferentes iteraciones. En el mundo del desarrollo de aplicaciones informáticas, el más importante de todos los artefactos que entregamos es el Software. Y este software se genera desde el código que generan los miembros del equipo.&lt;/p&gt;  &lt;p&gt;Bueno eso este claro. Y que menos se puede pedir al equipo que se aplique al máximo con el código que genera? Como desarrollador de software el código es tu producto final, y este debe ser desarrollado con la máxima calidad que nos sea posible.&lt;/p&gt;  &lt;p&gt;Algo que todos (los que entendemos como funciona el negocio del desarrollo de software..) tenemos claro, es que es más rentable asegurar al calidad de nuestros desarrollos desde las primeras etapas del proceso en vez de corregir los errores más tarde. El impacto de los errores crece exponencialmente cuanto más tarde se descubren. &lt;/p&gt;  &lt;p&gt;Por lo tanto, como desarrolladores profesionales que somos, debemos poner especial hincapié en mantener presente la calidad en nuestros proyectos. Es fácil de decir, pero como a menudo, no tan fácil de conseguir…&lt;/p&gt;  &lt;p&gt;Existen algunos grupos de problemas comunes que podemos identificar como focos problemáticos: &lt;/p&gt;  &lt;ol&gt;   &lt;li&gt;&lt;strong&gt;Comunicación pobre y malas interpretaciones        &lt;br /&gt;&lt;/strong&gt;La capacidad de comunicación del ser humano es uno de los factores que le diferencia del resto de las especies. El grado de abstracción que podemos aplicar a la misma es muy alto. Esta característica, nos permite transmitir mucha información de manera muy efectiva.       &lt;br /&gt;      &lt;br /&gt;Por ejemplo, si yo te digo, &lt;em&gt;singelton&lt;/em&gt;, &lt;em&gt;grano fino&lt;/em&gt;, o &lt;em&gt;capa de servicios&lt;/em&gt; y ambos tenemos un conocimiento equivalente en la materia, hemos conseguido transmitir una serie de conceptos más o menos complejos de manera optimizada.       &lt;br /&gt;      &lt;br /&gt;Es una herramienta potente, pero que debemos cuidar para evitar desviaciones igual de potentes. La comunicación debe ser clara y fluida, asegurando que el receptor ha comprendido el mensaje en la misma dimensión que deseamos emitirlo. No se debe escatimar en comunicación funcional, técnica, recabar &lt;em&gt;feedback&lt;/em&gt; del equipo y aplicar un poco de psicología (la empatía puede ser la clave). Colaborar en este juego es parte de la tarea de cualquier miembro de un equipo.       &lt;br /&gt;      &lt;br /&gt;&lt;/li&gt;    &lt;li&gt;&lt;strong&gt;Errores de programación        &lt;br /&gt;&lt;/strong&gt;Las personas&amp;#160; escriben código y las personas comenten errores. Ergo…el código tiene errores (ahora no abusemos del mismo para hacer chapuzas diciendo es intrínseco el error en la persona...)       &lt;br /&gt;      &lt;br /&gt;Escribir buen código no es fácil. Debemos tener en cuenta aspectos como seguridad, rendimiento, localización, mantenibilidad... y en tiempo record!       &lt;br /&gt;      &lt;br /&gt;Aunque apoyarnos en el CLR ayuda, siempre existirán &lt;em&gt;bugs&lt;/em&gt; que tendremos que corregir y realizar mantenimiento sobre el mismo. Y esto ocurre haciendo las cosas todo lo bien que podemos, esforzándonos al máximo como desarrolladores. Imagínate si no lo hacemos así…       &lt;br /&gt;      &lt;br /&gt;&lt;/li&gt;    &lt;li&gt;&lt;strong&gt;Falta de realimentación de pruebas        &lt;br /&gt;&lt;/strong&gt;Escribir pruebas unitarias es un trabajo que (casi) no aporta visibilidad. Lleva tiempo y no es código fácil de reutilizar. Aunque los desarrolladores sabemos que debemos escribirlas y esforzarnos y alcanzar la cobertura d código marcada por los parámetros de calidad del proyecto, a menudo nos enfrentamos a desincentivos que tientan a no realizarlas. Pero lo que es seguro, es que sin un buen conjunto de pruebas, (no tiene que ser muchas pero si bien diseñadas) es muy fácil cambiar código y no descubrir los efectos secundarios no deseados hasta demasiado tarde. (vamos creando un coladero…)       &lt;br /&gt;      &lt;br /&gt;&lt;/li&gt;    &lt;li&gt;&lt;strong&gt;Versión distorsionada&lt;/strong&gt;       &lt;br /&gt;Gracias a la metodología al principio, y a las herramientas de control de código fuente, más adelante no se han producido millones de asesinatos entre los desarrolladores. Aún así existen archivos y configuraciones de puestos que no son propios del código fuente cuyas diferencias producen errores que son difíciles de diagnosticar. Cuantas veces hemos oído eso de &amp;quot;En mi máquina funcionaba!&amp;quot;.       &lt;br /&gt;      &lt;br /&gt;&lt;/li&gt;    &lt;li&gt;&lt;strong&gt;Falta de transparencia        &lt;br /&gt;&lt;/strong&gt;Para desarrollar un proyecto con éxito hace falta todo. Como una de las piezas falle o no se comunique adecuadamente todo el proyecto se puede venir abajo como un castillo de naipes. Tradicionalmente, han sido mundos diferentes (e inconexos!!) aspectos como la infraestructura de desarrollo, el sistema de gestión del proyecto, el trazado de requisitos/errores, métricas...(Intenta sincronizar el s.v.n. con el Visio que se sacó tu gerente de la manga...;))       &lt;br /&gt;En esta situación, el equipo tiene poca visibilidad respecto al estado global del proyecto. (aparte de los odiados y poco fiables informes de estado...) &lt;/li&gt; &lt;/ol&gt;  &lt;p&gt;Cada una de estas cinco categorías son un foco potencial de problemas que afectan directamente a la calidad del código realizado. Esto implica que el mecanismo que el cliente emplea para evaluar el valor aportado, tiene problemas que afectan, directamente, a las sensaciones que transmitimos. La aparición de herramientas que nos permiten gestionar todos los aspectos relacionados con el desarrollo de manera orquestada vienen a facilitarnos la vida, y conocer sus posibilidades es un esfuerzo con seguro retorno de inversión. &lt;/p&gt;  &lt;p&gt;Por nosotros que no quede...&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/31098559-9014089405314917559?l=andoni-arroyo.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/andoniarroyo/~4/0TlI8hyOLZM" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/andoniarroyo/~3/0TlI8hyOLZM/desarrollador-con-calidad-vale-por-dos.html</link><author>noreply@blogger.com (Andoni Arroyo)</author><thr:total>0</thr:total><feedburner:origLink>http://andoni-arroyo.blogspot.com/2009/08/desarrollador-con-calidad-vale-por-dos.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-31098559.post-991420572005280196</guid><pubDate>Tue, 18 Aug 2009 13:30:00 +0000</pubDate><atom:updated>2009-08-18T15:30:01.015+02:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">Informática</category><category domain="http://www.blogger.com/atom/ns#">Arquitectura del Software</category><category domain="http://www.blogger.com/atom/ns#">Desarrollo de Software</category><title>¿Es lo mismo arquitectura por capas y N-Tier?</title><description>&lt;p&gt;Me parece importante, para optimizar la comunicación entre profesionales, que todos tengamos claros los conceptos y los apliquemos para referirnos exactamente a lo mismo. Esto nos evita malas interpretaciones y errores muy críticos sobre todo en entonos de desarrollo rápido de aplicaciones (&lt;a href="http://en.wikipedia.org/wiki/Rapid_application_development" target="_blank"&gt;RAD&lt;/a&gt;).&amp;#160; &lt;br /&gt;    &lt;br /&gt;Existen dos conceptos arquitectónicos que a veces tendemos a confundir. Estos son la “&lt;em&gt;Layered arquitecture&lt;/em&gt;” (arquitectura por capas) y la “&lt;em&gt;N-tier arquitecture&lt;/em&gt;” (arquitectura de N-niveles). Me voy a referir a ellas sin traducirlas, puesto que ambos conceptos (“&lt;em&gt;layer&lt;/em&gt;” y “&lt;em&gt;tier&lt;/em&gt;”) pueden verse traducidas (erróneamente en el caso de “&lt;em&gt;tier&lt;/em&gt;”) como “capa” lo cual fomenta aún más la propensión a errores.&lt;/p&gt;  &lt;p&gt;Veamos primero que es exactamente “&lt;strong&gt;&lt;em&gt;Layered architecture&lt;/em&gt;&lt;/strong&gt;”:&amp;#160; &lt;br /&gt;    &lt;br /&gt;Se centra en una &lt;strong&gt;distribución jerárquica de las roles y responsabilidades&lt;/strong&gt; proporcionando una separación efectiva de las preocupaciones. (cada cual que se apañe con sus problema…). El rol indica el modo y el tipo de interacción con las otras capas, y la responsabilidad indica la funcionalidad a alcanzar. &lt;/p&gt;  &lt;p&gt;Por ejemplo, el diseño de una típica aplicación Web comprende una capa de presentación (funcionalidad relacionada con la U.I.), capa de negocio (procesamiento de reglas de negocio) y capa de datos (funcionalidad relacionada con el accesos a datos.)&lt;/p&gt;  &lt;p&gt;El estilo de arquitectura por capas tiene algunas &lt;strong&gt;características&lt;/strong&gt; que&amp;#160; la identifica:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;Describe una descomposición de servicios de tal manera que las interacciones ocurren normalmente entre capas vecinas. (depende de lo laxos que queramos ser…)      &lt;br /&gt;&lt;/li&gt;    &lt;li&gt;Las capas de la aplicación pueden residir en el mismo ordenador fisco o pueden estar distribuidas en separados equipos. El concepto de distribución se aplica siempre que se produzca el mecanismo de &lt;a href="http://en.wikipedia.org/wiki/Marshalling_(computer_science)" target="_blank"&gt;marshaling&lt;/a&gt; para realizar una comunicación (siempre que no se comparta espacio de memoria…)       &lt;br /&gt;&lt;/li&gt;    &lt;li&gt;Los componente de cada capa se comunican con otros componente de otras capas a través de un conjunto de interfaces bien definidos. (sino apañados vamos…)      &lt;br /&gt;&lt;/li&gt;    &lt;li&gt;En alguna ocasión ha sido descrito como “pirámide invertida de reutilización” donde cada capa agrega sus propias responsabilidades&amp;#160; y abstracciones a la capas que están por debajo. &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;Que &lt;strong&gt;beneficios&lt;/strong&gt; conseguimos aplicando esta distribución en capas?&lt;/p&gt;  &lt;p&gt;Abstracción, encapsulamiento, capas de funcionalidad muy bien definidas, alta cohesión, reusabilidad (las capas inferiores de la pirámide no tienen dependencias de las superiores por lo que es fácil reutilizarlas) y débil acoplamiento (comunicación basada en abstracciones)    &lt;br /&gt;    &lt;br /&gt;La separación, reduce el riesgo y el impacto de los cambios tecnológicos. Por ejemplo al cambiar el mecanismo de persistencia de la aplicación las capas que lo consumen no tienen porque realizar cambios. Además aumenta el rendimiento (a partir de cierta carga de trabajo) al distribuir las capas sobre múltiples capas físicas. También aumenta la escalabilidad y la tolerancia a fallos.&lt;/p&gt;  &lt;p&gt;Este escenario es propicio para implementar una buena política de pruebas, permitiendo conmutar entre diferentes implementaciones de los interfaces (mock, servicios reales…)&lt;/p&gt;  &lt;p&gt;Por otro lado tenemos la &lt;strong&gt;“&lt;em&gt;N-Tier architecture&lt;/em&gt;”&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;El estilo de despliegue de esta arquitectura describe la separación de la funcionalidad en diferentes segmentos, de manera similar a la arquitectura por capas. &lt;strong&gt;pero cada segmento es un nivel que se encuentra físicamente en un equipo independiente.&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;Es un estilo &lt;strong&gt;que define el despliegue de las capas de la aplicación&lt;/strong&gt;, se caracteriza por por una descomposición funcional de la aplicación, componentes de servicios y su &lt;strong&gt;despliegue distribuido&lt;/strong&gt;, proveyendo mejoras de escalabilidad, disponibilidad&amp;#160; y utilización de recursos.&lt;/p&gt;  &lt;p&gt;Cada capa es completamente independiente del resto, excepto de aquella/s se encuentran inmediatamente por debajo de ella. La capa n sabe como manejar las peticiones a la capa n+1, como trasladar dicha petición a la capa n-1 (si es que existe) y como tratar el resultado de la misma.&lt;/p&gt;  &lt;p&gt;Las arquitecturas con “&lt;em&gt;N-Tiers&lt;/em&gt;” poseen por lo menos 3 capas lógicas separadas. Cada capa tiene una funcionalidad especifica, de la cual es responsable y están localizadas en diferentes servidores físicos. Una capa (“&lt;em&gt;layer”&lt;/em&gt;) se despliega en un nivel (“&lt;em&gt;tier”&lt;/em&gt;) si más de un servicio o aplicación es dependiente de la funcionalidad expuestas por la capa.&lt;/p&gt;  &lt;p&gt;Veamos los beneficios que nos aporta esta arquitectura:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;Mantenibilidad      &lt;br /&gt;Cada nivel es independiente de los demás, con lo que se consigue independencia. Se puede actualizar o modificar un nivel sin afectar a la aplicación en su conjunto.&amp;#160; &lt;br /&gt;&lt;/li&gt;    &lt;li&gt;Escalabilidad      &lt;br /&gt;Es razonablemente sencillo escalar puesto que los niveles están basadas en el despliegue de las capas.       &lt;br /&gt;&lt;/li&gt;    &lt;li&gt;Flexibilidad      &lt;br /&gt;Cada nivel puede ser gestionado o escalado independientemente, lo cual aumenta la flexibilidad.       &lt;br /&gt;&lt;/li&gt;    &lt;li&gt;Disponibilidad      &lt;br /&gt;Las aplicaciones pueden explotar la arquitectura modular empleando componentes fácilmente escalables.       &lt;br /&gt;&lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;&lt;strong&gt;Resumiendo un poco :&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;Podemos decir que para que una aplicación sea “&lt;em&gt;N-Tier&lt;/em&gt;”, es condición necesaria pero no suficiente que mantenga una arquitectura por capas. Esta característica nos permite cumplir los requisitos de despliegue (3 o más capas separadas) que hacen a una aplicación “&lt;em&gt;N-Tier&lt;/em&gt;”.     &lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/31098559-991420572005280196?l=andoni-arroyo.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/andoniarroyo/~4/9LfF0S63ljQ" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/andoniarroyo/~3/9LfF0S63ljQ/es-lo-mismo-arquitectura-por-capas-y-n.html</link><author>noreply@blogger.com (Andoni Arroyo)</author><thr:total>0</thr:total><feedburner:origLink>http://andoni-arroyo.blogspot.com/2009/08/es-lo-mismo-arquitectura-por-capas-y-n.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-31098559.post-6910961452088415659</guid><pubDate>Wed, 12 Aug 2009 20:00:00 +0000</pubDate><atom:updated>2009-08-13T10:55:56.751+02:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">Informática</category><category domain="http://www.blogger.com/atom/ns#">Ágil</category><category domain="http://www.blogger.com/atom/ns#">Kanban</category><category domain="http://www.blogger.com/atom/ns#">Desarrollo de Software</category><title>Dulce introducción al Kanban!!</title><description>&lt;p&gt;Bueno, parece que SCRUM ha puesto la pica en Flandes y se ha convertido en una metodología ampliamente conocida y respetada. Pues ya está, no? ya tenemos metodología ágil para cualquier tipo de proyecto y para siempre…&lt;br /&gt;&lt;br /&gt;Muy confiado tienes que ser para creerte eso…&lt;br /&gt;&lt;br /&gt;En mi trabajo hemos desarrollado un producto aplicando SCRUM con unos resultados muy satisfactorios. Dicho producto, se ha comenzado a implantar y ahora entra un equipo de soporte a mantener la primera versión del mismo y comienza una nueva rama de desarrollo de la siguiente versión.&lt;br /&gt;&lt;br /&gt;Estaba planteándome como organizar el equipo de soporte y no acababa de encajar SCRUM sobre la naturaleza de su trabajo(la verdad que esta y cualquier otra metodología…). Es muy difícil organizarse para planificar incluso un pequeño Sprint, puesto que no se conocen las tareas de antemano. Por lo tanto, llegué a la conclusión de que necesitamos para este tipo de proyectos (que no son pocos) algo todavía más adaptable que SCRUM…&lt;br /&gt;&lt;br /&gt;Tomando un café con el gran (aunque javero) Jorge Prieto me comentó algo sobre Kanbas y comencé a tirar del hilo para ver si me podía cuadrar eso que sonaba a pescado crudo…&lt;br /&gt;&lt;br /&gt;Así que vamos a aprovechar este post para explicar que es eso de Kanban compararlo con SCRUM e identificar sus conflictos potenciales. Antes que meternos en harina vamos a dejar las cosas claras, haciendo un pequeño resumen de SCRUM y Kanban&lt;/p&gt;&lt;p&gt;&lt;strong&gt;SCRUM (en pocas palabras)&lt;/strong&gt;&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Divide su organización en pequeños equipos auto-organizados y multidisciplinares. &lt;/li&gt;&lt;li&gt;Divide el trabajo en una lista de pequeños elementos muy concretos. &lt;/li&gt;&lt;li&gt;Ordenar la lista por orden de prioridad y estimar el esfuerzo relativo de cada elemento. &lt;/li&gt;&lt;li&gt;Dividido en iteraciones cortas de longitud fija (normalmente con entrega o demostración después de cada iteración.) &lt;/li&gt;&lt;li&gt;Optimizar el plan de liberación y actualizar las prioridades en colaboración con el cliente, sobre la base de conocimientos adquiridos por la inspección de la entrega después de cada iteración. &lt;/li&gt;&lt;li&gt;Optimizar el proceso por tener una retrospectiva después de cada iteración. &lt;/li&gt;&lt;/ul&gt;&lt;p&gt;Resumiendo el resumen:&lt;/p&gt;&lt;p&gt;Pasamos de &lt;strong&gt;“Muchas personas haciendo algo muy grande”&lt;/strong&gt; a &lt;strong&gt;“Pocas personas haciendo cosas pequeñas que se integran con regularidad para ver el conjunto.”&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Kanbas (en pocas palabras también)&lt;/strong&gt;&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Visualizar el flujo de trabajo&lt;br /&gt;Dividir el trabajo en trozos escribir cada uno de los elementos en una tarjeta y poner en la pared.&lt;br /&gt;Usar el nombre o columnas para ilustrar en que estado se encuentra cada elemento dentro del flujo de trabajo. &lt;/li&gt;&lt;li&gt;Límitar WIP (Work In Progress)&lt;br /&gt;Asignar límites explícitos obre cuantos elementos pueden estar en cada uno de los estados del flujo de trabajo. &lt;/li&gt;&lt;li&gt;Medir el tiempo&lt;br /&gt;Contar el tiempo promedio para completar un tema, a veces llamado "tiempo de ciclo" y, como es obvio, optimizar el proceso para que el tiempo tan pequeño y previsible como sea posible. &lt;/li&gt;&lt;/ul&gt;&lt;p&gt;&lt;img style="BORDER-RIGHT-WIDTH: 0px; DISPLAY: block; FLOAT: none; BORDER-TOP-WIDTH: 0px; BORDER-BOTTOM-WIDTH: 0px; MARGIN-LEFT: auto; BORDER-LEFT-WIDTH: 0px; MARGIN-RIGHT: auto" title="image" border="0" alt="image" src="http://lh3.ggpht.com/_cDGcKb7l-aU/SoK0mjHK2fI/AAAAAAAAA88/6hkV05yHY54/image%5B5%5D.png?imgmax=800" width="240" height="117" /&gt; &lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;Podemos observar que &lt;strong&gt;Kanban&lt;/strong&gt; es todavía &lt;strong&gt;menos prescriptivo que SCRUM&lt;/strong&gt;.&lt;br /&gt;&lt;br /&gt;Prescriptivo significa “reglas para seguir”. 100% prescriptivo implica que no tienes que usar el cerebro, ridículo verdad?…) y en este apartado vemos que SCRUM aporta mas reglas “&lt;em&gt;out-of-the-box&lt;/em&gt;” como por ejemplo encajar en un tiempo los Sprints cosa que Kanban no hace.&lt;br /&gt;&lt;br /&gt;Para hacernos una mejor composición podemos observar la escala de “prescriptividad” (toma ya!) de forma gráfica:&lt;/p&gt;&lt;p&gt;&lt;img style="BORDER-RIGHT-WIDTH: 0px; DISPLAY: block; FLOAT: none; BORDER-TOP-WIDTH: 0px; BORDER-BOTTOM-WIDTH: 0px; MARGIN-LEFT: auto; BORDER-LEFT-WIDTH: 0px; MARGIN-RIGHT: auto" title="image" border="0" alt="image" src="http://lh6.ggpht.com/_cDGcKb7l-aU/SoK0n39E_gI/AAAAAAAAA9A/apZBkDKlFFc/image%5B14%5D.png?imgmax=800" width="527" height="338" /&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;Como siempre podemos decir que la mejor opción es no limitarse a un herramienta en concreto. Probablemente la solución nuestros problemas se encuentre en una combinación de varias. Muchos equipo Kanban realizan una reunión diaria a primera hora (típica liturgia de SCRUM). Algunos equipos de SCRUM que he conocido, escriben su Backlog como Casos de Uso (típico de RUP) o limitan el tamaño de las colas (típico de Kanbas).&lt;/p&gt;&lt;p&gt;Así que como siempre “haz las cosas como mejor te funcionen”, ya os contaré el resultado de aplicar esta forma de trabajo con el equipo de soporte.&lt;br /&gt;&lt;br /&gt;Para terminar os cito a &lt;a href="http://es.wikipedia.org/wiki/Miyamoto_Musashi" target="_blank"&gt;Miyamoto Musashi&lt;/a&gt; que los japoneses algo saben de todo esto:&lt;/p&gt;&lt;p align="center"&gt;&lt;em&gt;“No desarrolles ninguna dependencia de arma o escuela de lucha”&lt;/em&gt;&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/31098559-6910961452088415659?l=andoni-arroyo.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/andoniarroyo/~4/v0L_VsHYUc0" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/andoniarroyo/~3/v0L_VsHYUc0/dulce-introduccion-al-kanban.html</link><author>noreply@blogger.com (Andoni Arroyo)</author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://lh3.ggpht.com/_cDGcKb7l-aU/SoK0mjHK2fI/AAAAAAAAA88/6hkV05yHY54/s72-c/image%5B5%5D.png?imgmax=800" height="72" width="72" /><thr:total>0</thr:total><feedburner:origLink>http://andoni-arroyo.blogspot.com/2009/08/dulce-introduccion-al-kanban.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-31098559.post-8413035737097298842</guid><pubDate>Wed, 12 Aug 2009 09:32:00 +0000</pubDate><atom:updated>2009-08-12T11:32:49.769+02:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">Globalización</category><category domain="http://www.blogger.com/atom/ns#">Emprender</category><category domain="http://www.blogger.com/atom/ns#">Negocio</category><title>Los mejores países para hacer negocio</title><description>&lt;p&gt;Si estáis pensando en globalizar vuestras líneas de negocio o cambiar de aires profesionales, os puede resultar interesante saber que el &lt;a href="http://www.worldbankgroup.org/" target="_blank"&gt;World Bank Group&lt;/a&gt; ha publicado su informe anual &amp;quot;Doing Business&amp;quot; que clasifica 181 países sobre lo propicio que es su regulación hacia los empresarios.&lt;/p&gt;  &lt;p&gt;El informe proporciona una medida cuantitativa de la normativa, que sirva como soporte a la decisión de abrir un negocio y se aplica a las pequeñas y medianas empresas nacionales. Las economías están clasificadas en base a un índice de facilidad de hacer negocios. (Índice creado por el propio World Bank Group)&lt;/p&gt;  &lt;p&gt;Los valores más altos de este índice indican un conjunto de reglamentos más ventajosos para las empresas y el fortalecimiento de la protección de los derechos de propiedad.    &lt;br /&gt;    &lt;br /&gt;Facilidad de hacer negocios:&lt;/p&gt;  &lt;ol&gt;   &lt;li&gt;&lt;strong&gt;Singapur.&lt;/strong&gt; &lt;/li&gt;    &lt;li&gt;&lt;strong&gt;Nueva Zelanda.&lt;/strong&gt; &lt;/li&gt;    &lt;li&gt;&lt;strong&gt;Estados Unidos.&lt;/strong&gt; &lt;/li&gt;    &lt;li&gt;Hong Kong. (es una Región Administrativa Especial…) &lt;/li&gt;    &lt;li&gt;Dinamarca. &lt;/li&gt;    &lt;li&gt;Reino Unido. &lt;/li&gt;    &lt;li&gt;Irlanda. &lt;/li&gt;    &lt;li&gt;Canadá. &lt;/li&gt;    &lt;li&gt;Australia. &lt;/li&gt;    &lt;li&gt;Noruega. &lt;/li&gt; &lt;/ol&gt;  &lt;p&gt;Los criterios tenidos en cuenta a la hora de confeccionar este ranking son:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;Facilidad de hacer negocios      &lt;br /&gt;Procedimientos, tiempo, costo y capital social mínimo para abrir un nuevo negocio. &lt;/li&gt;    &lt;li&gt;Permisos de Construcción      &lt;br /&gt;Procedimientos, tiempo y costo para obtener permisos de construcción, las inspecciones y las conexiones de servicios públicos. &lt;/li&gt;    &lt;li&gt;Emplear trabajadores      &lt;br /&gt;Índice de dificultad de contratación, índice de rigidez de horas, índice de dificultad de despido, coste de despido. &lt;/li&gt;    &lt;li&gt;Registro de la Propiedad      &lt;br /&gt;Procedimientos, tiempo y costo para la transferencia de bienes inmuebles comerciales. &lt;/li&gt;    &lt;li&gt;Obtención de crédito      &lt;br /&gt;Fuerza de los derechos legales, profundidad de crédito. &lt;/li&gt;    &lt;li&gt;La protección de los inversores      &lt;br /&gt;Fuerza de la protección de los inversores, grado de divulgación, grado de responsabilidad del director y la facilidad de adaptación del accionista. &lt;/li&gt;    &lt;li&gt;Impuestos      &lt;br /&gt;Número de pagos de impuestos, el tiempo necesario para preparar y presentar declaraciones de impuestos y pagar los impuestos, relación del total de impuestos con el porcentaje del beneficio. &lt;/li&gt;    &lt;li&gt;Comercio a través de las fronteras      &lt;br /&gt;Documentos, tiempo y el costo para exportar e importar. &lt;/li&gt;    &lt;li&gt;El cumplimiento de los contratos      &lt;br /&gt;Procedimientos, tiempo y costo para resolver una disputa comercial. &lt;/li&gt;    &lt;li&gt;Cierre de una empresa      &lt;br /&gt;La tasa de recuperación de la quiebra. &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;Como podéis comprobar está todo pensado...    &lt;br /&gt;    &lt;br /&gt;Si queréis profundizar más en el tema, pasaros por aquí &lt;a href="http://www.doingbusiness.org/economyrankings" target="_blank"&gt;World Bank - Doing Business&lt;/a&gt;…&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/31098559-8413035737097298842?l=andoni-arroyo.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/andoniarroyo/~4/t-CA7mHanhM" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/andoniarroyo/~3/t-CA7mHanhM/los-mejores-paises-para-hacer-negocio.html</link><author>noreply@blogger.com (Andoni Arroyo)</author><thr:total>0</thr:total><feedburner:origLink>http://andoni-arroyo.blogspot.com/2009/08/los-mejores-paises-para-hacer-negocio.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-31098559.post-1146968004044841830</guid><pubDate>Sun, 09 Aug 2009 22:15:00 +0000</pubDate><atom:updated>2009-08-10T00:15:56.414+02:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">Informática</category><category domain="http://www.blogger.com/atom/ns#">Ágil</category><category domain="http://www.blogger.com/atom/ns#">Metodología</category><title>¿Por que iterar?</title><description>&lt;p&gt;Aplicando el patrón C.S.P. (&lt;em&gt;Common Sense Pattern…&lt;/em&gt;) en nuestros desarrollos, observamos que debemos cumplir con las necesidades del cliente. Acto seguido, descubrimos, que estas cambian más que los nos gustaría (ouchh!). Por lo tanto, se crea la necesidad de ir ajustando el avance del proyecto a las necesidades reales (y cambiantes) del proyecto. &lt;/p&gt;  &lt;p&gt;¿Pero como…?    &lt;br /&gt;    &lt;br /&gt;La respuesta que nos aportan las metodologías agiles es sencilla, iterando. Partiendo el desarrollo de la aplicación en pequeños entregables que el usuario pueda probar e ir enriqueciendo. Suena lógico, pero vamos a hacer un esfuerzo de plasmar negro sobre blanco las principales ventajas que esta forma de trabajar nos ofrece:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;&lt;strong&gt;Gestión de riesgos        &lt;br /&gt;&lt;/strong&gt;Asumámoslo, el resultado deseado no es concebible por adelantado. Existen riesgos, algunos ya identificados y otros por identificar. Para gestionarlos correctamente debes demostrar o refutar tus requisitos y diseñar las suposiciones implementando incrementalmente elementos que son objetivos del sistema, empezando con los de más alto riesgo.       &lt;br /&gt;&lt;/li&gt;    &lt;li&gt;&lt;strong&gt;Económicos        &lt;br /&gt;&lt;/strong&gt;En un ambiente de negocio incierto (&lt;strike&gt;casi&lt;/strike&gt; todos los proyectos lo son !!) es clave optimizar los esfuerzos en las mayores prioridades del proyecto. Debemos manejar cada iteración como un conjunto de fichas de juego a apostar por un conjunto de funcionalidad que se pueda entregar, probar y que funcionen.       &lt;br /&gt;&lt;/li&gt;    &lt;li&gt;&lt;strong&gt;Enfoque        &lt;br /&gt;&lt;/strong&gt;Solo podemos mantener una cantidad limitada de elementos en la mente. Trabajando con pequeños lotes de trabajo podemos focalizar nuestros esfuerzos con un conjunto de funcionalidades que comprendemos y somos capaces de encajar y entender.       &lt;br /&gt;&lt;/li&gt;    &lt;li&gt;&lt;strong&gt;Motivación        &lt;br /&gt;&lt;/strong&gt;No existe un mecanismo mejor de motivación de acción prolongada (el dinero solo motiva en un espacio reducido de tiempo!!) para un profesional que comprobar como su creación se usa, es efectivo y valorado por los usuarios.       &lt;br /&gt;&lt;/li&gt;    &lt;li&gt;&lt;strong&gt;Control de la teoría        &lt;br /&gt;&lt;/strong&gt;Las iteraciones nos permiten controlar mejor las desviaciones, reduciendo el impacto de los errores en las estimaciones y crear un mecanismo de retroalimentación sobre los planes del proyecto.       &lt;br /&gt;&lt;/li&gt;    &lt;li&gt;&lt;strong&gt;Implicación de los interesados        &lt;br /&gt;&lt;/strong&gt;Los patrocinadores (clientes, usuarios, dirección…) pueden observar los resultados más rápidamente (cumpliendo así con la visibilidad, requisito fundamental de cualquier desarrollo) y así aportar mayor compromiso, implicación y financiación.       &lt;br /&gt;&lt;/li&gt;    &lt;li&gt;&lt;strong&gt;Aprendizaje continuo&lt;/strong&gt;       &lt;br /&gt;Todos los actores del proyecto aprenden en cada iteración. Los miembros del equipo adquieren conocimiento funcional y aportan mejoras desde la prospectiva tecnológica y los funcionales comprenden las implicaciones de automatizar los procesos empresariales. Todos aportan y el proyecto crece rápido y mejora. &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;Ya tenemos un conjunto de argumentos para convencer a los stakeholders más peleones acerca de las bondades de trabajar en pequeñas iteraciones, ahora el que quiera entender que entienda…&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/31098559-1146968004044841830?l=andoni-arroyo.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/andoniarroyo/~4/pOLV3_mv4So" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/andoniarroyo/~3/pOLV3_mv4So/por-que-iterar.html</link><author>noreply@blogger.com (Andoni Arroyo)</author><thr:total>0</thr:total><feedburner:origLink>http://andoni-arroyo.blogspot.com/2009/08/por-que-iterar.html</feedburner:origLink></item></channel></rss>

