martes, octubre 25, 2011

Cambio Casa

Hola Tod@s

Nos vamos a cambiar nuevamente de blog, esta seria la 3 vez, me cambio de wordpress , esperando escribir mas seguido y nuevos temas. Así que los espero

https://segatoazul.wordpress.com/

Saludos

lunes, octubre 17, 2011

PARTE 1 : TDD + JUNIT + MAVEN

Hola Tod@s:

Como tenia una deuda con migo , voy a volver a escribir y entregar mis conocimientos al mundo ...XD , así que vamos a empezar con el primero de los artículos que para mi punto de ver el desarrollo son los mas importantes, los test unitarios.

Los test unitarios son las forma de poder garantizar que nuestros desarrollos "lógicos" cumpla con una serie de escenarios mínimos antes de empaquetar y liberar la versión. A nivel de testing existen muchos niveles de test, pero este intenta atacar el primero que es cuando estamos en la trinchera programando y antes de enviar a producción o a los ambientes de pruebas con el cliente, y es el empaquetado.

Como el testunitarios, aunque se escuche y hable en todos los sitios y procesos de desarrollo, es menos común de lo que uno piensa, ya que la mayoría de los desarrolladores, le "echamos para adelante no mas" y obviamos todas estas "buenas practicas" .

Pero existen formas de obligar y o crear el habito a todos los desarrolladores. Acá voy a tocar 2 :

# Maven
# TDD

Maven (http://maven.apache.org/), es una herramienta de gestión de proyectos , basado en el concepto POM (Project Object Model ), "a mi me gusta mucho maven", ya que por regla sigue los siguientes pasos por defecto :

1.- Compilar
2.- Test
3.- Package
4.- deploy

Y te permite manejar las librerías y versiones, en un solo archivo. Lo bueno de estos 4 pasos (existen mas, me enfocare en los principales), es que uno al querer empaquetar, maven siempre te compila y corre los testunitarios que existen. Y con eso garantizar que mínimo compila, ya que los test si no se hacen , no corre nada.

El problema es que si no existen test, no sirve de nada.

Entonces acá entra los procesos de desarrollo y existe uno que es el TDD (http://es.wikipedia.org/wiki/TDD). El cual me exige seguir unos pasos antes de programar, para el común de los desarrolladores, esto es un "Aji en el Ass", ya que primero programo y si me "alcanza el tiempo hago test". Otra frase común.

El tiempo que se "invierte" en seguir estos pasos a la larga ayuda a tener un producto mejor. por ende minimizar las interacciones con producción o QA.

Pero menos blabla y "echemos para adelante". Voy a tratar el ejemplo mas simple, para que se entienda la idea del TDD.

1.- Creamos el proyecto (Tener maven instado y tener claro como funciona).

mvn archetype:generate -DarchetypeGroupId=org.apache.maven.archetypes -DgroupId=org.tdd  -DartifactId=my-app-tdd

Con este comando me genera el proyecto con la estructura básica, para empezar

2.-  Cambiamos la versión de junit y version de JAVA (http://es.wikipedia.org/wiki/JUnit).

Por defecto el pom.xml, viene con la versión 3.8.1,  pero yo uso la 4.1, así que solo se debe modificar esto. Con esto ya están  listo para iniciar, pueden usar el IDE que mas les guste, yo uso Eclipse

3.- Creamos nuestro primer test.



TDD, lo primero que me exige, es "Tener claro que voy a probar" o en palabras mas simple, "tener claro el requerimiento" (Esto es lo mas complicado). Para este ejemplo vamos a crear un CRUD de un Objeto.

La idea del primer test, es que falle. El test debe quedar algo así :


package org.tdd;

import static org.junit.Assert.assertTrue;

import org.junit.Test;

public class AppTest {
  

    @Test
    public void testCreate()
    {
        assertTrue( false );
    }
}

Al correr esto con maven falla :

# mvn clean test

-------------------------------------------------------
 T E S T S
-------------------------------------------------------
Running org.tdd.AppTest
Tests run: 1, Failures: 1, Errors: 0, Skipped: 0, Time elapsed: 0.097 sec <<< FAILURE!

Results :

Failed tests:
  testCreate(org.tdd.AppTest)

Tests run: 1, Failures: 1, Errors: 0, Skipped: 0

[INFO] ------------------------------------------------------------------------
[ERROR] BUILD FAILURE
[INFO] ------------------------------------------------------------------------
[INFO] There are test failures.
4.- Ahora que fallo lo arreglamos para que pase, pero apuntando al escenario real. Como es un CRUD , vamos a inciar con el create, osea hay que generar el VO.

package org.tdd.vo;

public class Book {

    private Integer _id;

    private String _name;

    private String description;

    public Book(Integer id, String name) {
        super();
        _id = id;
        _name = name;
    }

    [.. get y set]

}

5.- Modificamos el Test, ahora queda asi :

@Test
    public void testCreate() {
        Book book = new Book(1, "Test");
       
        assertTrue("Test".equals(book.getName()));
    }

Corremos el test y ahora pasa OK

-------------------------------------------------------
 T E S T S
-------------------------------------------------------
Running org.tdd.AppTest
Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.043 sec

Results :

Tests run: 1, Failures: 0, Errors: 0, Skipped: 0

[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESSFUL
[INFO] ------------------------------------------------------------------------

6.- Ahora agregamos mas logica, creamos un servicio para diferenciar esto,  hacemos nuevamente el test que falle, apuntando al Servicio :

# Manager

package org.tdd;

import org.tdd.service.BookService;
import org.tdd.service.IBookService;

public class ServiceManager {

    private static IBookService bookService = new BookService();

    public IBookService getBookService() {
        return bookService;
    }

}

# Service

package org.tdd.service;

import org.tdd.vo.Book;

public class BookService implements IBookService {

    public Book create(Book book) {
        // TODO Auto-generated method stub
        return null;
    }

}

# Test

@Test
    public void testCreate() {
        Book book = new Book(1, "Test");
       
        book = new ServiceManager().getBookService().create(book);
       
        assertTrue("Test".equals(book.getName()));
    }

Si ejecutamos este test, fallara ya que nuestro servicio no tiene logica, pero ya nos ayuda a tener nuestros desarrollos amarrados a un testunitario

-------------------------------------------------------
 T E S T S
-------------------------------------------------------
Running org.tdd.AppTest
Tests run: 1, Failures: 0, Errors: 1, Skipped: 0, Time elapsed: 0.102 sec <<< FAILURE!

Results :

Tests in error:
  testCreate(org.tdd.AppTest)

Tests run: 1, Failures: 0, Errors: 1, Skipped: 0

[INFO] ------------------------------------------------------------------------
[ERROR] BUILD FAILURE
[INFO] ------------------------------------------------------------------------
[INFO] There are test failures.

Ahora, hay que continuar con esta iteracion, vamos a agregando logica y nuestros test, deben ayudarnos a validar que todo lo que desarrollamos no lo pasamos a "llevar con los codos" y aqui entra maven, ya que si queremos empaquetar maven forzara que corrar las pruebas y por ende nos ayuda a validar nuestros codigos.

La idea es seguir complementando con mas Test, pero siguiendo la iteracion de fallo , solución y refactoring . Esto por cada escenario de prueba que necesitemos validar.


Eso, por ahora termino aqui, si alguien quiere iterar mas, sigo con mas ejemplos, pero en si esto es TDD para humanos ... XD

Saludos

viernes, enero 14, 2011

Tiempo Libre de Sobra ... XD

Hola Tod@s

Después de casi 1 año sin escribir nada (Por esta lleno de Pega), retomare con los artículos, en si los temas serán centrados a programación y a metodología, todo enfocado en mi experiencia personal en #sxb, espero le interese a alguien.

Los temas son :

* TDD con Junit
* Integración Continua con MAVEN
* Ruby and Rails (Plugin en Redmin)

Voy a agregar algunos temas de Agilidad y casos reales de implementación con sus pro y contra.

Saludos

jueves, abril 15, 2010

JBOSS Solaris

Hola Tod@s

Después de tener un problema instalando JBOSS en un maquina Solaris Sparc, la cual ocurría por 3 razones principalmente :

* Asignación de Memoria a JVM por parte del SO
* Asignación del Garbage Collector para SO
* Capa 8 .. XD

En si estos es mas una ayuda de memoria. El problema que ocurria era que al subir el servicio la JVM me arrojaba el siguiente problema :

Error occurred during initialization of VM Could not reserve enough space for object heap

Para solucionar este problema hay que hacer lo siguiente en el SO para asignar memoria al proceso :

#ulimit -S -v [mem que se necesita]

Para probar solo se puede corre lo siguiente :

#java -Xmx[mem]-version

Si no da error ya esta corregido el problema, si sigue dando problemas solo hay que asignar mas memoria con el comando ulimit.

Luego me daba el siguiente error :

# A fatal error has been detected by the Java Runtime Environment:
#
# SIGSEGV (0xb) at pc=0x00002b44b1da83ac, pid=2705, tid=1081280832
#
# JRE version: 6.0_18-b05
# Java VM: Java HotSpot(TM) 64-Bit Server VM (16.0-b12 mixed mode linux-amd64 )
# Problematic frame:
# V [libjvm.so+0x6223ac]
#
# If you would like to submit a bug report, please visit:
# http://java.sun.com/webapps/bugreport/crash.jsp
#

Este error ocurre por que para Solaris hay que asignarle otro garbage collector para que suba JVM, este problema se corrige asignando el siguiente parámetro al subir el servicio :

-XX:+UseSerialGC

Después de hacer esto el servicio subió sin problemas en el Servidor Solaris Sparc.

Si al hacer esto aun no funciona se puede hacer lo siguiente :

$ ulimit -Sa
$ ulimit -Ha

O ya lo ultimo es, en el archivo /etc/system se debe agregar lo siguiente :

set msgsys:msginfo_msgtql=1048576
set msgsys:msginfo_msgmni=256
set msgsys:msginfo_msgmax=8196
set msgsys:msginfo_msgmnb=8388608
set msgsys:msginfo_msgssz=2048
set msgsys:msginfo_msgseg=2048

Esto ultimo requiere reboot de la maquina.

Eso espero que a alguien mas le sirva esto.

viernes, noviembre 20, 2009

Form Validation Jquery

Hola

Acá le dejo un modificación que realice a un script de jquery para validar formulario.

Implementacion HTML

<script type="text/javascript" src="jquery/jquery-1.3.2.js"></script>
<script type="text/javascript" src="jquery/jquery.formvalidator.js"></script>

Form js
<script type="text/javascript">
$(function () {
$('#btUser').formValidator({
scope : '#user',
errorDiv : '#errorDiv'
});

});
</script>
Form HTML (Sample)

Usuarios

(*) Campos Obligatorios

Input (*)

<input id="input" name="input" class="input" value="" label="Input" required="true" type="text">

Number (*)

<input id="number" name="number" class="input" value="" req="numeric" minlength="2" maxlength="10" label="Number" required="true" type="text">

Double (*)

<input id="double" name="double" req="numeric" class="input" value="" label="Double" required="true" type="text">

Select (*)

<select id="select" name="select" class="input" label="Select" required="true">
<option value="0">...</option>
<option value="1">Nada</option>
</select>

Check

<input id="check" name="check" value="true" type="checkbox">

Radio

<input id="radio" name="radio" value="0" checked="checked" type="radio">Si
<input id="radio" name="radio" value="1" type="radio">No

Password (*)

<input id="password" name="password" req="same" class="input" value="" required="true" rel="password1" label="Password" type="password">

Re-Password (*)

<input id="password1" name="password1" req="same" class="input" value="" required="true" rel="password" label="Re-Password" type="password">

Calle

<input id="calle" name="calle" req="both" class="input" value="" required="true" rel="num" label="Calle" type="text">

Numero

<input id="num" name="num" class="input" value="" required="true" rel="num" label="Numero" type="text">

<input id="btUser" value="Insert" class="sendBtn" type="submit">

Código Javascript

/*
*
* Form Validation 2009
* @author Tolga Arican, Ivan A. Flores Correa
* @website www.utopicfarm.com, slacker-linux.blogspot.com
* @version 2.0.1
*
*/

(function($) {

$.fn.formValidator = function(options) {
$(this).click(function() {
var result = $.formValidator(options);

if (result && jQuery.isFunction(options.onSuccess)) {
options.onSuccess();
return false;
} else {
return result;
}
});
};

$.formValidator = function (options) {

// merge options with defaults
var merged_options = $.extend({}, $.formValidator.defaults, options);

// result boolean
var boolValid = true;

// result error message
var errorMsg = '<ul>';

// clean errors
$(merged_options.scope + ' .error-both, ' + merged_options.scope + ' .error-same, ' + merged_options.scope + ' .error-input').removeClass('error-both').removeClass('error-same').removeClass('error-input');

// Verificamos si se validan
$(merged_options.scope+' .input').each(function(){
thisValid = $.formValidator.validate($(this),merged_options);
boolValid = boolValid && thisValid.error;
if (!thisValid.error) errorMsg += thisValid.message;
});
errorMsg += '';

// submit form if there is and valid
if ((merged_options.scope != '') && boolValid) {
$(merged_options.errorDiv).fadeOut();
}

// if there is errorMsg print it if it is not valid
if (!boolValid && errorMsg != '') {
var tempErr = (merged_options.customErrMsg != '') ? merged_options.customErrMsg : errorMsg;
$(merged_options.errorDiv).hide().html(tempErr).fadeIn();
}

return boolValid;
};

$.formValidator.validate = function(obj,opts) {
var valAttr = obj.val();
var css = opts.errorClass;
var mail_filter = /^([a-zA-Z0-9_\.\-])+\@(([a-zA-Z0-9\-])+\.)+([a-zA-Z0-9]{2,4})+$/;
var numeric_filter = /(^-?\d\d*\.\d*$)|(^-?\d\d*$)|(^-?\.\d\d*$)|(^-?\d*$)/;
var tmpresult = true;
var result = true;
var errorTxt = '';
var label = obj.attr('label');
var required = obj.attr('required');
var req = obj.attr('req');
var name = obj.attr('name');
var type = obj.attr('type');

// Validamos
if (required == 'true') {
tmpresult = false;
if (valAttr != '') {
if (valAttr != '0') {
tmpresult = true;
}
}
if (!tmpresult) errorTxt +='<li>'+label+' '+opts.errorMsg.reqString+'</li>';
result = result && tmpresult;
}

// SAME FIELD VALIDATION
if (req == 'same') {

tmpresult = true;

group = obj.attr('rel');
tmpresult = true;
$(opts.scope+' .input[rel="'+group+'"]').each(function() {
if($(this).val() != valAttr || valAttr == '') {
tmpresult = false;
}
});
if (!tmpresult) {
$(opts.scope+' .input[rel="'+group+'"]').parent().parent().addClass('error-same');
errorTxt += '<li>'+opts.errorMsg.reqSame+'</li>';
} else {
$(opts.scope+' .input[rel="'+group+'"]').parent().parent().removeClass('error-same');
}

result = result && tmpresult;
}

// BOTH INPUT CHECKING
// if one field entered, the others should too.
if (req == 'both') {

tmpresult = true;

if (valAttr != '') {

group = obj.attr('rel');

$(opts.scope+' .input[rel="'+group+'"]').each(function() {
if($(this).val() == '') {
tmpresult = false;
}
});

if (!tmpresult) {
$(opts.scope+' .input[rel="'+group+'"]').parent().parent().addClass('error-both');
errorTxt += '<li>'+opts.errorMsg.reqBoth+'</li>';
} else {
$(opts.scope+' .input[rel="'+group+'"]').parent().parent().removeClass('error-both');
}
}

result = result && tmpresult;
}

// E-MAIL VALIDATION
if (req == 'email') {
tmpresult = mail_filter.test(valAttr);
if (!tmpresult) errorTxt += '<li>'+opts.errorMsg.reqMailNotValid+'</li>';
result = result && tmpresult;
}


// MINIMUM REQUIRED FIELD VALIDATION
var minlength = obj.attr('minlength');
if (obj.attr('minlength') != null) {
tmpresult = (valAttr.length >= minlength);
if (!tmpresult) errorTxt += '<li>'+label+' '+opts.errorMsg.reqMin.replace('%1', minlength)+'</li>';
result = result && tmpresult;
}
// NUMERIC FIELD VALIDATION
if (req == 'numeric') {
tmpresult = numeric_filter.test(valAttr);
if (!tmpresult) errorTxt += '<li>'+label+' '+opts.errorMsg.reqNum+'</li>';
result = result && tmpresult;
}

if (result) {
obj.removeClass(css);
} else {
obj.addClass(css);
}

return {
error: result,
message: errorTxt
};
};

setMsg = function() {

}

// CUSTOMIZE HERE or overwrite by sending option parameter
$.formValidator.defaults = {
onSuccess : null,
scope : '',
errorClass : 'error-input',
errorDiv : '',
errorMsg : {
reqString : 'es Requerido',
reqDate : 'Fecha no es valida',
reqNum : 'solo acepta Numeros',
reqMailNotValid : ' E-Mail no es valido',
reqMailEmpty : 'Please fill e-mail',
reqSame : 'Campos Re-confirmacion no son iguales',
reqBoth : 'Campos Relacionado(s) requerido',
reqMin : ' requiere %1 como minimo'
},
customErrMsg : ''
};
})(jQuery);

En que le interese le envío el ejemplo funcional