jueves, enero 17, 2008

TDD 4 everyone

Desconocido para muchos (para mí hasta hace año y medio), de los pocos que lo conocen, son menos los que lo usan (ni hablo de los que lo usan bien...). No obstante, hay gente que apuesta por TDD y aporta su granito de arena con aplicaciones que lo faciliten y con documentación que realmente merece la pena.

Aquí quiero hacer un breve compendio de recursos, aplicaciones y de blogs que nos acercan TDD, para que nos demos cuenta de que TDD no es exclusivo de una tecnología, es una forma de trabajar:

TDD para Javascript en ASP.NET:

TDD para Java:

Nota: alguien más habituado que yo a trabajar con Java podrá rellenar esta lista, porque en este campo estoy bastante limitado

TDD para .NET

Hay mucha más información, para ello tenéis que ir a una de las mejores fuentes de información sobre TDD... Google.

Un saludo @Madrid

¿TDD de propiedades?

Las propiedades tienen cierta lógica, de validación por ejemplo. Por ello, no sonaría descabellado que se lanzaran tests contra esas propiedades, pero ¿es realmente necesario?

En este caso es imposible decir un "Sí" o un "No" rotundo. Depende de la cantidad de lógica que tengamos en la propiedad en cuestión, puede ser o no necesario. Muchas veces usamos las propiedades cuando realmente un campo nos proporciona la misma funcionalidad, o cuando usamos clases que requieren inicialización, para inicializarlas y que no nos devuelvan NullException.

Cómo pone en este mensaje de un foro de Yahoo Groups da una guía bastante buena para esta duda y otras muchas:

Here's a rule of thumb for you: don't test anything when the complexity of the test approaches or surpasses the complexity of the code being tested (unless defect-free code is imperative, in whichcase you should expect to pay a high price to achieve it). In the caseof getters and setters, you're as likely to make an error in the test as you are in the code being tested (assuming you manually construct setters and getters; if not, then there can be no mistakes).

En resumen, no hagas tests de algo si los tests que lo prueban son igual de complicados o más que lo que está probando. Igual que puedes cometer un error en la aplicación, puedes cometerlo en el test.

Un saludo @Madrid

¿Por qué usamos y por qué no usamos TDD?

Bueno chicos, volvemos al TDD, que ya llevaba mucho tiempo desde el último artículo en este sentido. La discusión que quiero plantear hoy es ¿Por qué usamos TDD? y ¿Por qué no usamos TDD?

La verdad es que TDD no es una de las técnicas más utilizadas dentro de las metodologías. He tenido la suerte de conocerla y utilizarla en casos reales, que es donde se ve qué es lo que aporta y que es lo que no.

Varias veces hemos visto el famoso gráfico de los costes de los cambios según la fase en la que está el proceso. Evidentemente, un cambio en la fase de requisitos afecta bastante menos que un cambio cuando la aplicación está a punto de entregarse. Para refrescar la mente, dad un vistacillo a esta página.

Partiendo de que estamos de acuerdo con ese gráfico y, asumiendo que siempre ha habido, hay y habrá cambios no planeados en nuestra aplciación (cambios en los requerimientos, errores en el diseño que obligan a tocar módulos, mejora y optimización del rendimiento...), tenemos que encontrar una forma de poder absorver esos cambios con el mínimo impacto.

La solución es el desarrollo iterativo. Antes de aplicarlo, leed este artículo para poder aplicarlo lo mejor posible. La base de este modelo, es ir desarrollando la funcionalidad de mi aplicación poco a poco. Simplificando mucho este proceso, podríamos tener el siguiente caso con la tan manida calculadora.

  1. Hablamos con el cliente y nos dice que quiere una calculadora. Pero no quiere una calculadora normal y corriente, quiere una adaptada a su negocio. Iniciamos la captura de requisitos.
  2. Conforme llegan los primeros requisitos (que sume y que reste), el equipo de desarrollo comienza a implementar esas dos funcionalidades.
  3. Para cuando nos llegan otros dos requisitos (multiplicar y dividir) nuestra aplicación ya tiene el código necesario para sumar y restar, y estamos probándolos.
  4. El equipo de desarrollo ha acabado de probar los dos primeros requerimientos y empieza a desarrollar los otros dos. Mismo procedimiento: implementacion + pruebas + correccion de errores.
  5. Entre medias, el usuario quiere ver una demo de lo que vamos haciendo hasta ahora. Como nos movemos por funcionalidades concretas, podemos enseñarle la parte de sumar y restar. En caso de que hubieramos hecho todo en bloque, no tendríamos nada acabado, y no podríamos enseñar nada.
  6. Una vez vista la demo, nos dicen que no se deberían poder meter negativos en la suma, pero sí en la resta. El equipo de desarrollo adapta esa parte de la aplicación. La resta no se toca y siguen trabajando con la multiplicación y la división.
  7. Pasa el tiempo y, tras repetirse los puntos 1-6 varias veces, se entrega la aplicación a los usuarios para un UAT (test de aceptación del usuario). Concluyen que falta funcionalidad, que no se acordaron de decirnos porque lo daban por supuesto... No pasa nada, volvemos al punto 1, sabiendo que el resto de la aplicación no debería tener excesivo impacto.

Esto no es siempre tan fácil y tan teórico. Surgen prisas y nos saltamos puntos. O juntamos puntos. Además, el trabajo en equipo tiene particularidades que hacen que algunos pasos sean más complicados que otros.

Este desarrollo por ciclos se coplementa muy bien con TDD. Tests que prueban la funcionalidad (tanto que se cumplen los requisitos, como que los resultados son los correctos). Esos tests siempre están y me pueden decir qué es lo que debo hacer. Como dice Dan North en su blog:


I had introduced a bug. Bad me. Solution: Fix the bug.
The intended behaviour was still relevant but had moved elsewhere. Solution: Move the test and maybe change it.
The behaviour was no longer correct – the premise of the system had changed. Solution: Delete the test.

Son un punto de partida. Nueva funcionalidad necesitará nuevos tests, pero los que estén no cambiarán. Cambios en la funcionalidad necesitarán cambios en los tests e, incluso, algunos nuevos. Errores en la lógica de la aplicación necesitarán cambios en los tests o más tests o tests más precisos.

Nunca tengais miedo de cambiar un test si veis que no prueba lo que debe de probar.

Tras esta introducción, vamos a analizar las preguntas del principio:

¿Por qué no usamos TDD?

Empezamos con la negativa. Las causas más comunes son:

  1. No sabemos que existe, o, si lo sabemos, no sabemos cómo se aplica. Efectivamente, nadie nace sabido, pero existe una cantidad brutal de libros y de documentación sobre Agile, TDD, BDD, Testing...
  2. Es dificil montar un equipo que sepa usar TDD, y sin miedo. Algún día debe ser el primero. Por esa regla de tres, nadie habría empezado a usar OOP o los Web Services. Ante todo, que la gente que debe enseñarlo, se haya documentado muy bien y tenga una mínima experiencia.
  3. Tardamos más en desarrollar la aplicación. Esto es verdad, pero los que lo dicen como excusa deben decir también que el desarrollo es sólo una de las fases de un proyecto, que generalmente no llega a la mitad del tiempo del proyecto. Se alarga la fase de desarrollo, pero a cambio, se acortan la otras. Para ser más precisos, no es que se acorten, sino que se solapan.
  4. Mantener Tests + Codigo es más costoso que Mantener Código. Falso. En una aplicación donde un cambio afecta a 6 proyectos y 40 clases, es mucho más sencillo cambiar el código y ejecutar automáticamente los 300 tests que haya, para ver si afecta en algún otro punto, que ponerte a probar la aplicación exhaustivamente punto por punto y opción por opción.
  5. Tener tests, añade labor de documentación. Sí, totalmente de acuerdo, pero eso era bueno, ¿no? Más documentación, más informción, mejor mantenibilidad.
  6. Desconocimiento de herramientas. Visual Studio Team System 2005 integra el desarrollo y los tests, y permite automatizarlos. Visual Studio 2008 también trae los proyectos de test y, para los más humildes, siempre podéis usar NUnit junto con una Express Edition.

Y ahora, ¿Por qué usamos TDD? Muchas de las respuestas se han dado en los 6 puntos anteriores, pero podemos añadir más.

  1. Es una garantía de funcionamiento. Con unos tests bien diseñados, el hecho de pasar todos los tests, implica que nuestro código cumple los requisitos.
  2. Implica mayor conocimiento de la aplicación. Diseñar e implementar un test requiere saber exactamente qué es lo que debe de ejecutar nuestra lógica. Es decir, nos permite ver una caja negra que debe de cumplir los test, que va a hacer que nos centremos en QUÉ hace (funcionalidad) y no en COMO lo hace (código).
  3. No es exclusivo de un lenguaje. No es sólo de C#, ni VB.NET. Ni siquiera es exclusibo a .NET. Se puede usar en Java. Alguien que sabe TDD en un lenguaje lo sabe en todos.
  4. Mezcla gestión de proyecto con desarrollo. Permite que los desarrolladores tengan una visión más global de la aplicación, porque deben saber los requisitos para poder desarrollar los tests.
  5. Permite un análisis de efectividad. Cuanta más información tengamos de la evolución de un proyecto, mejor podremos detectar errores y subsanarlos, bien durante el desarrollo del proyecto, bien en el post-mortem. Los tests aportan información de cuanto código está testeado, cuanto funciona y cuanto no, cuanto influye un cierto cambio...
  6. Da una garantía entre fases. Saber en plena fase de desarrollo que el tiempo de test se reduce da cierta tranquilidad.

Estos son algunos puntos a favor de TDD. Por supuesto, usarlo implica riesgos. Pero, no usarlo también.

Estáis invitados a dar vuestra opinión al respecto.

Saludos @Madrid

miércoles, enero 16, 2008

Model View Controller Pattern

No se como es posible, pero, da igual que la aplicación que se está desarrollando sea de Windows Froms o ASP.NET, siempre aparecen líneas de código en los formularios, que no deberían estar allí.

Como pone en este artículo, esto dificulta testear los métodos de ese formulario (habria que hacerlo a mano). Por ello, debemos intentar separar la capa de presentación de la lógica de negocio.

Se puede utilizar el MVC (patron modelo-vista-controlador), que permite separar al máximo lo que corresponde al UI, al BL y la interacción entre ambas. Para ayudarnos, se está desarrollando un MVC Framework (que debería haber salido ya, pero no tengo noticias de ello; si alguien las tiene, feedbacks are welcome). la verdad, tengo ganas de que nos llegue ya esa preview para darle un vistacillo, porque muchas veces no usamos este tipo de patrones, simplemente, porque no abemos que existen.

Aqui teneis un walkthrough para implementar MVC sobre ASP.NET y aquí la guía dentro de la cual está metida, que tiene un link a la versión PDF, para que lo leais en el metro.

Un saludo @Madrid

lunes, enero 14, 2008

SPOIL: Simplificando el acceso a SQL

No te acostarás sin saber una cosa más, pero es que hoy estoy aprendiendo de tirón unas cuantas.
¿Qué es SPOIL? Son las siglas de Stored Procedure Object Interface Layer
Vale, pero ¿Que es SPOIL? Vale, lo pillo. SPOIL es algo así como usar el código que otros han escrito y probado, para que tu código sea más sencillo (programación orientada a objetos, vamos). Los chicos de Microsoft se han currado una librería que hace lo siguiente:
  • Permite un mapeo más eficaz entre tu DAL y la base de datos (en SQL, eso sí). Esto es, que si tengo que llamar a un SP que se llama Get_LastName y me devuelve el apellido de un usuario a partir de su ID (un entero), bastaría con que creara un método en el DAL con esa firma. Es decir, public string Get_LastName(int ID).
  • La propia librería se encarga de la converión de parámetros .NET a parámetros SQL. Simplemente hay que especificarle la cadena de conexión y el mapeo de parámetros.

Ya sabemos lo que es, pero, ¿es útil? Buena pregunta. He hecho algunas pruebas, pero no lo he usado en ninguna aplicación "real". Parece que se simplifica el mantenimiento, pero SOLO PARA SQL SERVER. Así, nos libramos de arrays conteniendo parámetros de SQL y líneas y líneas inicializándolos.

En contra, parece que se condensa demasiado el código, y a la hora de buscar errores tendremos que analizar en qué punto exacto está fallando (se acabó el típico mensaje de error y que sepas exactamente a qué parámetro se refiere). Además, debemos mantener una coherencia entre la nomenclatura en el código y en la base de datos. Otro contra es que usa Reflection, algo muy útil, pero muy lento. Tendremos que valorar el trabajo que ahorramos - el tiempo de procesador que añadimos.

En cualquier caso, os invito a hacer unas cuantas pruebas. Por lo menos el walkthrough que nos ofrecen en la MSDN.

Un saludo @Madrid

Errores comunes (I):"Esta aplicación es demasiado pequeña para desarrollarla por capas"

"Esta aplicación es demasiado pequeña para desarrollarla por capas", "Para dos llamadas a base de datos, en vez de usar procedimietnos almacenados, lo escribo a fuego en el código", "Si solo tengo 5 formularios, ¿por qué usar CSS?",...

Aquí van 3 frases que muchos hemos oído y dicho (me incluyo en ambos grupos, muy a mi pesar). Hay muchas más y la idea de esta sección que hoy se inaugura en este blog es que caigan esos mitos que dicen que "sólo las grandes aplicaciones se desarrollan siguiendo patrones, técnicas para escalabilidad, seguridad...".

Así que hoy empezamos con la primera:
"Esta aplicación es demasiado pequeña para desarrollarla por capas"

¿Quien no ha oído alguna vez esta frase? Generalmente viene acompañada de expresiones como "no tenemos tiempo para andar haciendo capas"... Hombre, si la vida de tu aplicacion es de un par de meses, y se compone exclusivamente de un formulario con dos textBoxes, pues puede que tengas razón. Pero es que la mayoría de las aplicaciones tiene varios formularios, que modifican y leen datos en una base de datos y que procesan algún tipo de información, ¿no?

Basta con que la aplicación deba acceder a base de datos, para que nos planteemos seriamente meter una capa DAL (Data Access Layer). No hace falta meterla en otro proyecto de la solución. Basta con crear otra clase. Lo importante es que todo esté estructurado.
Puede que mañana, esa aplicación que ahora de basa en Acces, pase a basarse en SQL Server (o MySQL, Oracle...) y entonces tendré que tocar clases que no debería tener que tocar.
Y si trabajo en equipo, la justificación es mucho más obvia. Si el experto en aplicaciones y el experto en bases de datos no es la misma persona, es mejor que esté en dos clases distintas, para que puedan trabajar a la vez. Y si el experto en interfaces no coincide con ninguno de los otros, necesitaremos 3 capas...

Por capas, no quiero decir que deba estar cada una en una máquina, insisto, sino es simplemente a nivel de organización (podeis dar un ojo a este post, para ver la opinion que suscita la separación física). En este artículo, David Hayden, nos compara también la división en layers y la de tiers, pero además hace un inciso en la importancia del TDD para mantener las aplicaciones divididas en layers y simples.

¿Cuantas capas debo usar? Bueno, .NET nos permite diferenciar la presentación del código de la página. En caso de que la aplciación sea muy simple, podemos usar ese código para meter la capa de negocio. Pero en caso de que algo, lo que sea, de esa capa de negocio se use en 2 o más formularios, deberíamos usar otra clase aparte. Para el diálogo aplicacion-base de datos, debería haber otra capa. Sirva como truco, que ninguna clase a parte de estas del DAL debería importar ninguna librería que se llame SQL, o JDBC, u Oracle...

Bueno, la próxima vez intentaremos matar otro de esos mitos que ayudar, lo que se dice ayudar, no ayudan demasiado.

Un saludo,

Los 10 consejos para escribir aplicaciones Web con alto performance

Antes de nada, disculparme por lo de "performance", pero no se me ocurría más que "rendimiento" y eso sería una sintesis excesiva y simplona en este caso.
En este artículo, Rob Howard nos da 10 consejos que deberíamos tener en cuenta todos los desarrolladores de aplicaciones Web. Mucho ojito al punto 1 (no se me había ocurrido, pero ya que lo comenta, se me ocurren una barbaridad de aplicaciones junto con la Enterprise Library) y al punto 9 (ya la he usado en alguna aplicación y, si tienes mucho código estático, como css y javascript externo, funciona genial).

El link es: http://msdn.microsoft.com/msdnmag/issues/05/01/ASPNETPerformance/

Ante todo, recomiendo fervientemente hacer caso de uno de los párrafos iniciales:

you can only learn how to write high-performance Web applications when you're faced with either fixing performance problems or running a high-throughput site.

Algo así como el castizo dicho de "la experiencia es la madre de la ciencia". Cada problema es una oportunidad de aprender, un reto. Y los retos nos hacen crecer (que bonito).

Un saludo :-) @Madrid

viernes, enero 11, 2008

Seguridad a nivel de página en ASP.NET

Buenas a todos, este es uno de los últimos post desde Madrid, y va a tratar sobre seguridad.

Cuando planificamos una aplicación, planificamos también quien va a tener acceso a la aplicacion que estamos desarrollando. La posibilidad más extendida es utilizar el web.config para configurar que usuarios van a poder acceder al site y quienes no.

Sin embargo, aqui vamos a analizar otra posibilidad que permite aplicar una cierta lógica a la autorización, más alla del simple "tú sí", "tú no", más orientada a objetos, pero menos a la escalabilidad que permiten los ficheros de configuración.

Supongamos que tenemos la página Default.aspx, Pagina1.aspx y Página2.aspx, y que quiero que sólo ciertos usuarios puedan acceder a esas páginas. Es un ejemplo simple que se hace facilmente con el web.config. Pero vamos a hacerlo con herencia.

Creamos una clase que se llame BasePage.cs, que herede de Page. Sobreescribimos el evento Init de la página, que nos permitirá ejecutar las acciones que queramos antes si quiera de que se genere el formulario.

La página quedaría así:


public class BasePage : Page
{
public BasePage() { }
protected sealed override void OnInit(EventArgs e)
{
if (!ValidateAccess())

throw new System.Security.Authentication.AuthenticationException();
base.OnInit(e);
}


private bool ValidateAccess()
{
WindowsIdentity identidad = WindowsIdentity.GetCurrent();
return (identidad.Name.Contains("nombreUsuario"));
}
}


Por supuesto, en el método ValidateAccess podríamos meter tanta lógica como quisieramos. Podríamos acceder a base de datos para comprobar si ese usuario tiene permiso para acceder en este momento a esa página, por ejemplo.

A partir de aqui, todas las páginas que hereden de esta clase, ejecutarán esa validación en el Init. Además, puesto que hemos incorporado la clausula "sealed", las páginas que hereden de nuestra clase no podran sobreescribir el método.

¿Y si el comportamiento no es el mismo para todas las páginas? Bueno, es más que probable que unas páginas tengan una lógica determinada, otras otra. Bastará con crear tantas clases como BasePage como criterios de seguridad tengamos y hacer heredar cada página de su correspondiente base.

Otra mejora consistiria en hacer el metodo ValidateAccess "virtual" para que cada página personalice su método para la validación.

Por supuesto, esto no debe aplicarse sin más. Hay ue analizar si es mejor este metodo que usar una distribución en carpetas, cada una con su Web.config. Queda a criterio del desarrolador.

Un saludo a todos :-)