<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	xmlns:georss="http://www.georss.org/georss" xmlns:geo="http://www.w3.org/2003/01/geo/wgs84_pos#" xmlns:media="http://search.yahoo.com/mrss/"
	>

<channel>
	<title>Te lo dije ...</title>
	<atom:link href="http://eamodeorubio.wordpress.com/feed/" rel="self" type="application/rss+xml" />
	<link>http://eamodeorubio.wordpress.com</link>
	<description>Ingenieria del Software en el siglo XXI (en español)</description>
	<lastBuildDate>Thu, 19 Jan 2012 16:33:28 +0000</lastBuildDate>
	<language>es</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.com/</generator>
<cloud domain='eamodeorubio.wordpress.com' port='80' path='/?rsscloud=notify' registerProcedure='' protocol='http-post' />
<image>
		<url>http://s2.wp.com/i/buttonw-com.png</url>
		<title>Te lo dije ...</title>
		<link>http://eamodeorubio.wordpress.com</link>
	</image>
	<atom:link rel="search" type="application/opensearchdescription+xml" href="http://eamodeorubio.wordpress.com/osd.xml" title="Te lo dije ..." />
	<atom:link rel='hub' href='http://eamodeorubio.wordpress.com/?pushpress=hub'/>
		<item>
		<title>No grabes navegaciones, ¡ haz BDD !</title>
		<link>http://eamodeorubio.wordpress.com/2012/01/10/no-grabes-navegaciones-haz-bdd/</link>
		<comments>http://eamodeorubio.wordpress.com/2012/01/10/no-grabes-navegaciones-haz-bdd/#comments</comments>
		<pubDate>Tue, 10 Jan 2012 09:30:54 +0000</pubDate>
		<dc:creator>Enrique Amodeo</dc:creator>
				<category><![CDATA[BDD]]></category>
		<category><![CDATA[TDD]]></category>

		<guid isPermaLink="false">http://eamodeorubio.wordpress.com/?p=649</guid>
		<description><![CDATA[Hola a todos, aquí estoy de nuevo tras un tiempo de inactividad. La verdad es que andaba yo sin ningún tipo de inspiración para un nuevo post cuando el mundo real me ha obligado a escribir este. La verdad es que en estos meses, tanto en conversaciones, como en twitter, como en varios cursos de [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=eamodeorubio.wordpress.com&amp;blog=12532304&amp;post=649&amp;subd=eamodeorubio&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>Hola a todos, aquí estoy de nuevo tras un tiempo de inactividad. La verdad es que andaba yo sin ningún tipo de inspiración para un nuevo post cuando el mundo real me ha obligado a escribir este. La verdad es que en estos meses, tanto en conversaciones, como en twitter, como en varios cursos de calidad, agilismo y testing que he impartido, han surgido de manera recurrente las siguientes preguntas: ¿y cómo engancho el selenium en todo esto? ¿Y cuándo grabo las navegaciones para automatizar las pruebas funcionales? ¿Y porque tanto rollo de BDD si ya tengo el producto &#8220;Super UI Test Automator Robot&#8221; que me graba las navegaciones? Y así una detrás de otra. Reconozco que si no te interesa el enfoque BDD ni el TDD, puedes seguir grabando navegaciones como modo de &#8220;automatizar test funcionales&#8221;. Para el resto de vosotros os ofrezco varias razones por las que considero que usar éste enfoque es una aberración:</p>
<p>La primera razón es bastante trivial, si haces BDD entonces tienes un enfoque &#8220;test first&#8221;, es decir, escribes el test antes que la implementación, y no se escribe ni una sola línea de código hasta que no tienes una especificación (test) en rojo. En este sentido es completamente imposible usar el paradigma de grabar navegaciones para automatizar el testing, ya que tienes que tener el test automatizado antes que la implementación y por lo tanto no puedes grabar nada.</p>
<p>La segunda razón tiene que ver con el mantenimiento. Si decidimos que el test de cada escenario de una historia de usuario se va a automatizar grabando una navegación, entonces lo que estamos testeando realmente es la UI y no la funcionalidad propiamente dicha. Cada vez que se produzca un cambio trivial en la UI de una página o panel, vamos a tener que grabar de nuevo todas las navegaciones que usen ese panel o página, aunque la funcionalidad no haya cambiado realmente. Claramente al usar el paradigma de &#8220;grabar navegación&#8221; estamos acoplando nuestros tests al diseño fino de la interfaz de usuario, que como todos sabemos, cambia con más frecuencia que la funcionalidad propiamente dicha de la aplicación. Un simple cambio en el atributo &#8220;name&#8221; o &#8220;id&#8221; de un elemento, o eliminar un botón de &#8220;buscar&#8221; para hacer una búsqueda en tiempo real, nos va a estropear las navegaciones.</p>
<p>Ojo, también nos podemos meter en este lío haciendo BDD, con por ejemplo Cucumber, si no tenemos cuidado. Pero mi argumento es que si usamos una herramienta que graba navegaciones como base de nuestra estrategia de testing funcional, este problema es inevitable. Por el contrario si decidimos usar un enfoque basado en programar nuestros tests podemos evitarlo fácilmente. ¿Cómo? Simplemente usando el <a href="http://code.google.com/p/selenium/wiki/PageObjects">patrón &#8220;page object&#8221;</a>, e implementar cada &#8220;page object&#8221; con algún framework de automatización de UI, como <a href="http://seleniumhq.org/docs/03_webdriver.html">WebDriver de Selenium</a> o <a href="http://watir.com/">Watir</a>. De esta forma si se produce un cambio en una UI, que no altere la funcionalidad, entonces sólo necesitamos retocar el &#8220;page object&#8221; correspondiente, sin necesidad de modificar nada en nuestros tests, escenarios y steps.</p>
<p>El que nuestros tests sean código hecho por nosotros es bueno. Podemos aplicar todas las técnicas de ingeniería del software que conocemos y aumentar la mantenibilidad de nuestros tests. Eso es, recordad que el código de test tiene que ser mantenible, y todo el tema de legibilidad, DRY y SOLID se le aplica, y por lo tanto podemos usar toda nuestra habilidad para que esto se cumpla.</p>
<p>Bien, y esto es todo, ¡ no diréis después que mis posts son muy largos <img src='http://s1.wp.com/wp-includes/images/smilies/icon_wink.gif' alt=';-)' class='wp-smiley' />  !</p>
<p>P.S. Sois programadores, ¡ que no os asuste programar ! ¡ No os escondais en herramientas !</p>
<br />Filed under: <a href='http://eamodeorubio.wordpress.com/category/metodologias/agile/bdd/'>BDD</a>, <a href='http://eamodeorubio.wordpress.com/category/metodologias/agile/tdd/'>TDD</a>  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/eamodeorubio.wordpress.com/649/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/eamodeorubio.wordpress.com/649/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/eamodeorubio.wordpress.com/649/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/eamodeorubio.wordpress.com/649/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/eamodeorubio.wordpress.com/649/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/eamodeorubio.wordpress.com/649/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/eamodeorubio.wordpress.com/649/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/eamodeorubio.wordpress.com/649/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/eamodeorubio.wordpress.com/649/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/eamodeorubio.wordpress.com/649/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/eamodeorubio.wordpress.com/649/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/eamodeorubio.wordpress.com/649/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/eamodeorubio.wordpress.com/649/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/eamodeorubio.wordpress.com/649/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=eamodeorubio.wordpress.com&amp;blog=12532304&amp;post=649&amp;subd=eamodeorubio&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://eamodeorubio.wordpress.com/2012/01/10/no-grabes-navegaciones-haz-bdd/feed/</wfw:commentRss>
		<slash:comments>12</slash:comments>
	
		<media:content url="http://0.gravatar.com/avatar/84999f5cc6fd4e8741735e557388b0aa?s=96&#38;d=http%3A%2F%2F0.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D96&#38;r=G" medium="image">
			<media:title type="html">eamodeorubio</media:title>
		</media:content>
	</item>
		<item>
		<title>CAS2011: ¿Nos estamos mirando el ombligo?</title>
		<link>http://eamodeorubio.wordpress.com/2011/10/26/cas2011-%c2%bfnos-estamos-mirando-el-ombligo/</link>
		<comments>http://eamodeorubio.wordpress.com/2011/10/26/cas2011-%c2%bfnos-estamos-mirando-el-ombligo/#comments</comments>
		<pubDate>Wed, 26 Oct 2011 09:30:20 +0000</pubDate>
		<dc:creator>Enrique Amodeo</dc:creator>
				<category><![CDATA[General]]></category>

		<guid isPermaLink="false">http://eamodeorubio.wordpress.com/?p=643</guid>
		<description><![CDATA[Hola a todos, tras digerir un poco la experiencia CAS2011, saco dos conclusiones: Esta CAS2011 me ha gustado más que la del año pasado. Desde mi punto de vista la organización ha mejorado y ha habido más caras nuevas. Nos estamos mirando el ombligo. Algunos sabréis que hace poco estuve en la ScrumGathering 2011, organizada [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=eamodeorubio.wordpress.com&amp;blog=12532304&amp;post=643&amp;subd=eamodeorubio&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>Hola a todos, tras digerir un poco la experiencia CAS2011, saco dos conclusiones:</p>
<ul>
<li>Esta CAS2011 me ha gustado más que la del año pasado. Desde mi punto de vista la organización ha mejorado y ha habido más caras nuevas.</li>
<li>Nos estamos mirando el ombligo.</li>
</ul>
<div>Algunos sabréis que hace poco estuve en la ScrumGathering 2011, organizada por la ScrumAlliance en Londres. Cuando la gente se me presentaba, el diálogo resultante llevaba más o menos las siguientes líneas:</div>
<div><strong>Agilista Internacional</strong>: ¿Ah, Español?</div>
<div><strong>Agilista de pueblo</strong> (o sea, yo): Sí</div>
<div><strong>AI</strong>: ¿Y allí hay agilistas también?</div>
<div><strong>AP</strong>: Sí, claro, tenemos dos eventos importantes al año, la CAS y el AOS</div>
<div><strong>AI</strong>: ¿Y va mucha gente?</div>
<div><strong>AP</strong>: Sí, entre 150 y 250 personas a cada una</div>
<div><strong>AI</strong>: ¡ Wow, es mucha gente ! Pero, &#8230;. ¡ no había oído hablar de estas conferencias en mi vida !&#8221;</div>
<div><strong>AP</strong>: Claro, por que es todo en español</div>
<div><strong>AI</strong>: WTF !</div>
<div>Iteremos sobre toda la gente con la que hablé y os hacéis una idea de lo quemado que me volví al pueblo. Pero eso no fue lo peor, lo peor fue que la mesa redonda de la CAS2011, ¡ fue en español ! El pobre J.B. Rainsberger tuvo que hablar en castellano, ¡ inaudito ! Seguro que <a href="http://twitter.com/jbrains">@jbrains</a> no vuelve a ninguna conferencia española&#8230;</div>
<div>Creo que ha llegado el momento de dar un paso adelante, sacudirnos los complejos y desencasquetarnos la boina de la cabeza. ¿Por qué no empezamos a montar la siguiente CAS pensando en que sea un evento internacional? Creo que eso tendrá al menos los siguientes beneficios:</div>
<div>
<ul>
<li>Variedad en los asistentes y en las propuestas.</li>
<li>Proyección internacional de la comunidad española.</li>
<li>Atraerá a más patrocinadores. Una CAS de 300 o 400 personas con ámbito internacional seguro que es más atractiva que una de 200 con proyección nacional.</li>
<li>Networking. No es networking si siempre hablamos con la gente que conocemos (gracias por recordarme esto <a href="http://twitter.com/david_bonilla">@david_bonilla</a>). Si vienen personas de todo el mundo las oportunidades de networking aumentan.</li>
<li>Cuando yo vaya a conferencias internacionales no tendré que escuchar más WTF y sufrir más miradas condescendientes <img src='http://s0.wp.com/wp-includes/images/smilies/icon_smile.gif' alt=':-)' class='wp-smiley' /> </li>
</ul>
<div>Por lo tanto yo propongo que orientemos el siguiente evento a un ámbito más amplio. La web y los folletos en inglés. Las sesiones impartidas en inglés. Los voluntarios ayudando en inglés. Nuestros pesos pesados promocionando a nivel internacional (<a href="http://twitter.com/ecomba">@ecomba</a>, <a href="http://twitter.com/david_bonilla">@david_bonilla</a>, <a href="http://twitter.com/xquesada">@xquesada</a>, <a href="http://twitter.com/acyment">@acyment</a> &#8230;). Y cualquier acción que se os ocurra.</div>
</div>
<div>¿Y el precio? Pues no podemos seguir pensando en pagar 4 perras. Si queremos una conferencia como dios manda hay que pagar más dinero, ¿200 o 300 euros la early bird? Yo se de gente que se puede gastar 200 euros en un fin de semana de fiesta y después dicen que 200 euros es mucho dinero por un fin de semana de agilismo.</div>
<div>Os dejo con una reflexión, ¿qué es la CAS? ¿Un evento de agilismo organizado por españoles para españoles? ¿O un evento de agilismo organizado en España para el mundo entero? Vosotros decidís.</div>
<br />Filed under: <a href='http://eamodeorubio.wordpress.com/category/general/'>General</a>  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/eamodeorubio.wordpress.com/643/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/eamodeorubio.wordpress.com/643/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/eamodeorubio.wordpress.com/643/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/eamodeorubio.wordpress.com/643/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/eamodeorubio.wordpress.com/643/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/eamodeorubio.wordpress.com/643/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/eamodeorubio.wordpress.com/643/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/eamodeorubio.wordpress.com/643/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/eamodeorubio.wordpress.com/643/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/eamodeorubio.wordpress.com/643/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/eamodeorubio.wordpress.com/643/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/eamodeorubio.wordpress.com/643/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/eamodeorubio.wordpress.com/643/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/eamodeorubio.wordpress.com/643/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=eamodeorubio.wordpress.com&amp;blog=12532304&amp;post=643&amp;subd=eamodeorubio&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://eamodeorubio.wordpress.com/2011/10/26/cas2011-%c2%bfnos-estamos-mirando-el-ombligo/feed/</wfw:commentRss>
		<slash:comments>21</slash:comments>
	
		<media:content url="http://0.gravatar.com/avatar/84999f5cc6fd4e8741735e557388b0aa?s=96&#38;d=http%3A%2F%2F0.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D96&#38;r=G" medium="image">
			<media:title type="html">eamodeorubio</media:title>
		</media:content>
	</item>
		<item>
		<title>HTML5Party: Autoflagelación, o cosas que pasan cuando haces waterfall</title>
		<link>http://eamodeorubio.wordpress.com/2011/10/05/html5party-autoflagelacion-o-cosas-que-pasan-cuando-haces-waterfall/</link>
		<comments>http://eamodeorubio.wordpress.com/2011/10/05/html5party-autoflagelacion-o-cosas-que-pasan-cuando-haces-waterfall/#comments</comments>
		<pubDate>Wed, 05 Oct 2011 08:44:27 +0000</pubDate>
		<dc:creator>Enrique Amodeo</dc:creator>
				<category><![CDATA[Agile]]></category>

		<guid isPermaLink="false">http://eamodeorubio.wordpress.com/?p=640</guid>
		<description><![CDATA[Hola a todos, algunos sabréis que @etnassoft, @pasku1 y yo estuvimos en la HTML5Party de Madrid participando en una hackaton. La verdad es que me gustó mucho el evento y me divertí bastante, también tomé notas del &#8220;cómo se hizo&#8221; ya que me gustó mucho como la organizaron. Pero este post no es para hablar [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=eamodeorubio.wordpress.com&amp;blog=12532304&amp;post=640&amp;subd=eamodeorubio&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>Hola a todos, algunos sabréis que <a href="http://www.etnassoft.com/">@etnassoft</a>, <a href="http://twitter.com/pasku1">@pasku1</a> y yo estuvimos en la HTML5Party de Madrid participando en una hackaton. La verdad es que me gustó mucho el evento y me divertí bastante, también tomé notas del &#8220;cómo se hizo&#8221; ya que me gustó mucho como la organizaron. Pero este post no es para hablar de lo bonita que fue la hackaton, sino para diseccionar el &#8220;fracaso&#8221; de nuestra aplicación. La verdad es que me gusta mucho diseccionar los fracasos, ya que es en este tipo de ejercicios donde más se aprende.</p>
<p>Algunos pensareis que las hackatones son situaciones especiales donde no se aplican las reglas normales del desarrollo de software. Como tenemos poco tiempo sólo puedes ponerte a codificar como pollo sin cabeza, echar jornadas maratonianas y beber mucho red bull&#8230; ¡ nada más lejos de la verdad ! Este tipo de concursos representan muy bien la mayoría de los proyectos que te vas a encontrar en el día a día normal. Veamos&#8230; tiempo y recursos insuficientes, lista de requisitos a todas luces excesiva, problemas de última hora, contratiempos, pánico y la sensación de no llegar a producción, o sea, ¡ el verdadero &#8220;mundo real&#8221; ! Por lo tanto si al participar en una hackaton dejas de lado la disciplina de trabajo, entonces es probable que en un proyecto de verdad también abandones la disciplina. Por eso, cuando me presenté me dije: &#8220;esto hay que hacerlo con TDD y entrega continua de valor a muerte&#8221; Je, je, que iluso. Veamos que pasó.</p>
<p>El primer día empezamos bien, nos reunimos y nos pusimos de acuerdo en la funcionalidad, hicimos una maqueta papel, y nos pusimos manos a la obra. El compañero <a href="http://www.etnassoft.com/">@etnassoft</a> decidió hacer una maqueta HTML y <a href="http://twitter.com/pasku1">@pasku1</a> y yo nos pusimos a hacer BDD. Todo bien, ¿no? ¡ Mal ! Esa fue la raíz de todos los problemas. Si vas a hacer entrega continua de valor, no puedes dividirte en equipos de especialistas, todos tienen que trabajar en equipo para sacar lo más rápidamente posible cada historia de usuario. Lo que terminó ocurriendo, de forma inconsciente, es que la UI se desarrolló por completo, para todas las historias de usuario. Igualmente, el servidor se desarrolló por separado para todas las historias de usuario. Lo curioso de esto, es que fue un fenómeno totalmente subconsciente, fruto de separarnos &#8220;temporalmente&#8221;. En el fragor de la batalla nos olvidamos de que teníamos que centrarnos en historias y no en capas. Cierto, cada capa se desarrolló por historias, pero no integramos hasta que estuvieron todas las historias hechas en cada componente, ¡demasiado tarde!</p>
<p>En un enfoque orientado a la entrega continua de valor, hubiéramos integrado la UI y el servidor por cada historia. Los problemas los hubiéramos detectado al principio, cuando es más fácil, al ser la aplicación pequeña, y encontrarnos más descansados. Además de ser más eficientes hubiéramos eliminado el factor pánico, al tener al menos algunas historias (las más importantes) listas para producción.</p>
<p>¿Hicimos TDD? ¡ Sí ! ¿De que sirvió? De poco. Nuestra capa de &#8220;negocio&#8221; quedó cubierta por bastantes tests, ¡ pero ninguna capa de negocio sirve sino está conectada a una UI ! Esto debe servir de lección a los que piensen que sólo con prácticas de ingeniería y usar tecnologías y frameworks puedes llegar al éxito de tu proyecto. Tus prácticas de ingeniería deben usarse en el contexto de unas buenas prácticas de gestión de proyectos, y viceversa. Todas las prácticas se apoyan e interactúan unas con otras y están pensadas para cubrir las debilidades de las demás.</p>
<p>Durante el transcurso de la hackaton ocurrieron los consabidos e inevitables imprevistos de todos los proyectos (lo dicho, igualito que el mundo real). A saber:</p>
<ul>
<li>Se cayó el github. ¡Nooooo!</li>
<li>Twitter tuvo un bajón de rendimiento. Todas las peticiones tardaban al menos 30 seg. Eso hizo que nuestro ciclo de pruebas integradas fuera impracticable. Ayer probé y la respuesta era instantánea.</li>
<li>Un espacio en una cadena de texto de una configuración nos estuvo fastidiando durante 4 horas hasta que nos dimos cuenta.</li>
<li>Los drivers de node.js para MongoDB fueron un dolor.</li>
<li>Heroku no quería arrancar&#8230;. (¿qué demonios le pasó a la nube ese fin de semana?)</li>
<li>Un troll se coló por twitter y nos desconcertó bastante. Sí, es cierto, cosas que pasan.</li>
</ul>
<div>¿Son estos imprevistos una excusa para no haber entregado la funcionalidad prevista? En absoluto, si hubiéramos hecho entrega continua y usado una &#8220;bala trazadora&#8221;, nos hubiéramos dado cuenta al principio de los problemas con MongoDB y Twitter y hubiéramos hecho un workaround cuando aun estábamos a tiempo.</div>
<div>¿Cómo terminamos el proyecto? Al final nos encontramos con una UI muy bonita (menos mal que estaba <a href="http://www.etnassoft.com/">@etnassoft</a>) y un servidor sin fallos, pero sin integrar, sin ninguna funcionalidad en producción, cansados y a falta de 5 horas para entregar. En un esfuerzo final conseguimos integrar un 30% de las historias de usuario, pero no precisamente las más interesantes. Si lo hubiéramos hecho con el enfoque ágil, al final de la hackaton nos hubiéramos encontrado con la funcionalidad más interesantes en producción, y no hubiéramos sufrido tanto.</div>
<div>¡ También hicimos cosas bien ! TDD, ritmo sostenible, usar estándares, buen diseño y arquitectura, refactorizar (pero no tanto como hubiera querido), puestas en común, trabajo en equipo, buen ambiente&#8230; y por eso no puedo terminar el post sin hacer mención de honor a <a href="http://twitter.com/pasku1">@pasku1</a> y <a href="http://www.etnassoft.com/">@etnassoft</a>. Ha sido un placer trabajar con los dos y una experiencia muy divertida e instructiva. ¡ La próxima ganamos fijo !</div>
<div>P.S. Al final ganamos el segundo premio, que no está nada mal (Pero es que soy un tío exigente)</div>
<p>P.S.S. Enhorabuena a los organizadores, ¡en especial a <a href="http://twitter.com/VictorSanchez">@VictorSanchez</a>!</p>
<br />Filed under: <a href='http://eamodeorubio.wordpress.com/category/metodologias/agile/'>Agile</a>  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/eamodeorubio.wordpress.com/640/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/eamodeorubio.wordpress.com/640/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/eamodeorubio.wordpress.com/640/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/eamodeorubio.wordpress.com/640/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/eamodeorubio.wordpress.com/640/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/eamodeorubio.wordpress.com/640/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/eamodeorubio.wordpress.com/640/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/eamodeorubio.wordpress.com/640/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/eamodeorubio.wordpress.com/640/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/eamodeorubio.wordpress.com/640/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/eamodeorubio.wordpress.com/640/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/eamodeorubio.wordpress.com/640/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/eamodeorubio.wordpress.com/640/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/eamodeorubio.wordpress.com/640/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=eamodeorubio.wordpress.com&amp;blog=12532304&amp;post=640&amp;subd=eamodeorubio&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://eamodeorubio.wordpress.com/2011/10/05/html5party-autoflagelacion-o-cosas-que-pasan-cuando-haces-waterfall/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
	
		<media:content url="http://0.gravatar.com/avatar/84999f5cc6fd4e8741735e557388b0aa?s=96&#38;d=http%3A%2F%2F0.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D96&#38;r=G" medium="image">
			<media:title type="html">eamodeorubio</media:title>
		</media:content>
	</item>
		<item>
		<title>Explicaciones y despedidas: me marcho de atSistemas</title>
		<link>http://eamodeorubio.wordpress.com/2011/09/05/explicaciones-y-despedidas-me-marcho-de-atsistemas/</link>
		<comments>http://eamodeorubio.wordpress.com/2011/09/05/explicaciones-y-despedidas-me-marcho-de-atsistemas/#comments</comments>
		<pubDate>Mon, 05 Sep 2011 08:17:36 +0000</pubDate>
		<dc:creator>Enrique Amodeo</dc:creator>
				<category><![CDATA[General]]></category>

		<guid isPermaLink="false">http://eamodeorubio.wordpress.com/?p=623</guid>
		<description><![CDATA[Hola a todos, la mayoría de vosotros sabréis que recientemente he tomado la decisión de abandonar atSistemas, la empresa que me ha visto crecer como profesional durante estos últimos 11 años. Han sido muchos años, llenos de buenos recuerdos, trabajo duro y éxitos profesionales, pero nada dura eternamente. Desde hace dos años empecé a sentir [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=eamodeorubio.wordpress.com&amp;blog=12532304&amp;post=623&amp;subd=eamodeorubio&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>Hola a todos, la mayoría de vosotros sabréis que recientemente he tomado la decisión de abandonar atSistemas, la empresa que me ha visto crecer como profesional durante estos últimos 11 años. Han sido muchos años, llenos de buenos recuerdos, trabajo duro y éxitos profesionales, pero nada dura eternamente.</p>
<p>Desde hace dos años empecé a sentir que existe otra forma de trabajar posible, basado en los conceptos de desarrollo Agile y Lean. Desgraciadamente para mi, la reciente crisis ha hecho que tal forma de trabajo sea imposible de implantar en atSistemas de forma simple y sin poner en peligro a la empresa (que ofrece actualmente bastante más de 350 puestos de empleo). Me marcho manteniendo relaciones cordiales con mi antigua empresa y espero seguir colaborando con ellos en cualquier proyecto agile que les surja.</p>
<p>Reconociendo este hecho, decidí abandonar atSistemas e intentar demostrar que se puede ganar dinero trabajando de forma ágil, y anteponiendo la calidad a la tarifa. De esta forma podré llevar a cabo mis ideas con mi propio dinero y bajo mi propia cuenta y riesgo. El intentar encontrar y explotar mercado para esta filosofía de trabajo es un objetivo personal que pienso perseguir con mucha energía. Si os digo la verdad, ahora me encuentro muy ilusionado y lleno de fuerza. Sólo el tiempo dirá si he apostado por caballo ganador, pero yo tengo fe en mi. Es la misma confianza que hizo que me marchara de Sevilla a Madrid a trabajar en una empresa que en aquel entonces no conocía de nada, a una ciudad desconocida, sin experiencia laboral, con el dinero justo para vivir un mes y habiéndome leído por primera vez lo que era una JSP en el AVE. Yo diría que aquella fue una decisión acertada, y no veo por que ésta no puede serlo.</p>
<p>Ahora quiero despedirme de toda la gente con la que he trabajado en atSistemas; toda la gente que me despidió el viernes y me hizo saltar una lagrimita cuando no miraban; despedirme de los chic@s de Cádiz, mis &#8220;conejillos de indias&#8221;, con los que experimenté con el agilismo y mis malditos &#8220;frameworks de la muerte&#8221; (aun me queda algo de aquella botella de serie limitada); despedirme de los compañeros de Barcelona (Aleix, tenemos que vernos); despedirme de &#8220;mis&#8221; arquitectos, espero que sigáis defendiendo el fuerte, y también de las chicas de administración y de RRHH. También me despido de los comerciales (sí, también de vosotros) a los que les di la brasa con mis ideas.&nbsp;Aunque espero que no sea una despedida absoluta, sino que nos vayamos viendo de vez en cuando (y Lourdes, espero mandarte alguna factura de vez de en cuando <img src='http://s0.wp.com/wp-includes/images/smilies/icon_smile.gif' alt=':-)' class='wp-smiley' /> ).</p>
<p>Tengo que dar también las gracias a gente que no es parte de atSistemas por ayudarme y apoyarme, me refiero como no, a la comunidad ágil en España, que además me ayudaron a comprender que no era el único que estaba haciendo &#8220;locuras&#8221; por ahí. El encontrar esta comunidad ha sido algo muy importante para mi, y me ha animado a salir de la &#8220;cueva&#8221;. Me sorprendí de sus &#8220;retuits&#8221; y mensajes de ánimo cuando anuncié mi nueva etapa personal y profesional. Me resultó revelador que me dierais enhorabuenas más que ánimos :-O.</p>
<p>Y por supuesto un beso a mi mujer, @mcberros, que me ha dado soporte incondicional en esta arriesgada (y emocionante) decisión.</p>
<p>Y aquí os dejo un par de fotos. En la primera están muchos, pero faltan muchos más, que están distribuidos por todas partes de España:</p>
<p><a href="http://eamodeorubio.files.wordpress.com/2011/09/atrozascrewsmall.jpg"><img class="aligncenter size-full wp-image-625" title="La gente de la oficina de las Rozas" src="http://eamodeorubio.files.wordpress.com/2011/09/atrozascrewsmall.jpg?w=500&#038;h=375" alt="La gente de la oficina de las Rozas" width="500" height="375" /></a></p>
<p>Y aquí la otra foto, donde se atestigua por qué no me sentía parte de atSistemas&#8230;</p>
<p><a href="http://eamodeorubio.files.wordpress.com/2011/09/atrozasgirlssmall.jpg"><img class="aligncenter size-full wp-image-626" title="Las chicas de las Rozas" src="http://eamodeorubio.files.wordpress.com/2011/09/atrozasgirlssmall.jpg?w=500&#038;h=375" alt="Las chicas de las Rozas" width="500" height="375" /></a></p>
<p>&#8230;porque obviamente soy el más feo de la oficina <img src='http://s0.wp.com/wp-includes/images/smilies/icon_smile.gif' alt=':-)' class='wp-smiley' /> </p>
<p>Saludos a todos y espero que podamos hacer una quedada.</p>
<p>P.S. Y por supuesto gracias por el iPad2, ¡ que era lo que me faltaba para convertirme en un apple fan boy !</p>
<p>P.S.S. No puede faltar la foto de la botella edición limitada:</p>
<p><a href="http://eamodeorubio.files.wordpress.com/2011/09/thebottle.jpg"><img class="aligncenter size-full wp-image-627" title="Edición limitada @eamodeorubio" src="http://eamodeorubio.files.wordpress.com/2011/09/thebottle.jpg?w=500" alt="Edición limitada @eamodeorubio"   /></a></p>
<br />Filed under: <a href='http://eamodeorubio.wordpress.com/category/general/'>General</a>  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/eamodeorubio.wordpress.com/623/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/eamodeorubio.wordpress.com/623/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/eamodeorubio.wordpress.com/623/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/eamodeorubio.wordpress.com/623/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/eamodeorubio.wordpress.com/623/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/eamodeorubio.wordpress.com/623/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/eamodeorubio.wordpress.com/623/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/eamodeorubio.wordpress.com/623/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/eamodeorubio.wordpress.com/623/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/eamodeorubio.wordpress.com/623/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/eamodeorubio.wordpress.com/623/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/eamodeorubio.wordpress.com/623/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/eamodeorubio.wordpress.com/623/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/eamodeorubio.wordpress.com/623/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=eamodeorubio.wordpress.com&amp;blog=12532304&amp;post=623&amp;subd=eamodeorubio&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://eamodeorubio.wordpress.com/2011/09/05/explicaciones-y-despedidas-me-marcho-de-atsistemas/feed/</wfw:commentRss>
		<slash:comments>13</slash:comments>
	
		<media:content url="http://0.gravatar.com/avatar/84999f5cc6fd4e8741735e557388b0aa?s=96&#38;d=http%3A%2F%2F0.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D96&#38;r=G" medium="image">
			<media:title type="html">eamodeorubio</media:title>
		</media:content>

		<media:content url="http://eamodeorubio.files.wordpress.com/2011/09/atrozascrewsmall.jpg" medium="image">
			<media:title type="html">La gente de la oficina de las Rozas</media:title>
		</media:content>

		<media:content url="http://eamodeorubio.files.wordpress.com/2011/09/atrozasgirlssmall.jpg" medium="image">
			<media:title type="html">Las chicas de las Rozas</media:title>
		</media:content>

		<media:content url="http://eamodeorubio.files.wordpress.com/2011/09/thebottle.jpg" medium="image">
			<media:title type="html">Edición limitada @eamodeorubio</media:title>
		</media:content>
	</item>
		<item>
		<title>Estimación (3): Técnicas ágiles</title>
		<link>http://eamodeorubio.wordpress.com/2011/05/16/estimacion-3-tecnicas-agiles/</link>
		<comments>http://eamodeorubio.wordpress.com/2011/05/16/estimacion-3-tecnicas-agiles/#comments</comments>
		<pubDate>Mon, 16 May 2011 09:47:05 +0000</pubDate>
		<dc:creator>Enrique Amodeo</dc:creator>
				<category><![CDATA[Agile]]></category>

		<guid isPermaLink="false">http://eamodeorubio.wordpress.com/?p=592</guid>
		<description><![CDATA[Acabo con este post la serie dedicada a la estimación. Aunque no lo parezca, entre el primer artículo y el segundo de esta serie ya he explicado lo más importante de la estimación en proyectos ágiles. Todo se resume en cinco reglas sencillas: No estimes si no lo necesitas. Normalmente se estima para adelantar una [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=eamodeorubio.wordpress.com&amp;blog=12532304&amp;post=592&amp;subd=eamodeorubio&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>Acabo con este post la serie dedicada a la estimación. Aunque no lo parezca, entre el <a href="http://eamodeorubio.wordpress.com/2011/05/03/estimacion-1-%C2%BFhasta-que-punto-se-puede/">primer artículo</a> y el <a href="http://eamodeorubio.wordpress.com/2011/05/09/estimacion-2-%C2%BFestimar-tareas-o-funcionalidades/">segundo</a> de esta serie ya he explicado lo más importante de la estimación en proyectos ágiles. Todo se resume en cinco reglas sencillas:</p>
<ol>
<li>No estimes si no lo necesitas. Normalmente se estima para adelantar una previsión a los interesados en el proyecto y para evaluar si algo se debe implementar o no.</li>
<li>Sólo debe estimar personal experto, que haya construido software similar en el pasado.</li>
<li>Estima por comparación, y no usando unidades absolutas.</li>
<li>No compares cosas dispares, tanto en tamaño como en nivel de abstracción. Por ejemplo, tareas con historias de usuario, o historias de usuario con releases.</li>
<li>No necesitas estimar tareas.</li>
</ol>
<p>La regla número 2 nos la dice explícitamente Scrum: el PO sólo estima el valor y el equipo de desarrollo estima el coste. Cada uno estima dentro de su área de conocimiento. Ninguna de las partes debe admitir presiones por parte de la otra para que cambie su estimación. Se asume un equipo experto, si algún miembro es un junior, yo recomiendo no darle mucho peso a su estimación, pero que participe en ella para que vaya cogiendo experiencia.</p>
<p>La forma más sencilla de aplicar la regla número 3 es no permitir usar unidades absolutas, como horas, dinero, etc. Simplemente se coge una funcionalidad a estimar y se pregunta, ¿en qué grado esta funcionalidad es más grande o pequeña que esta otra? ¿En qué grado el cliente valora más esta funcionalidad que aquella otra? A dichas preguntas se debe responder en unidades relativas, por ejemplo, &#8220;es el doble&#8221;, &#8220;es similar&#8221;, &#8220;es un 123% mayor&#8221;, etc.</p>
<p>Si a la regla número 3 le añadimos la 4, obtenemos una escala de medida relativa pero que a la vez está simplificada. Si sólo debemos comparar cosas que sean similares, ¿tiene sentido decir que esta funcionalidad es 100 veces más grande que esta otra? No. Claramente las dos cosas que estamos comparando no se encuentran al mismo nivel. Otro problema es intentar obtener una precisión en la estimación absurda, similar o incluso mayor a nuestro margen de error. No es razonable estimar que tal funcionalidad es 1.07 veces más grande que tal otra, cuando normalmente nuestro margen de error es mucho mayor de un 7%. Para reforzar estas ideas se han propuesto varias escalas de medida, y al realizar una estimación no se puede asignar un valor que no aparezca en la escala.</p>
<p>La más famosa de dichas escalas es la <strong>escala de Cohn</strong>. En la escala de Cohn se admiten los siguientes valores: 0, 1, 2, 3, 5, 8, 13, 20, 40, 100. Si os fijáis en escalas pequeñas tenemos 0, 1, 2 y 3, admitiendo que podemos tener cierta precisión. A escalas más grandes, 5, 8, 13, 20, 40 y 100, hay huecos. Estos huecos indican que no debemos invertir esfuerzo en ajustar nuestra precisión ya que estaríamos excediendo el margen de error que normalmente tenemos al estimar.</p>
<p>Siguiendo con el razonamiento que defiendo a lo largo de toda esta serie, ¿tiene sentido decir que una funcionalidad es 20 veces mayor que otra? Seguramente no, y estemos comparando funcionalidades en escalas muy distintas de tamaño. Normalmente una funcionalidad mayor que 5 u 8 se etiqueta como <strong><em>épica</em></strong>. De hecho las funcionalidades épicas normalmente no caben en un sprint, y por lo tanto no son aptas para ser implementadas. Si en vez de Scrum usas kanban, tampoco te salvas, ya que si introduces en el sistema funcionalidades de tamaño muy variable, tanto tu tiempo de entrega como tu productividad se van al garete (teoría de colas). Por lo tanto las funcionalidades épicas son carne de analista funcional, no se aceptan en la fase de desarrollo y deben ser analizadas y descompuestas con más rigor.</p>
<p>Lo inverso ocurre con funcionalidades de tamaño 0. En este caso se consideran tan pequeñas que no merece la pena de gastar esfuerzo en estimarlas. Normalmente representan un nivel de abstracción por debajo del que estamos tratando. Podría se una tarea en vez de una funcionalidad, o un simple detalle de ésta. En general cuando tenemos varias cosas de tamaño cero, o bien las descartamos por estar en un nivel de abstracción inadecuado, o bien las fusionamos si están relacionadas entre si.</p>
<p>Si tenemos en cuenta estas dos prácticas, podemos llegar a la conclusión de que la escala de Cohn, aunque útil para principiantes, no es realmente lo que buscamos. Así llegamos a la otra escala que se usa mucho: <strong>tallas de camiseta</strong>. Los valores admisible son S, M, L y XL. Las funcionalidades XL se consideran épicas. Sólo se aceptarán funcionalidades S, M o L. Este sistema simplifica el proceso de estimación y evita que caigamos en las trampas de estimar en horas o con una precisión irreal. La dificultad de este sistema estriba en que la capacidad del equipo debe medirse también en tallas de camiseta. Por ejemplo: en un sprint el equipo será capaz de 1 funcionalidad L, 2 M y 4 S. Esto puede causar problemas de estilo de &#8220;si tenemos 1 funcionalidad L, pero no hemos escogido ninguna que sea M o S, ¿podemos escoger otra funcionalidad L?&#8221;.  Una posible solución es definir equivalencias entre tallas: 1 L son 2 M y 6 S, pero 1 M son 2 S.</p>
<p>Otra posible solución para este problema <strong>es simplemente no usar una escala</strong>. En esta modalidad las funcionalidades o bien son épicas o no lo son. En este caso se deben descomponer todas las funcionalidades de forma que sus tamaños no sólo sean comparables, sino muy similares y constantes.  De esta forma el proceso de estimación se simplifica enormemente, y si se hace bien se reduce la variabilidad de las funcionalidades a implementar. Esto último es especialmente importante, ya una mayor variabilidad implica peores estimaciones y también peor productividad (de nuevo teoría de colas). De esta forma acercamos bastante Kanban a Scrum, donde realmente estaríamos haciendo Kanban si la capacidad de nuestro equipo fuera siempre igual a su límite de WIP. También nos permite estar alineados con la regla 1. La dificultad de esta técnica radica en que tanto el equipo como PO deben ganar mucha experiencia estimando, analizando las funcionalidades y conociendo la capacidad de la otra parte. Por lo tanto sólo lo veo factible en equipos muy maduros.</p>
<p>Finalmente, la regla número 5 simplemente nos indica que tanto al PO como a los <em>stakeholders</em> del proyecto no les interesa saber la descomposición en tareas del proyecto. Si las funcionalidades se descomponen o no en tareas, y si éstas se estiman o no, es una cosa del equipo de desarrollo. Al PO no el interesa el <em>Sprint Burndown</em>, ni el <em>Task Board</em>, sino el <em>Project Burndown</em>, el reporte de bugs y el flujo acumulado de entrega de funcionalidad. Como excepción a esta regla tenemos el caso en el que parte del equipo de desarrollo pertenece al cliente, o que tal vez no hay un equipo sino varios equipos de especialistas que forman un <em>pipeline</em>. Para asegurar una correcta coordinación, puede ser razonable hacer un plan de tareas y llevar un seguimiento de éstas, pero obviamente esta forma de estructurar equipos no es la recomendada en un proyecto gestionado de forma ágil.</p>
<p>Como apunte meramente personal, mi posición con respecto a la estimación es bastante pesimista, ya he visto muchas veces como hasta la estimación más cuidadosa fracasaba, y como planes muy bonitos plantados sobre un &#8220;project&#8221; se iban al garete en cuanto tenían el más mínimo contacto con la realidad. Mi opinión personal es que hay que estimar en formato &#8220;rápido y sucio&#8221;, y el proceso de desarrollo que uséis debe estar preparado para trabajar con este tipo de estimaciones aproximadas. Bueno, pues con esto acabo la serie sobre estimación, espero que os haya sido útil.</p>
<br />Filed under: <a href='http://eamodeorubio.wordpress.com/category/metodologias/agile/'>Agile</a>  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/eamodeorubio.wordpress.com/592/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/eamodeorubio.wordpress.com/592/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/eamodeorubio.wordpress.com/592/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/eamodeorubio.wordpress.com/592/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/eamodeorubio.wordpress.com/592/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/eamodeorubio.wordpress.com/592/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/eamodeorubio.wordpress.com/592/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/eamodeorubio.wordpress.com/592/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/eamodeorubio.wordpress.com/592/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/eamodeorubio.wordpress.com/592/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/eamodeorubio.wordpress.com/592/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/eamodeorubio.wordpress.com/592/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/eamodeorubio.wordpress.com/592/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/eamodeorubio.wordpress.com/592/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=eamodeorubio.wordpress.com&amp;blog=12532304&amp;post=592&amp;subd=eamodeorubio&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://eamodeorubio.wordpress.com/2011/05/16/estimacion-3-tecnicas-agiles/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
	
		<media:content url="http://0.gravatar.com/avatar/84999f5cc6fd4e8741735e557388b0aa?s=96&#38;d=http%3A%2F%2F0.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D96&#38;r=G" medium="image">
			<media:title type="html">eamodeorubio</media:title>
		</media:content>
	</item>
		<item>
		<title>Estimación (2): ¿Estimar tareas o funcionalidades?</title>
		<link>http://eamodeorubio.wordpress.com/2011/05/09/estimacion-2-%c2%bfestimar-tareas-o-funcionalidades/</link>
		<comments>http://eamodeorubio.wordpress.com/2011/05/09/estimacion-2-%c2%bfestimar-tareas-o-funcionalidades/#comments</comments>
		<pubDate>Mon, 09 May 2011 09:25:09 +0000</pubDate>
		<dc:creator>Enrique Amodeo</dc:creator>
				<category><![CDATA[Agile]]></category>

		<guid isPermaLink="false">http://eamodeorubio.wordpress.com/?p=590</guid>
		<description><![CDATA[Una de las cosas sobre las que se discutió en la lista de agile-spain y que me animó a escribir estos posts sobre estimación fue si era conveniente o no estimar las tareas técnicas. Cuando en este post hable de tareas me referiré a tareas técnica (construir un servicio, definir una tabla, documentar, etc). En [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=eamodeorubio.wordpress.com&amp;blog=12532304&amp;post=590&amp;subd=eamodeorubio&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>Una de las cosas sobre las que se discutió en la lista de agile-spain y que me animó a escribir estos posts sobre estimación fue si era conveniente o no estimar las tareas técnicas. Cuando en este post hable de tareas me referiré a tareas técnica (construir un servicio, definir una tabla, documentar, etc). En contrapartida tenemos las funcionalidades que son directamente utilizables por el usuario y le aportan valor. Desde el punto de vista del desarrollo de software, existen varias actividades en las que nos vemos forzados a estimar, las más importantes son:</p>
<ul>
<li>Evaluar si es razonable o no presentarse a un proyecto cerrado, y que coste y tiempo podemos ofertar. El problema precisamente  está en que esta evaluación se realiza en el momento de hacer la oferta, que es justo donde tenemos menos información sobre el proyecto, y por tanto, menor precisión en la estimación. Además la estimación deja de ser una estimación y se transforma en un contrato. En este sentido los proyectos cerrados son muy arriesgados. La única circunstancia en la que el riesgo sería aceptable es que el proyecto que se presupuesta sea muy similar a otros que hayamos hecho en el pasado, y que el tamaño de éste no sea muy grande. Aquí lo único que podemos hacer es estimar el tamaño del proyecto en comparación con proyectos pasados. Para ello podemos hacer una captura de requisitos de alto nivel y asumir un entorno tecnológico y arquitectura similar a la de proyectos pasados.</li>
<li>Release plan. En el release plan nos comprometemos a definir que funcionalidades se pondrán en producción en que momento. La release plan se puede hacer de dos formas: orientada a fecha u orientada a funcionalidad. En la primera las fechas de entrada en producción son críticas y lo que estimamos es cuanta funcionalidad podrá entrar para esa fecha. O sea, tiempo fijo, alcance variable. En la segunda modalidad el alcance es fijo y lo que es variable es el tiempo, intentando estimar cuándo podremos poner en producción un conjunto predefinido de funcionalidad.</li>
</ul>
<p>Si lo pensáis bien, en ninguna de las dos actividades anteriores es necesario estimar tareas. ¿Por qué? Simplemente porque ni a mi jefe ni a mi cliente le interesa saber cuanto voy a tardar en hacer una tarea. Lo que les interesa realmente es cuando voy a tener disponible tal funcionalidad, release o proyecto y cuanto me va a costar. Algunos diréis, sí, sí, pero es que yo descompongo en tareas, las estimo y después las sumo. Yo os digo que estais gastando dinero inútilmente en analizar una funcionalidad para ver que tareas os salen, y que vuestro margen de error no va a disminuir significativamente con respecto a una estimación directa de la funcionalidad. Dicho esto, ¿cómo estimo entonces una funcionalidad? Como dije <a href="http://wp.me/pQAdW-9t">en mi anterior post</a>, los seres humanos somos buenos estimando por comparación, por lo tanto lo sensato es comparar la funcionalidad a estimar con otras similares implementadas en circunstancias similares en el pasado. Como veis no es necesario descomponer, ya que a nadie, excepto a nosotros, le importan las tareas, y el método que propongo es más sencillo y barato. Comparar una funcionalidad con otras ya hechas es más simple que hacer un análisis de que tareas se necesitan para realizar la funcionalidad, y después estimar cada tarea por separado.</p>
<p>Existen un par de dificultades en la regla anterior de &#8220;no analizar&#8221;. La primera es que lo que estemos estimando sea de tamaño &#8220;grande&#8221;. Según lo explicado en <a href="http://wp.me/pQAdW-9t">el anterior post</a>, cuanto más grande y a más largo plazo estimemos, peor precisión obtendremos. Podríamos pensar en comparar un proyecto cerrado con otro proyecto cerrado implementado anteriormente, pero normalmente los proyectos son lo suficientemente grandes como para que nuestro error de estimación no sea práctico. Lo mismo se aplica con las releases y los release plan. También puede ocurrir con las funcionalidades que sean especialmente grandes. ¿Qué hacemos? Pues simplemente dividir. Dividir proyectos en releases, dividir releases en funcionalidades y funcionalidades grandes en otras más pequeñas. Dividir hasta que la precisión que podamos alcanzar con cada trozo sea razonable (y no más). Pero, ¿no es lo mismo ésto que el caso anterior de dividir una funcionalidad en tareas? No. Veamos las razones:</p>
<ul>
<li>Al cliente le interesan las funcionalidades, no las tareas. El cliente evaluará el resultado final en función de las funcionalidades entregadas. Por lo tanto el plan de proyecto debe expresarse en funcionalidades, y no en tareas, para que el cliente pueda hacer un seguimiento que pueda entender (¿Se nos retrasó esta funcionalidad?¿Cuántas funcionalidades nos quedan?)</li>
<li>Funcionalidades y tareas están en dos niveles de abstracción diferentes. Podemos dividir un proyecto en releases, y estas en funcionalidades, y las funcionalidades en otras más pequeñas, que no abandonamos el nivel de abstracción que representa el &#8220;qué tiene que hacer el sistema&#8221;. El realizar estas divisiones y refinamiento de la funcionalidad es en realidad el &#8220;análisis funcional&#8221;. Las tareas están en otro nivel de abstracción, el &#8220;cómo pensamos construir el sistema nosotros&#8221;. En este sentido el salto entre funcionalidad y tareas es más brusco y propenso a error, y realmente hacerlo es parte del &#8220;diseño técnico&#8221;. ¿Queremos empezar a hacer el diseño técnico antes de planificar y estimar?</li>
</ul>
<p>La otra dificultad se produce cuando no tenemos experiencia previa con algún proyecto o funcionalidad similar, es decir, no existe nada con lo que comparar. En general en esta circunstancia nuestra estimación va a ser muy arriesgada hagamos lo que hagamos. Estaríamos tentado de analizar dicha funcionalidad en tareas, con la esperanza que las tareas que salgan nos resulten familiares y podamos estimarlas. Esto es un error. Reflexionemos, si no tenemos experiencia con este tipo de funcionalidad, ¿cómo vamos a ser capaces de hacer el análisis y diseño técnico de la funcionalidad para descomponerla en tareas de forma precisa? Sí, podemos hacer esta descomposición, pero seguramente esté mal, o nos falten tareas o no hayamos tenido en cuenta las peculiaridades (para nosotros desconocidas) de esa funcionalidad o proyecto. Existe otra forma mejor, y es hacer una prueba de concepto, o &#8220;spike&#8221;. Invirtamos algo de dinero en hacer una implementación a pequeña escala de lo que queremos estimar, y usemos el conocimiento adquirido para hacer nuestra estimación. Sí, es más caro y lento, no es perfecto, pero es menos arriesgado que el enfoque anterior.</p>
<p>Finalmente, desde un punto de vista más específico de Scrum, existe otra razón para no estimar las tareas. Recordemos que la planificación en Scrum se basa en el ordenamiento de ítemes en el backlog en función de su ROI. El ROI se entiende como la relación entre el valor del ítem y su coste y/o tamaño. Es decir, en Scrum no sólo se estima el coste sino el valor. Si descompongo una funcionalidad en tareas y estimo cada tarea por separado, no sólo debo estimar el coste de cada una de ellas, sino su valor. Como el valor de una tarea es cero, el ROI de cada tarea es cero también. ¡ Si sumo el ROI de todas las tareas me sale que el ROI de la funcionalidad es cero ! Esto ocurre debido a que hemos sido inconsistentes y hemos cambiado de nivel de abstracción alegremente. Una señal de que hemos violado el nivel de abstracción pertinente es que las cuentas no salen, ya que el todo es mayor que la suma de las partes.</p>
<p>En el próximo post contaré algunas técnicas de estimación ágiles.</p>
<br />Filed under: <a href='http://eamodeorubio.wordpress.com/category/metodologias/agile/'>Agile</a>  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/eamodeorubio.wordpress.com/590/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/eamodeorubio.wordpress.com/590/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/eamodeorubio.wordpress.com/590/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/eamodeorubio.wordpress.com/590/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/eamodeorubio.wordpress.com/590/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/eamodeorubio.wordpress.com/590/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/eamodeorubio.wordpress.com/590/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/eamodeorubio.wordpress.com/590/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/eamodeorubio.wordpress.com/590/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/eamodeorubio.wordpress.com/590/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/eamodeorubio.wordpress.com/590/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/eamodeorubio.wordpress.com/590/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/eamodeorubio.wordpress.com/590/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/eamodeorubio.wordpress.com/590/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=eamodeorubio.wordpress.com&amp;blog=12532304&amp;post=590&amp;subd=eamodeorubio&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://eamodeorubio.wordpress.com/2011/05/09/estimacion-2-%c2%bfestimar-tareas-o-funcionalidades/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
	
		<media:content url="http://0.gravatar.com/avatar/84999f5cc6fd4e8741735e557388b0aa?s=96&#38;d=http%3A%2F%2F0.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D96&#38;r=G" medium="image">
			<media:title type="html">eamodeorubio</media:title>
		</media:content>
	</item>
		<item>
		<title>Estimación (1): ¿Hasta que punto se puede?</title>
		<link>http://eamodeorubio.wordpress.com/2011/05/03/estimacion-1-%c2%bfhasta-que-punto-se-puede/</link>
		<comments>http://eamodeorubio.wordpress.com/2011/05/03/estimacion-1-%c2%bfhasta-que-punto-se-puede/#comments</comments>
		<pubDate>Tue, 03 May 2011 09:30:35 +0000</pubDate>
		<dc:creator>Enrique Amodeo</dc:creator>
				<category><![CDATA[Agile]]></category>

		<guid isPermaLink="false">http://eamodeorubio.wordpress.com/?p=587</guid>
		<description><![CDATA[Hola a todos, aquí estoy después de un buen tiempo. La verdad es que tanto el trabajo como algunos asuntos personales me han tenido bastante ocupado y no he podido escribir mucho; pero ojeando la lista de correo de agile-spain me han dado ganas de escribir sobre un tema: la estimación. La verdad es que [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=eamodeorubio.wordpress.com&amp;blog=12532304&amp;post=587&amp;subd=eamodeorubio&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>Hola a todos, aquí estoy después de un buen tiempo. La verdad es que tanto el trabajo como algunos asuntos personales me han tenido bastante ocupado y no he podido escribir mucho; pero ojeando la lista de correo de agile-spain me han dado ganas de escribir sobre un tema: la estimación.</p>
<p>La verdad es que existe bastante controversia entre si es conveniente estimar o no y cómo ha de hacerse correctamente. Los que me conocéis ya estareis anticipando mi respuesta: estima sólo lo justo y necesario y no te esfuerces en ser más preciso de lo que realmente necesitas o puedes. Este es el enfoque que cualquier profesional pragmático debería usar y olvidarse de cualquier postura &#8220;idealista&#8221;. Para aplicar esta idea en la práctica debemos antes tener claro qué es estimar, cuál es nuestro objetivo a la hora de estimar, y que grado de precisión podemos esperar de forma realista de nuestras estimaciones.</p>
<p>En el contexto del desarrollo de software, estimar es la actividad que realizamos para <strong>predecir</strong> el coste de realizar una tarea y/o implementar una unidad de funcionalidad, basándonos en nuestra <strong>experiencia pasada</strong> con tareas o funcionalidades <strong>similares</strong>. ¿Qué grado de precisión podemos esperar de tales estimaciones? Pues básicamente todo depende de la cantidad de experiencia que tengamos. Si no hemos tenido experiencia en tareas similares en el pasado, nuestra estimación resultará inútil. Ojo, experiencia en actividades similares, no experiencia en cualquier cosa. Por lo tanto sólo existen dos maneras sensatas de estimar:</p>
<ul>
<li>Usar un sistema informático, que gracias a una amplia base de datos de mediciones de cuanto se tardó realmente en el pasado en hacer tareas similares, y mediante un modelo estadístico, nos ofrezca un intervalo de confianza de cuanto esfuerzo necesitaremos en realizar una tarea. Hago énfasis, intervalo de confianza, no una &#8220;media&#8221;.</li>
<li>Usar personal experto en el entorno tecnológico que se va a usar, que tenga un entendimiento claro de la tarea que se va a hacer y con experiencia a sus espaldas. Este personal de nuevo nos podrá ofrecer un intervalo como estimación.</li>
</ul>
<p>En este sentido no debería estimar ni el cliente, ni personal senior pero no familiarizado con la tecnología a usar, ni nadie no implicado en la construcción del software. Esto coincide con lo que nos dice Scrum de que sea el equipo de desarrollo quien estime y no el PO. Sin embargo tampoco recomiendo que estime el personal junior, tal vez puede intentar estimar para aprender, pero no habría que darle mucho peso a su estimación. Quizás esto último no sea muy ágil, pero a mi me parece de sentido común.</p>
<p>En cualquier caso, existe un límite natural a la precisión de nuestras estimaciones:</p>
<ul>
<li>Cuanta menos variabilidad exista entre las tareas mejor estimaremos, ya que nuestra experiencia pasada será más representativa. Variabilidad en cualquier aspecto: tecnología, tamaño, complejidad, funcionalidad, etc.</li>
<li>Las predicciones sobre tareas/funcionalidades grandes son menos precisas que las hechas sobre tareas más pequeñas. Esto es especialmente cierto si hablamos de precisión relativa (%).</li>
<li>Las predicciones a largo plazo son siempre menos precisas que las hechas a corto plazo. Esto es debido a que cuanto más tiempo pueda transcurrir, más posibilidad hay de que ocurran imprevistos o de que las circunstancias cambien o varíen.</li>
<li>La experiencia más reciente suele ser más representativa que la más antigua, ya que se han podido producir cambios en nuestro entorno. Por ejemplo: nuevas tecnologías, cambios en el equipo (para mejor o para peor), etc.</li>
<li>El ser humano es mejor estimando por comparación entre objetos del mismo tipo. Somos muchos más precisos adivinando que una tarea es aproximadamente un 50% más grande que otra tarea del mismo tipo, que intentando asignar tiempo o dinero directamente a cada tarea por separado.</li>
</ul>
<p>O sea, para que tenga sentido el esfuerzo y dinero que vamos a gastar en estimar se deben cumplir algunos prerrequisitos:</p>
<ul>
<li>Tener personal con experiencia en las tareas y tecnologías implicadas.</li>
<li>Que haya poca variabilidad en las tareas a estimar, es decir, que sean similares en todos los aspectos relevantes.</li>
<li>No malgastar esfuerzos, y usar un grado de precisión realista a la hora de estimar, en función del tamaño de lo que estemos estimando y la escala de tiempo. Podemos hacer una estimación grosera, en meses, de una tarea que está en la escala de años, y una más fina de horas para una tarea que está en la escala de una jornada, pero es absurdo estimar con precisión de días una tarea en la escala de un año.</li>
<li>Usar estimaciones relativas (por comparación) en vez de absolutas. Es importante no comparar dos cosas que estén en escalas distintas, tanto de tamaño como de tiempo.</li>
</ul>
<p>Mientras no se cumplan los anteriores requisitos no tiene sentido ponerse a estimar, ya que simplemente los resultados obtenidos no nos servirán de nada. Si no se cumplen estos requisitos lo mejor es &#8220;adivinar&#8221; y &#8220;tirarse a la piscina&#8221;, ya que es igual de preciso pero más barato.</p>
<p>¿Radical? Pensadlo bien ¿Para que queremos estimar? En el fondo siempre que estimamos lo hacemos para asumir un compromiso con nuestro cliente, ya sea directamente o indirectamente a través de nuestros jefes: ¿cuándo estará terminado? ¿Podréis acabar esta funcionalidad antes de la semana que viene? ¿Te comprometes a hacer el proyecto en este tiempo y con tanto dinero? El hecho de asumir un compromiso nos lleva a correr el riesgo de no cumplirlo, y como tal lo debemos evitar a no ser que sea absolutamente necesario. En caso de que realmente necesitemos comprometernos formalmente debemos evaluar el nivel de riesgo de no cumplir esta promesa, lo cual depende sobre todo de la precisión de nuestra estimación. Por lo tanto, siguiendo el razonamiento de este post, no tiene sentido estimar si nuestra precisión no es aceptable, ya que estaríamos ante un riesgo incontrolado.</p>
<p>Así que ya sabeis, la próxima vez que monteis un plan de proyecto para un proyecto cerrado, o que comprometais una fecha de entrega, pensad antes si vuestras previsiones realmente tienen sentido, y no gasteis dinero en absurdos cálculos basados en cosas como los &#8220;puntos función&#8221;.</p>
<p>En próximos post abordaré la polémica sobre si estimar tareas o funcionalidades, y distintas técnicas ágiles para hacerlo.</p>
<br />Filed under: <a href='http://eamodeorubio.wordpress.com/category/metodologias/agile/'>Agile</a>  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/eamodeorubio.wordpress.com/587/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/eamodeorubio.wordpress.com/587/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/eamodeorubio.wordpress.com/587/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/eamodeorubio.wordpress.com/587/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/eamodeorubio.wordpress.com/587/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/eamodeorubio.wordpress.com/587/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/eamodeorubio.wordpress.com/587/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/eamodeorubio.wordpress.com/587/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/eamodeorubio.wordpress.com/587/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/eamodeorubio.wordpress.com/587/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/eamodeorubio.wordpress.com/587/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/eamodeorubio.wordpress.com/587/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/eamodeorubio.wordpress.com/587/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/eamodeorubio.wordpress.com/587/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=eamodeorubio.wordpress.com&amp;blog=12532304&amp;post=587&amp;subd=eamodeorubio&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://eamodeorubio.wordpress.com/2011/05/03/estimacion-1-%c2%bfhasta-que-punto-se-puede/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	
		<media:content url="http://0.gravatar.com/avatar/84999f5cc6fd4e8741735e557388b0aa?s=96&#38;d=http%3A%2F%2F0.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D96&#38;r=G" medium="image">
			<media:title type="html">eamodeorubio</media:title>
		</media:content>
	</item>
		<item>
		<title>Diseño software ágil (4): SOLID (1) ¿Tus clases son bombero/torero?</title>
		<link>http://eamodeorubio.wordpress.com/2011/03/07/diseno-software-agil-4-solid-1-%c2%bftus-clases-son-bomberotorero/</link>
		<comments>http://eamodeorubio.wordpress.com/2011/03/07/diseno-software-agil-4-solid-1-%c2%bftus-clases-son-bomberotorero/#comments</comments>
		<pubDate>Mon, 07 Mar 2011 09:49:15 +0000</pubDate>
		<dc:creator>Enrique Amodeo</dc:creator>
				<category><![CDATA[Agile]]></category>
		<category><![CDATA[Refactor]]></category>
		<category><![CDATA[Single Responsability]]></category>
		<category><![CDATA[SOLID]]></category>

		<guid isPermaLink="false">http://eamodeorubio.wordpress.com/?p=567</guid>
		<description><![CDATA[Después del interludio con el spring io, vuelvo a la carga con el tema del diseño ágil de software. Como ya comenté, considero que dentro de las limitaciones de tiempo y dinero de un proyecto, hay que estar continuamente reestructurando el código con el objetivo de que sea fácil y barato cambiarlo cada vez que [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=eamodeorubio.wordpress.com&amp;blog=12532304&amp;post=567&amp;subd=eamodeorubio&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>Después del <a href="http://eamodeorubio.wordpress.com/2011/02/21/springio-2011-%C2%BFvmware-vs-oracle/">interludio con el spring io</a>, vuelvo a la carga con el tema del diseño ágil de software. <a href="http://eamodeorubio.wordpress.com/2010/12/20/diseno-software-agil-1-la-calidad-del-software-es-solo-un-medio-no-un-fin/">Como ya comenté</a>, considero que dentro de las limitaciones de tiempo y dinero de un proyecto, hay que estar continuamente reestructurando el código con el objetivo de que sea fácil y barato cambiarlo cada vez que se produzca un cambio funcional, añadamos un nuevo requisito o necesitemos arreglar un bug. A estas reestructuraciones de código se les llama &#8220;refactors&#8221;.</p>
<p>Un refactor es una transformación de código que no altera la funcionalidad de este, pero sí su estructura. La idea es hacer refactors que hagan que nuestro código sea más flexible y maleable para poder alterarlo de forma rápida. El truco está en saber si al aplicar un refactor estamos mejorando nuestro código o si simplemente lo estamos complicando ¿Qué criterios sigo yo para evaluar si un refactor es bueno o no? Básicamente sólo sigo los tres siguientes:</p>
<ul>
<li>Que el código resultante sea más <strong>legible</strong>.  <a href="http://eamodeorubio.wordpress.com/2010/12/27/diseno-software-agil-2-el-codigo-fuente-es-la-documentacion/">Como ya expliqué</a> considero este el criterio más importante.</li>
<li>Que se respeten los principios <strong>DRY y &#8220;experto en información&#8221;</strong>. Ya los explicaré en otro post</li>
<li>Que se respeten los principios <strong>SOLID</strong>. Entre este post y los siguientes pienso ir explorándolos.</li>
</ul>
<p>¿Qué es el SOLID? SOLID es un acrónimo que consolida 5 principios: <em>Single responsability, Open/Closed, Liskov substitution, Interface segregation y Dependency inversion</em>. En este post me ocuparé del principio de única responsabilidad (Single responsability o SRP), o sea la S  de SOLID.</p>
<p><strong>El principio de única responsabilidad (SRP) simplemente nos dice que ningún artefacto de código debe tener más de una única responsabilidad, y por lo tanto debe implementar una única funcionalidad</strong>. El principio aplica a sistemas, aplicaciones, frameworks, objetos y métodos. Obviamente según el artefacto al que se aplique, la amplitud del concepto de única responsabilidad cambia. Pero en este post nos vamos a centrar en cómo afecta a nuestra clases y objetos.</p>
<p>¿Cómo sabemos si un artefacto, como una clase o un método, respeta este principio? Es muy sencillo, simplemente  debemos preguntarnos a nosotros mismos sobre cuantas razones diferentes podemos tener para querer cambiar dicho artefacto. <strong>Un artefacto que cumple el principio de única responsabilidad sólo puede ser cambiado debido a una única razón</strong>. Si encontramos múltiples razones para cambiar un artefacto entonces no cumple dicho principio y debe ser refactorizado. A mi me gusta llamar a este principio, el principio del bombero/torero. El hecho de que el personaje de bombero/torero nos cause risa es que es totalmente ridículo que una misma persona realice tareas de dos profesiones tan diferentes <em>al mismo tiempo</em>. Si lo vemos absurdo en una persona, ¿porque nos quedamos tan tranquilos cuando vemos una clase que es un bombero/torero?</p>
<p>Para entender mejor este principio veamos un ejemplo. Suponed que tenemos una historia de usuario tal que sigue:</p>
<p><em>&#8220;<strong>Cuando</strong> se realiza una transferencia importante</em></p>
<p><em><strong>Entonces</strong> se genera un mensaje con información sobre dicha transferencia</em></p>
<p><em><strong>Y</strong> se notifica a las personas de interés</em></p>
<p><em><strong>Para que</strong> den su aprobación y así evitar el fraude fiscal&#8221;</em></p>
<p>Hablando con el cliente me dice que la persona de interés es un auditor, y que había pensado en notificarle vía mail. Las transferencias importantes son aquellas por encima de 1000 euros (son un poco ratas). Cómo estoy codificando en JAVA y usando el famoso framework Zprin, el código que me sale es el siguiente:</p>
<p><pre class="brush: java; wrap-lines: false;">public class AuditorTransferenciasMonetarias {
  // Inyección de dependencias con el famoso framework Zprin (TM)
  // Con este framework somos productivos de la leche
  private ZprinPropertySource systemConfiguration;
  private ZprinTemplateEngine templateEngine;
  private ZprinMailIt mailIt;

  public void transferenciaRealizada(Transferencia transferencia) {
    if(this.esTransferenciaImportante(transferencia)) {
      String auditor=this.obtenerDireccionMailAuditor();
      String mensaje=this.componerMensajeAviso(transferencia);
      ConexionMail conexionMail=null;
      try {
        conexionMail=this.abrirConexionMail();
        conexionMail.enviar(new Mail().to(auditor).withBody(mensaje));
      } finally {
        if(conexionMail!=null)
          conexionMail.cerrar();
      }
    }
  }
  private boolean esTransferenciaImportante(Transferencia transferencia) {
    return transferencia.importe()&gt;1000;
  }
  private String obtenerDireccionMailAuditor() {
    return this.systemConfiguration.getProperty(&quot;auditor.email&quot;);
  }
  private String componerMensajeAviso(Transferencia transferencia) {
    return this.templateEngine.getTemplate(&quot;aviso-transferencia-importante.ztpl&quot;).execute(transferencia);
  }
  private MailConnection abrirConexionMail() {
    return this.mailIt.openConnectionTo(this.systemConfiguration.getProperty(&quot;servers.mail&quot;));
  }
}
</pre></p>
<p>Buen código, al usar el framework soy muy productivo y hago la clase super rápido, es más me quito de encima problemas complejos como el envío de mails, el acceso a propiedades configurables, o el tener que hacerme un motor de plantillas <img src='http://s2.wp.com/wp-includes/images/smilies/icon_razz.gif' alt=':-P' class='wp-smiley' />  Sólo tiene un problema, que no cumple el SRP (maldito SOLID, quién lo habrá inventado). SRP nos dice que la clase sólo debe tener una responsabilidad y la única manera en la que esta debería tener que cambiarse es cuando hay alguna alteración en dicha responsabilidad. En este caso la responsabilidad viene definida por la historia de usuario, así que mientras esta no cambie de forma significativa, entonces no deberíamos vernos forzados a cambiar la implementación. Obviamente el código descrito arriba no cumple esta propiedad. Vayamos por partes.</p>
<p>Suponed que el criterio para clasificar a una transferencia como importante cambia. Nos veríamos forzados a tocar nuestra clase, aunque realmente nuestra historia de usuario es la misma. Para evitarlo alteramos nuestro código:</p>
<p><pre class="brush: java; wrap-lines: false;">public class AuditorTransferenciasMonetarias {
  // ....
  public void transferenciaRealizada(Transferencia transferencia) {
    if(transferencia.esImportante()) {
      String auditor=this.obtenerDireccionMailAuditor();
      String mensaje=this.componerMensajeAviso(transferencia);
      ConexionMail conexionMail=null;
      try {
        conexionMail=this.abrirConexionMail();
        conexionMail.enviar(new Mail().to(auditor).withBody(mensaje));
      } finally {
        if(conexionMail!=null)
          conexionMail.cerrar();
      }
    }
  }
  // ....
}
</pre></p>
<p>Como vemos ahora la clase Transferencia tiene un método que nos indica si es importante o no. Si el criterio de importancia cambia nos da igual, ya que este método nos protege de dicho cambio. Si el cliente decide que quiere un motor de reglas parametrizable en runtime mediante un backoffice, el afectado es Transferencia no la clase que estamos construyendo.</p>
<p>Otro motivo de cambio ajeno a nuestra responsabilidad es que la definición de &#8220;personas interesadas&#8221; cambie. De repente queremos notificar no sólo a un auditor, sino a varios y además al director de la sucursal. Para protegernos de ello veamos el siguiente cambio:</p>
<p><pre class="brush: java; wrap-lines: false;">public class AuditorTransferenciasMonetarias {
  // ....
  // Ahora tenemos un colaborador de &quot;negocio&quot;
   // que está al mismo nivel de abstracción que esta clase
  private DirectorioEmpleados directorioEmpleados;

  public void transferenciaRealizada(Transferencia transferencia) {
    if(transferencia.esImportante()) {
      String mensaje=this.componerMensajeAviso(transferencia);
      ConexionMail conexionMail=null;
      try {
        conexionMail=this.abrirConexionMail();
        conexionMail.enviar(rellenarDestinatarios(new Mail().withBody(mensaje)));
      } finally {
        if(conexionMail!=null)
          conexionMail.cerrar();
      }
    }
  }
  private Mail rellenarDestinatarios(Mail mail) {
    for(Empleado interesado: this.interesadosEnTransferenciasImportantes())
      mail=mail.to(interesado.email());
    return mail;
  }
  private List&lt;Empleado&gt; interesadosEnTransferenciasImportantes() {
    return this.directorioEmpleados.empleadosConRol(Empleado.INTERESADOS_TRANSFERENCIAS_IMPORTANTES);
  }
  // ....
}
</pre></p>
<p>Ahora gracias a la interface DirectorioEmpleados, podemos buscar a todos los empleados que necesitamos notificar. Para ello buscamos por rol. La asociación empleado/rol se puede definir aparte, e incluso ser dinámica y cambiar en runtime. Observad que hemos añadido un colaborador que está al mismo nivel de abstracción de la clase que estamos codificando, y que el código ahora se parece un poco más a la definición de la historia de usuario.</p>
<p>Otro motivo por el cual podemos vernos obligados a cambiar esta clase, es que ahora los mensajes no se envíen por mail, sino por SMS. O peor, ¡ que se envíen a la vez por SMS, Mail, y chat a la vez ! Como no queremos que nos pillen con eso (que me conozco al cliente, que cambia de opinión constantemente) volvemos a &#8220;mejorar&#8221; el código:</p>
<p><pre class="brush: java; wrap-lines: false;">public class AuditorTransferenciasMonetarias {
  // ...
  private SistemaMensajeriaCorporativa mensajero;

  public void transferenciaRealizada(Transferencia transferencia) {
    if(transferencia.esImportante()) {
      this.mensajero
            .enviar(
              new Mensaje()
                   .a(this.interesadosEnTransferenciasImportantes())
                   .conContenido(this.componerMensajeAviso(transferencia))
      );
    }
  }
  // ....
}
</pre></p>
<p>Esta vez hemos introducido el sistema de mensajería corporativa, que nos permite enviar un mensaje de forma abstracta a varios empleados. Ya está, ya no hay más motivos de cambio&#8230; no perdón nos queda otro motivo y gordo. Hablando con nuestro amigo el &#8220;friki&#8221;, nos cuenta que el framework Zprin ya no es el acabose y que ha salido el framework XprinGio, y que a Zprin se queda sin soporte en menos de dos años. Nos olemos la tostada, en cuanto se entere el arquitecto jefe del temita nos manda cambiar de framework, o peor, si se entera el jefe de proyecto que sólo nos quedan dos años de soporte, toma migración. Hay que protegerse a toda costa de tan temida migración:</p>
<p><pre class="brush: java; wrap-lines: false;">public class AuditorTransferenciasMonetarias {
  private DirectorioEmpleados directorioEmpleados;
  private SistemaMensajeriaCorporativa mensajero;
  private PlantillasCorporativas almacenDePlantillas;

  public void transferenciaRealizada(Transferencia transferencia) {
    if(transferencia.esImportante()) {
      this.mensajero
            .enviar(
              new Mensaje()
                   .a(this.interesadosEnTransferenciasImportantes()
                   .conContenido(this.componerMensajeAviso(transferencia))
      );
    }
  }
  private Documento componerMensajeAviso(Transferencia transferencia) {
    return this.almacenDePlantillas.usandoPlantilla(&quot;avisos/transferencia-importante&quot;).crearDocumentoCon(transferencia);
  }
  private List&lt;Empleado&gt; interesadosEnTransferenciasImportantes() {
    return this.directorioEmpleados.empleadosConRol(Empleado.INTERESADOS_TRANSFERENCIAS_IMPORTANTES);
  }
}
</pre></p>
<p>Esta vez hemos eliminado todo dependencia con Zprin, y tenemos un motor de plantillas abstracto. Obviamente cuando implementemos el motor de plantillas, o el sistema de mensajería nos acoplaremos a Zprin, pero en una posible migración, sólo tendremos que cambiar estos servicios y no todas las clases de negocio. Otro cambio es que ahora la plantilla genera un Documento en vez de un String. Además la clase Documento sabrá serializarse en cualquier formato que se necesite por parte del mecanismo de mensajería (String, XML, HTML, JSON, PDF&#8230;) lo que permite tener sistemas de mensajería más complejos.</p>
<p>Como se observa, si seguimos el principio de única responsabilidad nuestros artefactos tendrán una alta cohesión y por lo general un bajo acoplamiento, ya que quedan pocos métodos muy relacionados entre si y muy cortos. Pero lo mejor es que se tenderá a que la tasa de cambios de un único artefacto baje, y que éstos cambios sean más localizados, ya que sólo se va a necesitar modificarlo ante un único tipo de cambio al existir una relación uno a uno entre responsabilidad y clase. Obviamente este era un ejemplo de código algo artificial, y seguro que le sacais pegas, pero creo que podéis captar la idea.</p>
<p>Pero no es oro todo lo que reluce, más adelante en esta serie veremos el principio DRY y el &#8220;experto en información&#8221; y como ambos se terminan pegando con el principio de única responsabilidad, con lo que se produce un conflicto grave. Para colmo, el principio de segregación de interfaces nos puede complicar también la vida. Armonizar todos estos principios, es el caballo de batalla del diseño orientado a objetos. De hecho, respetar cada principio por separado es sencillo, lo difícil es juntarlos todos, ya que veréis que es como si unos principios contradijeran a otros ¿Terminará siendo la OO en realidad un paradigma fracasado y contradictorio?</p>
<br />Filed under: <a href='http://eamodeorubio.wordpress.com/category/metodologias/agile/'>Agile</a>, <a href='http://eamodeorubio.wordpress.com/category/metodologias/agile/refactor/'>Refactor</a>, <a href='http://eamodeorubio.wordpress.com/category/metodologias/solid/single-responsability/'>Single Responsability</a>, <a href='http://eamodeorubio.wordpress.com/category/metodologias/solid/'>SOLID</a>  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/eamodeorubio.wordpress.com/567/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/eamodeorubio.wordpress.com/567/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/eamodeorubio.wordpress.com/567/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/eamodeorubio.wordpress.com/567/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/eamodeorubio.wordpress.com/567/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/eamodeorubio.wordpress.com/567/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/eamodeorubio.wordpress.com/567/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/eamodeorubio.wordpress.com/567/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/eamodeorubio.wordpress.com/567/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/eamodeorubio.wordpress.com/567/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/eamodeorubio.wordpress.com/567/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/eamodeorubio.wordpress.com/567/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/eamodeorubio.wordpress.com/567/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/eamodeorubio.wordpress.com/567/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=eamodeorubio.wordpress.com&amp;blog=12532304&amp;post=567&amp;subd=eamodeorubio&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://eamodeorubio.wordpress.com/2011/03/07/diseno-software-agil-4-solid-1-%c2%bftus-clases-son-bomberotorero/feed/</wfw:commentRss>
		<slash:comments>11</slash:comments>
	
		<media:content url="http://0.gravatar.com/avatar/84999f5cc6fd4e8741735e557388b0aa?s=96&#38;d=http%3A%2F%2F0.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D96&#38;r=G" medium="image">
			<media:title type="html">eamodeorubio</media:title>
		</media:content>
	</item>
		<item>
		<title>SpringIO 2011: ¿VMWare vs. Oracle?</title>
		<link>http://eamodeorubio.wordpress.com/2011/02/21/springio-2011-%c2%bfvmware-vs-oracle/</link>
		<comments>http://eamodeorubio.wordpress.com/2011/02/21/springio-2011-%c2%bfvmware-vs-oracle/#comments</comments>
		<pubDate>Mon, 21 Feb 2011 09:30:49 +0000</pubDate>
		<dc:creator>Enrique Amodeo</dc:creator>
				<category><![CDATA[Filosofada]]></category>
		<category><![CDATA[JAVA]]></category>

		<guid isPermaLink="false">http://eamodeorubio.wordpress.com/?p=559</guid>
		<description><![CDATA[Hola a todos, pensaba hacer una reseña al uso sobre el SpringIO 2011 Madrid, pero las distintas sesiones a las que asistí me han dejado una idea bastante persistente en la cabeza: VMWare se está posicionando como clara competencia de Oracle en el mundo de las aplicaciones empresariales JAVA (plataforma JVM mejor dicho). Como la [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=eamodeorubio.wordpress.com&amp;blog=12532304&amp;post=559&amp;subd=eamodeorubio&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>Hola a todos, pensaba hacer una reseña al uso sobre el SpringIO 2011 Madrid, pero las distintas sesiones a las que asistí me han dejado una idea bastante persistente en la cabeza: VMWare se está posicionando como clara competencia de Oracle en el mundo de las aplicaciones empresariales JAVA (plataforma JVM mejor dicho). Como la mayoría de vosotros sabeis VMWare compró SpringSource, así que ahora todas las decisiones estratégicas sobre el desarrollo de Spring se toman con la participación y el consentimiento de VMWare. Pensar otra cosa sería pecar de excesiva inocencia.</p>
<p>En la conferencia me percaté de que varios temas se repetían una y otra vez en las distintas charlas: Grails, Cloud Computing, noSQL y &#8220;Portable Service Abstractions&#8221;. Comentaré primero lo que se habló sobre cada uno de estos temas y después explicaré porqué todos ellos me hacen pensar que VMWare se postula como seria competencia de Oracle.</p>
<p>Sin saber mucho de Grails, me da la impresión que es un framework &#8220;orientado a la base de datos&#8221;. En los ejemplos que he visto siempre se habla del MVC, pero todos los modelos Grails que he visto no son más que JavaBeans (a.k.a. registros COBOL recauchutados), eso sí, codificados en Groovy, que es mas &#8220;cool&#8221;. Después tienes las vistas, que no son más que JSPs (perdonad, GSPs) y un controlador escrito en Groovy que en realidad es un controlador de Spring MVC (que es casi igual a un backing bean de JSF). Vamos, más modelo anémico. Ciertamente es mucho mejor que un modelo anémico que podamos hacer en JAVA, y sí, no hay que picar apenas código (se agradece), con lo cual considero a Grails la plataforma perfecta para este tipo de aplicaciones. Si estoy metiendo la pata perdonadme, pero ya sabéis que me hierve la sangre con este tema ¡ Si alguien sabe como hacer buena OO con Grails que me lo diga !</p>
<p>Dejando de lado esta diatriba, la charla a la que asistí de Grails fue muy interesante. Peter Ledbrook explicó de forma bastante clara como integrar Grails con el resto de la empresa. ¿Qué hacemos si queremos hacer un build con ANT? ¿Y con MAVEN? ¿Y si ya existe un modelo hecho con JPA? ¿Y si resulta que el administrador de base de datos nos obliga a una determinada nomenclatura? La verdad es que resolvió bastante bien todos estos escenarios, aunque la parte de integración con MAVEN me dio la impresión de estar un pelín verde. Quizás el mayor problema es cuando ya existe un esquema de base de datos que tenemos que respetar. Aquí es donde la solución que dio no me terminó de parecer clara, y me pareció que proponía que se hiciera un modelo JPA y se integrara éste modelo con Grails. Está claro que en SpringSource se han dado cuenta de que uno de los obstáculos principales para que Grails triunfe es poder integrarse con los elementos más usuales en un sistema empresarial.</p>
<p>Otro punto que se habló de Grails fue integrar GORM (motor de mapeo Objeto/Relacional de Grails) con bases de datos noSQL. Se mencionó este tema en la segunda key note e @ialcazar me comentó un poco sobre una sesión que se dio a este respecto. No termino de ver como se puede integrar un motor de mapeo objeto/relacional con una base de datos no relacional ¡ Precisamente una de las ventajas de una base de datos noSQL es que no necesitamos un mapeo Objeto/Relacional ! No termino de verle el sentido técnico, pero sí el de marketing. En cualquier caso creo que es una iniciativa muy interesante de la comunidad de Grails, esperemos que lo consigan sin cargarse la escalabilidad que nos da un noSQL. También noté preocupación por el rendimiento de Grails, y se ve que están trabajando muy duro para mejorarlo.</p>
<p>Otro tema que estuvo bastante presente fue el Cloud Computing. Durante la primera key note y alguna que otra charla se habló de que el objetivo a medio plazo es preparar a Spring para permitir desarrollar aplicaciones en la nube. Realmente no termino de ver que problema hay con las APIs actuales de Spring y la nube, así que todo esto me suena a simple marketing. En este sentido me hubiera gustado que hablaran de tecnologías como vFabric o GemFire, pero claro, aunque son parte de VMWare, técnicamente no forman parte de Spring, con lo que hubiera estado fuera de lugar nombrarlas. Tal vez cuando se hablaba de adaptar Spring a la nube se refirieran a conseguir mayor rendimiento, y sobre todo escalabilidad y elasticidad, cosa fundamental en este tipo de entornos.</p>
<p>Quizás en este sentido se entienda el esfuerzo por integrarse con sistemas de persistencia noSQL, que proporcionan mayor escalabilidad a las aplicaciones. Una de las charlas más interesantes fue la de Spring Data de Costin Landau. Realmente me gustó la propuesta de Spring de montar un API &#8220;estándar&#8221; para noSQL, sobre todo teniendo en cuenta que JEE no proporciona nada comparable. En concreto las APIs de bajo nivel y el concepto de &#8220;repositorio&#8221; me resultó interesante. También la idea de dar cobertura a bases de datos documentales y orientadas a grafos me resultó bastante atractiva. Sin embargo a otras propuestas, como incorporar un sistema de persistencia mixto que mantuviera parte del modelo en BBDD relacional y parte en noSQL no acabo de verles el sentido. Tal vez sea un compromiso de &#8220;marketing&#8221; para que a la gente no le de miedo adoptar noSQL, ya que seguirían teniendo el respaldo de bases de datos tradicionales. A mi simplemente me parece una postura originada por el miedo de la gente a noSQL. Ya sabéis que pienso que si el sistema tiene las consultas bien definidas, el enfoque noSQL es totalmente superior al tradicional, y que sólo usaría un sistema SQL si realmente el conjunto de consultas las va a decidir el usuario en runtime, como son el caso de bussiness inteligence y data mining por ejemplo.</p>
<p>En la línea de noSQL la charla sobre Redis de Alberto Gimeno fue curiosa. Personalmente pienso que Redis está un poco verde todavía, aunque a alguno le puede interesar el concepto de clave/valor avanzado. Al contrario que un clave/valor simple, el valor almacenado puede ser no sólo un array de bytes, sino estructuras de datos como contadores, listas, mapas o sets. Para cada tipo de datos REDIS proporciona un conjunto de operaciones específicas, que se pueden ejecutar de forma atómica, y extienden el paradigma clásico del clave/valor. No termino de ver por qué esta complejidad extra es necesaria, pero sí que es verdad que facilita a un recién llegado al noSQL la transición desde el mundo de las BBDD relacionales. En todo caso me alegró ver que la gente empieza a usar sistemas noSQL, ya sabéis de que pié cojeo.</p>
<p>Otro tema que fue hilo conductor de esta conferencia fue el concepto de &#8220;Portable Service Abstraction&#8221;. Este nombre es una forma &#8220;cool&#8221; de decir que si desarrollamos contra interfaces &#8220;estándar&#8221;, nuestro código será portable a otros entornos. Es una idea muy vieja, y es lo que intentó JEE. Como ejemplos de estas &#8220;Portable Service Abstraction&#8221; podemos tener Spring Data, Spring REST, Spring AMQP, Spring Social, Spring Mobile y Spring Android. En general me gusta el enfoque de Spring de hacer APIs sencillas, y de reaccionar de forma rápida y ágil a las necesidades de los desarrolladores. Sin embargo no es oro todo lo que reluce. No entiendo la necesidad de Spring REST, desde mi punto de vista JAX-RS era un estándar más que suficiente. De hecho ambos estándares son tan similares, que es difícil distinguir dos aplicaciones hechas sobre cada una de ellas. Por otro lado Spring Mobile y Spring Android me decepcionaron, ya que apenan aportan valor. El primero básicamente sólo te detecta el tipo de dispositivo móvil y te redirige a una página de presentación u otra en función de éste. Vamos, nada que no exista ya en las múltiples arquitecturas multicanal &#8220;clásicas&#8221;. Spring Android es sólo un cliente para hacer llamadas al servidor. Los que sí me gustaron bastante fueron Spring Social, Spring Data y Spring AMQP. En concreto este último, ya que me pareció que el RabbitMQ era genial.</p>
<p>Toda esta información que recibí en la SpringIO me hizo ver que VMWare está intentando atacar a Oracle por varios frentes:</p>
<ul>
<li><strong>Spring como substituto de JEE</strong>. Aunque Spring es compatible con JEE, en el fondo lo que pretende es que programemos contra sus APIs en vez de las de JEE, aduciendo motivos de portabilidad. Esto es gracioso, ya que JEE nos propone exactamente lo mismo: una aplicación programada contra JEE es portable al ser éste el estándar de iure para el desarrollo de aplicaciones empresariales. Así que, ¿cuál API es más estándar, JEE o Spring? Esta claro que Spring ha sabido evolucionar sus APIs de forma más ágil y práctica que JEE, con todos sus comités. Todo esto es una amenaza clara contra Oracle, que es la actual &#8220;dueña&#8221; de JEE.</li>
<li><strong>Tomcat y Spring tc Server como substitutos de WebLogic (y de paso de WebSphere).</strong> Si vamos a programar contra Spring en vez de contra JEE no tiene sentido comprar un servidor JEE completo como WebLogic o WebSphere, nos basta un contenedor de Servlets como Tomcat. Para los que no lo sepáis WebLogic es de Oracle.</li>
<li><strong>AMQP y RabbitMQ contra JMS</strong>. Aunque RabbitMQ se integra con JMS, en realidad es una alternativa viable a JMS, y a cosas como MQSeries.</li>
<li><strong>Grails como substituto de JSF</strong>. Como ya sabréis el modelo de programación web JEE es JSF. De hecho Oracle ha invertido en su implementación de JSF, llamada <strong>Oracle ADF,</strong> y en <strong>un IDE especial para ADF basado en Eclipse</strong>. Oracle ADF y su IDE nos permite hacer aplicaciones orientadas a base de datos muy rápidamente (o eso me han contado). Está claro que <strong>SpringToolSuite junto con Grails es competencia directa</strong> de esta tecnología.</li>
<li><strong>noSQL contra las bases de datos relacionales</strong>. Como sabéis Oracle es dueña no sólo de la base de datos relacional más famosa del mundo, sino que con la compra de Sun, puede hacerse con el control de MySQL. Obviamente apostar por noSQL es un golpe directo a la linea de flotación de Oracle. Curiosamente el único sistema noSQL del que se habló con detalle en la conferencia fue de REDIS, que está &#8220;esponsorizado&#8221; por VMWare.</li>
<li><strong>Cloud Computing contra hosting tradicional</strong>. El Cloud Computing es un escenario que creo beneficia más a VMWare que a Oracle. El primero, ha hecho una apuesta fuerte en este sentido con vFabric y vmForce. Si tienes una instalación propia, puede venir un comercial de Oracle a venderte WebLogic y la base de datos de turno. En un cloud no. Si convences a una empresa para irse al cloud, es más que probable que sus bases de datos Oracle queden en desuso.</li>
</ul>
<p>En definitiva, Spring pretende suplantar a JEE como plataforma estandarizada para el desarrollo de aplicaciones empresariales con JAVA. Bueno, tal vez yo sea un poco suspicaz, pero esto es lo que realmente leo entre lineas de la conferencia SpringIO. Por cierto fue un éxito de público, y en general el nivel de las sesiones y talleres fue bastante alto. Enhorabuena a la organización, ya que no creo que con 20 euros se pudiera haber hecho mejor. ¿A alguien le pareció caro? A mi no.</p>
<br />Filed under: <a href='http://eamodeorubio.wordpress.com/category/filosofada/'>Filosofada</a>, <a href='http://eamodeorubio.wordpress.com/category/lenguajes-programacion/java/'>JAVA</a>  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/eamodeorubio.wordpress.com/559/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/eamodeorubio.wordpress.com/559/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/eamodeorubio.wordpress.com/559/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/eamodeorubio.wordpress.com/559/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/eamodeorubio.wordpress.com/559/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/eamodeorubio.wordpress.com/559/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/eamodeorubio.wordpress.com/559/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/eamodeorubio.wordpress.com/559/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/eamodeorubio.wordpress.com/559/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/eamodeorubio.wordpress.com/559/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/eamodeorubio.wordpress.com/559/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/eamodeorubio.wordpress.com/559/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/eamodeorubio.wordpress.com/559/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/eamodeorubio.wordpress.com/559/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=eamodeorubio.wordpress.com&amp;blog=12532304&amp;post=559&amp;subd=eamodeorubio&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://eamodeorubio.wordpress.com/2011/02/21/springio-2011-%c2%bfvmware-vs-oracle/feed/</wfw:commentRss>
		<slash:comments>10</slash:comments>
	
		<media:content url="http://0.gravatar.com/avatar/84999f5cc6fd4e8741735e557388b0aa?s=96&#38;d=http%3A%2F%2F0.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D96&#38;r=G" medium="image">
			<media:title type="html">eamodeorubio</media:title>
		</media:content>
	</item>
		<item>
		<title>Diseño software ágil (3): Deconstruyendo los números romanos</title>
		<link>http://eamodeorubio.wordpress.com/2011/01/10/diseno-software-agil-3-deconstruyendo-los-numeros-romanos/</link>
		<comments>http://eamodeorubio.wordpress.com/2011/01/10/diseno-software-agil-3-deconstruyendo-los-numeros-romanos/#comments</comments>
		<pubDate>Mon, 10 Jan 2011 10:00:22 +0000</pubDate>
		<dc:creator>Enrique Amodeo</dc:creator>
				<category><![CDATA[Agile]]></category>
		<category><![CDATA[Refactor]]></category>
		<category><![CDATA[Ruby]]></category>
		<category><![CDATA[TDD]]></category>

		<guid isPermaLink="false">http://eamodeorubio.wordpress.com/?p=538</guid>
		<description><![CDATA[Andaba yo buscando un ejemplo de código para demostrar el concepto del TDD, refactor y diseño emergente, cuando mi señora me apuntó al coding dojo en Ruby, organizado por @madridrb el pasado día 30 de Diciembre, donde durante las cervezas post-evento se me ocurrió este post. El dojo, donde el señor @ecomba propuso hacer la [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=eamodeorubio.wordpress.com&amp;blog=12532304&amp;post=538&amp;subd=eamodeorubio&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>Andaba yo buscando un ejemplo de código para demostrar el concepto del <strong>TDD, refactor y diseño emergente</strong>, cuando mi señora me apuntó al coding dojo en Ruby, organizado por @madridrb el pasado día 30 de Diciembre, donde durante las cervezas post-evento se me ocurrió este post. El dojo, donde el señor @ecomba propuso hacer la kata de los números romanos, se encontraba con bastante más gente de lo normal, y es que este hombre tiene mucho tirón. La idea era ir turnándose cada 3 minutos en un ordenador e ir avanzando la kata. Como éramos bastantes, y no había mucho tiempo, al final realmente no pudimos avanzar lo suficiente, y tuvo que acabarla @ecomba de forma rápida y sin poder entretenerse mucho. Esto hizo que tuviera que dar algunos saltos de diseño. Posteriormente en las cervezas me enteré que muchos asistentes no estaban muy versados en esto del TDD y que estaban confusos. Sobre todo la mayor discusión trataba sobre por qué era importante hacer TDD y refactor en pasos muy pequeños y qué ventaja daba a la hora de diseñar el código. Así que en ese momento supe que mi siguiente post iba a ser un ejemplo con código sobre <strong>cómo conseguir un diseño emergente a base de Refactor y TDD en pasos pequeños (baby steps)</strong>.</p>
<p>Este es uno de los posts más difíciles que he hecho ya que voy a intentar mostrar mis procesos mentales de diseño, y como me enfrento a un problema de programación (sencillo por cierto). Aviso a los asistentes del coding dojo que el código final al que llego en este post es diferente al que hizo @ecomba, lo que demuestra que no suele existir una única implementación &#8220;óptima&#8221;, y que el resultado puede variar en función de criterios personales y algo del azar. No tengo experiencia alguna en Ruby, sólo he hecho los koans y esta kata, con lo que he usado un Ruby muy básico y sencillo al no conocer bien el lenguaje y la librería de objetos. Sin embargo guiado por el TDD y el refactor creo que llego a una solución bastante compacta. Empecemos&#8230;</p>
<p>Lo primero de todo es familiarizarse con la funcionalidad a implementar. Ni el TDD ni el refactor son un sustituto de ponerse a pensar, sólo un guía para nuestro proceso creativo, por lo que debemos tener alguna idea del objetivo funcional que debe alcanzar nuestro código. No es necesario ser un experto en la funcionalidad, sino saber por donde van más o menos los tiros y no ir dando palos de ciego. Aquí va la funcionalidad de los números romanos, al menos lo que recordaba cuando me puse a tirar código:</p>
<ul>
<li>Queremos convertir un número entero en un número romano. Nada más.</li>
<li>Los romanos no representaban de forma explícita ni el cero ni los números negativos.</li>
<li>Existen un conjunto de 13 símbolos o numerales básicos (nosotros tenemos 10). Cada uno de estos tiene un valor predefinido, pero ninguno representa el 0 o valor negativo.</li>
<li>Para representar un número, se concatenan estos numerales, y sus valores se van sumando hasta que se obtiene el valor del número.</li>
<li>Algunos casos como el 4 o el 9 son especiales y se representan de forma especial.</li>
</ul>
<p>Así que llegué a mi casa, abrí el vim, me instalé el rspec y secuestré el &#8220;mug of vi&#8221; de mi mujer para que me sirviera de chuleta (soy penoso con el vi y quería aprender, que lo pasé muy mal en el dojo). Lo primero que se hace siempre es coger el caso más básico, y que cosa más básica que el número 1. En rspec queda:</p>
<p><pre class="brush: ruby; auto-links: false; wrap-lines: false;">describe &quot;Roman number&quot; do
	it &quot;I is equivalent to 1&quot; do
		1.to_roman.should == 'I'
	end
end</pre></p>
<p>Evidentemente falla, con lo que hay que añadir una implementación. Pero siguiendo las reglas del TDD y refactor, debe ser la implementación más simple posible que pase el test, ya lo pondremos bonito después si existiera una razón de peso. Para los que no sepan Ruby, en éste lenguaje las clases son abiertas, por lo que el enfoque de diseño tomado es añadir un método &#8220;to_roman&#8221; a la clase &#8220;Fixnum&#8221; que representa a los enteros.  La implementación es obvia:</p>
<p><pre class="brush: ruby; auto-links: false; highlight: [1,2,3,4,5]; wrap-lines: false;">class Fixnum
	def to_roman
		'I'
	end
end

describe &quot;Roman number&quot; do
	it &quot;I is equivalent to 1&quot; do
		1.to_roman.should == 'I'
	end
end</pre></p>
<p>Vamos a probar ahora con el número 5, que es otro de los numerales básicos romanos. La estrategia de momento es ir añadiendo numerales básicos, a ver que nos sale. El test y su correspondiente implementación:</p>
<p><pre class="brush: ruby; auto-links: false; highlight: [3,13,14,15]; wrap-lines: false;">class Fixnum
	def to_roman
		return 'V' if self == 5
		'I'
	end
end

describe &quot;Roman number&quot; do
	it &quot;I is equivalent to 1&quot; do
		1.to_roman.should == 'I'
	end

	it &quot;V is equivalent to 5&quot; do
		5.to_roman.should == 'V'
	end
end</pre></p>
<p>La técnica es sencilla, copiar y pegar lo que funcionó en el caso del 1. Reemplazamos los valores adecuados y cubrimos cada caso con un if. Estamos en modo &#8220;pasar tests&#8221;, hasta el momento no hemos detectado duplicación y no hemos refactorizado nada. Pero esto ya empieza a oler a cuerno quemado. Volvemos a repetir, esta vez para el 10. La cosa queda:</p>
<p><pre class="brush: ruby; auto-links: false; highlight: [3,18,18,19,20]; wrap-lines: false;">class Fixnum
	def to_roman
		return 'X' if self == 10
		return 'V' if self == 5
		'I'
	end
end

describe &quot;Roman number&quot; do
	it &quot;I is equivalent to 1&quot; do
		1.to_roman.should == 'I'
	end

	it &quot;V is equivalent to 5&quot; do
		5.to_roman.should == 'V'
	end

	it &quot;X is equivalent to 10&quot; do
		10.to_roman.should == 'X'
	end
end</pre></p>
<p>Ya se observa claramente la duplicación. Tenemos dos (o tres, según se mire) lineas con la misma estructura de código. Esto es normal ya que hemos estado haciendo copy&amp;paste. Ahora toca reflexionar sobre la intención de nuestro código, ¿qué queremos hacer en realidad? ¿Refleja el código actual esa intención (es expresivo)? Es obvio que lo que queremos hacer es mapear números a numerales romanos, y que existe una correspondencia uno a uno. En realidad estamos haciendo una búsqueda de un literal romano por número entero a base de un montón de ifs. El uso de una simple Hash (o mapa o diccionario) nos elimina las líneas duplicadas y nos da un código más expresivo (si elegimos bien los nombres). Tras refactorizar me sale lo siguiente:</p>
<p><pre class="brush: ruby; auto-links: false; highlight: [2,5]; wrap-lines: false;">class Fixnum
	ARABIC_TO_ROMAN_NUMERAL = { 10 =&gt; 'X', 5 =&gt; 'V', 1 =&gt; 'I' }

	def to_roman
		ARABIC_TO_ROMAN_NUMERAL[self]
	end
end
# .......</pre></p>
<p>Por brevedad no me entretendré con los siguientes 10 numerales romanos, y pasaré al siguiente problema, ¿qué pasa si un número no se corresponde con un literal romano? Según el funcional hay que concatenar los numerales hasta sumar el número deseado. Como caso más sencillo de este escenario añado el test para el número 2 que debe transformarse en &#8216;II&#8217;. Además voy a refactorizar un poco los ejemplos de test, agrupándolos por escenario. En RSpec usaré un contexto por escenario (no se si esto es purista pero a mi me parece bien). El test ahora es:</p>
<p><pre class="brush: ruby; auto-links: false; wrap-lines: false;"># .........
describe &quot;Roman number&quot; do
	context &quot;has basic numerals with different values&quot; do
		it &quot;I is equivalent to 1&quot; do
			1.to_roman.should == 'I'
		end

		it &quot;V is equivalent to 5&quot; do
			5.to_roman.should == 'V'
		end

		it &quot;X is equivalent to 10&quot; do
			10.to_roman.should == 'X'
		end
	end

	context &quot;concatenates numerals in descending order until they sum up the desired integer&quot; do
		it &quot;II is equivalent to 2&quot; do
			2.to_roman.should == 'II'
		end
	end
end</pre></p>
<p>Como veis un contexto para los numerales básicos y otro para los que no lo son. Añado la implementación más básica que se me ocurre, si el número coincide con un numeral básico lo devuelvo y acabo, si no, devuelvo &#8216;II&#8217; a cascoporro:</p>
<p><pre class="brush: ruby; auto-links: false; highlight: [5,6]; wrap-lines: false;">class Fixnum
	ARABIC_TO_ROMAN_NUMERAL = { 10 =&gt; 'X', 5 =&gt; 'V', 1 =&gt; 'I' }

	def to_roman
		return ARABIC_TO_ROMAN_NUMERAL[self] if ARABIC_TO_ROMAN_NUMERAL[self]
		'II'
	end
end
# ........</pre></p>
<p>Añado un test para el número 3, que debe resultar en &#8216;III&#8217; y su correspondiente implementación. Pero esta vez me lo curro un poco más:</p>
<p><pre class="brush: ruby; auto-links: false; highlight: [6,19,20,21]; wrap-lines: false;">class Fixnum
	ARABIC_TO_ROMAN_NUMERAL = { 10 =&gt; 'X', 5 =&gt; 'V', 1 =&gt; 'I' }

	def to_roman
		return ARABIC_TO_ROMAN_NUMERAL[self] if ARABIC_TO_ROMAN_NUMERAL[self]
		'I' + (self - 1).to_roman
	end
end

describe &quot;Roman number&quot; do

#      ......................

	context &quot;concatenates numerals in descending order until they sum up the desired integer&quot; do
		it &quot;II is equivalent to 2&quot; do
			2.to_roman.should == 'II'
		end

		it &quot;III is equivalent to 3&quot; do
			3.to_roman.should == 'III'
		end
	end
end</pre></p>
<p>Como veis esta vez he sido más sofisticado y en vez de meter un &#8216;III&#8217; if self == 3, he leído bien el funcional y se me ha ocurrido un algoritmo. Siguiendo el espíritu de concatenar hasta sumar el número, se me ocurre que puedo tomar el numeral &#8216;I&#8217; y restarle su valor al número que quiero convertir. El resultado de esta resta, qué es lo que queda para conseguir sumar el número deseado, lo convierto a su vez en un número romano y lo concateno. Aquí hemos tenido que <strong>parar y reflexionar sobre la funcionalidad para obtener una idea creativa</strong>. El TDD nos ha servido para llegar a un punto donde esta idea se nos pueda ocurrir con facilidad.</p>
<p>Sigamos, ¿qué pasa con otros casos? Añado tests para el 6, el 11 el 15 y el 20. Los hago pasar haciendo copy&amp;paste del caso del 2 y el 3, reemplazando &#8216;I&#8217; y 1, por &#8216;V&#8217; y 5 para pasar el test del 11, y &#8216;X&#8217; y 10 para pasar el test del número 9. La cosa queda así:</p>
<p><pre class="brush: ruby; auto-links: false; highlight: [6,7,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39]; wrap-lines: false;">class Fixnum
	ARABIC_TO_ROMAN_NUMERAL = { 10 =&gt; 'X', 5 =&gt; 'V', 1 =&gt; 'I' }

	def to_roman
		return ARABIC_TO_ROMAN_NUMERAL[self] if ARABIC_TO_ROMAN_NUMERAL[self]
		return 'X' + (self - 10).to_roman if self &gt; 10
		return 'V' + (self - 5).to_roman if self &gt; 5
		'I' + (self - 1).to_roman
	end
end

describe &quot;Roman number&quot; do

#      .................

	context &quot;concatenates numerals in descending order until they sum up the desired integer&quot; do
		it &quot;II is equivalent to 2&quot; do
			2.to_roman.should == 'II'
		end

		it &quot;III is equivalent to 3&quot; do
			3.to_roman.should == 'III'
		end

		it &quot;VI is equivalent to 6&quot; do
			6.to_roman.should == 'VI'
		end

		it &quot;XI is equivalent to 11&quot; do
			11.to_roman.should == 'XI'
		end

		it &quot;XV is equivalent to 15&quot; do
			15.to_roman.should == 'XV'
		end

		it &quot;XX is equivalent to 20&quot; do
			20.to_roman.should == 'XX'
		end
	end
end</pre></p>
<p>Fijaros en el orden en que pongo las líneas de código, primero evalúo los numerales con valor más alto y después las de valor más bajo. Si lo hacemos en otro orden los tests fallan, al devolverme por ejemplo &#8216;VVI&#8217; en vez de &#8216;XI&#8217;. En este caso los tests son los que nos han hecho darnos cuenta de que hay que ordenar los numerales de mayor a menor, y además de sumar el valor, debe ser la representación más corta posible. Esto no lo tenía yo nada claro por el funcional que indiqué más arriba. En este caso los tests nos aclaran la funcionalidad.</p>
<p>Sin embargo de nuevo tenemos duplicación y el código da repelús. La misma estructura de código repetida en tres líneas, sólo varía en el numeral romano usado en cada caso y su correspondiente valor numérico. ¿Podemos sustituir esta duplicación por una regla parametrizable? ¿Quizás un método auxiliar que recibiera como parámetros el numeral romano y el valor numérico? Esta solución eliminaría algo de duplicación, pero aun quedaría duplicada la estructura de la cascada de ifs. <strong>Es esto último lo que más me preocupa, ya que se viola el principio abierto/cerrado</strong>. Cuando quisiéramos añadir un nuevo numeral (cuando nuestro cliente recordara uno nuevo), tendríamos que &#8220;abrir&#8221; el método to_roman para añadir otra línea más. Esto es más grave que unos cuantos caracteres repetidos. Hay que <strong>pararse a pensar de nuevo</strong>, es hora de ganarse el sueldo. Lo que se me ocurrió es lo siguiente:</p>
<p><pre class="brush: ruby; auto-links: false; highlight: [6,7,8]; wrap-lines: false;">class Fixnum
	ARABIC_TO_ROMAN_NUMERAL = { 10 =&gt; 'X', 5 =&gt; 'V', 1 =&gt; 'I' }

	def to_roman
		return ARABIC_TO_ROMAN_NUMERAL[self] if ARABIC_TO_ROMAN_NUMERAL[self]
		ARABIC_TO_ROMAN_NUMERAL.each do | arabic_number, roman_numeral |
			return roman_numeral + (self - arabic_number).to_roman if self &gt; arabic_number
		end
	end
end
#  .............</pre></p>
<p>La idea es recorrer la colección de numerales, de forma que encontremos el numeral romano de más valor, que sea inferior al número que buscamos, y usamos dicho numeral en la regla recursiva que descubrimos antes para calcular el resultado. Podríamos haber usado un bucle for, pero sospecho que no están bien vistos en el mundo de Ruby, así que uso el método iterador each, y le paso un bloque de código. En cuanto encuentro el numeral buscado devuelvo el valor y el bucle (perdón, la iteración) termina. De paso ya no necesito ese método auxiliar que se me ocurrió antes, ya que la regla recursiva sólo se usa una vez y es bastante compacta. Me encanta cuando los planes salen bien&#8230; WTF! ¡ Fallan los tests ! ¡ Qué c*** pasa ! ¡ Es la hora del debugger !</p>
<p>Lo que ocurre es que el método each itera las entradas de la hash en el orden que le sale de las gónadas. Es una sorpresa, ya que <a href="http://www.ruby-doc.org/core/classes/Hash.html">según la documentación</a>, debería iterarlos en el orden en que los añades a la hash. Ya estoy por mandar un bug a la comunidad de Ruby cuando descubro mi fallo. Estoy usando Ruby 1.8.x y la documentación es de la 1.9.x. Algo huele a quemado, busco un poco y efectivamente: originalmente el orden de iteración de las hash era aleatorio, pero a partir de la 1.9.x es por orden de inserción. Esto de añadir cambios que rompen la API y cambiar sólo el &#8220;minor version&#8221; no es buena idea.</p>
<p>Total, que tengo una implementación que supuestamente funciona en Ruby 1.9 (no lo he probado), pero no en 1.8. Algo he de hacer. De momento me calmo un poco, y me dedico a arreglar otra duplicación de código que me está matando, la primera línea del método to_roman. Lo que hago es lo siguiente:</p>
<p><pre class="brush: ruby; auto-links: false; highlight: [5,6,7,8]; wrap-lines: false;">class Fixnum
	ARABIC_TO_ROMAN_NUMERAL = { 10 =&gt; 'X', 5 =&gt; 'V', 1 =&gt; 'I' }

	def to_roman
		return '' if self == 0
		ARABIC_TO_ROMAN_NUMERAL.each do | arabic_number, roman_numeral |
			return roman_numeral + (self - arabic_number).to_roman if self &gt;= arabic_number
		end
	end
end
# ..............</pre></p>
<p>Directamente elimino la línea y cambio self&gt;arabic_number por self&gt;=arabic_number. La idea es que si encuentro un numeral que sea exactamente igual al valor buscado, también puedo aplicar la regla recursiva. En este caso el resto es 0, que como sabemos no se representa en números romanos. Se soluciona devolviendo cadena vacía como caso base de la recursividad cuando el número es 0, eliminando la fea duplicación que teníamos como caso base.</p>
<p>Ahora ya puedo centrarme en hacerlo retrocompatible con Ruby 1.8. Simplemente ordeno de forma explícita la hash en orden descendiente (de mayor a menor). Un cambio trivial:</p>
<p><pre class="brush: ruby; auto-links: false; highlight: [2]; wrap-lines: false;">class Fixnum
	ARABIC_TO_ROMAN_NUMERAL = { 10 =&gt; 'X', 5 =&gt; 'V', 1 =&gt; 'I' }.sort.reverse

# ................

end</pre></p>
<p>Dicho sea de paso, esta ordenación me devuelve un array, con lo que en vez de una hash termino con un array de pares clave/valor en la constante ARABIC_TO_ROMAN_NUMERAL. Debido a que itero con el método each, y a que realmente había dejado de usar la búsqueda por clave, el cambio es transparente.</p>
<p>Ahora toca enfrentarse a la tercera fase de la especificación funcional: los casos especiales. Los romanos no escribían &#8216;IIII&#8217; para el número 4, sino &#8216;IV&#8217;. Lo mismo con el 9 que se representa como &#8216;IX&#8217; en vez de &#8216;VIIII&#8217; (esta regla es para los números romanos clásicos, la versión más primitiva no la tenía). Añado estos ejemplos y obviamente los tests fallan. Tal vez tenga que hacer un algoritmo de simplificación, de modo que si hay tres numerales seguidos iguales los sustituya por la versión simplificada. Parece difícil. Antes de complicarme la vida, y por si cuela, se me ocurre añadir &#8216;IX&#8217; y &#8216;IV&#8217; a los numerales básicos. Sorprendentemente funciona, me olvido de algoritmos complicados. Finalmente añado algunos tests con números complicados, para asegurarme que todo funciona bien. El código final es:</p>
<p><pre class="brush: ruby; auto-links: false; highlight: [2,18,19,20,26,27,28,61,62,63,64,65,66,67,68,69,70,71,72,73]; wrap-lines: false;">class Fixnum
	ARABIC_TO_ROMAN_NUMERAL = { 10 =&gt; 'X', 9 =&gt; 'IX', 5 =&gt; 'V', 4 =&gt; 'IV', 1 =&gt; 'I' }.sort.reverse

	def to_roman
		return '' if self == 0
		ARABIC_TO_ROMAN_NUMERAL.each do | arabic_number, roman_numeral |
			return roman_numeral + (self - arabic_number).to_roman if self &gt;= arabic_number
		end
	end
end

describe &quot;Roman number&quot; do
	context &quot;has basic numerals with different values&quot; do
		it &quot;I is equivalent to 1&quot; do
			1.to_roman.should == 'I'
		end

		it &quot;IV is equivalent to 4&quot; do
			4.to_roman.should == 'IV'
		end

		it &quot;V is equivalent to 5&quot; do
			5.to_roman.should == 'V'
		end

		it &quot;IX is equivalent to 9&quot; do
			9.to_roman.should == 'IX'
		end

		it &quot;X is equivalent to 10&quot; do
			10.to_roman.should == 'X'
		end
	end

	context &quot;concatenates numerals in descending order until they sum up the desired integer&quot; do
		it &quot;II is equivalent to 2&quot; do
			2.to_roman.should == 'II'
		end

		it &quot;III is equivalent to 3&quot; do
			3.to_roman.should == 'III'
		end

		it &quot;VI is equivalent to 6&quot; do
			6.to_roman.should == 'VI'
		end

		it &quot;XI is equivalent to 11&quot; do
			11.to_roman.should == 'XI'
		end

		it &quot;XV is equivalent to 15&quot; do
			15.to_roman.should == 'XV'
		end

		it &quot;XX is equivalent to 20&quot; do
			20.to_roman.should == 'XX'
		end
	end

	context &quot;converts even complex examples (to gain more trust in our implementation)&quot; do
		it &quot;XVIII is equivalent to 18&quot; do
			18.to_roman.should == 'XVIII'
		end

		it &quot;XIX is equivalent to 19&quot; do
			19.to_roman.should == 'XIX'
		end

		it &quot;XXXVII is equivalent to 37&quot; do
			37.to_roman.should == 'XXXVII'
		end
	end
end</pre></p>
<p>Como veis el código es diferente al que propuso @ecomba. Curiosamente @ialcazar me mostró <a href="https://gist.github.com/762505">la solución de @cavalle</a> que es bastante similar a la mía, seguramente porque ambos hemos optado por un enfoque recursivo. Eso sí, ninguna de las tres soluciones tiene métodos de más de 4 líneas de código <img src='http://s1.wp.com/wp-includes/images/smilies/icon_wink.gif' alt=';-)' class='wp-smiley' /> . Notad que he tomado dos decisiones de diseño importantes: me he decidido por un diseño recursivo, y los casos especiales, como &#8216;IV&#8217; o &#8216;IX&#8217;, los trato como numerales básicos. ¿Qué ocurriría si hubiéramos decidido que los casos especiales no son numerales básicos? ¿A alguien le interesa explorar este camino?</p>
<p>¿Para que nos ha servido el TDD? En este caso nos ha servido para <strong>guiar el proceso de pensamiento</strong>. <strong>Añadiendo código poco a poco puedo detectar duplicación, violaciones de principios SOLID, y otros problemas rápidamente</strong>. Es en estos momentos donde TDD+Refactor en pasos pequeños, nos obliga a parar y pensar. Hasta que no tengamos una visión más profunda del problema, no podremos avanzar, y ésta forma de trabajar nos golpea en la cabeza obligándonos a reflexionar. Sin embargo no olvidemos que el problema de los números romanos es pura algorítmica. En casos más complejos como diseño OO el TDD brilla en todo su esplendor.</p>
<p>Si queréis, podéis <a href="https://github.com/eamodeorubio/fun/commits/master/ruby_fun/romans.rb">entrar github y echarle un vistazo a todo el histórico de &#8220;baby steps&#8221; que fui haciendo</a>. ¿Alguien se anima a hacerlo en otro lenguaje?</p>
<br />Filed under: <a href='http://eamodeorubio.wordpress.com/category/metodologias/agile/'>Agile</a>, <a href='http://eamodeorubio.wordpress.com/category/metodologias/agile/refactor/'>Refactor</a>, <a href='http://eamodeorubio.wordpress.com/category/lenguajes-programacion/ruby/'>Ruby</a>, <a href='http://eamodeorubio.wordpress.com/category/metodologias/agile/tdd/'>TDD</a>  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/eamodeorubio.wordpress.com/538/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/eamodeorubio.wordpress.com/538/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/eamodeorubio.wordpress.com/538/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/eamodeorubio.wordpress.com/538/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/eamodeorubio.wordpress.com/538/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/eamodeorubio.wordpress.com/538/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/eamodeorubio.wordpress.com/538/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/eamodeorubio.wordpress.com/538/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/eamodeorubio.wordpress.com/538/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/eamodeorubio.wordpress.com/538/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/eamodeorubio.wordpress.com/538/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/eamodeorubio.wordpress.com/538/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/eamodeorubio.wordpress.com/538/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/eamodeorubio.wordpress.com/538/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=eamodeorubio.wordpress.com&amp;blog=12532304&amp;post=538&amp;subd=eamodeorubio&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://eamodeorubio.wordpress.com/2011/01/10/diseno-software-agil-3-deconstruyendo-los-numeros-romanos/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
	
		<media:content url="http://0.gravatar.com/avatar/84999f5cc6fd4e8741735e557388b0aa?s=96&#38;d=http%3A%2F%2F0.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D96&#38;r=G" medium="image">
			<media:title type="html">eamodeorubio</media:title>
		</media:content>
	</item>
	</channel>
</rss>
