web 2.0

sábado, 17 de abril de 2010

Inyección de la Dependencia II: Práctico y Fácil

En la primera parte vimos un ejemplo por demás sencillo, el clásico Hola Mundo! utilizando la Inyección de Dependencia mediante Spring!

En esta segunda parte, continuaremos con otro ejemplo igual de sencillo, más útil, pero que al final de cuentas nos encontraremos con un problema!

Buscando Archivos!
Vamos a realizar un sencillo buscador de archivos! El API de Java incorpora una interfaz llamada FileFilter que contiene al método accept, este método deberá contener toda la lógica requerida para filtrar de una lista de archivos, aquellos que cumplan con nuestras características! De tal modo que pasaremos una referencia de FileFilter al método listFiles de la clase File.

Para empezar, creamos una clase que implemente a la interfaz FileFilter.

package archivos;

import java.io.File;
import java.io.FileFilter;

/**
 *
 * @author windoctor
 */
public class FileExtensionFileFilter implements FileFilter{

    private String extension;

    public FileExtensionFileFilter(String extension){
        this.extension = extension;
    }

    public boolean accept(File pathname) {
        String nameLower = pathname.getName().toLowerCase();

        return (pathname.isFile() &&
                (nameLower.indexOf(extension) > 0)? true:false);
    }    
}

Posteriormente, vamos a crear una clase que se encargue de listar todos los archivos que cumplan con nuestro criterio de búsqueda!

package archivos;

package archivos;

import java.io.File;
import java.io.FileFilter;
import java.io.FileNotFoundException;

/**
 *
 * @author windoctor
 */
public class BuscadorArchivo {
    private String directorio;
    private String extension;
    private FileFilter filter;

    public BuscadorArchivo(String directorio, String extension){
        this.directorio = directorio;
        this.extension = extension;
    }

    public File[] listar() throws FileNotFoundException{
        File dir = new File(directorio);
        //Si no existe, lanzamos una excepción
        if(!dir.exists())
            throw new FileNotFoundException
                    ("No existe el directorio "+directorio);

        //Este es nuestro filtro, el cual pasaremos al método listFiles
        filter = new FileExtensionFileFilter(extension);
        File[] files = dir.listFiles(filter);

        if(files == null || files.length <= 0){
            System.out.println("No existen archivos "+extension);
            return null;
        }
        else
            return files;
    }
}
Ahora en el applicationContext.xml vamos a agregar la definición de la clase anterior:
<bean id="beanArchivo" class="archivos.BuscadorArchivo">
   <constructor-arg index="0" value="/home/windoctor/Documentos" />
   <constructor-arg index="1" value=".mp3" />
</bean>
Como vemos, la clase BuscadorArchivo tiene un constructor que recibe 2 parámetros de tipo String y que serán inyectados vía Spring. De tal suerte que al ejecutar el siguiente código, obtendremos una lista de archivos:
package archivos;

import java.io.File;
import java.io.FileNotFoundException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.xml.XmlBeanFactory;
import org.springframework.core.io.FileSystemResource;

/**
 *
 * @author windoctor
 */
public class ArchivoMain {
    public static void main(String args[]){
        BeanFactory factory = new XmlBeanFactory(
                new FileSystemResource("web/WEB-INF/applicationContext.xml"));
        BuscadorArchivo buscador = (BuscadorArchivo)
                factory.getBean("beanArchivo");
        try {
            File[] files = buscador.listar();
            int size = files.length;
             //Ahora que tenemos todos los archivos filtrados, solo los listamos
            for(int i = 0; i < size; i++){
                File file = files[i];
                String nameFile = file.getName();
                long fileSize = file.length();
                String msg = nameFile + " - Size: "+fileSize;
                System.out.println(msg);
            }
        }
        catch (FileNotFoundException ex) {}
    }
}
Si tenemos archivos mp3 en la carpeta, la consola mostrará una salida similar a esta:

Pista5.mp3 - Size: 4877446
Pista20.mp3 - Size: 3669863
Pista10.mp3 - Size: 10081612

Hasta este punto parece que todo ha salido bien y ya tenemos una idea más clara sobre lo que es la inyección de la dependencia, aunque este ejemplo no es mucho mejor que el anterior y aun nos puede parecer algo tonto la DI. En este punto vamos a realizar una prueba unitaria mediante JUnit! Las pruebas unitarias son algo que muchos no hacemos pese a las enormes ventajas que esto aporta! En NetBeans vamos a agregar a la librería de nuestro proyecto a JUnit 4.5. En la carpeta de "Test Packages" colocaremos la clase de unidad que crearemos a continuación.
package archivo.test;

import archivos.BuscadorArchivo;
import java.io.File;
import java.io.FileNotFoundException;
import org.junit.Assert;
import org.junit.Test;

/**
 *
 * @author windoctor
 */
public class ArchivoTest {

    @Test
    public void listarTest(){
        BuscadorArchivo buscador = new 
                  BuscadorArchivo("/home/windoctor/Documentos", ".mp3");
        try {
            File[] files = buscador.listar();
            Assert.assertNotNull(files);
        } 
        catch (FileNotFoundException ex) {

        }
    }
}

Al ejecutar el código anterior obtendremos una salida de JUnit como la que muestra la imagen de abajo.


Nuestra prueba unitaria ha resultado exitosa! Sin embargo, aún nos falta probar a la clase FileExtensionFileFilter, así que debemos hacer lo mismo.... Un momento... Sin darnos cuenta, ya hemos probado a "FileExtensionFileFilter" dado que BuscadorArchivo obtiene por si mismo una referencia de ese objeto!

En la primera parte de este tutorial, mencionamos que una de las características deseables del Software es que tenga un débil acoplamiento! Desafortunadamente en este ejemplo esta característica no se esta cumpliendo del todo!

Si pensamos un poco más, caeremos en la cuenta que con el ejemplo anterior estamos limitados a filtrar archivos únicamente por su extensión! Pues BuscadorArchivo recupera por si mismo a un FileExtensionFileFilter... ¿Y si deseamos filtrar en base a que un archivo de texto contenga cierta palabra?

El anterior ejemplo es sencillo, pero si lo trasladamos a clases de un Sistema empresarial que es grande y tiene decenas, cientos o miles de clases, las pruebas unitarias se vuelven difíciles de realizar por el fuerte acoplamiento que existe, además que el mantenimiento se complica!

La solución consiste en inyectar objetos FileFilter en BuscadorArchivo, dado que FileFilter es una interfaz, podemos crear tantos filtros de archivos según nuestras necesidades. Realizaremos una modificación a la clase BuscadorArchivo

public class BuscadorArchivo {
    private String directorio;
    private FileFilter filter;

    public BuscadorArchivo(String directorio){
        this.directorio = directorio;
    }

    //Ahora al Buscador de archivos se le asigna un Filtro en lugar
    //de que Él mismo obtenga un filtro.
    public void setFilter(FileFilter filter){
        this.filter = filter;
    }

    public File[] listar() throws FileNotFoundException{
        File dir = new File(directorio);
        //Si no existe, lanzamos una excepción
        if(!dir.exists())
            throw new FileNotFoundException
                    ("No existe el directorio "+directorio);


        File[] files = dir.listFiles(filter);

        if(files == null || files.length <= 0){
            System.out.println("No existen archivos con el criterio de búsqueda");
            return null;
        }
        else
            return files;
    }
}

La diferencia ahora es que BuscadorArchivo ya no recupera por si mismo un filtro, por el contrario, el filtro le es inyectado mediante un método setFilter. Para que Spring pueda hacer esta inyección, debemos modificar también el archivo applicationContext.xml:

<bean id="beanFilter" class="archivos.FileExtensionFileFilter">
<constructor-arg index="0" value=".mp3" />
</bean>

<bean id="beanAnalizadorXml" class="archivos.BuscadorArchivo">
<constructor-arg index="0" value="/home/windoctor/Documentos" />
<property name="filter" ref="beanFilter" />
</bean>

Podemos observar que ahora hemos definido un nuevo bean FileExtensionFileFilter que es inyectado al beanArchivo. El beanArchivo ahora tiene una etiqueta property que consta de 2 atributos, name y ref.


  • name: nombre del atributo de la clase. En este caso, hemos agregado a BuscadorArchivo un atributo llamado filter, este nombre es el que deberá colocarse esta propiedad.
  • ref: Es la referencia de otro bean que se ha declarado en el applicationContext.xml
Con la modificación anterior tenemos  un código con un menor acoplamiento, ahora es posible asignarle realizar búsquedas de archivos con diferentes filtros y no necesariamente por extensión como originalmente sucedía!

Puedes descargar el proyecto en NetBeans de la primera y segunda parte de este tutorial desde aquí.

Cerraremos este tutorial sobre la Inyección de la Dependencia mediante Spring con una tercera y última parte en donde veremos otro ejemplo más que nos permita comprender de mejor manera la DI.

Saludos!!!

Cualquier error encontrado en este tutorial, reportarlo como comentario dentro del mismo!
La información contenida aquí se utiliza con fines educativos y su utilización en ambientes de producción es únicamente responsabilidad de quien lo hace.

lunes, 12 de abril de 2010

Inyección de la Dependencia I: Práctico y Fácil

Spring es un Framework de código abierto, creado originalmente para mitigar la odiosa complejidad de los EJB (La especificación de EJB 3 ha sido considerablemente más ligera y fácil de utilizar). Una de las características más conocidas de Spring es trabajar con la Inyección de la Dependencia y la Programación Orientada a Aspectos. Omitiremos un poco la discusión sobre el término Inversión del Control (IoC) que es más general, para otra ocasión!


Alta Cohesión y Débil Acoplamiento

Se dice que el Software debe tener dos características fundamentales, una alta cohesión y un débil acoplamiento. La cohesión se refiere a la manera en la que agrupamos todos los "artefactos de software" (un término quizá más apropiado es "unidad de software"). Con "agrupar" debe entenderse a la facilidad con la que pueden ensamblarse todos nuestros componentes de software, métodos, clases, paquetes, etc.

El débil acoplamiento se refiere al grado de dependencia que existe entre las unidades de software, es decir, si tenemos dos clases, A y B, y alguna de ellas depende en gran medida de la otra y no esta presente, la clase o método dependiente no podrá realizar efectivamente su tarea. El acoplamiento a nivel de métodos es más fácil de comprender con el siguiente ejemplo:


public int multiplicar(int a, int b){
        int c = resta(a,b);
        return 2 * c;
    }
    
    public int resta(int a, int b){
        return a-b;
    }

Vemos pues que existe una fuerte dependencia del método multiplicar con el método restar! El método multiplicar llama al método restar. En gran medida, esto es lo que debemos evitar! Sin embargo, es importante aclarar el término "débil acoplamiento" y "desacoplamiento", este segundo término da a entender algo total y absoluto, mientras que el primero dice que puede haber acoplamiento por que definitivamente no es posible desarrollar Software con cero acoplamiento! Sin embargo, mediante algunas técnicas es posible reducirlo!

Spring Framework fomenta el débil acoplamiento mediante la Inyección de dependencias que es lo siguiente que veremos.

Inyección de la Dependencia

La Inyección de la dependencia sigue un sencillo principio, "No me llames, YO te llamo". Lo anterior describe perfectamente la tarea de la DI (Dependency Injection), es decir, cuando desarrollamos Software, sabemos de antemano que existen clases relacionadas, cada objeto se hace responsable de llamar y crear a otros objetos que necesita para poder llevar a cabo su tarea. Para aclarar lo anterior vamos a realizar el ya clásico programa del "Hola Mundo!". Utilizaremos NetBeans 6.8 por su sencillez y simplicidad de primera mano (omitiremos su lentitud), desde luego que Eclipse es un mejor IDE, pero en Eclipse debemos instalar un plugin para trabajar más cómodamente con Spring y NetBeans ya lo trae por defecto (por ello utilice el término "de primera mano").

En NetBeans creamos un proyecto web y llegado a la opción de Frameworks, seleccionamos Spring Web MVC.

Vamos a crear una interfaz llamada ISaludo:

public interface ISaludo {

    void saludar();

}

Así como la clase que implemente la interfaz:

public class Saludo implements ISaludo{
    public String mensaje;

    public Saludo(String mensaje){
        this.mensaje = mensaje;
    }
    public void saludar() {
        System.out.println(mensaje);
    }
}

Vemos que la clase Saludo recibe una cadena en su constructor, esto podría ser  otro tipo de Objeto creado por nosotros mismos. Lo que vamos a hacer aquí es tan sencillo que no se le vera utilidad a nivel de aplicación y en realidad, mucho del poder de Spring puede ser visto con mayor facilidad a nivel de Arquitectura! Vamos a concentrarnos en aplicar la DI.

Dentro de la carpeta WEB-INF, NetBeans ha creado un archivo XML llamado applicationContext.xml, en el tendremos a las etiquetas y dentro de ellas colocaremos lo siguiente:


        
El pequeño fragmento anterior, tendrá la tarea de instanciar un objeto de tipo Saludo (véase que esta dentro del paquete saludo), a este objeto lo vamos a referenciar por "beanSaludo". Además podemos ver que la clase Saludo recibe en su constructor una cadena de texto, misma que inyectaremos desde Spring mediante el atributo constructor-arg. Finalmente creamos una clase para ejecutar este ejemplo, el más sencillo de todos los que pueda haber!

public class SaludoTest {

    public static void main(String args[]){
        BeanFactory context=
                new XmlBeanFactory(new 
                FileSystemResource("AQUI LA RUTA/applicationContext.xml"));

        ISaludo saludo = (ISaludo) context.getBean("beanSaludo");
        saludo.saludar();
    }

}
Al ejecutar la clase anterior, podremos observar en la consola de NetBeans la siguiente salida:

 "Hola, este es nuestro primer ejemplo DI!!" 

 Lo primero a resaltar es que dicho mensaje no ha sido establecido! Podría pensarse en primera instancia que hubiera sido lo mismo colocar el mensaje en algún archivo de texto pero en realidad si lo hubiéramos hecho así, en algún lugar del código tendríamos que leer el archivo obtener el valor y "settearlo" al atributo mensaje de la clase Saludo! Sin embargo, nótese que en este sencillo ejemplo, Spring ha INYECTADO dicho recurso automáticamente por nosotros, es decir, nosotros no hemos hecho nada como esto:

Saludo saludo = new Saludo("hola mundo!");  

ni tampoco

saludo.setMensaje("Hola mundo"); 

Lo que se debe notar es que Spring como por arte de magia a inyectado el recurso (la cadena de texto) por nosotros! Sin aplicar la DI, el código del método main quedaria mucho más simple:

public class SaludoTest {
    public static void main(String args[]){
        Saludo saludo = new 
               Saludo("Hola, este es nuestro primer ejemplo DI!!");
        saludo.saludar();
    }

}

Con el código anterior, obtendriamos el mismo resultado pero sin la utilización de Spring! Este ejemplo es tan sencillo que el poder de la DI no es notoria, al contrario, lo hace ver como algo inútil, sin embargo, este ejemplo es meramete educativo y debe bastar para entender a que se refiere la "Inyección de la Dependencia" (NO me llames, YO te llamo). Más adelante veremos ejemplos más útiles en donde se vera de mejor forma la utilidad de la DI.

Saludos!!


Cualquier error encontrado en este tutorial, reportarlo como comentario dentro del mismo!
La información contenida aquí se utiliza con fines educativos y su utilización en ambientes de producción es únicamente responsabilidad de quien lo hace.

domingo, 4 de abril de 2010

¿Qué es un EJB?... La triste realidad del Sector Académico

Este es un vídeo que me ha dejado sin palabras! Incluso es tan vergonzoso que me niego a creer que es verdad, pero si lo es, realmente es solo una muestra de la realidad que vive el sector académico en muchas partes del mundo, principalmente en países latinoamericanos, México desde luego no es la excepción! El video, lo he visto de este blog. Fueron unos alumnos de la UTN los que grabaron esta clase y la animaron en este video...

No soy el desarrollador senior pero tampoco soy un desarrollador Junior y aun así no he podido entender en palabras de este profesor lo que es un EJB!!!





Pese a ello, la arrogancia de muchos catedráticos es notable! Los "Títulos" de posgrado ("Maestrías", "Doctorados") han originado en el Sector académico una cortina de humo y un lamentable conformismo!

Podría enumerar a cada uno de mis maestros que tuve, pero por respeto a su persona (no como a catedráticos) no lo haré, más sin embargo, muchos de ellos siempre me dieron risa cuando hacían alarde a sus maestrías y a sus doctorados y ellos mismos aceptaban que nunca les había gustado el desarrollo de sw. 

Afortunadamente, existen también verdaderos catedráticos (aunque muy pocos) que saben de lo que hablan y se preocupan verdaderamente por la educación! Entre ellos por ejemplo, Raul Oramas, profesor de la Universidad de Occidente el cual tiene un esquema de capacitación gratuito en tecnología Java de muy alto nivel
http://www.profesorjava.com/ ... Profesores como Raúl, son los que realmente se necesitan en lugar de tener a catedráticos encerrados como ratas de laboratorio en sus cubículos con el pretexto de ser "investigadores"... ¿Qué investigan? ¿Cuáles han sido sus aportes a la comunidad científica? ¿En realidad han servido o dado frutos sus investigaciones? Y con "frutos" no me refiero a nada palpable, pues la investigación científica puede tardar años en materializar sus investigaciones, más bien me refiero a si las supuestas investigaciones que realizan muchos académicos realmente son ineditas y han servido de base para otras investigaciones teóricas?

Nunca ocultare mi antipatía por el sector académico! Me bastaron 4 años de carrera y haber conocido a la planta docente de mi "honorable" institución de donde soy egresado para darme cuenta que quizá solo 1 (o siendo menos estricto 2) profesores son verdaderos académicos, los demás... los demás son simplemente... mejor le dejo hasta aquí!

Saludos!!


sábado, 3 de abril de 2010

El giro positivo del UML

Sencillamente esta es una sátira genial que escribió ya hace algunos años Bertrand Meyer y que tradujo Javier Smaldone en su blog.

En el blog de Javier Smaldone, hubo una discusión entre el y Fernando Pinciroli.

Es muy importante ser fríos y objetivos, si bien Javier Smaldone comenta puntos muy ciertos sobre el UML, también cae en el exceso de desprestigiar totalmente no solo a UML sino a RUP.

Como en uno de los artículos que escribí titulado El Fracaso de los proyectos de Software, apoyado en uno de los artículos más interesantes de Martín Fowler, comento que el modelado en UML debe manejarse con cuidado, pues la idea de "primero modela y luego construyes" encaja perfectamente en la Ingeniería Civil y Mecánica donde la naturaleza de sus problemas son suceptibles de un análisis matemático para determinar el comportamiento de una entidad bajos ciertas circunstancias y esto en definitiva obliga casi a un modelado previo.
Desafortunadamente en el Software la idea de realizar primero un "Diagrama de clases" e invertir mucho tiempo en ello para diseñar una Arquitectura es realmente absurda!


Es importante aclarar que no estoy del todo de acuerdo con Javier y Bertrand Meyer, por el contrario, pienso que algunos diagramas UML son útiles siempre y cuando se tomen como una ayuda para aclarar cuestiones de diseño y no como documentación base del proyecto ya que esto último desvía la atención de las organizaciones en lo que es realmente importante... dejar un valor de negocio al cliente! En breve publicaré la traducción de "La Fiebre del UML" que hace un tiempo leí.

Sin más que comentar, lean este artículo, disfrútenlo, diviértanse y sobre todo, tómenlo con mesura, más aún si son estudiantes!