http://www.slideshare.net/fungfung/refactoringch7-moving-feature-btw-objects
http://www.source-code.biz/snippets/java/3.htm, just use vector f.e.
http://www.ensta-paristech.fr/~diam/java/online/notes-java/data/expressions/22compareobjects.html
http://pivotallabs.com/users/alex/blog/articles/273-lovely-demeter-meter-maid, LOL , al final se calienta el tema
http://www.purpletech.com/blog/index.php?itemid=25
http://moffdub.wordpress.com/2008/09/27/domain-driven-method-naming-guidelines/#comment-236
viernes, 26 de agosto de 2011
Test Driven Develpment SMELL thoughts
Cuando enuncio un test , y luego desarrollo el código para conseguir ponerlo en verde , veo que al poner assertions de tipo TRUE FALSE, el error no me escupe el resultado que comparo, mientras que si pongo un equals si que me lo da.
SMELL -> assertsTrue and assertsFalse use.
GOOD PRACTICE -> no uses assertions tipo True/false mas que como último remedio.
Otro problema que me he encontrado es que a veces para depurar el código y ver la razón por la que no me ha funcionado un test, me veo obligado a poner salidas por el stdout que me muestren algún valor de variables en el código, o en el test.
Si te ves obligado a ello , probablemente debes pensar primero si tu test es lo suficiente unitario, "solo probar una funcionalidad cada vez", o bien si en los métodos de tu código estas necesitando extract type refactoring (class, method, field).
SMELL -> logs, debug intermediate variables, system.out.println, .......
GOOD PRACTICE -> reescribe el código o crea un nuevo test antes de usar logs para depurar el código.
En algunos al escribir un test sobre una funcionalidad complicada me veo perdido pues para poner verde el test debo de programar mucho código con muchos methodos privados. Normalmente esto metodos lo que hacen es calcular datos necesarios o validar variables, hay que ver los métodos y clases involucradas y usar el fallback de ellas para probar cada una de las opciones , y expander el test haciendolo mas vervose y probando cada una de las opciones. Por ejemplo metodos que devuelvan un booleano ,pensar un test que pruebe el resultado de la funcionalidad completa con ese booleano a false, y luego en true, asi con todo.
SMELL -> too many methods or classes creates for acomplish a test. Need to change the scope of a method to public , just to test it.
GOOD PRACTICE -> Split test in each case depending on secundary methods results.
SMELL -> assertsTrue and assertsFalse use.
GOOD PRACTICE -> no uses assertions tipo True/false mas que como último remedio.
Otro problema que me he encontrado es que a veces para depurar el código y ver la razón por la que no me ha funcionado un test, me veo obligado a poner salidas por el stdout que me muestren algún valor de variables en el código, o en el test.
Si te ves obligado a ello , probablemente debes pensar primero si tu test es lo suficiente unitario, "solo probar una funcionalidad cada vez", o bien si en los métodos de tu código estas necesitando extract type refactoring (class, method, field).
SMELL -> logs, debug intermediate variables, system.out.println, .......
GOOD PRACTICE -> reescribe el código o crea un nuevo test antes de usar logs para depurar el código.
En algunos al escribir un test sobre una funcionalidad complicada me veo perdido pues para poner verde el test debo de programar mucho código con muchos methodos privados. Normalmente esto metodos lo que hacen es calcular datos necesarios o validar variables, hay que ver los métodos y clases involucradas y usar el fallback de ellas para probar cada una de las opciones , y expander el test haciendolo mas vervose y probando cada una de las opciones. Por ejemplo metodos que devuelvan un booleano ,pensar un test que pruebe el resultado de la funcionalidad completa con ese booleano a false, y luego en true, asi con todo.
SMELL -> too many methods or classes creates for acomplish a test. Need to change the scope of a method to public , just to test it.
GOOD PRACTICE -> Split test in each case depending on secundary methods results.
miércoles, 24 de agosto de 2011
Test Driven Develpment Issues in refactoring
I am practicing with the Kata minesWeesper, an in the development of the code i have introduce a Class that parses the file.
When that Class parses and find a pair of numbers valid (see kata doc) it returns that pair.
First i was coding that pair as int[2], in order to make an extract class refactoring when the code was write, so my methods like getNextDimensions() returns a int[2].
I wrote the test in Junit and in order to check the answer i had compared to a new int[2]= [expectedResultLines,expecterResulColumns].
Once all my test pass, i began to refactor code. (this could be a point of my error, but not the clue), when i did the refactor, i created a class MapDimensions , which stores the dimensions of the map in two variables.
And now a find me changing all the test and the clients of my class.
How i could avoid that mistake?
I don't know just now but i can expose some clues.
SMELL.- test comparing primitive results.--> change to a class container.
think also to use encapsulate field
Good practice --> introduce name of the expected type of answer in test name
introduce "expected" word in the declaration of the expected result to mach in the test.
When that Class parses and find a pair of numbers valid (see kata doc) it returns that pair.
First i was coding that pair as int[2], in order to make an extract class refactoring when the code was write, so my methods like getNextDimensions() returns a int[2].
I wrote the test in Junit and in order to check the answer i had compared to a new int[2]= [expectedResultLines,expecterResulColumns].
Once all my test pass, i began to refactor code. (this could be a point of my error, but not the clue), when i did the refactor, i created a class MapDimensions , which stores the dimensions of the map in two variables.
And now a find me changing all the test and the clients of my class.
How i could avoid that mistake?
I don't know just now but i can expose some clues.
SMELL.- test comparing primitive results.--> change to a class container.
think also to use encapsulate field
Good practice --> introduce name of the expected type of answer in test name
introduce "expected" word in the declaration of the expected result to mach in the test.
jueves, 18 de agosto de 2011
Test System.out.println() Junit
Durante la realizacion de una kata
minesweeper
Me surgió la implementación de una clase que mantiene los mapas de minas, y que debe tener un método publico el cual imprime el mapa de minas.
al principio lo que hice fué crear un metodo tambien publico llamado expresate() que devolvia la cadena que luego se imprimiria mediante un System.out.println(), sin embargo esto lo que suponia era la exposicion de una metodo en el api que no tenia porque ser publico.
al refactorizar y hacer los metodos privados excepto los necesarios para el api, me encontraba con el problema de comprobar que es lo que sale por el stdOut
esto lo solucioné mirando en una pagina que me indicaba como hacerlo así que ...
antes tenia:
y ahora:
notese adema de las variables creadas y el método llamado, el comparador:
se debe introducir el retorno de carro y el final de linea del println() que hay en el código del método imprimete()
minesweeper
Me surgió la implementación de una clase que mantiene los mapas de minas, y que debe tener un método publico el cual imprime el mapa de minas.
al principio lo que hice fué crear un metodo tambien publico llamado expresate() que devolvia la cadena que luego se imprimiria mediante un System.out.println(), sin embargo esto lo que suponia era la exposicion de una metodo en el api que no tenia porque ser publico.
al refactorizar y hacer los metodos privados excepto los necesarios para el api, me encontraba con el problema de comprobar que es lo que sale por el stdOut
esto lo solucioné mirando en una pagina que me indicaba como hacerlo así que ...
antes tenia:
package buscaminas;
import junit.framework.TestCase;
public class MapaMinasTest extends TestCase {
public void testProcesaLineaVacia() {
String lineaAProcesar = "......";
int ordenTablero = lineaAProcesar.length();
MapaMinas testMapa = new MapaMinas(1,ordenTablero);
testMapa.procesaLinea(0, lineaAProcesar);
String resultado=testMapa.expresate(0);
assertEquals("000000", resultado);
}
y ahora:
package buscaminas;
import java.io.ByteArrayOutputStream;
import java.io.PrintStream;
import junit.framework.TestCase;
public class MapaMinasTest extends TestCase {
private final ByteArrayOutputStream outContent = new ByteArrayOutputStream();
private final ByteArrayOutputStream errContent = new ByteArrayOutputStream();
public void testProcesaLineaVacia() {
System.setOut(new PrintStream(outContent));
System.setErr(new PrintStream(errContent));
String lineaAProcesar = "......";
int ordenTablero = lineaAProcesar.length();
MapaMinas testMapa = new MapaMinas(1,ordenTablero);
testMapa.procesaLinea(0, lineaAProcesar);
testMapa.imprime();
assertEquals("000000\r\n", outContent.toString());
System.setOut(null);
System.setErr(null);
}
notese adema de las variables creadas y el método llamado, el comparador:
assertEquals("000000", resultado);
assertEquals("000000\r\n", outContent.toString());
se debe introducir el retorno de carro y el final de linea del println() que hay en el código del método imprimete()
miércoles, 17 de agosto de 2011
File Read good Practice
Muchas veces nos encontramos ante la lectura de un fichero que contiene datos que nuestro programa debe procesar.
Seguro que existen muchas "recomendaciones" al respecto pero yo no encuentro ninguna ahora así que voy a poner lo que me parece hoy por hoy y según se amplíe mi conocimiento y experiencia lo modificaré.
1.- ¿Comprobamos que existe el fichero y su integridad?
los siguientes puntos pueden depender de si una información posterior en el fichero puede alterar el proceso de información anterior. pero se trata de tener una norma genérica.
2.- ¿leemos los datos de golpe o secuencialmente linea tras linea?
3.- ¿procesamos los datos según los estamos leyendo o los almacenamos en memoria?
4.- ¿si los almacenamos , liberamos la memoria al final?
ventajas de guardar el puntero a donde estamos leyendo en un variable global
ventajas de leer todo
Seguro que existen muchas "recomendaciones" al respecto pero yo no encuentro ninguna ahora así que voy a poner lo que me parece hoy por hoy y según se amplíe mi conocimiento y experiencia lo modificaré.
1.- ¿Comprobamos que existe el fichero y su integridad?
los siguientes puntos pueden depender de si una información posterior en el fichero puede alterar el proceso de información anterior. pero se trata de tener una norma genérica.
2.- ¿leemos los datos de golpe o secuencialmente linea tras linea?
3.- ¿procesamos los datos según los estamos leyendo o los almacenamos en memoria?
4.- ¿si los almacenamos , liberamos la memoria al final?
ventajas de guardar el puntero a donde estamos leyendo en un variable global
ventajas de leer todo
lunes, 15 de agosto de 2011
replace conditional with polymorphism
Este metodo de refactorizacion ha ido cambiando , he empezado a trabajar con el ejemplo que se puede ver en Refactorización: Reemplazar un condicional por polimorfismo
y he acabado implementando un factory patter al estilo de la web
el codigo inicial era , completado para que funcione.
esto pasa de la forma que se puede observar en el archivo de MoonEdit
y he acabado implementando un factory patter al estilo de la web
el codigo inicial era , completado para que funcione.
double final MAX_VEHICLE_SPEED = 18;
double final TRUKC_LOAD_FACTOR = 28;
double final BUS_SAFETY_FACTOR = 44;
double loadFactor;
double safetyFactor;
double getSpeed(){
_type= "CAR";
_load = 12;
_risk = 3;
setLoadFactor (TRUCK_LOAD_FACTOR);
setSafetyFactor (BUS_SAFETY_FACTOR);
switch (_type) {
case CAR:
return getMaxSpeed();
case TRUCK:
return getMaxSpeed() - getLoadFactor()* _load;
case BUS:
return getMaxSpeed() - getSafetyFactor()*_risk;
}
double getMaxSpeed()
{
return MAX_VEHICLE_SPEED;
}
private setLoadFactor(Double factor)
{
loadFactor = 0;
if (factor) loadFactor = factor;
}
double getLoadFactor()
{
return loadFactor;
}
private setSafetyFactor(Double factor)
{
safetyFactor = 0;
if (factor) safetyFactor = factor;
}
double getSafetyFactor()
{
return safetyFactor;
}
esto pasa de la forma que se puede observar en el archivo de MoonEdit
Class Cliente
{
private Integer _load;
private Integer _risk;
privat String _type;
double getSpeed()
{
_load = 12;
_risk = 3;
return new VehicleFactory(_type,_load,_risk).getVehicle().getSpeed(); //smell
}
}
Class VehicleFactory
{
final String CAR = "car";
final String BUS = "bus";
final String TRUNCK = "truck";
getVehicle(String type, Integer load , Integer risk)
{
switch (type)
{
case CAR:
return new Car();
case TRUCK:
return new Truck(load);
case BUS:
return new Bus(risk);
}
return new Exception ("Vehiclefactory","no vehicle type");
}
}
Class abstract Vehicle
{
private integer _maxSpeed;
private Integer getMaxSpeed()
{
return _maxSpeed;
}
private setMaxSpeed(Integer speed)
{
_maxSpeed = speed;
}
public abstract Double getSpeed()
}
Class Car extends Vehicle
{
private final Integer CAR_MAX_SPEED = 18;
public Car()
{
setMaxSpeed(CAR_MAX_SPEED);
}
public Double getSpeed()
{
return getMaxSpeed();
}
}
Class Truck
{
private final Integer TRUCK_MAX_SPEED = 18;
private final Integer TRUCK_LOAD_FACTOR = 28;
private Integer _loadFactor;
private Integer _load;
public Truck(Integer load)
{
setMaxSpeed(TRUCK_MAX_SPEED);
setLoadFactor(TRUNK_LOAD_FACTOR);
if (load) _load = load else load = 0;
}
public Integer getLoadFactor()
{
return _loadFactor;
}
private setLoadFactor (Integer loadFactor)
{
_loadFactor = loadFactor;
}
private Double getSpeed()
{
return getMaxSpeed() + getLoadFactor() * _load;
}
}
Class Bus
{
private final Integer BUS_MAX_SPEED = 18;
private final Integer BUS_SAFETY_FACTOR = 44;
private Integer _safetyFactor;
private Integer risk;
public Bus(Integer risk)
{
setMaxSpeed(BUS_MAX_SPEED);
setSafetyFactor (BUS_SAFETY_FACTOR);
if (risk) _risk = risk else _risk =0; ahora luego hago los seters para ponerlo bien.
}
public Integer getsafetyFactor()
{
return _safetyFactor;
}
private setSafetyFactor (Integer safetyFactor)
{
_safetyFactor = safetyFactor;
}
private abstract Double getSafetySpeed()
{
return getMaxSpeed() - getSafetyFactor() * risk;
}
private Double getSpeed()
{
return getSafetySpeed();
}
}
miércoles, 10 de agosto de 2011
lecturas que voy haciendo
pongo en negrita las que me han parecido mas interesantes o despertado algún otro interés.
http://avdi.org/devblog/2011/07/05/demeter-its-not-just-a-good-idea-its-the-law/
http://misko.hevery.com/2008/07/18/breaking-the-law-of-demeter-is-like-looking-for-a-needle-in-the-haystack/
http://www.dan-manges.com/blog/37
http://www.dan-manges.com/blog/37de la pagina 6 en adelante
http://avdi.org/devblog/2011/06/28/do-or-do-not-there-is-no-try/
http://pragprog.com/articles/tell-dont-ask
http://avdi.org/devblog/2011/07/05/demeter-its-not-just-a-good-idea-its-the-law/
http://misko.hevery.com/2008/07/18/breaking-the-law-of-demeter-is-like-looking-for-a-needle-in-the-haystack/
http://www.dan-manges.com/blog/37
http://www.dan-manges.com/blog/37de la pagina 6 en adelante
http://avdi.org/devblog/2011/06/28/do-or-do-not-there-is-no-try/
http://pragprog.com/articles/tell-dont-ask
Suscribirse a:
Entradas (Atom)