jueves, 13 de julio de 2017

Mi estrategia para generar Ahorro

Hoy se cumple un año desde que me dispuse iniciar un agresivo plan de ahorros, no hace falta mencionar la importancia de contar con un ahorro o de disminuir gastos para cubrir una deuda, en mi caso para primeramente reducir una deuda. Aquí les comparto algunas acciones que he tomado, no necesariamente están ordenados.

1.- Usar la bicicleta para ir de la casa al trabajo
Si si, ya se que viajar en bicicleta es peligroso, pero según mi experiencia esto es más que un mito, al menos en Santiago de Chile hay una gran libertad para moverse en bicicleta.

Costo de viajar en metro

ConceptoMonto
Diario x 21 480
Semanal x 57 400
Mensual x 429 600
Anual x 12355 200
TOTAL355 200

Costo de Viajar en Bicicleta


ConceptoMonto
Bicicleta MTB210 000
Candado18 000
Refaccion Frenos11 500
Refaccion Frenos6 900
TOTAL246 400
Si consideramos el costo de la bicicleta dentro del gasto, tenemos:
Ahorro = 355 200 - 246 400 = 108 800

Si sólo consideramos el gasto en refacciones para el mantenimiento, tenemos:
Ahorro = 355 200 - 18 400 = 336 800

Como pueden observar, incluso considerando el costo de la bicicleta + candado, se obtiene un ahorro considerable.

2.- Elegir sabiamente la tarjeta de credito
En el mundo globalizado en el que vivimos contar con una tarjeta de credito se vuelve una necesidad, las tarjetas de credito tienen costos asociados, después de mucho investigar me quedo con dos tarjetas de credito, ademas les explicaré un truco qué encontré.

Tarjeta Lider Mastercard Preferente


InstituciónLider - WalmartObservaciones
Costo de mantencion0
Comision compra internacional0
Seguros Integrales0
Seguro desgravamen700No es obligatorio pero es recomendable
Beneficios- Se puede pagar en caja y
con otra tarjeta de credito
como medio de pago

Tarjeta Santander 3 2 1

InstituciónSantander
Costo de mantencion0Hay que tener buen historial y llorarle al
banco para lograr este beneficio
Comision compra internacional3,50%No usarla para compras internaciones
Seguros Integrales0
Seguro desgravamen0
BeneficiosDevuelve el 3% en las compras en Combustible (hasta $3.000 todos los meses)
Devuelve el 2% en las compras en Grandes Tiendas (hasta $8.000 todos los meses)
Devuelve el 1% en las compras en Supermercados (hasta $4.000 todos los meses)
En total, devuelve hasta $15.000 todos los meses y hasta $180.000 al año

El truco que yo aplico es usar la tarjeta lider para todas mis compras y pago el monto facturado en caja con la tarjeta de santander, al pagar en caja se considera un gasto del rubro Supermercados y me devuelven el 1% 


lunes, 10 de julio de 2017

Java Swing: SwingWorker y el hilo que despacha los Eventos

Concurrencia en Swing
Cuando programamos aplicaciones con componentes Swing, debemos tener mucho cuidado con la concurrencia(ejecutar más de una tarea en paralelo). Un programa Swing diseñado correctamente es aquel que usa la concurrencia para crear una interfaz de usuario que no se "congele" mientras que el programa ejecuta una tarea que toma mucho tiempo. El programa siempre está disponible para responder a las peticiones del usuario, no importa lo que esté haciendo. Para crear un programa responsive(que reacciona rapidamente y positivamente) el programador debe aprender como el framework Swing emplea los hilos.
Un programador Swing trata con los siguientes tipos de hilos:

  • Hilos iniciales, el hilo que inicia la ejecución del codigo de la aplicación.
  • El hilo que despacha los eventos(EDT), donde todo el código que maneja eventos es ejecutado. La mayoria del código que interactua con componentes Swing debe ser ejecutado en este hilo.
  • Hilos Background(Worker Threads), donde aquellas tareas que consumen un tiempo considerable(más de un segundo para mi criterio) son ejecutadas.

El programador no necesita explicitamente codificar la creación de estos hilos: El trabajo del programador es utilizar estos hilos para crear un programa Swing mantenible y responsive.
Como cualquier otro programa corriendo en la plataforma Java, un programa Swing puede adicionalmente crear otros hilos y pools de hilos, siempre y cuando se maneje correctamente la concurrencia.

El fragmento de código del siguiente programa no maneja correctamente la concurrencia

/**
 *
 * @author Roberto Lopez
 */
public class WrongSwingProgram {
 
 public static void main(String args[]){
  final JLabel label = new JLabel();
  
  Thread anyThread = new Thread(new Runnable() {
   @Override
   public void run() {
    label.setText("Hola mundo!!");
    label.setPreferredSize(new Dimension(150, 32));
   }
  });
  
  anyThread.start();
 }
}

El componente Swing label está siendo manipulado por el código que será ejecutado en el hilo anyThread, un hilo que no es el hilo EDT, esto puede generar inconsistencias ya que más de un hilo puede manipular el estado del objeto. Más adelante veremos cómo manejar correctamente la concurrencia en programas Swing.

Hilos Iniciales
Todo programa tiene asociado un conjunto de Hilos que se inician junto con el programa. En un programa estandar solo se tiene un hilo, el hilo que invoca al metodo main de la clase. En applets uno de los hilos inicial es aquel que construye el objeto apple e invoca a los metodos init y start; estas acciones pueden ocurrir en un solo hilo,  o en dos o tres diferentes hilos, dependiendo de la implementación de la plataforma Java. A estos hilos se les llama Hilos Iniciales.

En programas Swing, el hilo inicial no tiene mucho que hacer. La mayor parte del trabajo consiste en crear un objeto Runnable que inicializa la GUI y programa su ejecución en el hilo de eventos EDT, mas adelante explicaré en detalle el hilo de eventos.
Una vez que la GUI esta creada, el progama es principalmente manejado por eventos GUI, cada uno de los cuales ejecutan una tarea corta en el hilo de eventos. Encolar tareas en hilo de eventos sin que necesariamente sean eventos es posible, ya que no existe restricción, sin embargo deben ser tareas que consuman muy poco tiempo, menos de un segundo a mi criterio, así no interferimos con el procesamiento de eventos, para tareas que demanden más de un segundo de tiempo sera necesario usar un hilo worker.

Un hilo inicial encola la tarea que crea la GUI (en el hilo de eventos) invocando a javax.swing.SwingUtilities.invokeLater o javax.swing.SwingUtilities.invokeAndWait. Ambos metodos toman un solo argumento: el objeto Runnable que define la nueva tarea. La unica diferencia la podemos deducir por sus nombres, invoqueLater simplemente encola la tarea en el hilo EDT y regresa; invoqueAndWait espera hasta que la tarea termine y solo cuando esta haya terminado regresa.

Por qué no simplemente es el hilo inicial el encargado de crear la GUI? Esto se debe a que la mayoria del codigo interactua con componentes Swing debe ser ejecutado en el hilo que despacha eventos. Esta restricción será explicada más adelante.

El hilo que despacha eventos EDT
El código que maneja los eventos Swing se ejecuta en un hilo especial conocido como el hilo que despacha los eventos. La mayoría del código que invoca metodos de componentes Swing también se ejecutan en este hilo. Esto es necesario porque la mayoria de los componentes Swing no son "thread safe": acceder a estos metodos desde varios hilos es peligroso, los hilos pueden modificar el estado del objeto uno sobre otro o errores de consistencia de memoria (diferentes hilos tienen una vista inconsistente de lo que debería ser el mismo dato). Todo código que accesa o invocación de metodos de componentes Swing debe ser ejecutado desde el hilo que despacha los eventos. Programas que ignoren esta regla pueden funcionar correctamente la mayor parte del tiempo, pero están sujetos a comportamientos y errores impredecibles que son dificiles de reproducir.

Es útil pensar en los códigos que se ejecutan en el hilo que despacha los eventos como un conjunto de tareas pequeñas. La mayoria de estas tareas son invocaciones de metodos que manejan eventos tales como ActionListener.actionPerformed. Otras tareas pueden ser encoladas en el hilo mediante el código de la aplicación, usando invoqueLater o invoqueAndWait.
Las tareas a ejecutarse en el hilo que despacha eventos debe terminar muy rapidamente, de no ser así se corre el riesgo que el hilo no esté disponible para ejecutar los eventos de la interfaz de usuario.
Si necesitas determinar si tu codigo está siendo ejecutado por el hilo que despacha eventos, invocar a javax.swing.SwingUtilities.isEventDispatchThread.

Worker Threads y SwingWorker
Cuando un programa Swing necesita ejecutar una tarea que consume un tiempo considerable (más de un segundo a mi criterio), generalmente usaremos un WorkerThread, también conocido como un background thread. Cada tarea corriendo en un worker thread es representado por una instancia de javax.swing.SwingWorker. SwingWorker es una clase abstracta; debes crear una subclase para crear tu propio SwingWorker y poder crear instancias; las clases internas son muy usadas para crear objetos SwingWorker simples.

SwingWorker proporciona un conjunto de caracteristicas de control y comunicación:

  • La subclase SwingWorker puede sobreescribir al metodo done, que es automaticamente invocado y ejecutado en el hilo que despacha los eventos, se llama cuando la tarea a ejecutar ha finalizado.
  • SwingWorker implementa a java.util.concurrent.Future. Esta interfaz permite a la tarea que se ejecuta en modo background retornar un valor a otro hilo. Otros metodos en esta interface permite cancelar la tarea y consultar por el estado de la tarea, saber si ha finalizado o fue cancelado.
  • La tarea ejecutándose en background puede entregar resultados del avance de la tarea, invocando a SwingWorker.publish, haciendo que se invoque a SwingWorker.process sobre el hilo que despacha los eventos.
  • La tarea ejecutándose en background puede definir un conjunto propios de propiedades. Cambios sobre estás propiedades disparan eventos, los metodos del manejo de eventos son ejecutados en el hilo que despacha los eventos, el EDT.
Una tarea simple que se ejecuta en modo background (en segundo plano, fuera de la GUI)

Vamos a empezar con a una tarea que es muy simple pero que puede consumir un buen de tiempo en ejecutarse. La clase TumbleItem carga un conjunto de imagenes que se usaran en una animación. Si los archivos de las imagenes son cargados desde un hilo inicial (el hilo main, por ejemplo), pasará un buen tiempo antes que la GUI se muestre. Si los archivos de las imagenes son cargados desde el hilo que despecha los eventos EDT, la GUI quedará congelada temporalmente y no responderá a otros eventos.
Para evitar estos problemas, TumbleItem crea y ejecuta una instancia de SwingWorker desde el hilo inicial. El metodo doInBackground, ejecutandose en un WorkerThread, carga las imagenes dentro un arreglo de ImageIcon, y devuelve una referencia del arreglo. Entonces, el metodo done se ejecuta en el Hilo que despacha los eventos, para recuperar la referencia al arreglo invocamos el metodo get. Cargar las imagenes en modo background permitirá construir y visualizar inmediamente la GUI, sin tener que esperar a que la carga de imagenes termine.

Aquí el código que define y ejecuta el objeto SwingWorker.


SwingWorker worker = new SwingWorker<ImageIcon[], Void>() {
    @Override
    public ImageIcon[] doInBackground() {
        final ImageIcon[] innerImgs = new ImageIcon[nimgs];
        for (int i = 0; i < nimgs; i++) {
            innerImgs[i] = loadImage(i+1);
        }
        return innerImgs;
    }

    @Override
    public void done() {
        //Remove the "Loading images" label.
        animator.removeAll();
        loopslot = -1;
        try {
            imgs = get();
        } catch (InterruptedException ignore) {}
        catch (java.util.concurrent.ExecutionException e) {
            String why = null;
            Throwable cause = e.getCause();
            if (cause != null) {
                why = cause.getMessage();
            } else {
                why = e.getMessage();
            }
            System.err.println("Error retrieving file: " + why);
        }
    }
};



El poyecto completo lo puedes descargar desde mi repositorio en GitHub

Toda clase concreta que extienda de SwingWorker debe implementar el metodo doInBackground; la implementación del metodo done es opcional.
Observa que SwingWorker es una clase generica, con dos tipos de parametros. El primer tipo de parametro especifica el tipo que retornará el metodo doInBackground, y también para el metodo get, que es invocado por otro hilo que recibe el objeto retornado por doInBackground. El segundo tipo de parametro de SwingWorker especifica un tipo para resultados preliminares que son retornados mientras la tarea en background todavía está activa.
Para este ejemplo no retornamos resultados preliminares así que especificamos el tipo Void, mas adelante sacaré una nueva versión con resultados preliminares.
Es posible que te preguntes si el codigo que obtiene el arreglo de iconos imgs es innecesariamente complicado. ¿Por qué hacemos que doInBackground retorne un objeto y usamos el metodo done para recuperarlo? ¿Por qué no solo obtenemos el arreglo imgs directamente del metodo doInBackground? El problema es que el objeto imgs  es creado en el hilo worker y usado en el hilo que despacha los eventos. Cuando los objetos son compartidos entre hilos siguiendo esta forma, nos aseguramos que los cambios hechos en un hilo son visibles en los otros. Usando get lo garantizamos, porque usando get creamos una relación happens before(relación entre el resultado de dos eventos, tal que uno de estos eventos debe ocurrir antes que otro evento) entre el codigo que crea el arreglo imgs y el codigo que lo usa.
Actualmente hay dos formas de recuperar el objeto retornado por doInBackground.


  • Invocando SwingWorker.get sin argumentos. Si la tarea en background no ha finalizado, get bloquea el hilo hasta que termine la tarea.
  • Invocando SwingWorker.get con argumentos indicando un time-out. Si la tarea en background no ha finalizado, el metodo get bloquea el hilo hasta que termine la tarea - al menos que el time-out expire primero, en ese caso get lanza una Excepción java.util.concurrent.TimeoutException.

Hay que tener cuidado cuando se invoque al metodo get desde el hilo que despacha los eventos. Hasta que get retorne, la GUI no podrá procesar más eventos, y la GUI quedará "congelada". No invoque el metodo get sin argumentos al menos que estes completamente seguro de que la tarea en background ha finalizado completamente.

Referencia
https://docs.oracle.com/javase/tutorial/uiswing/concurrency/index.html

martes, 20 de junio de 2017

Conquistando la cima del Manquehuito

Hace meses que me nació el deseo de tomarme una foto con la imponente cordillera detrás de mi, la universidad, el trabajo y la salud, me lo habían estado impidiendo. Me puse a buscar un lugar que fuera fácil de acceder y que permitiera contemplar la cordillera. Recordé que había escuchado del cerro Manquehuito, en voz de un excompañero de ciclismo. Este domingo justo coincidió con un sábado de lluvia, era el día perfecto, tenía que subir.


Llamé a mi amigo Pablo Veneno, un cuate aperrado, que disfruta de los retos, quien prefiere un día de actividad a una noche de fiesta mientras te emborrachas hasta el amanecer. No me defraudó y acepto acompañarme.
Sábado en la noche, fui a una fiesta, esta vez me propuse no tomar nada de alcohol y me mantuve firme, nada de alcohol. Disfruté del ambiente, de la comida y del baile. Me retiré temprano para reponer energía y partir al cerro el domingo en la mañana.
Domingo en la maña me despierto temprano, saco a pasear a mi perrito Tommy, desayuno y preparo la mochila, llevo frutas como plátano y naranja, un litro de agua (debí haber llevado 2 litros), galletas y una colación.
Al llegar al punto de encuentro donde quede de juntarme con Pablo, me llevé una grata sorpresa, se habían unido más personas, incluso uno de ellos ya había hecho el recorrido por lo que su experiencia fue bien recibida.
Por fortuna el transporte publico te deja muy cerca del sendero para subir al cerro, caminamos no más de 2 horas, un camino muy empinado, fuimos despacio, a nuestro ritmo. Mientras caminaba, pensaba en que quizás no lograría llegar a la cima, el viento, el frió y un malestar en la garganta complicaban el camino. Pero a pesar de dar pasos lentos y pequeños, mientras transcurría el tiempo estábamos cada vez más cerca de la cima, así hasta que finalmente llegamos.
Una vez arriba, se siente el aire limpio al respirar, estar ahí valió todo el esfuerzo, aire limpio y una vista espectacular, de hecho mientras escribo estás lineas recuerdo perfectamente cada detalle, el dolor en las piernas, el frió, el viento helado y la garganta con dolor, pero nada de esto importaba, ya estaba en la cima, eso era lo que importaba.
El descenso fue más rápido, pero las piernas flaqueaban, el frió aumentaba, estaba agotado pero feliz, sentir que logré cumplir mi deseo, tomarme una foto con la cordillera de fondo.
Total gastado: 5 USD












domingo, 23 de abril de 2017

Punto de Inflexión en mi vida

Este año viene acompañado de muchas decepciones, estoy decepcionado de mi mismo, de mi persona, de lo que soy y de lo que tengo. Creo que decepcionarse de uno mismo no es malo, lo malo es saberlo y no actuar. He llegado a aceptar que pareciera que durante casi 30 años he estado dormido mientras el mundo avanzaba, y de pronto despierto, mi burbuja se rompe y me enfrento a la realidad, a un mundo salvaje. Te sientes decepcionado cuando descubres que no estás preparado para hacerle frente a las adversidades de la vida, que mientras el mundo evolucionaba tu te dormías. Pero ya desperté y ahora tengo un deseo ferviente de cambiar, de darle un giro inesperado a mi vida y avanzar hacia objetivos definidos.
Voy a iniciar un largo camino para adquirir nuevas habilidades, un camino en el que el esfuerzo, sacrificio y dedicación son fundamentales.

El reto para la primera semana será llegar puntual y bien presentable al trabajo

jueves, 9 de marzo de 2017

Java: Leer una cadena desde consola e imprimirla al reves

Es muy común en las clases de programación de Java el solicitar un programa que lea una cadena desde la consola y luego la imprima al reves. Para ello podemos hacerlo de dos formas, la primera es usar la clase StringBuilder, la segunda es desarrollar un metodo propio. Aquí les dejo un programa en en Java que usa las dos formas.


/*
 * Tutorials
 * Copyright (C) 20017 Roberto Lopez marcos.roberto.lopez@gmail.com
 * 
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 * 
 * Roberto Lopez
 * CDMX, México
 * https://marcosrobertos.blogspot.com
 * Email: marcos.roberto.lopez@gmail.com
 */
 
package com.rlopez.tutorials.string;

import java.util.Scanner;

/**
 *
 * @author Cliente
 */
public class ReverseString {
   public static void main(String args[]){
      System.out.println("Ingresa una palabra [presione enter para confirmar]");
      Scanner scanner = new Scanner(System.in);
      String world = scanner.nextLine();
      //first way create a string builder instance, reverse the same instance
      //of string builder
      System.out.println("Reverse using StringBuilder.reverse(): "
      + (new StringBuilder(world).reverse()));
      //second way use my own method, reverse and return a new instance of
      //string
      System.out.println("Reverse using my owner reverse(): "
      + (ReverseString.reverse(world)));
   }
   
   public static String reverse(String toReverse){
      char characters[] = new char[toReverse.length()];
      int j = 0;
      for(int i = toReverse.length() - 1; i >= 0; i--){
         characters[j++] = toReverse.charAt(i);
      }
      return new String(characters);
   }
}

Salida:

compile-single:
run-single:
Ingresa una palabra [presione enter para confirmar]
Hola buenos días
Reverse using StringBuilder.reverse(): saíd soneub aloH
Reverse using my owner reverse(): saíd soneub aloH

viernes, 24 de febrero de 2017

Instalar Oracle Java JDK8 en Ubuntu 16.04

Introducción

Me ausente de Linux por un periodo de 5 años, hoy regreso y lo encuentro mucho más guapo, he decidido volver. Como fanático de la programación lo primero que haré será instalar Java + Netbeans. Ubuntu por defecto viene con OpenJDK, en el pasado tuve malas experiencias con OpenJDK, prefiero instalar el JDK de Oracle.

Paso 1. Verificar que JDK tenemos

La instalación de Ubuntu que tengo no viene instalado con el OpenJDK, para ver si tenemos alguna versión instalada ejecutamos lo siguiente:














En caso de tener instalado el OpenJDK, hay que desinstalarlo, para hacerlo seguir este tutorial


Paso 2. Agregamos el repositorio de Java a nuestra lista de fuentes


Agregamos el repositorio a nuestra lista de fuentes, ejecutar el siguiente comando:















Nos pide confirmación para continuar, presionar enter para continuar














Si todo va bien veremos esta última pantalla













Paso 3. Actualizamos nuestra lista de fuentes

Para actualizar nuestra lista de fuentes ejecutamos lo siguiente:










Al terminar veremos la siguiente pantalla

















Paso 4. Instalar Java JDK 8

Ejecutamos el siguiente comando







Nos pedirá confirmación, presionar Y y luego enter













Nos advierte que debemos aceptar la Licencia















Aceptamos la Licencia













Esperamos unos minutos y al terminar muestra la siguiente pantalla














Tomar nota del mensaje con el titulo "important", para no tener ningún conflicto vamos a instalar lo que nos pide







Al finalizar veremos la siguiente pantalla













Reiniciamos el equipo y comprobamos la instalación, ejecutamos los siguientes dos comando














Así hemos finalizado con éxito la instalación de Oracle Java JDK 8 en Ubuntu 16.04

viernes, 17 de febrero de 2017

Maven: Que es?

Introducción

Hace ya un par de meses que decidí estudiar la plataforma JEE, la mayoría de los tutoriales que hay en la web están basados en Maven, la mayoría de esos ejemplos no funcionan a la primera ya que los archivos de configuración de Maven pueden estar obsoletos, diferencias entre el ambiente,distinto IDE, diferentes versiones de los componentes, y así. Hay que tener conocimientos sólidos en Maven para adaptar los tutoriales a nuestro ambiente particular.

Es así que decidí estudiar Maven a profundidad, hay un buen número de tutoriales y referencias en la web en español, pero no encontré uno escrito a profundidad, que explique con lujo de detalle todos los conceptos. He obtenido un libro muy completo de Maven, está en ingles, trataré de traducirlo para tenerlo como guía y aprender todos los conceptos de Maven.

¿Qué es Maven?

La respuesta a esta pregunta depende de quien lo pregunte, la mayoría de los usuarios que usan Maven lo consideran cómo una "herramienta build": herramienta usada para compilar, empaquetar y distribuir módulos desde el código fuente. Ingenieros y gerentes de proyectos podrían referirse a Maven cómo algo más completo: una herramienta de gestión(administración) de proyectos. ¿Cual es la diferencia? Una herramienta build como Ant, está enfocado exclusivamente en pre procesar, compilar, empaquetar, probar y distribuir. Una herramienta de gestión de proyectos cómo Maven proporciona un amplio conjunto de características encontrados en una herramienta build, es decir, es una herramienta build y algo más. Además de ser una herramienta build, Maven también puede generar distintos tipos de reportes, generar sitios web, y facilitar la comunicación entre miembros de un equipo de desarrollo.
Una definición más formal de Apache Maven: Maven es una herramienta de gestión de proyectos, que incluye un pom (Project Object Model) el modelo de objetos del proyecto, un conjunto de estándares, un ciclo de vida del proyecto, un sistema de gestión de dependencias, y lógica para ejecutar plugins en las fases del ciclo de vida. Cuando tu usas Maven, tu describes tu proyecto usando un pom definido correctamente, después Maven aplicará lógica de forma transversal (profundidad máxima para cada objeto) al conjunto de plugins compartidos o personalizados. Más adelante veremos que son los plugins.
No dejes que te intimide el hecho de que Maven sea una herramienta de gestión de proyectos. Si sólo estabas buscando una herramienta build, Maven puede hacer el trabajo. De hecho. los primeros artículos de este libro cubrirán la mayoría de los casos de usos comunes: usando Maven para construir y distribuir tu proyecto.

Convención Sobre Configuración

Convención sobre Configuración, también conocido como CoC es un concepto simple que busca minimizar el número de decisiones que un desarrollador necesita hacer, ganando así en simplicidad pero no perdiendo flexibilidad por ello.
Frameworks populares como Ruby on Rails y EJB3 han comenzado a adquirir estos principios como respuesta a la complejidad de los frameworks, tal como es el caso de la especificación inicial EJB 2.1. Para ilustrar el concepto de Convención sobre Configuración, considere la persistencia en EJB3: todo lo que necesitas hacer para tener un bean persistente es agregar a tu clase la anotación @Entity. El framework asume que el nombre de la tabla y columnas están en base al nombre de la clase y sus atributos. Sin embargo tu puedes sobreescribir estos nombres en caso de ser necesario, pero en la mayoría de los casos encontrarás que usar el framework con sus configuraciones por defecto te permitirá una rápida ejecución del proyecto.
Maven incorpora este concepto proporcionando configuraciones y comportamientos por defecto para los projectos. Sin ninguna configuración, se asume que el código fuente estará en ${basedir}/src/main/java y se asume que los recursos estarán en ${basedir}/src/test, y se asume que un proyecto generará un archivo JAR. Maven asume que tu quieres el código byte compilado en ${basedir}/target/classes y entonces crear en ${basedir}/target un archivo JAR para distribuir. Mientras esto puede parecer trivial, considera el hecho de que en Ant se tiene que definir la ubicación de todos estos directorios. Ant no tiene idea de donde pueden estar el código fuente o los recursos en un proyecto. Tu tienes que proporcionar explicita mente esta información. La adopción del concepto Convención sobre configuración de Maven, va más allá de simple ubicaciones de directorios. Los plugins principales de Maven aplican un conjunto común de convenciones para compilar código fuente, empaquetar distribuciones, generar sitios web, y muchos otros procesos. Si tu sigues las convenciones, Maven requerirá esfuerzos mínimos, sólo coloca el código fuente en el directorio correcto y Maven se encargará del resto.
Un efecto secundario de usar sistemas que siguen el concepto de "Convención sobre Configuración" es que el usuario final puede sentir que está siendo forzado a usar un enfoque o metodología particular. Si bien es cierto que Maven tiene algunas opiniones bases que no deberían ser desafiadas, la mayoría de las características que vienen por defecto pueden ser personalizados. Por ejemplo, la ubicación  del código fuente de un proyecto y la ubicación de los recursos, estos pueden ser personalizados, los nombres de los archivos JAR también pueden ser personalizados, . Si no quieres seguir la convención, Maven te permitirá adaptar las características por defecto con tal de adaptarlos a tus requerimientos específicos.


Referencia:
Maven: The complete Reference, Sonatype, http://www.sonatype.org/nexus/resources/resources-book-links-and-downloads/