miércoles, 29 de abril de 2009

Optimización de bucles

Para comenzar nuestro periplo con la optimización de aplicaciones vamos a comenzar por algo fácil, muy probablemente ésto le parecerá obvio a muchos desarrolladores pero para todo aquel que empieza no vien mal una ayuda.

La primera medida a tener en cuenta es que debemos sacar del bucle todo aquellos valores invariables, ya que su computo no cambiará en las iteraciones (es lo que se suele llamar "invariantes del bucle").

 int r = 10;
for (int i=0; i<100; i++){
pi =3.14159;

float dist = pi*r*r;
}

En el ejemplo puede verse claramente que la variable pi debería situarse fuera del bucle, ya que de dejarlo así la asignación se ejecutará 100 veces en lugar de 1. Además de esto es importante sacar del bucle todo el código que no se usae estrictamente para el calculo que se quiere realizar en el bucle.

Otro aspecto importante que suele pasarse por alto es el calculo del limite en el bucle, muchas veces este limite se calcula mediante una función que ponemos en el mismo bucle, esto implica que dicha función se invoca una vez para cada iteración con su correspondiente coste.

 List lista = new ArrayList()
// inicializacion del list con 100 elementos.
lista.put("1");
...
lista.put("100");
for (int i=0; i<lista.size();i++){
...
}

Como vemos en el ejemplo la función size se invocará una vez por cada iteración. Una forma más optima para hacer esto es calculando el tamaño del bucle antes, como vemos a continuación:

 List lista = new ArrayList();
// inicializacion del list con 100 elementos.
lista.put("1");
...
lista.put("100");
int size = lista.size();
for (int i=0; i<size;i++){
...
}

Por último, otro aspecto a tener en cuenta al utilizar bucles es que usando las palabras reservadas continue y break podemos finalizar una iteración o el bucle completo. El uso de continue es interesante cuando dentro del blucle se comprueban ciertas condiciones que nos indicarán si el dato tratado en la iteración nos interesa o no, en caso de no quere tratarlo podemos ejecutar la instrucción continue para seguir con la siguiente iteración ahorrandonos el coste computacional del resto del cuerpo del bucle. El uso de break es muy útil en situaciones en las que buscamos un elelmento determinado dentro de una colección, en el momento que lo encontremos ejecutaremos un break y abortaremos la ejecucion del resto de iteracioen del bucle.

 List lista = new ArrayList();
// inicializacion del list con 10 elementos.
lista.put("1");
...
lista.put("10");
int size = lista.size();
for (int i=0; i<size;i++){
String element = lista.get(i);
if (element.equals("1")){
continue;
}
if (element.equals("5")){
break;
}

}

Como vemos inicialmente el bucle debería ejecutarse 10 veces, pero como estamos buscando el elemento 5 solo se ejecutara cinco veces, además de eso el primer elemento no comprobará la segunda condición ya que nos saltamos la iteración.

lunes, 27 de abril de 2009

Optimización de código

Durante el tiempo que llevo desarrollando software uno de los aspectos que mejor se me ha quedado grabado en la mente. En los inicios todo desarrollador novato se siente contento tan sólo con que su código funcione y "haga lo que debe". Pero con el transcurso del tiempo uno se va dando cuenta que una aplicación informática no sólo debe hacer lo que debe sino que debe hacerlo rápido y con el menor consumo de recursos de la máquina posible.

Personalmente los retos importante de optimización a los que me he enfrentado los he encontrado en dos aplicaciones de naturaleza distinta. La primera de ellas una aplicación de tratamiento de imágenes ecográficas desarrollada en C++. La segunda una aplicación web RIA (Rich Internet Application) desarrollada en Flex y que usa servicios Java. En ambos casos casos le hecho de tener un código ineficiente puede suponer que la aplicación no sea usable. En el primer caso, puedo decir que el tratamiento de imágenes es muy costoso y se basa en convoluciones de matrices, por lo tanto optimizar dichas operaciones puede suponer una disminución del coste y sobre todo del tiempo de espera para obtener los resultados. En el segundo caso el problema es obvio, si hemos decidido desarrollar una aplicación rica es porque queremos que la "experiencia del usuario" (User Experience o UX) sea de calidad. Un código poco optimizado puede arruinar esa "experiencia de usuario". Por tanto, en adelante trataré de describir mis experiencias optimizando código así como el uso de algunas herramientas para dicha labor.

A la hora de optimizar el código tenemos dos grandes bloques principalmente: la optimización de la velocidad y la optimización de los recursos

Optimización de velocidad

Se basan en optimizar el código eliminando código inútil y/o redundante para que las operaciones se realicen los más rápidamente posible.

Las técnicas más básicas y obvias de este tipo son:
  • Eliminar código innecesario. Muchas veces se deja código que no hace nada pululando por ahí.
  • Encapsular la funcionalidad en Funciones/procedimientos adecuadamente.
  • No realizar llamadas innecesarias.
  • Optimización de bucles. Controlar el número de iteraciones, para no iterar innecesariamente y sacar el código que no sea especifico del bucle.
  • Restringir el uso de operaciones de Strings. Las concatenaciones y extracciones de string son bastante costosas.
  • Pasar objetos por referencia mejor que por valor, ya que nos ahorramos copiar el objeto.
  • Minimizar el acceso a disco.
Optimización de recursos
En este caso lo que queremos es que la funcionalidad se desempeño usando el mínimo numero de recursos como la memoria y liberando todos los recursos no usados al finalizar evitando fugas de memoria (memory leaks), que progresivamente ralentizarán la aplicación y pueden llegar a colgarla.
Las técnicas más básicas y obvias de este tipo son:
  • Liberar los recursos (memoria) una vez se termina de usar. Dicho así puede parecer fácil, pero dependiendo del lenguaje que usemos la cosa puede complicarse, más adelante explicare las complicaciones que pueden darse en un entorno Flex al tratar con componentes de la interfaz gráfica.
  • Intentar que nuestros módulos/librerías tengan el menor tamaño posible.
  • Si usamos librerías/módulos parcialmente no tenemos por que cargar todo, cargaremos sólo lo que usaremos.
En adelante iré publicando algunos artículos sobre mis vivencias con la optimización de código, espero que les ayude.

martes, 14 de abril de 2009

Iniciación a Maven 2 (Parte 2)

Retomamos la iniciación a Maven donde la habíamos dejado, hablando del fichero POM.

El Fichero POM
Como ya habíamos comentado anteriormente el fichero POM (Project Object Model) es un fichero XML donde podemos configurar nuestro proyecto con Maven. El fichero pom.xml más básico sería algo así:


Como vemos, hemos configurado el proyecto para crear un Jar cuyo nombre es ejemploMaven y que se encuentra en el paquete fraguaDigital.ejemplos, además hemos definido que se trata de la versión 1.0-SNAPSHOT (una versíón snapshot es una versión Beta que no es definitiva). Asimismo, hemos definido un nombre para el proyecto y una url.

El otro apartado interesante de este pom.xml inicial son las dependencias, en este caso de ejemplo hemos añadido una dependencia con la librería JUnit en su versión 3.8.1. Maven intentará resolver esta dependencia desde nuestro repositorio local (usualmente en C:\Documents and Settings\Usuario\.m2\repository, pero puede ser configurado para que este en otra ubicación). Como es obvio la dependencia debe encontrarse en el repositorio, ya sea por que la hemos instalado manualmente (usando mvn install) o porque la ha descargado de un repositorio de internet. Podemos definir los repositorios de internet que usaremos añadiendo en el pom.xml:

Existen muchos repositorios maven en internet, incluso podremos crearnos uno propio (esto lo trataremos más adelante). Algunos de los repositorios Maven que más he usado son:
Y para buscar las dependencias y sus versiones concretas podemos usar Maven Repository

Compilar el proyecto
Para compilar el proyecto tán sólo debemos situarnos en el directorio principal del proyecto (el que contiene el pom.xml) y ejecutar el comando:
   mvn compile

Con esto generará una carpeta target que contendrá las classes y recursos.

Si lo que queremos es generar el paquete (Jar, War, etc...) ejecutaremos:
   mvn package


Integración con IDEs
Todo esto está muy bien para gestionar la creación de los paquetes dependenicas, etc, pero a la hora de trabajar lo usual es usar un IDE tipo Eclipse o IDEA. Maven nos permite generar un proyecto para estos IDEs usando los comandos:
   mvn eclipse:eclipse
mvn idea:idea

Pero para poder hacer esto previamente debemos definir en el pom.xml que usaremos el plugin adecuado, por ejemplo si usamos eclipse añadiremos:

En este caso hemos definido en la configuración que el la naturaleza del proyecto es Spring, pero eso puede cambiarse en la configuración. La configuración para el plugin podemos verla aquí.

Con esto creo que ya está bien por hoy, en articulos futuros hablaremos de los plugins, que dan gran funcionalidad a Maven.

Saludos.

martes, 7 de abril de 2009

Iniciación a Maven 2 (Parte 1)

Maven es una herramienta para gestíón y construcción de proyectos creada por Jason van Zyl, de Sonatype, en 2002. Inicialmente se concibio como una herramienta para gestionar proyectos Java, pero actualmente podemos gestionar también otro tipo de proyectos (personalmente la he usado con proyectos Java y Flex).

Puede que estén pensando que es otra herramienta tipo ANT (Apache), inicialmente era así, pero actualmente Maven 2 es una herramienta mucho más evolucionada y posee una gran cantidad de plugins que permiten hacer todo tipo de cosas (ya hablaremos de los plugins más adelante). La versión actual de Maven es la 2.1.0.

Una de las mayores ventajas de Maven es la posibilidad de usarlo en red, es decir, podemos definir una serie de repositorios a los que acudir cuando nuestro proyecto necesite algún recurso. Estos recursos pueden ser de terceros o propias plugins para maven , como librerías (Jar para Java y Swc para Flex). Incluso podremos definir un repositorio propio en la que desplegar nuestras librerías y así compartirlas con los miembros de un grupo de trabajo.

Las partes del ciclo de vida principal del proyecto Maven son:
1. compile
2. test
3. package
4. install
5. deploy

La idea es que al ejecutar una meta (goal) se ejecutarán todas las anteriores, si alguna de ellas fallará se pararía el proceso informando del error.
Por ejemplo, cuando se ejecuta mvn install Maven verificará si mvn package ha sido ejecutado exitosamente (el archivo jar existe en target/), en cuyo caso no será ejecutado otra vez.

Existen otras metas fuera del ciclo de vida de Maven y se puede ir añadiendo más metas mediante la configuración de plugins en el fichero de configuración. Una de estas metas de bastante importanciós es clean.

Instalación de Maven
Instalar Maven es extremadamente fácil, tan sólo es necesario ir a la sección de descargas de la página oficial de Maven (http://maven.apache.org/download.html)
y descargarlo (en zip o tar). Lo descomprimimos en una carpeta (P.Ej: C\Tools\Maven-2.1.0) y a continuación hemos de añadir la
carpeta bin de Maven en la variable de entorno PATH. Con esto ya estaría instalado. Para comprobar que todo ha ido bien podemos ejecutar el comando "mvn --version"

Creación de un proyecto
Una característica muy destacable de Maven es que nos permite crear un proyecto a partir de un arquetipo previamente definido, pero no necesariamente por nosotros. la lista de arquetipos podemos verla en aquí. Si nos fijamos en la lista podemos ver que con un simple comando podemos crear toda la estructura de un proyecto JSF, Spring, Struts y/o otros muchos más, y con cierta funcionalidad.
Por ejemplo, el comando para crear proyecto con el arquetipo de Spring es el siguiente:

mvn archetype:create -DgroupId=org.appfuse.archetypes -DartifactId=appfuse-basic-spring


Ésto no implica que no podamos partir desde cero, pero si tenemos en mente un cierto tipo de aplicación la puesta en marcha del proyecto será mínima.

Para crear un proyecto tán solo es necesario crear a mano la estructura de directorio que deseemos y crear el fichero POM en el directorio padre. La estrcutura típica es la siguiente

EjemploMaven
+---src
¦ +---main
¦ ¦ +---java //Para nuestros fuentes
¦ ¦ +--- paquetes
¦ ¦ +---...
¦ ¦ +---App.java
¦ +---test
¦ ¦ +---java //Para test de Junit
¦ ¦ +---paquetes...
¦ ¦ +---...
¦ ¦ +---AppTest.java
+---pom.xml


En paralelo a estos directorios y si lo necesitamos, podemos crear otros directorios. El nombre de estos nuevos directorios es standard en maven, el estandar lo podemos ver aquí.

El Fichero POM
Para usar maven en un proyecto tán sólo es necesario definr un fichero POM (Project Object Model), que es un fichero XML. Es el fichero de configuración de Maven donde inicialmente definiremos:
* El tipo de empaquetamiento (Jar, War, etc).
* Los directorios de fuentes y test.
* Los directorios de recursos para la aplicacion y los test.
* Las dependencias de nuestro proyecto

Además en este fichero definiremos todos los plugins, metainformación sobre desarrolladores, propiedades del proyecto etc.
--------

Como vemos Maven es un mundo muy interesante, pero muy extenso y como veo que el post esta cerciendo demasiado dejaré la configuracón del fichero pom y los comandos para la siguiente vez.

Saludos, nos vemos en la segunda parte.

sábado, 4 de abril de 2009

Integración BlazeDS con Spring

Una muy buena noticia, para todos los desarrolladores Flex que usamos BlazeDS para comunicarnos con un servidor Java, Spring esta desarrollado "Spring BlazeDS Integration".

Este proyecto nos simplificará enormemente la vida a la hora de conectar una aplicación Flex a un servidor Java desarrollado con Spring. Simplificará mucho los ficheros de configuración, la cuál la realizaremos creando beans (sintaxis < bean>).

Aún esta en Milestone 2, pero ya se plantea liberala como RC1 (Release Candidate 1). Entre otras cosas permitirá definir el messageBroker, los remote objects, pero sin lugar a dudas el aspecto que más me ha gustado viendo la documentación de referencia es que también incluirá la configuración para Spring Security (anteriormente conocido como Acegi Security). Con lo cuál podremos asegurar de forma simple nuestras aplicaciones Flex.

Podemos ver el anunció en la página oficial de Spring. En dicha página también podemos encontrar este enlace a adobeTV, en el que Christophe Coenraets hace una gran introducción a Spring BlazeDS Integration.

P.D: Spring security nos da funcionalidades de autorización y autentificación para el uso de nuestros servicios, pero eso ya lo explicaremos en otros post.

Saludos.

miércoles, 1 de abril de 2009

Vistas materializadas en Hibernate

Recientemente he descubierto las posibilidades de una característica de Hibernate que puede parecer obvia para todos aquellos usuarios avanzados, pero que no lo es tanto y que además puede pasarse por alto fácilmente en la documentación.

Hibernate permite crear vistas de datos (una query precalculada) en el mapping de un objeto, pero la gran virtud que le encuentro a este mecanismo es la posibilidad de crear vistas materializadas (en Oracle se llama así), que no es otra cosa sino una vista de datos que crea una tabla que se actualiza al trabajar con la vista.

En el mapping podemos definir la vista como una consulta SQL en el tag subselect y user el tag synchronize para definir las tablas con las que sincronizaremos la vista.

Veamos un ejemplo extraido de la documentación de hibernate (apartado 5.1.3)