El Blog de Ana Buigues » Desarrollo http://anabuigues.com Wed, 07 Dec 2011 16:07:47 +0000 es-ES hourly 1 http://wordpress.org/?v=3.4 Diviértete practicando TDD con Pulse y TDGotchi http://anabuigues.com/2011/09/20/diviertete-practicando-tdd-con-pulse-y-tdgotchi/ http://anabuigues.com/2011/09/20/diviertete-practicando-tdd-con-pulse-y-tdgotchi/#comments Tue, 20 Sep 2011 17:41:33 +0000 Ana Buigues http://anabuigues.com/?p=3597 El Test Driven Development  o desarrollo guiado por pruebas es una técnica de diseño de software que se basa en tres sencillos pasos:

  1. Rojo: escribimos la prueba primero cuando la funcionalidad está todavía por implementar, provocando el rojo.
  2. Verde: escribimos el código más sencillo que haga que la prueba funcione, provocando el verde.
  3. Refactorización: arreglar el código, extrayendo métodos, quitando duplicados, mejorando el nombre de métodos, clases, atributos…

Es importante que sigamos los pasos al pie de la letra, porque de lo contrario, no llegaremos a exprimir al máximo la técnica como herramienta de diseño.

Pulse y TDGotchi son dos plugins de Eclipse que nos ayudan a divertirnos mientras practicamos TDD.

Pulse

Pulse hace una analogía a lo que sería la representación de los latidos de nuestro corazón en los monitores de los hospitales, de forma que nos muestra nuestro pulso practicando TDD. Cuando obtenemos un rojo en nuestros test se mostrará un pico hacia abajo, cuando obtengamos un verde se mostrará un pico hacia arriba y cuando refactorizemos se mostrará un pequeño pico azul hacia arriba. Se muestra como una vista en Eclipse.

¿Y para qué nos sirve? pues para comprobar que realmente seguimos los pasos de TDD, a mi me ayudó para darme cuenta de que algunas veces me saltaba algún paso. Además podemos guardar nuestras sesiones de pulsos para posteriormente ver nuestro progreso, o compararlas con otros compañeros a modo de pique por ver quién lo hace mejor :P

TDGotchi

TDGotchi funciona como los famosos tamagotchi que se pusieron de moda hace tiempo (yo tuve uno). Es una mascota virtual que se alimenta de tus tests y tus refactorings. El sistema de puntuación para alimentar a nuestra mascota es el siguiente:

Como veis, obtener un doble rojo es penalizado de una forma bastante elevada así que cuidado con ellos porque cuando realizamos tres o cuatro de ellos la puntuación negativa es tan alta que casi imposible de remontar, lo bueno (o malo según se vea) es que cuando abrimos de nuevo nuestro Eclipse, la puntuación vuelve a estar a 0.

La mascota irá aumentado o disminuyendo de nivel, dependiendo de nuestra puntuación, nos podemos convertir en un zombi con una puntuación negativa o ir mejorando nuestro nivel cuanto mayor sea la puntuación obtenida.

Este plugin ayuda a seguir el sistema de tres pasos de TDD a raja tabla, ya que nadie quiere convertirse en un zombie!!!

Por último felicitar a su creador @Sebastian por el gran trabajo realizado y hacer que practicar TDD sea tan divertido.

]]>
http://anabuigues.com/2011/09/20/diviertete-practicando-tdd-con-pulse-y-tdgotchi/feed/ 12
Implementación de un Scaffolding con Grails http://anabuigues.com/2011/09/12/implementacion-de-un-scaffolding-con-grails/ http://anabuigues.com/2011/09/12/implementacion-de-un-scaffolding-con-grails/#comments Mon, 12 Sep 2011 17:47:13 +0000 Ana Buigues http://anabuigues.com/?p=3604 Problema: necesito crear una interfaz web sencilla para rellenar una base de datos.

Solución: realizar un scaffolding con Grails

¿Qué es Scaffolding?

El Scaffolding es un término introducido por Rails y que está presente en otros frameworks como Grails, permite la generación automática de código para las cuatro operaciones básicas de cualquier aplicación que son la creación, lectura, edición y borrado, en inglés se conoce como CRUD. La idea es que partiendo del esquema de base de datos, generar el código necesario para implementar el CRUD. En Grails se consigue escribiendo muy pocas líneas de código.

Grails permite dos tipos de scaffolding, dinámicos y estáticos. En el scaffolding dinámico el código se genera en tiempo de ejecución, de modo que  cualquier cambio en las clases de dominio genera un nuevo scaffolding,  el estático, genera código estático tanto de vistas como de controladores de forma que después podemos modificarlo como queramos.

Para mi problema, con el scaffolding estático me salgo.

Crear el proyecto Grails

Para la creación del proyecto he utilizado el Netbeans, bien te descargas la versión del Netbeans que incluye Grails o bien lo instalas como un plugin desde el Netbeans. Al crear el proyecto veremos la siguiente estructura:

Las partes que nos interesan son:

  • Configuration: entre otras cosas contiene los ficheros de configuración de la base de datos (DataSource.groovy). Por defecto viene configurado hsqldb. Si queremos otra base de datos hay que cambiar la configuración.
  • Controllers: donde crearemos los controladores.
  • Domain Classes: donde crearemos las clases de dominio.

Implementación del Scaffolding

Primero he cambiado la configuración de la base de datos a Mysql:

dataSource {
    pooled = true
    driverClassName = "com.mysql.jdbc.Driver"
    username = "root"
    password = ""
}
development {
        dataSource {
            dbCreate = "update" // one of 'create', 'create-drop','update'
            url = "jdbc:mysql://localhost:3306/clm_web"
        }
}

Creamos las clases de dominio que necesitemos, para ello, hacemos click derecho sobre Domain Classes -> Nuevo -> Grails Domain Class. Por defecto todas las propiedades en un objeto de dominio son obligatorias, y grails realiza una validación automática en el momento de guardar el objeto en base de datos. Para controlar la validación de las propiedades podemos definir restricciones mediante la palabra reservada constraints.

class Category {
    static mapping = {
        table 'categories'
    }
    static constraints = {
        id(blank:false,nullable:false)
        seo_url(blank:false,nullable:false)
        title(blank:false,nullable:false)
        description(blank:false,nullable:false)
    }
    Integer id
    String seo_url
    String title
    String description
}

Para cada uno de los dominios creamos un controlador para los que se desee tener un scaffold, hacemos click derecho sobre Controllers -> Nuevo -> Grails Controller.

Modificamos el controlador de la siguiente forma:

class CategoryController {
    static scaffold = true
}

Lanzamos las aplicación y en la página inicial podremos ver un enlace que nos lleva al CRUD del objeto de dominio que hemos creado. Si queremos cambiar el orden en que muestra los campos, es tan simple como cambiar el orden en el código del objeto y reiniciar.

Las vistas que ofrece son las siguientes:

  • Listado

  • Añadir un elemento nuevo

  • Modificar o borrar elementos ya creados

]]>
http://anabuigues.com/2011/09/12/implementacion-de-un-scaffolding-con-grails/feed/ 16
Code Kata – FizzBuzz http://anabuigues.com/2011/03/31/code-kata-fizzbuzz/ http://anabuigues.com/2011/03/31/code-kata-fizzbuzz/#comments Thu, 31 Mar 2011 16:41:59 +0000 Ana Buigues http://anabuigues.com/?p=3437 Siguiendo con la iniciativa de 12meses12katas paso a contaros el desafío de este mes, en si el problema es muy muy sencillo, la idea es la siguiente:  para el intervalo de números entre 1 y 100, si uno de ellos resulta múltiplo de 3 o contiene un 3, el resultado debe ser la palabra “Fizz”, si el número es múltiplo de 5 o contiene un 5, el resultado debe ser la palabra “Buzz”, si el número es múltiplo tanto de 3 como de 5, el resultado debe ser “FizzBuzz”. ¿Sencillo verdad?

Bueno, nos ponemos a ello, este mes he decidio realizarla en Javascript, ya que nunca he realizado TDD sobre Javascript y tenía mucha curiosidad. Así que lo primero fué investigar que frameworks hay disponibles y para mi asombro he visto que hay muchos! como por ejemplo QUnit, jqUnit, JsUnit, YUI Test, JSTestDriver, Jspec, Inspect, Jasmine etc… yo me he decantado por Jasmine, ya que es muy sencillito de utilizar, su sintaxis es muy clara y apenas requiere configuración. Además tiene una interfaz para mostrar el resultado de los test, la podeís ver al final del post.

Como siempre recomendaros que os paséis por github del proyecto para ver las distintas soluciones que están aportando a la iniciativa.

A continuación os dejo el código de la kata

function FizzBuzz() {
};
FizzBuzz.prototype.fizz = "Fizz";
FizzBuzz.prototype.buzz = "Buzz";
FizzBuzz.prototype.say = function(number) {
 var result = "";
 if (this.isMultipleOfThree(number) || this.containsTree(number))
 result += this.fizz;
 if (this.isMultipleOfFive(number) || this.containsFive(number))
 result += this.buzz;
 if (result.length == 0)
 result += number;
 return result;
};
FizzBuzz.prototype.isMultipleOfThree = function(number) {
 return number % 3 === 0;
};
FizzBuzz.prototype.isMultipleOfFive = function(number) {
 return number % 5 === 0;
};
FizzBuzz.prototype.containsTree = function(number) {
 return number.toString().indexOf('3') != -1;
};
FizzBuzz.prototype.containsFive = function(number) {
 return number.toString().indexOf('5') != -1;
};

Los tests realizados con Jasmine

describe("FizzBuzz", function() {
 var fizzBuzz;
 beforeEach(function() {
 fizzBuzz = new FizzBuzz();
 });
 it('should return number', function() {
 expect(fizzBuzz.say(2)).toEqual('2');
 expect(fizzBuzz.say(4)).toEqual('4');
 expect(fizzBuzz.say(7)).toEqual('7');
 expect(fizzBuzz.say(19)).toEqual('19');
 });
 it('should return Fizz', function() {
 expect(fizzBuzz.say(3)).toEqual('Fizz');
 expect(fizzBuzz.say(13)).toEqual('Fizz');
 expect(fizzBuzz.say(18)).toEqual('Fizz');
 expect(fizzBuzz.say(96)).toEqual('Fizz');
 });
 it('should return Buzz', function() {
 expect(fizzBuzz.say(5)).toEqual('Buzz');
 expect(fizzBuzz.say(20)).toEqual('Buzz');
 expect(fizzBuzz.say(95)).toEqual('Buzz');
 expect(fizzBuzz.say(100)).toEqual('Buzz');
 });
 it('should return FizzBuzz', function() {
 expect(fizzBuzz.say(15)).toEqual('FizzBuzz');
 expect(fizzBuzz.say(35)).toEqual('FizzBuzz');
 expect(fizzBuzz.say(54)).toEqual('FizzBuzz');
 expect(fizzBuzz.say(75)).toEqual('FizzBuzz');
 expect(fizzBuzz.say(90)).toEqual('FizzBuzz');
 });
});

Aquí os muestro la interfaz que nos ofrece Jasmine para ver el resultado del los test:

]]>
http://anabuigues.com/2011/03/31/code-kata-fizzbuzz/feed/ 7
Code Kata – RomanNumerals http://anabuigues.com/2011/02/15/code-kata-febrero-romannumerals/ http://anabuigues.com/2011/02/15/code-kata-febrero-romannumerals/#comments Tue, 15 Feb 2011 21:49:25 +0000 Ana Buigues http://anabuigues.com/?p=3391 Siguiendo con la iniciativa lanzada por 12meses12katas en la que ya participé el mes pasado realizando mi primera code kata, este mes sigo experimentando en el mundo de las katas. Recomiendo a todo programador, que si tiene un poco de tiempo (las katas se realizan en un tiempo máximo de 2 horas) que prueben la experiencia, ya que estos ejercicios te permiten mejorar la técnica de desarrollo, aplicando TDD, que implica escribir los tests primero, provocar un fallo, implementar la corrección del fallo y refactorizar.

La kata de este mes trata de resolver el problema de las conversiones entre números enteros y romanos.  Para hacer que la kata sea un reto mayor, he decido resolverla en Python que representa un poco más de dificultad que si la realizase en Java, ya que estoy más acostumbrada a programar en Java, En Python soy una principiante,  por lo que seguramente el código escrito para solucionar la kata se podría mejorar, así que sí veís algún fallo no dudeís en comentarlo!

Podeís ver las distintas soluciones que estan aportando a la iniciativa desde el github del proyecto. Os aconsejo que os paseís por ahi para ver la multitud de soluciones que se pueden dar a un mismo problema y la diversidad de lenguajes de programación con la que se resuelven.

A continuación os dejo el código de la kata

class RomanNumerals(object):
    def __init__(self):
        #inicializaciones para la conversión de entero a romano
        self.values =[ 1000, 900, 500, 400, 100, 90, 50, 40, 10, 9, 5, 4, 1 ]
        self.symbols =[ "M", "CM", "D", "CD", "C", "XC", "L", "XL", "X", "IX", "V", "IV", "I" ]
        #inicializaciones para la conversión de romano a entero
        self.value =[ 1000, 500, 100, 50, 10, 5, 1 ]
        self.symbol = "MDCLXVI";
    def intToRoman(self, num):
        '''
            Realiza la conversión de un número entero a romano.
        '''
        output = ""
        index = 0
        #finalizamos cuando el número es 0
        while num > 0:
            while num >= self.values[index]:
                #añadimos el símbolo a la solución
                output = output + self.symbols[index]
                #restamos el valor númerico
                num = num - self.values[index]
            index = index + 1
        return output
    def romanToInt(self, num):
        '''
            Realiza la conversión de un número romano a entero
        '''
        indexSymbol = 0
        output = 0
        index = 0
        valid = True
        lastValue = 0
        while valid and index < len(num):
            #obtenemos el símbolo
            car = num[index]
            #obtenemos el índice del símbolo
            indexSymbol = self.symbol.index(car)
            if(indexSymbol >= 0):
                #sumamos su valor correspondiente
                output = output + self.value[indexSymbol]
                # si el valor es mayor que el último valor, tenemos que restar el último valor sumado
                if self.value[indexSymbol] > lastValue:
                    output = output - 2 * lastValue
                lastValue = self.value[indexSymbol]
            else:
                valid = False
            index = index + 1
        return output

Con su correspondiente test

import unittest
from RomanNumerals import RomanNumerals
class Test(unittest.TestCase):
    def setUp(self):
        self.roman = RomanNumerals()
    def testSimple(self):
        self.checkConversion(1,"I")
        self.checkConversion(4,"IV")
        self.checkConversion(5,"V")
        self.checkConversion(9,"IX")
        self.checkConversion(10,"X")
        self.checkConversion(40,"XL")
        self.checkConversion(50,"L")
        self.checkConversion(90,"XC")
        self.checkConversion(100,"C")
        self.checkConversion(400,"CD")
        self.checkConversion(500,"D")
        self.checkConversion(900,"CM")
        self.checkConversion(1000,"M")
    def testTens(self):
        self.checkConversion(11,"XI")
        self.checkConversion(12,"XII")
        self.checkConversion(13,"XIII")
        self.checkConversion(14,"XIV")
        self.checkConversion(19,"XIX")
        self.checkConversion(20,"XX")
        self.checkConversion(24,"XXIV")
        self.checkConversion(31,"XXXI")
        self.checkConversion(38,"XXXVIII")
        self.checkConversion(45,"XLV")
        self.checkConversion(71,"LXXI")
        self.checkConversion(87,"LXXXVII")
        self.checkConversion(99,"XCIX")
    def testHundreds(self):
        self.checkConversion(109,"CIX")
        self.checkConversion(203,"CCIII")
        self.checkConversion(303,"CCCIII")
        self.checkConversion(304,"CCCIV")
        self.checkConversion(450,"CDL")
        self.checkConversion(546,"DXLVI")
        self.checkConversion(671,"DCLXXI")
        self.checkConversion(788,"DCCLXXXVIII")
        self.checkConversion(888,"DCCCLXXXVIII")
        self.checkConversion(999,"CMXCIX")
    def testThousands(self):
        self.checkConversion(1010,"MX")
        self.checkConversion(1111,"MCXI")
        self.checkConversion(1234,"MCCXXXIV")
        self.checkConversion(2342,"MMCCCXLII")
        self.checkConversion(2999,"MMCMXCIX")
    def checkConversion(self,numeral, roman):
        self.assertEquals(roman, self.roman.intToRoman(numeral))
        self.assertEquals(numeral, self.roman.romanToInt(roman))
if __name__ == "__main__":
    unittest.main()

]]> http://anabuigues.com/2011/02/15/code-kata-febrero-romannumerals/feed/ 5 Mi primera Code Kata http://anabuigues.com/2011/02/01/mi-primera-code-kata/ http://anabuigues.com/2011/02/01/mi-primera-code-kata/#comments Tue, 01 Feb 2011 17:40:00 +0000 Ana Buigues http://anabuigues.com/?p=3344 Ayer hice junto a Héctor Rodes mi primera Code Kata, gracias a la iniciativa de 12meses12katas, donde cada mes se propone una nueva kata. Abierta a todo el mundo y a todos los lenguajes de programación, excelente para poder practicar y aprender.

Y…¿qué es una Code Kata? pues una Code Kata hace referencia a un ejercicio de programación en el cual se resuelve un problema más o menos complejo donde el objetivo es mejorar las cualidades de un programador mediante la práctica y resolución repetitiva de problemas.

Lo que obtenemos de todo esto es obligarnos a encontrar una solución a un problema y además nos permite contrastar nuestra solución con la de otras personas, de esta forma podemos descubrir nuevas formas de resolver el mismo problema, y si la programas en parejas es todavía más divertido.

Para Enero el ejercicio de la Code Kata era el String Calculator, la idea es hacer un programa que sume  los números de una cadena separados por diferentes delimitadores, por ejemplo: “8*5%3″ . Si queréis ver el código de la gente que ha realizado la Code Kata podéis visitar el github del proyecto. El nuestro está en el directorio de animalaes.

Nuestra solución

La hemos realizado en Java, con la ayuda de la clase Scanner de Java para parsear la cadena mediante expresiones regulares. Se admiten sugerencias sobre mejoras o lo que sea.

package com.anabuigues;
import java.io.ByteArrayInputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
import java.util.regex.Pattern;
/**
 * Implementación sencilla de la calculadora para la kata de enero.<br />
 * <br />
 * La implementación está realizada usando java 6 estándar apoyándose en la
 * clase Scanner que permite trocear al vuelo un imput a partir de un o n
 * delimitadores. Para ello extrae los delimitadores y construye una expresión
 * reguar válida para el scanner al que se le solicitan los diferentes enteros
 * para ir sumándolos.
 *
 *
 * @author A. Buigues (@animalaes), H. Rodes (@hector_rodes)
 *
 */
public class StringCalculator {
	public int add(String numbers) throws Exception {
		int returnValue;
		if (numbers == null || numbers.isEmpty()) {
			returnValue = 0;
		} else {
			ByteArrayInputStream bais = new ByteArrayInputStream(
					numbers.getBytes());
			Scanner sc = new Scanner(bais);
			String delimiters = null;
			// Delimiters
			if (numbers.startsWith("//")) {
				sc.useDelimiter("//|\n");
				if (sc.hasNext()) {
					delimiters = sc.next();
				}
			}
			delimiters = getScannerFormattedDelimiters(delimiters);
			// Process number lines with numbers to be added
			sc.useDelimiter(delimiters);
			int sum = 0;
			int currentNumber;
			List<Integer> negativeValues = new ArrayList<Integer>();
			while (sc.hasNext()) {
				currentNumber = sc.nextInt();
				if (currentNumber < 0) {
					negativeValues.add(currentNumber);
				} else if (currentNumber <= 1000) {
					sum += currentNumber;
				}
			}
			checkNegativeValues(negativeValues);
			returnValue = sum;
		}
		return returnValue;
	}
	/**
	 * Método auxiliar que comprueba si hay números negativos y forma el mensaje
	 *
	 * @param negativeValues
	 *            Lista de números negativos
	 * @throws Exception
	 *             Si la lista de números negativos contiene algún número
	 */
	private void checkNegativeValues(List<Integer> negativeValues)
			throws Exception {
		if (negativeValues != null && negativeValues.size() > 0) {
			StringBuilder sb = new StringBuilder("negatives not allowed");
			for (int negative : negativeValues) {
				sb.append(" ").append(negative);
			}
			throw new Exception(sb.toString());
		}
	}
	/**
	 * Genera la cadena de delimitadores necesaria para ser usada en el scanner
	 * y así poder procesar los números.<br />
	 * Siempre introduce el \n como un delimitador válido.<br />
	 * En caso de que los delimiters sean vacÌos o nulos usa la , y el \n como
	 * delimitadores por defecto
	 *
	 * @param delimiters
	 *            Los delimitadores introducidos
	 * @return Cadena con los delimitadores en el formato que espera el Scanner
	 */
	private String getScannerFormattedDelimiters(String delimiters) {
		String delimitersExpression;
		if (delimiters == null || delimiters.isEmpty()) {
			delimitersExpression = ",|\n";
		} else {
			String currentDelimiter;
			StringBuilder sb = new StringBuilder();
			Scanner scDelimiters = new Scanner(delimiters).useDelimiter(Pattern
					.quote("]") + "|" + Pattern.quote("["));
			while (scDelimiters.hasNext()) {
				currentDelimiter = scDelimiters.next();
				if (!currentDelimiter.isEmpty()) {
					sb.append(Pattern.quote(currentDelimiter)).append("|");
				}
			}
			sb.append("\n");
			delimitersExpression = sb.toString();
		}
		return delimitersExpression;
	}
}

Y su test

package com.anabuigues;
import junit.framework.Assert;
import org.junit.Test;
/**
 *
 * @author A. Buigues (@animalaes), H. Rodes (@hector_rodes)
 *
 */
public class CalculatorTest {
	private StringCalculator calculator = new StringCalculator();
	@Test
	public void basicCalculator() throws Exception {
		Assert.assertEquals(0, calculator.add(""));
		Assert.assertEquals(1, calculator.add("1"));
		Assert.assertEquals(10, calculator.add("7,3"));
		Assert.assertEquals(10, calculator.add("7\n2,1"));
		Assert.assertEquals(27, calculator.add("5\n5\n8,2,4\n2,1"));
	}
	@Test
	public void simpleDelimiterCalculator() throws Exception {
		Assert.assertEquals(16, calculator.add("//[*]\n5*5*6"));
		Assert.assertEquals(20, calculator.add("//[*]\n5*5*6\n4"));
		Assert.assertEquals(20, calculator.add("//[*][;][,]\n5,5;6\n4"));
		Assert.assertEquals(20,
				calculator.add("//[*][;][pollofrito]\n5pollofrito5;6\n4"));
	}
	@Test
	public void bigNumbersCalculator() throws Exception {
		Assert.assertEquals(1005, calculator.add("//[*]\n5*1000*1001"));
	}
	@Test
	public void negativeNumbersCalculator() throws Exception {
		try {
			Assert.assertEquals(1005, calculator.add("//[*]\n5*-23*45*-34"));
		} catch (Exception e) {
			Assert.assertTrue("-23 must be in error message ", e.getMessage()
					.indexOf("-23") != -1);
			Assert.assertTrue("-34 must be in error message ", e.getMessage()
					.indexOf("-34") != -1);
		}
	}
	@Test
	public void notDefinedDelimiterCalculator() throws Exception {
		try {
			Assert.assertEquals(8, calculator.add("//[*]\n5;3"));
			Assert.fail("Delimiter ; is not allowed but it has been used");
		} catch (Exception e) {
		}
	}
}

Ahora toca ponerse con la de febrero!!

]]> http://anabuigues.com/2011/02/01/mi-primera-code-kata/feed/ 4