Estudio: Los programadores Java son los más infelices y los programadores Swift los más barbudos

(3 comentarios)

Vivimos en una sociedad llena de estereotipos y prejuicios, y el mundo de la programación no es una excepción: los programadores Java llevan traje y corbata, a los programadores Ruby les gustan los colores brillantes, y si programas en Haskell eres un bicho raro.

Para estudiar estas generalizaciones, y para perder un día entero de trabajo en la oficina, los chicos de Trestle Technology han hecho un pequeño estudio muy informal y nada científico usando la API de análisis de rostros de Microsoft y las fotografías de los perfiles de GitHub de cientos de programadores. Este es el resultado.

[Pulsa para continuar]

La diferencia entre Java y JavaScript

(5 comentarios)

Uno es básicamente un juguete, diseñado para escribir pequeños trozos de código, usado y abusado tradicionalmente por programadores inexpertos.

El otro es un lenguaje de script para navegadores web.

~ Shog9, en StackOverflow

Desarrollo rápido en Android con anotaciones

(4 comentarios)

Si llevas un tiempo programando en Java recordarás esas decenas de líneas de código de inicialización y aquellos enormes XML de configuración con los que teníamos que lidiar en frameworks como Spring, JPA o JSF antes de que se popularizaran las anotaciones. En Android esa tendencia todavía no ha impuesto, pero os alegrará saber que sí existen librerías externas con las que reducir enormemente el código auxiliar y centrarnos en lo que realmente importa.

La opción más interesante es AndroidAnnotations, ya que es muy completa, no impone penalización alguna en el rendimiento y no nos obliga a que nuestras actividades extiendan de una cierta clase, lo que al carecer Java de herencia múltiple complicaría ligeramente el uso de librerías como ActionBarSherlock. ¿Suena bien? Entonces genera un proyecto con AndroidAnnotations en AndroidKickstarR y sigue leyendo; te aseguro que no te vas a arrepentir.

Asociar un layout a una actividad o fragmento

Sin AndroidAnnotations:

public class Actividad extends Activity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.actividad);
    }
}

Con AndroidAnnotations podemos usar la anotación @EActivity (de enhanced activity o actividad mejorada) y pasarle el identificador del layout:

@EActivity(R.layout.actividad)
public class MyActivity extends Activity {}

De forma parecida a las actividades, con la anotación @EFragment podemos obviar el método onCreateView del fragmento. Sin AndroidAnnotations:

public class Fragmento extends Fragment {
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.fragmento, container, false);
        return view;
    }
}

Con AndroidAnnotations:

@EFragment(R.layout.fragmento)
public class Fragmento extends Fragment {
}

Inyección de vistas

Sin AndroidAnnotations:

public class Actividad extends Activity {
	Button btnGuardar;
	EditText txtNombre;

	@Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.actividad);
		
		btnGuardar = (Button) findViewById(R.id.btnGuardar);
		txtNombre = (EditText) findViewById(R.id.txtNombre);
    }
}

Con AndroidAnnotations usaríamos la anotación @ViewById pasando como parámetro el identificador de la vista

@EActivity(R.layout.actividad)
public class Actividad extends Activity {
	@ViewById(R.id.btnGuardar)
	Button btnGuardar;
	
	@ViewById(R.id.txtNombre)
	EditText txtNombre;
}

Si el nombre de la variable es igual al identificador de la vista el parámetro se puede obviar:

@EActivity(R.layout.actividad)
public class Actividad extends Activity {
	@ViewById Button btnGuardar;
	@ViewById EditText txtNombre;
}

También podemos inyectar fragmentos con @FragmentById

@EActivity(R.layout.actividad)
public class Actividad extends Activity {
	@ViewById Button btnGuardar;
	@ViewById EditText txtNombre;
	@FragmentById Fragmento fragmento;
}

Manipular las vistas

Si usamos @ViewById para inyectar la vistas, por la manera que tiene de funcionar AndroidAnnotations, no tendremos todavía las instancias asociadas en onCreate, por lo que si tenemos que hacer algo con las vistas tendremos que anotar uno o varios métodos con @AfterViews. Esto, que a alguno le puede parecer un incordio, a mí personalmente me gusta, porque prefiero extraer el resto del código a otros métodos siguiendo el Principio de Responsabilidad Única.

De esta forma un código como

public class Actividad extends Activity {
	TextView txtVersion;
	TextView txtFecha;

	@Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.actividad);
		
		txtVersion = (TextView) findViewById(R.id.txtVersion);
		txtFecha = (TextView) findViewById(R.id.txtFecha);
		
		establecerVersion();
		establecerFecha();
    }
	
	void establecerVersion() {
		try {
			PackageInfo infoPaquete = getPackageManager().getPackageInfo(getPackageName(), 0);
			txtVersion.setText(infoPaquete.versionName);
		} catch(NameNotFoundException e) {
			e.printStackTrace();
		}
	}
	
	void establecerFecha() {
		DateFormat formato = new SimpleDateFormat("dd-MM-yyyy HH:mm:ss");
		Date fecha = new Date();
		String strFecha = formato.format(fecha);
		txtFecha.setText(strFecha);
	}
}

se convertiría en lo siguiente

@EActivity(R.layout.actividad)
public class Actividad extends Activity {
	@ViewById TextView txtVersion;
	@ViewById TextView txtFecha;
	
	@AfterViews
	void establecerVersion() {
		try {
			PackageInfo infoPaquete = getPackageManager().getPackageInfo(getPackageName(), 0);
			txtVersion.setText(infoPaquete.versionName);
		} catch(NameNotFoundException e) {
			e.printStackTrace();
		}
	}
	
	@AfterViews
	void establecerFecha() {
		DateFormat formato = new SimpleDateFormat("dd-MM-yyyy HH:mm:ss");
		Date fecha = new Date();
		String strFecha = formato.format(fecha);
		txtFecha.setText(strFecha);
	}
}

Eventos

Android cuenta con un atributo XML android:onClick con el que es muy rápido y sencillo asociar un listener a un evento clic. El equivalente en AndroidAnnotations es la anotación @Click, a la que se le pasa el identificador de la vista a la que se asocia el listener (se puede obviar en caso de que el nombre del método coincida con el identificador de la vista o que sea igual pero con el sufijo Clicked).

@EActivity(R.layout.actividad)
public class Actividad extends Activity {
	@Click(R.id.button1)
	void mostrarVersion() {
		// ...
	}

	@Click
	void mostrarFecha() {
		// ...
	}

	@Click
	void guardarClicked() {
		// ...
	}
}

En este caso la ventaja de las anotaciones no es tan obvia; quizás el poder ver la asociación entre la vista y el método en un golpe de vista. Tiene mayor interés el que podamos asociar listeners para unos pocos eventos más de forma igual de sencilla, con @LongClick para pulsaciones largas o @TextChange para cambios de texto.

Menús

Con la anotación @OptionsMenu podemos inflar el XML de menú, ahorrándonos sobreescribir onCreateOptionsMenu. Con @OptionsItem asociamos las distintas opciones de menú con distintos listeners, pasando el id de la opción a la anotación (también se puede obviar el id si coincide con el nombre del método, o si es igual pero con el sufijo Selected).

Versión sin anotaciones:

public class Actividad extends Activity {
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.actividad);
	}

	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		getMenuInflater().inflate(R.menu.actividad, menu);
		return true;
	}

	
	@Override
	public boolean onOptionsItemSelected(MenuItem item) {
		switch (item.getItemId()) {
			case R.id.actualizar:
				actualizar();
				return true;
			case R.id.acercaDe:
				acercaDeSelected();
				return true;
			default:
			  return false;
		}
	}

	
	void actualizar() {
		// ...
	}	

	
	void acercaDeSelected() {
		// ...
	}	
}

Versión con anotaciones:

@EActivity(R.layout.actividad)
@OptionsMenu(R.menu.actividad)
public class Actividad extends Activity {
	@OptionsItem(R.id.actualizar)
	void actualizar() {
		// ...
	}	

	@OptionsItem
	void acercaDeSelected() {
		// ...
	}	
}

Inyección de recursos

Para cada tipo de recurso existe una anotación que permite inyectar dicho recurso en nuestra clase pasándole simplemente el identificador (o sin pasarle nada si el nombre del recurso coincide con el de la variable): AnimationRes, BooleanRes, ColorRes, ColorStateListRes, DimensionPixelOffsetRes, DimensionPixelSizeRes, DimensionRes, DrawableRes, HtmlRes, IntArrayRes, IntegerRes, LayoutRes, MovieRes, StringArrayRes, StringRes, TextArrayRes, TextRes.

De esta forma en lugar de:

String nombreApp = getResources().getString(R.string.nombreApp);

simplemente podríamos escribir:

@StringRes String nombreApp;

Además, en el caso concreto de que queramos obtener una cadena HTML de un archivo de recurso y establecerla como texto en un TextView, podemos llevar a cabo ambos pasos con una simple anotación @FromHtml.

Hilos de ejecución

¿Harto de usar AsyncTask o similares para ejecutar un cierto código en un hilo distinto del principal o de interfaz de usuario?

void ejecutarTareaSegundoPlano(URL urls) {
	new AsyncTask<URL, Integer, Long> {
		protected Long doInBackground(URL... urls) {
			int numUrls = urls.length;
			Long tamanyoDescarga = 0;
			for (int i = 0; i < numUrls; i++) {
				tamanyoDescarga += ClienteHttp.descargar(urls[i]);
				publishProgress((int) ((i / (float) numUrls) * 100));
			}
			return totalSize;
		}

		protected void onProgressUpdate(Integer... progreso) {
			actualizarProgreso(progreso[0]);
		}

		protected void onPostExecute(Long tamanyoDescarga) {
			mostrarDialogo("Descargados " + tamanyoDescarga[0] + " bytes");
		}
	}.execute();
}

¿Qué tal si pudieras usar la anotación @Background para indicar que un método debe ejecutarse en un hilo en segundo plano y @UiThread para que se ejecute en el hilo de interfaz de usuario? De esta forma el ejemplo anterior se reduciría a:

@Background
void descargarArchivos(URL urls) {
	int numUrls = urls.length;
	Long tamanyoDescarga = 0;
	for (int i = 0; i < numUrls; i++) {
		tamanyoDescarga += ClienteHttp.descargar(urls[i]);
		actualizarEstadoDescarga((int) ((i / (float) numUrls) * 100));
	}
	mostrarDialogoFinDescarga(tamanyoDescarga);
}

@UiThread
void actualizarEstadoDescarga(int progreso) {
	actualizarProgreso(progreso);
}

@UiThread
void mostrarDialogoFinDescarga(Long tamanyoDescarga) {
	mostrarDialogo("Descargados " + tamanyoDescarga + " bytes");
}

Guardar y recuperar el estado

Esta es otra de esas tareas repetitivas que suponen gran cantidad de código. Comparemos una implementación típica con su correspondiente versión con anotaciones.

public class Actividad extends Activity {
    Jugador jugador;
    int puntuacion;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        if(savedInstanceState != null) { 
            jugador = (Jugador)savedInstanceState.getSerializable("jugador");
			puntuacion = savedInstanceState.getInt("puntuacion");
        }
    }

    @Override
    protected void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        outState.putSerializable("jugador", jugador);
        outState.putInt("puntuacion", puntuacion);
    }
}
@EActivity(R.layout.actividad)
public class Actividad extends Activity {
    @InstanceState
    Jugador jugador;

    @InstanceState
    int puntuacion;
}

Otras funcionalidades de interés

  • @Trace nos permite trazar la ejecución de un método escribiendo una entrada en el log cuando se entra y se sale del método.
  • @HierarchyViewerSupport permite utilizar la herramienta Hierarchy Viewer aunque no dispongamos de un teléfono con permisos de root o de desarrollo
  • @RoboGuice nos permite integrar AndroidAnnotation con el framework de inyección de dependencias del mismo nombre (basado en Guice, de Google)
  • @OrmLiteDao nos permite integrar AndroidAnnotation con el framework de mapeo objeto-relacional OrmLite
  • @EView y @EViewGroup facilitan la creación de vistas personalizadas
  • @SystemService nos permite inyectar un servicio del sistema


El lenguaje de los grandes programadores

(49 comentarios)

Hace un par de días comenzaba una nueva edición del Code Jam de Google, la famosa competición de programación que la empresa viene organizando desde hace ya 8 años. A parte de proporcionar una gran selección de problemas con los que practicar nuestras habilidades, sus estadísticas también pueden servirnos para comprobar cuáles son los lenguajes de programación preferidos por los desarrolladores, y qué lenguajes utilizan los mejores programadores (sobre una muestra de 12.200 participantes).

[Pulsa para continuar]

Un programa escrito en Haskell, que imprime un programa en Perl, que imprime…

(21 comentarios)

¿Un programa escrito en Haskell, que al ejecutarse imprime un programa en Perl, que al ejecutarse imprime un programa en Python, que al ejecutarse imprime un programa en Ruby, que al ejecutarse imprime un programa en C, que al ejecutarse imprime un programa en Java, que al ejecutarse imprime el programa original? Sí, es como para que te duela la cabeza, aunque el código, que podéis ver después del salto, es de lo más sencillo.

Este tipo de programas que se imprimen a sí mismos como salida (aunque en este caso, con una peculiaridad extra) se conocen con el nombre de quines, en honor al filósofo estadounidense Willard Van Orman Quine.

[Pulsa para continuar]

Eclipse 3.5: Si Galileo programara en Java…

(14 comentarios)

Día grande para la comunidad Eclipse con el lanzamiento del nuevo Eclipse 3.5 (Eclipse Galileo) y 32 proyectos más relacionados. Las novedades, que son muchas, en Eclipse 3.5 – New and Noteworthy.

Eclipse 3.5, Galileo

Java vs. Python

(67 comentarios)

Tengo la impresión de que Java fue diseñado para hacer que fuera difícil escribir mal código, mientras que Python está diseñado para hacer que sea sencillo escribir buen código.

— Magnus Lycka

Ofuscar código Java

(32 comentarios)

Asumámoslo: es imposible proteger al 100% nuestro código de miradas indiscretas. Pero eso no implica que no podamos dificultar un poco el proceso de decompilar nuestro código. Y este es el objetivo de los ofuscadores de código.

Un ejemplo de este tipo de herramientas es la aplicación GPL ProGuard que permite, además de ofuscar nuestras clases Java, optimizarlas, comprimirlas y añadirles información de preverificación, de forma que la carga de las clases en Java SE 6 y Java ME 6 sea más rápida y más eficiente.

La herramienta funciona buscando primeramente clases, campos, métodos y atributos no utilizados, los cuáles elimina; pasa entonces a optimizar el bytecode y eliminar instrucciones innecesarias; y, por último, elimina la información de depuración y renombra las clases, campos y métodos restantes utilizando nombres cortos y poco legibles.