Tag Archives: ingeniería del software

TDD: Un ejemplo práctico sobre como mejorar la calidad de tu código

 

Ultimamente se habla mucho de diseño ágil pero la realidad de muchas empresas de desarrollo dista mucho de implementarlo de forma eficiente o directamente de usarlo en cualquiera de sus aspectos

Y es que el agilismo es una metodología muy fácil de entender pero costosa de poner en práctica si no se hace de la manera adecuada.

Por ese mismo motivo he visto que sería interesante dedicar una entrada a explicar de forma práctica y sencilla qué es TDD y cómo se utiliza en un proyecto.

 

Lo primero de todo confesar que no soy un experto en la materia y por ello es de obligada necesidad indicar que, si quereis profundizar más en estos temas, vayais a la web www.dirigidoportests.com de Carlos Blé, autor de “Diseño Ágil con TDD” el libro de cabecera de todo aquel desarrollador que quiera empezar a trabajar con esta metodología.

Además dar las gracias encarecidamente a Javier Casal por darme las clases magistrales de TDD y la gente de 12Meses12Katas por el ejemplo práctico para compartir con todos vosotros :)

 

¿Qué es TDD (Test Driven Development)?

El diseño dirigido por test, o TDD, es una técnica de diseño e implementación de software consistente en generar las pruebas unitarias justas y necesarias para obtener la implementación de las funciones que el cliente necesita minimizando los errores que llegan a producción.

El diseño por test no solo nos ahorra implementar más de lo debido si no que nos informa de si un cambio posterior “rompe” algo de lo que ya hemos implementado y nos facilita la tarea de entregar un código más limpio y libre de errores.

TDD no se trata de escribir cientos y cientos de pruebas si no se escribir las que necesites (y cuanto más simples mejor) para cumplir las necesidades del cliente y poder, posteriormente, empezar a desarrollar para cumplir dichos requisitos.

 

Como indico en el título esto es un ejemplo práctico sobre como utilizar TDD para resolver un problema concreto por lo que he hecho uso del problema de Noviembre del 2011 de 12Meses12Katas para ilustrar este post: KataPotter

Para ello vamos a crear una biblioteca de clases C# en Visual Studio 2010 y usaremos el framework de pruebas NUnit.

 

Explicando el problema

Bien, el problema que se nos plantea es la creación de un programa que calcule el importe de una coleción de libros aplicando un determinado descuento en función de los distintos tipos de libros que compremos. Partiendo de que cada libro tiene un coste de 8€ el cliente nos indica que, si se adquieren dos libros distintos, se aplique un 5% de descuento a ambos libros, un 10% si se compran 3, un 20% para 4 distintos y un 25% para la serie completa de 5 libros.

Otra condición del cliente es que el programa obtenga el precio más económico si hay varias combinaciones posibles de packs.

 

Como entrada recibiremos un array con los códigos de los libros a comprar (de 0 a 4) y como salida obtendremos un valor double.

¡Muy bien! Ya sabemos que tenemos que hacer y que quiere el cliente por lo que vamos a escribir las primeras pruebas.

 

Pruebas Sencillas

Lo primero que debemos hacer es escribir unas pruebas sencillas que implementen los casos más básicos. La primera y más sencilla es que cuando nuestra cesta de compra esté vacia el precio total es 0. En NUnit sería así:

[Test]
public void EmptyBasket()
{
     Assert.AreEqual(0, _bookPriceCalculator.CalculateBasket(new int[] { }));
}

Sin entrar en explicar la sintaxis de NUnit simplemente indicar que esta prueba comprueba que si se le pasa un array vacio el sistema devuelve 0.

¿Cómo resolvemos esta prueba con la menor cantidad de código posible? Muy fácil:

public double CalculateBasket(int[] books)
{
     return 0;
}

¡Exacto! Esa es la solución más sencilla que hace que la prueba sea correcta. Obviamente en cuanto añadamos una segunda prueba tendremos que rehacer nuestro código pero de esto se trata TDD.

¡Ok! Vamos ha añadir una nueva prueba para indicar una nueva condición impuesta por el cliente: Cada libro vale 8€

[Test]
public void TwoSameBook()
{
     Assert.AreEqual(8 * 2, _bookPriceCalculator.CalculateBasket(new int[] { 0, 0 }));
}

En esta prueba indicamos que si se compran dos veces el libro “0” el precio total es de 16€. ¿Cómo modificamos nuestro método para que pase las dos pruebas?

public double CalculateBasket(int[] books)
{
     return books.Length * 8;
}

¡Vale! No es muy elegante pero solucionaría cualquier prueba que no implique un descuento por lo que podemos cerrar el capítulo de pruebas sencillas.

 

Añadiendo Funcionalidad: Calculando Descuentos

Nuestro cliente nos había puesto como premisa que, si se compraban dos o más libros distintos había que aplicar un descuento determinado por lo que vamos a crear una serie de pruebas de ejemplo que implementen esta funcionalidad:

[Test]
public void TwoDifferentBooks()
{
            Assert.AreEqual(8 * 2 * 0.95, _bookPriceCalculator.CalculateBasket(new int[] { 0, 1 }));
}

[Test]
public void SeveralDiscountsTwo_One()
{
            Assert.AreEqual(8 + (8 * 2 * 0.95), _bookPriceCalculator.CalculateBasket(new int[] { 0, 0, 1 }));
}

Como veis en las pruebas tan solo declaramos una entrada de datos y la solución que nuestro cliente espera. Es trabajo del desarrollador el encontrar el modo en que el código del programa satisfaga todas las nuevas pruebas sin “romper” ninguna de las anteriores ya implementadas.

La solución que se me ha ocurrido a mi es hacer una clase “BookPack” que simbolice un “paquete de libros” donde todos los libros deben de ser distintos por lo que cada compra se traduce realmente en varios “BookPacks” cada uno con su precio y descuento.

Sin tener en cuenta la última condición (que indicaba que se ha de escoger la combinación más económica), la solución más sencilla es esta:

List<BookPack> BookPacks = new List<BookPack>();

foreach (int bookCode in books)
{
     BookPack currentBookPack = null;
     
     foreach (var bookPack in BookPacks)
     {
          if (!bookPack.HasThisBook(bookCode))
          {
              currentBookPack = bookPack;          
          }
     }

     if (currentBookPack == null)
            {
                BookPacks.Add(new BookPack(bookCode));
            }
            else
            {
                currentBookPack .Books.Add(bookCode);
            }
}
return BookPacks.Sum(bookPack => BookPack.GetBookPackPrice(bookPack.Books.Count));

Donde “GetBookPackPrice” devuelve el precio del paquete en función de cuantos libros tiene:

public static double GetBookPackPrice(int quantity)
        {
            return 8 * quantity * GetDiscountPerDifferentBooks(quantity);
        }
//GetDiscountPerDifferentBooks devuelve 1, 0.95, 0.9, 0.8 o 0.75 en función de si se compran 1, 2, 3, 4 o 5 libros distintos respectivamente.

Con esto ya tenemos implementada tanto la funcionalidad básica (ningún libro o varios libros iguales) como el descuento básico por “paquetes de libros”. Sólo nos faltaría añadir la última condición del cliente: que se elija la combinación más económica a la hora de hacer los paquetes.

 

Pruebas Finales: Obteniendo el paquete más económico

No es lo mismo hacer dos paquetes de 4 libros (51.2€ en total) que 1 de 5 y otro de 3 (51.6€). Con el código anterior obtendríamos la opción más desfavorable ya que solo se crea un nuevo paquete cuando el libro actual ya se encuentra en el paquete actual y no se tiene en cuenta el importe final.

Para añadir esta nueva funcionalidad vamos a escribir la última prueba:

[Test]
        public void SeveralDiscountsFourFour()
        {
            Assert.AreEqual(2 * (8 * 4 * 0.8), _bookPriceCalculator.CalculateBasket(new int[] { 0, 0, 1, 1, 2, 2, 3, 4 }));
        }

La implementación para este caso consiste en cambiar el concepto “CurrentBookPack” que tan solo va rellenando paquetes por “CheapestBookPack” el cual compara entre los distintos paquetes y se queda con el más económico.

Como el código resultante ya es más largo y enrevesado como para ponerlo en un post mejor lo veis directamente en mi repositorio de GitHub para este ejemplo ;-):

https://github.com/vfportero/Noviembre-KataPotter/tree/master/vfportero

 

Conclusiones Finales

Creo que este es un gran ejemplo para explicar las virtudes de TDD ya que en un mismo proyecto hemos tenido que hacer 3 modificaciones que han alterado por completo el funcionamiento de la aplicación

Al principio solo teníamos que calcular importes sencillos (8 * unidades), después se añadió unos descuentos por volumen para terminar con un sistema más inteligente que se queda con la combinación más económica.

Ahora extrapola este ejemplo a un proyecto real con cientos de clases y miles de líneas y piensa que pasaría si tuvieras que hacer este tipo de cambios… asusta, ¿verdad?

Y es que ¿cuantas veces hemos “arreglado algo y roto otro cosa”? ¿cuantas veces los requerimientos del software cambian y debemos adaptarnos rapidamente a las nuevas necesidades? ¿cuantas veces programamos más de lo debido?

 

TDD ayuda a solucionar estos problemas facilitandote el modo en el que organizas tus tareas. Cuando programas primero una prueba estás abstrayendote de algoritmos y estrategias para centrarte en entender el problema y la solución exacta que quiere el cliente.

Si logras crear pruebas simples que explican una pequeña parte del código podrás tener un sistema casi perfecto cuando el producto se entregue además de ganar en flexibilidad en caso de los requerimientos cambien en medio del desarrollo.

 

Está claro que escribir pruebas antes de programar es un trabajo extra que en muchos casos no se puede asumir pero, a la larga, ahorra mucho tiempo en mantenimiento y evita problemas de código heredado.

 

TDD, como otras herramientas dentro del agilismo, solo te da una serie de “buenas practicas” que te ayudan a mejorar tu calidad como desarrollador. Está en tu mano decidir hasta que punto utilizar TDD :-)

 

Para terminar solo invitar a todos aquellos interesados en este tema a que se pasen por la web de 12Meses12Katas donde encontraran ejemplos y soluciones a problemas como este “KataPotter” que hemos explicado aquí. Os recomiendo que os junteis con ese amigo programador con el que siempre haceis el friki, compreis una caja de cervezas, y empeceis a trabajar con una de estas Katas en parejas.

Mientras uno programa una prueba el otro programa el código que la implementa y viceversa. Vereis como TDD se ve de otra manera 😉

 

¡Nos vemos Compilando!

Arquitectura MVC, ¿como puede mejorar mi aplicación?

Y es que ultimamente hemos oido mucho hablar sobre MVC pero, ¿qué es realmente y para que se usa? Empecemos desde el principio:

 

MVC son las siglas de Model-View-Controller (Modelo-Vista-Controlador) y es un patrón de la arquitectura del software descrito en 1979 por el Noruego Trygve Reenskaug.

 

El punto principal de MVC es dividir la aplicación en tres capas reales, una para datos, otra para la lógica y otra para la presentación consiguiendo que sea mantenible, escalable y reutilizable.

Para explicar en qué consiste y como funciona vamos a utilizar como ejemplo una hipotética aplicación web .NET que accede a una base de datos SQL SERVER a la que aplicamos este patrón.

  • El “Modelo“, o capa de datos, es el conjunto de clases que representan la información con la que vamos a trabajar y su lógica de negocio. En nuestro ejemplo serían las clases en las que consultamos a la base de datos SQL SERVER mediante, por ejemplo. modelos de Entity Framework.
  • La “Vista“, o capa de presentación, define el modo en el que el usuario ve los datos y como interactúa con ellos. Una página HTML con formularios sería un ejemplo claro de este tipo de capa.
  • El “Controlador“, o capa de lógica, es la que gestiona las peticiones de la Vista solicitando los datos necesarios al Modelo y adaptándolos para su correcta visualización. En .NET serían métodos que actuan como respuesta a un POST de un formulario HTML, captura los datos que el usuario ha introducido y solicita lo necesario al Modelo para retroalimentar la Vista.

 

 

Para terminar de explicar el funcionamiento vamos a platear un formulario de Login en nuestra web de ejemplo.

La Vista sería la página HTML con un <form> con dos <input> uno para el usuario y otro para la contraseña.

Al hacer submit del formulario la petición iría al Controlador que recupera esos datos y solicita al Modelo que busque si el usuario/contraseña introducidos son válidos.

El Modelo realiza la consulta a base de datos y le devuelve el resultado al Controlador que es el que determina si el intento de Login ha sido correcto o no. En caso de ser correcto iniciamos sesión en el sistema y redirijimos a una página de incio del usuario (por ejemplo), en caso de ser erroneo volvemos a la misma vista pero indicando un mensaje de error y el sistema vuelve al punto inicial en el que se espera una acción por parte del usuario.

 

Ventajas de usar MVC

 

  • Escalabilidad

La principal ventaja de separar la aplicación en tres capas reales es la escalabilidad.

Un par de ejemplos: bastaría con recargar el modelo si añades o editas una tabla o crear una nueva vista si quieres hacer una versión para navegador de dispositivo móvil.

  • Simplicidad

Otra gran ventaja es la simplicidad con la que se puede gestionar y mantener el sistema así como la posibilidad de trabajar en paralelo. Puedes tener a diseñadores trabajando en las vistas mientras que los desarrolladores se pueden centrar en el Controlador y el Modelo. ¿Qué quieres cambiar el diseño de la web? Tan solo edita el HTML y la aplicación seguirá funcionando.

  • Desarollo mediante TDD

Al tener la lógica separada de la interfaz es mucho más sencillo crear las pruebas unitarias y desarrollar mediante TDD (Test Driven Development). Sobre esto último dedicaré un artículo más adelante.

  • Rapidez y limpieza de código.

No hay ViewState, ni HTML autogenerado por controles, ni mantenimiento de estado en el código. Lo que interpreta el navegador es exactamente lo que hemos escrito. Eso hace que la página sea más ligera y cargue en menos tiempo.

  • Facilidad para el uso de jQuery

Al tener en la Vista código HTML directamente podemos integrar controles jQuery de forma más sencilla que en WebForms.

 

Conclusiones: ¿WebForms o MVC?

Como habeis podido comprobar en este punto las ventajas de usar este patrón son muchas pero no es oro todo lo que reluce.

MVC es una arquitectura muy compleja que requiere una abstracción mayor por parte del desarrollador que hace que el desarrollo sea más lento por eso solo es recomendable usarlo en ciertos tipos de proyectos.

Si lo que necesitas es hacer un prototipo o RAD, entonces utiliza WebForms.

Si necesitas que la página almacene datos y no quieres estar continuamente haciendo peticiones a la capa de persistencia, entonces utiliza WebForms.

Si tu equipo de desarrollo es pequeño y no trabajais con TDD, entonces utiliza WebForms.

 

En cambio, si tu equipo está segmentado en Diseñadores y Desarrolladores, dispones de conocimientos avanzados de JavaScript y Ajax y necesitas tener un control total del código generado MVC es el patrón que debes utilizar. Si además es un proyecto de cierta embergadura, necesitais controlar mediante pruebas unitarias y va cambiando/ampliandose de forma constante MVC es la solución.

 

Nos vemos Compilando!!

Creando la capa de datos: Entity Framework vs LINQ to SQL

Una de las cosas que más interés me ha generado durante mi vida como desarrollador es como conseguir una buena capa de persistencia, consistente, flexible y transparente para el nivel de aplicación sin mezclar consultas sql’s o crear manualmente clases que repiten funcionalidad y datos.

He trabajado con varias herramientas, desde las más rudimentarias clases estáticas con métodos que ejecutaban sql “a pelo” hasta clases generadas a mano que por debajo usaban una instancia de DataRow (que por cierto no es serializable y no se puede usar con servicios WCF); hasta que en el framework 4.0 de .NET se incluyó el Entity Framework (EF) y LINQ to Entities.

 

Pero antes, un poco de historia:

Ya en la versión 3.5 de .NET nuestros amigos de Redmond incluyeron una nueva herramienta de O/RM (object relational mapping) conocida como “LINQ to SQL”. Con LINQ to SQL podíamos modelar una base de datos relacional con clases .NET de forma automática lo que nos permitia seleccionar, editar, insertar o eliminar datos tan solo editando las clases y colecciones generadas.

Para poder trabajar con estas clases se añadió soporte para lenguaje “LINQ” (Language Integrated Query) que no es más que un modo de expresar consultas similares al sql normal contra cualquier colección (ya sea generado por el modelador de LINQ to SQL o bien creada manualmente). LINQ incluye tipado, comprobación de las consultas en tiempo de compilación, expresiones lambda y tipos anónimos e intellisense lo que lo convierte en un lenguaje para consultas mucho más potente que el sql clásico.

Con estas dos herramientas juntas podemos obtener una serie de clases generadas automaticamente de una base de datos y trabajar con ellas manipulando datos sin necesidad de escribir una sola linea SQL.

 

Más adelante, con la versión 4.0 de .NET se incluyó ADO .NET Entity Framework y su LINQ to Entities que ofrecía una nueva forma de modelar bases de datos en entidades de forma automática más compleja y flexible pero con un funcionamiento básicamente similar ya que también se trabaja mediante consultas LINQ.

 

Visto esto os preguntareis: “Pues tiene buena pinta pero…¿qué diferencias existen entre LINQ to SQL y Entity Framework?

Aunque son casi lo mismo LINQ to SQL y EF han tenido vidas paralelas y, hoy en día, EF se ha impuesto de manera aplastante. La gran diferencia es que LINQ to SQL se creó con la finalidad de ser un RAD (Rapid Application Development) por lo que se dejaron alguna cosas en el tintero que se solventaron con EF:

  • LINQ to SQL sólo permite conectarse a SQL Server y ser usado en C# o VB.NET. EF en cambio soporta varios proveedores como MySql, Oracle, SQL Server, XML, etc…
  • LINQ to SQL mapea cada tabla/vista como una clase o “entidad” sin permitir herencia, entidades lógicas o entidades de negocio. EF lo implementa completamente.

 

Como veis Entity Framewok está preparado para modelar la capa de datos de una forma más generica y flexible lo que nos permite abordar proyectos de mayor envergadura aunque si lo que buscamos es una forma rápida de modelar nuestra base de datos SQL SERVER y no necesitamos grandes florituras LINQ to SQL nos valdría perfectamente.

En futuras entradas explicaré de forma más practica como modelar una base de datos y como hacer las típicas consultas (Select, Insert, Update, Delete) con Entity Framework.

 

Nos vemos Compilando!

Nace Compilando.ES

La vida de un ingeniero del software pasa por muchas fases.

 

Al principio no le prestas mucha atención a lo que codificas y sólo quieres tener resultados lo más pronto posible sin pensar en las consecuencias; pero llega un momento (usualmente cuando te toca revisar el código meses después) que esas prisas sólo han servido para obtener un producto mediocre, poco flexible e incompresible.

Después empiezas a encontrarte problemas que ya has resuelto en otros proyectos y que has codificado de distintas formas varias veces y empiezas a construir tus propios controles o dll’s que vas usando proyecto tras proyecto para evitar la engorrosa tarea de repetir hasta la saciedad una y otra vez lo mismo. En ese momento empiezas a entender de que va esto de la Ingeniería del Software.

 

Y es que lo bonito de este mundo es que está en constante evolución.

Herramientas que pensabas eran insustituibles meses después están desfasadas. Metodologías que te vendían como definitivas solo son un paso más para la obtención de un producto más limpio y eficaz. Frameworks que aportaban potencia hasta ese momento inalcanzable se convierten en antiguallas con el paso del tiempo.

 

Y lo mismo pasa con los Ingenieros del Software. Esta es una profesión de alto riesgo donde no estar al día significa que has perdido valor, donde no pasarte gran parte de tu tiempo investigando y leyendo a los grandes hace que te quedes un paso por detrás. Y en este mundo, cuando la tecnología te supera, es hora de dejarte a un lado y dejar pasar a los que vienen fuerte apretando por detrás.

 

Es por este mismo motivo que me he animado a crear compilando.es, un pequeño espacio en Internet en el cual depositar mi granito de arena sobre mis experiencias como desarrollador, analista y jefe de equipo y sobretodo un medio en el que poder ayudar y orientar al que tenga dudas y está empenzando con ilusión en este basto mundo que es la Ingeniería del Software.

¿De qué se hablará aquí?

  Sobre todo de tecnologías Microsoft que son las que me han acompañado (hasta ahora y esperemos que por muchos años) en mi aventura como desarrollador pero siempre desde un punto de vista práctico y orientado a aportar, aunque sea minimante, algo de valor y calidad.

.NET, Sql Server, jQuery, servidores Windows, IIS, Visual Studio, metodologías y ayudas para el programador son las principales areas que se tratarán en esta web siempre que tenga el tiempo suficiente para escribir y organizar mis ideas.

 

¿Quien escribe estas líneas?

Me llamo Víctor Fernández Portero, trabajo como Analista, Desarrollador y Jefe de Proyectos desde el 2006 en Domitienda.com, una de las empresas de hosting españolas más especializadas y preparadas en lo que a servicios Windows se refiere.

 

En fin, espero que os paseis por aquí a menudo si os interesa este apasionante mundo y si no os quereis perder nada no dudeis en subscribiros al RSS o seguid mi cuenta de twitter.

 

Nos vemos Compilando!!!